From fd618e37e772ac7b78c91ff2464485c4e758a527 Mon Sep 17 00:00:00 2001 From: DeltaW0x Date: Tue, 10 Dec 2024 17:07:14 +0100 Subject: [PATCH 1/5] Pipeline caching --- include/SDL3/SDL_gpu.h | 81 +++++++++++++++++++ src/dynapi/SDL_dynapi.sym | 3 + src/dynapi/SDL_dynapi_overrides.h | 3 + src/dynapi/SDL_dynapi_procs.h | 3 + src/gpu/SDL_gpu.c | 45 +++++++++++ src/gpu/SDL_sysgpu.h | 16 ++++ src/gpu/d3d12/SDL_gpu_d3d12.c | 24 ++++++ src/gpu/metal/SDL_gpu_metal.m | 113 ++++++++++++++++++++++++++- src/gpu/vulkan/SDL_gpu_vulkan.c | 125 +++++++++++++++++++++++++++++- 9 files changed, 408 insertions(+), 5 deletions(-) diff --git a/include/SDL3/SDL_gpu.h b/include/SDL3/SDL_gpu.h index cee0b731bc6b7..6611f4366d05f 100644 --- a/include/SDL3/SDL_gpu.h +++ b/include/SDL3/SDL_gpu.h @@ -298,6 +298,19 @@ typedef struct SDL_GPUComputePipeline SDL_GPUComputePipeline; */ typedef struct SDL_GPUGraphicsPipeline SDL_GPUGraphicsPipeline; +/** + * An opaque handle representing a pipeline cache. + * + * Used during pipeline creation. + * + * \since This struct is available since SDL 3.1.3 + * + * \sa SDL_CreateGPUPipelineCache + * \sa SDL_ReleaseGPUPipelineCache + * \sa SDL_FetchGPUPipelineCacheData + */ +typedef struct SDL_GPUPipelineCache SDL_GPUPipelineCache; + /** * An opaque handle representing a command buffer. * @@ -1700,6 +1713,22 @@ typedef struct SDL_GPUComputePipelineCreateInfo SDL_PropertiesID props; /**< A properties ID for extensions. Should be 0 if no extensions are needed. */ } SDL_GPUComputePipelineCreateInfo; +/** + * A structure specifying the parameters of a pipeline cache. + * + * \since This struct is available since SDL 3.1.3 + * + * \sa SDL_CreateGPUPipelineCache + * \sa SDL_FetchGPUPipelineCacheData + */ +typedef struct SDL_GPUPipelineCacheCreateInfo +{ + size_t checksum_size; /**< The size in bytes of the cache checksum. */ + void* checksum_data; /**< A pointer to the checksum data. */ + size_t cache_size; /**< The size in bytes of the pipeline cache. */ + void* cache_data; /**< A pointer to the cache data. */ +} SDL_GPUPipelineCacheCreateInfo; + /** * A structure specifying the parameters of a color target used by a render * pass. @@ -2009,6 +2038,7 @@ extern SDL_DECLSPEC SDL_GPUDevice *SDLCALL SDL_CreateGPUDeviceWithProperties( #define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_MSL_BOOLEAN "SDL.gpu.device.create.shaders.msl" #define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_METALLIB_BOOLEAN "SDL.gpu.device.create.shaders.metallib" #define SDL_PROP_GPU_DEVICE_CREATE_D3D12_SEMANTIC_NAME_STRING "SDL.gpu.device.create.d3d12.semantic" +#define SDL_PROP_GPU_PIPELINE_USE_CACHE "SDL.gpu.pipeline.use.cache" /** * Destroys a GPU context previously returned by SDL_CreateGPUDevice. @@ -2136,6 +2166,43 @@ extern SDL_DECLSPEC SDL_GPUGraphicsPipeline *SDLCALL SDL_CreateGPUGraphicsPipeli SDL_GPUDevice *device, const SDL_GPUGraphicsPipelineCreateInfo *createinfo); +/** + * Creates a pipeline cache object to be used during pipeline builds. + * + * \param device a GPU Context. + * \param createinfo a struct containing the pipeline cache data. Set everything to NULL/0 in order to force a cache rebuild + * \returns a pipeline cache object on success, or NULL on failure; call + * SDL_GetError() for more information. + * + * \since This function is available since SDL 3.1.3. + * + * \sa SDL_CreatePipelineCache + * \sa SDL_ReleasePipelineCache + * \sa SDL_RetrievePipelineCacheData + */ +extern SDL_DECLSPEC SDL_GPUPipelineCache* SDLCALL SDL_CreateGPUPipelineCache( + SDL_GPUDevice* device, + const SDL_GPUPipelineCacheCreateInfo* createinfo); + +/** + * Fetches a pipeline cache object data. This can then be stored to disk and loaded on the next application run + * + * \param device a GPU Context. + * \param pipeline_cache pipeline cache object to fetch data from + * \param createinfo a struct that will contain the cache's serializable data + * \returns true on success, or false on failure; call + * SDL_GetError() for more information. + * + * \since This function is available since SDL 3.1.3. + * + * \sa SDL_CreatePipelineCache + * \sa SDL_ReleasePipelineCache + */ +extern SDL_DECLSPEC bool SDLCALL SDL_FetchGPUPipelineCacheData( + SDL_GPUDevice* device, + SDL_GPUPipelineCache* pipeline_cache, + SDL_GPUPipelineCacheCreateInfo* createinfo); + /** * Creates a sampler object to be used when binding textures in a graphics * workflow. @@ -2496,6 +2563,20 @@ extern SDL_DECLSPEC void SDLCALL SDL_ReleaseGPUGraphicsPipeline( SDL_GPUDevice *device, SDL_GPUGraphicsPipeline *graphics_pipeline); +/** + * Frees the given pipeline cache as soon as it is safe to do so. + * + * You must not reference the pipeline cache after calling this function. + * + * \param device a GPU context. + * \param pipeline_cache a pipeline cache to be destroyed. + * + * \since This function is available since SDL 3.1.3. + */ +extern SDL_DECLSPEC void SDLCALL SDL_ReleaseGPUPipelineCache( + SDL_GPUDevice* device, + SDL_GPUPipelineCache* pipeline_cache); + /** * Acquire a command buffer. * diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym index cba2c637298b0..7c0f7d868721c 100644 --- a/src/dynapi/SDL_dynapi.sym +++ b/src/dynapi/SDL_dynapi.sym @@ -1205,6 +1205,9 @@ SDL3_0.0.0 { SDL_RunOnMainThread; SDL_SetGPUAllowedFramesInFlight; SDL_RenderTextureAffine; + SDL_CreateGPUPipelineCache; + SDL_FetchGPUPipelineCacheData; + SDL_ReleaseGPUPipelineCache; # extra symbols go here (don't modify this line) local: *; }; diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index 7dd37385ad352..a7aece4f828f3 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -1230,3 +1230,6 @@ #define SDL_RunOnMainThread SDL_RunOnMainThread_REAL #define SDL_SetGPUAllowedFramesInFlight SDL_SetGPUAllowedFramesInFlight_REAL #define SDL_RenderTextureAffine SDL_RenderTextureAffine_REAL +#define SDL_CreateGPUPipelineCache SDL_CreateGPUPipelineCache_REAL +#define SDL_FetchGPUPipelineCacheData SDL_FetchGPUPipelineCacheData_REAL +#define SDL_ReleaseGPUPipelineCache SDL_ReleaseGPUPipelineCache_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index 1a9acd50010f4..d17ad912b1597 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -1236,3 +1236,6 @@ SDL_DYNAPI_PROC(bool,SDL_IsMainThread,(void),(),return) SDL_DYNAPI_PROC(bool,SDL_RunOnMainThread,(SDL_MainThreadCallback a,void *b,bool c),(a,b,c),return) SDL_DYNAPI_PROC(bool,SDL_SetGPUAllowedFramesInFlight,(SDL_GPUDevice *a,Uint32 b),(a,b),return) SDL_DYNAPI_PROC(bool,SDL_RenderTextureAffine,(SDL_Renderer *a,SDL_Texture *b,const SDL_FRect *c,const SDL_FPoint *d,const SDL_FPoint *e,const SDL_FPoint *f),(a,b,c,d,e,f),return) +SDL_DYNAPI_PROC(SDL_GPUPipelineCache*,SDL_CreateGPUPipelineCache,(SDL_GPUDevice *a,const SDL_GPUPipelineCacheCreateInfo *b),(a,b),return) +SDL_DYNAPI_PROC(bool,SDL_FetchGPUPipelineCacheData,(SDL_GPUDevice *a,SDL_GPUPipelineCache *b,SDL_GPUPipelineCacheCreateInfo *c),(a,b,c),return) +SDL_DYNAPI_PROC(void,SDL_ReleaseGPUPipelineCache,(SDL_GPUDevice *a,SDL_GPUPipelineCache *b),(a,b),) diff --git a/src/gpu/SDL_gpu.c b/src/gpu/SDL_gpu.c index 5763e793dd729..68b1bca66667a 100644 --- a/src/gpu/SDL_gpu.c +++ b/src/gpu/SDL_gpu.c @@ -862,6 +862,37 @@ SDL_GPUGraphicsPipeline *SDL_CreateGPUGraphicsPipeline( graphicsPipelineCreateInfo); } +SDL_GPUPipelineCache* SDL_CreateGPUPipelineCache( + SDL_GPUDevice* device, + const SDL_GPUPipelineCacheCreateInfo* createinfo) +{ + CHECK_DEVICE_MAGIC(device, NULL); + if (createinfo == NULL) { + SDL_InvalidParamError("createinfo"); + return NULL; + } + + return device->CreatePipelineCache(device->driverData, createinfo); +} + +bool SDL_FetchGPUPipelineCacheData( + SDL_GPUDevice* device, + SDL_GPUPipelineCache* pipeline_cache, + SDL_GPUPipelineCacheCreateInfo* createinfo) +{ + CHECK_DEVICE_MAGIC(device, false); + if (pipeline_cache == NULL) { + SDL_InvalidParamError("pipeline_cache"); + return false; + } + if (createinfo == NULL) { + SDL_InvalidParamError("createinfo"); + return false; + } + + return device->FetchPipelineCacheData(device->driverData, pipeline_cache, createinfo); +} + SDL_GPUSampler *SDL_CreateGPUSampler( SDL_GPUDevice *device, const SDL_GPUSamplerCreateInfo *createinfo) @@ -1279,6 +1310,20 @@ void SDL_ReleaseGPUGraphicsPipeline( graphics_pipeline); } +void SDL_ReleaseGPUPipelineCache( + SDL_GPUDevice* device, + SDL_GPUPipelineCache* pipeline_cache) +{ + CHECK_DEVICE_MAGIC(device, ); + if (pipeline_cache == NULL) { + return; + } + + device->ReleasePipelineCache( + device->driverData, + pipeline_cache); +} + // Command Buffer SDL_GPUCommandBuffer *SDL_AcquireGPUCommandBuffer( diff --git a/src/gpu/SDL_sysgpu.h b/src/gpu/SDL_sysgpu.h index 2cf8f6459b74a..451ca9ab32a8f 100644 --- a/src/gpu/SDL_sysgpu.h +++ b/src/gpu/SDL_sysgpu.h @@ -459,6 +459,15 @@ struct SDL_GPUDevice SDL_GPURenderer *driverData, const SDL_GPUGraphicsPipelineCreateInfo *createinfo); + SDL_GPUPipelineCache* (*CreatePipelineCache)( + SDL_GPURenderer* driverData, + const SDL_GPUPipelineCacheCreateInfo* createinfo); + + bool (*FetchPipelineCacheData)( + SDL_GPURenderer* driverData, + SDL_GPUPipelineCache* pipelineCache, + SDL_GPUPipelineCacheCreateInfo* createinfo); + SDL_GPUSampler *(*CreateSampler)( SDL_GPURenderer *driverData, const SDL_GPUSamplerCreateInfo *createinfo); @@ -534,6 +543,10 @@ struct SDL_GPUDevice SDL_GPURenderer *driverData, SDL_GPUGraphicsPipeline *graphicsPipeline); + void (*ReleasePipelineCache)( + SDL_GPURenderer* driverData, + SDL_GPUPipelineCache* pipelineCache); + // Render Pass void (*BeginRenderPass)( @@ -869,6 +882,8 @@ struct SDL_GPUDevice ASSIGN_DRIVER_FUNC(DestroyDevice, name) \ ASSIGN_DRIVER_FUNC(CreateComputePipeline, name) \ ASSIGN_DRIVER_FUNC(CreateGraphicsPipeline, name) \ + ASSIGN_DRIVER_FUNC(CreatePipelineCache, name) \ + ASSIGN_DRIVER_FUNC(FetchPipelineCacheData, name) \ ASSIGN_DRIVER_FUNC(CreateSampler, name) \ ASSIGN_DRIVER_FUNC(CreateShader, name) \ ASSIGN_DRIVER_FUNC(CreateTexture, name) \ @@ -886,6 +901,7 @@ struct SDL_GPUDevice ASSIGN_DRIVER_FUNC(ReleaseShader, name) \ ASSIGN_DRIVER_FUNC(ReleaseComputePipeline, name) \ ASSIGN_DRIVER_FUNC(ReleaseGraphicsPipeline, name) \ + ASSIGN_DRIVER_FUNC(ReleasePipelineCache, name) \ ASSIGN_DRIVER_FUNC(BeginRenderPass, name) \ ASSIGN_DRIVER_FUNC(BindGraphicsPipeline, name) \ ASSIGN_DRIVER_FUNC(SetViewport, name) \ diff --git a/src/gpu/d3d12/SDL_gpu_d3d12.c b/src/gpu/d3d12/SDL_gpu_d3d12.c index 7b024f0b024b6..45708ad593953 100644 --- a/src/gpu/d3d12/SDL_gpu_d3d12.c +++ b/src/gpu/d3d12/SDL_gpu_d3d12.c @@ -2875,6 +2875,23 @@ static SDL_GPUGraphicsPipeline *D3D12_CreateGraphicsPipeline( return (SDL_GPUGraphicsPipeline *)pipeline; } +static SDL_GPUPipelineCache* D3D12_CreatePipelineCache( + SDL_GPURenderer* driverData, + const SDL_GPUPipelineCacheCreateInfo* createinfo) +{ + // Not yet implemented + return NULL; +} + +static bool D3D12_FetchPipelineCacheData( + SDL_GPURenderer* driverData, + SDL_GPUPipelineCache* pipelineCache, + SDL_GPUPipelineCacheCreateInfo* createinfo) +{ + // Not yet implemented + return false; +} + static SDL_GPUSampler *D3D12_CreateSampler( SDL_GPURenderer *driverData, const SDL_GPUSamplerCreateInfo *createinfo) @@ -3854,6 +3871,13 @@ static void D3D12_INTERNAL_ReleaseBlitPipelines(SDL_GPURenderer *driverData) SDL_free(renderer->blitPipelines); } +static void D3D12_ReleasePipelineCache( + SDL_GPURenderer* driverData, + SDL_GPUPipelineCache* pipelineCache) +{ + // Not yet implemented +} + // Render Pass static void D3D12_SetViewport( diff --git a/src/gpu/metal/SDL_gpu_metal.m b/src/gpu/metal/SDL_gpu_metal.m index 981355a3ad88b..2dc3cdb5ac5a1 100644 --- a/src/gpu/metal/SDL_gpu_metal.m +++ b/src/gpu/metal/SDL_gpu_metal.m @@ -513,6 +513,17 @@ static MTLDepthClipMode SDLToMetal_DepthClipMode( Uint32 threadcountZ; } MetalComputePipeline; +/* +typedef struct MetalPipelineCache +{ + id pipelineCache; + size_t checksumSize; + void* checksumData; + size_t cacheBlobSize; + void* cacheBlob; +} MetalPipelineCache; +*/ + typedef struct MetalBuffer { id handle; @@ -1018,6 +1029,26 @@ static void METAL_ReleaseGraphicsPipeline( } } +static void METAL_ReleasePipelineCache( + SDL_GPURenderer* driverData, + SDL_GPUPipelineCache* pipelineCache) +{ + /* + @autoreleasepool { + MetalRenderer* renderer = (MetalRenderer*)driverData; + MetalPipelineCache* metalPipelineCache = (MetalPipelineCache*)pipelineCache; + + if (metalPipelineCache->checksumData != NULL) + { + SDL_free(metalPipelineCache->checksumData); + metalPipelineCache->checksumSize = 0; + } + metalPipelineCache->pipelineCache = nil; + SDL_free(metalPipelineCache); + } + */ +} + // Pipeline Creation static SDL_GPUComputePipeline *METAL_CreateComputePipeline( @@ -1071,6 +1102,11 @@ static void METAL_ReleaseGraphicsPipeline( MetalRenderer *renderer = (MetalRenderer *)driverData; MetalShader *vertexShader = (MetalShader *)createinfo->vertex_shader; MetalShader *fragmentShader = (MetalShader *)createinfo->fragment_shader; + + /* + MetalPipelineCache* pipelineCache = SDL_GetPointerProperty_REAL(createinfo->props,SDL_PROP_GPU_PIPELINE_USE_CACHE,NULL); + */ + MTLRenderPipelineDescriptor *pipelineDescriptor; const SDL_GPUColorTargetBlendState *blendState; MTLVertexDescriptor *vertexDescriptor; @@ -1084,7 +1120,17 @@ static void METAL_ReleaseGraphicsPipeline( MetalGraphicsPipeline *result = NULL; pipelineDescriptor = [MTLRenderPipelineDescriptor new]; - + + /* + if(@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) + { + if(pipelineCache->pipelineCache != nil) + { + pipelineDescriptor.binaryArchives = @[pipelineCache->pipelineCache]; + } + } + */ + // Blend for (Uint32 i = 0; i < createinfo->target_info.num_color_targets; i += 1) { @@ -1171,7 +1217,16 @@ static void METAL_ReleaseGraphicsPipeline( pipelineDescriptor.vertexDescriptor = vertexDescriptor; } - + + /* + if(@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) + { + if(pipelineCache != NULL){ + [pipelineCache->pipelineCache addRenderPipelineFunctionsWithDescriptor:pipelineDescriptor error:&error]; + } + } + */ + // Create the graphics pipeline pipelineState = [renderer->device newRenderPipelineStateWithDescriptor:pipelineDescriptor error:&error]; @@ -1201,6 +1256,60 @@ static void METAL_ReleaseGraphicsPipeline( } } +static SDL_GPUPipelineCache* METAL_CreatePipelineCache( + SDL_GPURenderer* driverData, + const SDL_GPUPipelineCacheCreateInfo* createinfo) +{ + // Implementing it is easy, but there's not way to get the binary data out of MTLBinaryArchive without bouncing it to a file first + /* + if(@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)){ + @autoreleasepool { + MetalRenderer* renderer = (MetalRenderer*)driverData; + MetalPipelineCache* pipelineCache = (MetalPipelineCache*)SDL_malloc(sizeof(MetalPipelineCache)); + + MTLBinaryArchiveDescriptor* archiveDescriptor = [[MTLBinaryArchiveDescriptor alloc] init]; + NSError* error; + pipelineCache->pipelineCache = [renderer->device newBinaryArchiveWithDescriptor:archiveDescriptor error:&error]; + + if (error != NULL) { + SET_ERROR_AND_RETURN("Creating pipeline cache failed: %s", [[error description] UTF8String], NULL); + } + if (createinfo->checksum_size != 0 && createinfo->checksum_data != NULL) + { + pipelineCache->checksumSize = createinfo->checksum_size; + pipelineCache->checksumData = SDL_malloc(createinfo->checksum_size); + SDL_memcpy(pipelineCache->checksumData, createinfo->checksum_data, createinfo->checksum_size); + } + else + { + pipelineCache->checksumSize = 0; + pipelineCache->checksumData = NULL; + } + return (SDL_GPUPipelineCache*)pipelineCache; + } + } + else{ + return NULL; + } + */ + return NULL; +} + +static bool METAL_FetchPipelineCacheData( + SDL_GPURenderer* driverData, + SDL_GPUPipelineCache* pipelineCache, + SDL_GPUPipelineCacheCreateInfo* createinfo) +{ + /* + MetalRenderer* renderer = (MetalRenderer*)driverData; + MetalPipelineCache* metalPipelineCache = (MetalPipelineCache*)pipelineCache; + createinfo->checksum_size = metalPipelineCache->checksumSize; + createinfo->checksum_data = metalPipelineCache->checksumData; + return true; + */ + return false; +} + // Debug Naming static void METAL_SetBufferName( diff --git a/src/gpu/vulkan/SDL_gpu_vulkan.c b/src/gpu/vulkan/SDL_gpu_vulkan.c index 359aecdfeb0f8..7c7a7f3a018e6 100644 --- a/src/gpu/vulkan/SDL_gpu_vulkan.c +++ b/src/gpu/vulkan/SDL_gpu_vulkan.c @@ -906,6 +906,15 @@ typedef struct VulkanComputePipeline SDL_AtomicInt referenceCount; } VulkanComputePipeline; +typedef struct VulkanPipelineCache +{ + VkPipelineCache pipelineCache; + size_t checksumSize; + void* checksumData; + size_t cacheBlobSize; + void* cacheBlob; +} VulkanPipelineCache; + typedef struct RenderPassColorTargetDescription { VkFormat format; @@ -6153,6 +6162,8 @@ static SDL_GPUGraphicsPipeline *VULKAN_CreateGraphicsPipeline( VulkanGraphicsPipeline *graphicsPipeline = (VulkanGraphicsPipeline *)SDL_malloc(sizeof(VulkanGraphicsPipeline)); VkGraphicsPipelineCreateInfo vkPipelineCreateInfo; + VulkanPipelineCache* pipelineCache = SDL_GetPointerProperty(createinfo->props, SDL_PROP_GPU_PIPELINE_USE_CACHE, NULL); + VkPipelineShaderStageCreateInfo shaderStageCreateInfos[2]; VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo; @@ -6448,15 +6459,21 @@ static SDL_GPUGraphicsPipeline *VULKAN_CreateGraphicsPipeline( vkPipelineCreateInfo.basePipelineHandle = VK_NULL_HANDLE; vkPipelineCreateInfo.basePipelineIndex = 0; - // TODO: enable pipeline caching vulkanResult = renderer->vkCreateGraphicsPipelines( renderer->logicalDevice, - VK_NULL_HANDLE, + (pipelineCache != NULL) ? pipelineCache->pipelineCache : VK_NULL_HANDLE, 1, &vkPipelineCreateInfo, NULL, &graphicsPipeline->pipeline); + if (pipelineCache != NULL) + { + renderer->vkGetPipelineCacheData(renderer->logicalDevice, pipelineCache->pipelineCache, &pipelineCache->cacheBlobSize, NULL); + pipelineCache->cacheBlob = SDL_realloc(pipelineCache->cacheBlob, pipelineCache->cacheBlobSize); + renderer->vkGetPipelineCacheData(renderer->logicalDevice, pipelineCache->pipelineCache, &pipelineCache->cacheBlobSize, pipelineCache->cacheBlob); + } + SDL_stack_free(vertexInputBindingDescriptions); SDL_stack_free(vertexInputAttributeDescriptions); SDL_stack_free(colorBlendAttachmentStates); @@ -6488,6 +6505,8 @@ static SDL_GPUComputePipeline *VULKAN_CreateComputePipeline( VulkanRenderer *renderer = (VulkanRenderer *)driverData; VulkanComputePipeline *vulkanComputePipeline; + VulkanPipelineCache* pipelineCache = SDL_GetPointerProperty(createinfo->props, SDL_PROP_GPU_PIPELINE_USE_CACHE, NULL); + if (createinfo->format != SDL_GPU_SHADERFORMAT_SPIRV) { SET_STRING_ERROR_AND_RETURN("Incompatible shader format for Vulkan!", NULL); } @@ -6541,12 +6560,19 @@ static SDL_GPUComputePipeline *VULKAN_CreateComputePipeline( vulkanResult = renderer->vkCreateComputePipelines( renderer->logicalDevice, - (VkPipelineCache)VK_NULL_HANDLE, + (pipelineCache != NULL) ? pipelineCache->pipelineCache : VK_NULL_HANDLE, 1, &vkShaderCreateInfo, NULL, &vulkanComputePipeline->pipeline); + if (pipelineCache != NULL) + { + renderer->vkGetPipelineCacheData(renderer->logicalDevice, pipelineCache->pipelineCache, &pipelineCache->cacheBlobSize, NULL); + SDL_realloc(pipelineCache->cacheBlob, pipelineCache->cacheBlobSize); + renderer->vkGetPipelineCacheData(renderer->logicalDevice, pipelineCache->pipelineCache, &pipelineCache->cacheBlobSize, &pipelineCache->cacheBlobSize); + } + if (vulkanResult != VK_SUCCESS) { VULKAN_INTERNAL_DestroyComputePipeline(renderer, vulkanComputePipeline); CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateComputePipeline, NULL); @@ -6558,6 +6584,78 @@ static SDL_GPUComputePipeline *VULKAN_CreateComputePipeline( return (SDL_GPUComputePipeline *)vulkanComputePipeline; } +static SDL_GPUPipelineCache* VULKAN_CreatePipelineCache( + SDL_GPURenderer* driverData, + const SDL_GPUPipelineCacheCreateInfo* createinfo) +{ + VulkanRenderer* renderer = (VulkanRenderer*)driverData; + VulkanPipelineCache* pipelineCache = (VulkanPipelineCache*)SDL_malloc(sizeof(VulkanPipelineCache)); + VkPipelineCache vkPipelineCache; + VkResult vulkanResult; + + // Here I'll eventually need to implement the checksum control + VkPipelineCacheCreateInfo vkPipelineCacheInfo; + vkPipelineCacheInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO; + vkPipelineCacheInfo.pNext = NULL; + vkPipelineCacheInfo.flags = 0; + vkPipelineCacheInfo.initialDataSize = createinfo->cache_size; + vkPipelineCacheInfo.pInitialData = createinfo->cache_data; + + vulkanResult = renderer->vkCreatePipelineCache( + renderer->logicalDevice, + &vkPipelineCacheInfo, + NULL, + &vkPipelineCache); + + if (vulkanResult != VK_SUCCESS) + { + SDL_free(pipelineCache); + CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreatePipelineCache, NULL); + return NULL; + } + + pipelineCache->pipelineCache = vkPipelineCache; + + if (createinfo->cache_size != 0 && createinfo->cache_data != NULL) + { + pipelineCache->cacheBlobSize = createinfo->cache_size; + pipelineCache->cacheBlob = SDL_malloc(createinfo->cache_size); + SDL_memcpy(pipelineCache->cacheBlob, createinfo->cache_data, createinfo->cache_size); + } + else + { + pipelineCache->cacheBlobSize = 0; + pipelineCache->cacheBlob = NULL; + } + if (createinfo->checksum_size != 0 && createinfo->checksum_data != NULL) + { + pipelineCache->checksumSize = createinfo->checksum_size; + pipelineCache->checksumData = SDL_malloc(createinfo->checksum_size); + SDL_memcpy(pipelineCache->checksumData, createinfo->checksum_data, createinfo->checksum_size); + } + else + { + pipelineCache->checksumSize = 0; + pipelineCache->checksumData = NULL; + } + + return (SDL_GPUPipelineCache*)pipelineCache; +} + +static bool VULKAN_FetchPipelineCacheData( + SDL_GPURenderer* driverData, + SDL_GPUPipelineCache* pipelineCache, + SDL_GPUPipelineCacheCreateInfo* createinfo) +{ + VulkanPipelineCache* vulkanPipelineCache = (VulkanPipelineCache*)pipelineCache; + createinfo->checksum_size = vulkanPipelineCache->checksumSize; + createinfo->checksum_data = vulkanPipelineCache->checksumData; + createinfo->cache_size = vulkanPipelineCache->cacheBlobSize; + createinfo->cache_data = vulkanPipelineCache->cacheBlob; + + return true; +} + static SDL_GPUSampler *VULKAN_CreateSampler( SDL_GPURenderer *driverData, const SDL_GPUSamplerCreateInfo *createinfo) @@ -6945,6 +7043,27 @@ static void VULKAN_ReleaseGraphicsPipeline( SDL_UnlockMutex(renderer->disposeLock); } +static void VULKAN_ReleasePipelineCache( + SDL_GPURenderer* driverData, + SDL_GPUPipelineCache* pipelineCache) +{ + VulkanRenderer* renderer = (VulkanRenderer*)driverData; + VulkanPipelineCache* vulkanPipelineCache = (VulkanPipelineCache*)pipelineCache; + + if (vulkanPipelineCache->cacheBlob != NULL) + { + SDL_free(vulkanPipelineCache->cacheBlob); + vulkanPipelineCache->cacheBlobSize = 0; + } + if (vulkanPipelineCache->checksumData != NULL) + { + SDL_free(vulkanPipelineCache->checksumData); + vulkanPipelineCache->checksumSize = 0; + } + renderer->vkDestroyPipelineCache(renderer->logicalDevice, vulkanPipelineCache->pipelineCache, NULL); + SDL_free(vulkanPipelineCache); +} + // Command Buffer render state static VkRenderPass VULKAN_INTERNAL_FetchRenderPass( From 1a37185b815bdf847617ba2a478ddd01829f000a Mon Sep 17 00:00:00 2001 From: DeltaW0x Date: Wed, 11 Dec 2024 00:43:59 +0100 Subject: [PATCH 2/5] Initial D3D12 pipeline cache implmentation --- src/gpu/d3d12/SDL_gpu_d3d12.c | 78 +++++++++++++++++++++++++++++++---- 1 file changed, 70 insertions(+), 8 deletions(-) diff --git a/src/gpu/d3d12/SDL_gpu_d3d12.c b/src/gpu/d3d12/SDL_gpu_d3d12.c index 45708ad593953..0c3ed84c43e40 100644 --- a/src/gpu/d3d12/SDL_gpu_d3d12.c +++ b/src/gpu/d3d12/SDL_gpu_d3d12.c @@ -1017,6 +1017,15 @@ struct D3D12ComputePipeline SDL_AtomicInt referenceCount; }; +typedef struct D3D12PipelineCache +{ + ID3DBlob* pipelineCache; + size_t checksumSize; + void* checksumData; + size_t cacheBlobSize; + void* cacheBlob; +} D3D12PipelineCache; + struct D3D12TextureDownload { D3D12Buffer *destinationBuffer; @@ -2531,6 +2540,8 @@ static SDL_GPUComputePipeline *D3D12_CreateComputePipeline( size_t bytecodeSize; ID3D12PipelineState *pipelineState; + D3D12PipelineCache* pipelineCache = SDL_GetPointerProperty(createinfo->props, SDL_PROP_GPU_PIPELINE_USE_CACHE, NULL); + if (!D3D12_INTERNAL_CreateShaderBytecode( renderer, SDL_GPU_SHADERSTAGE_COMPUTE, @@ -2556,6 +2567,12 @@ static SDL_GPUComputePipeline *D3D12_CreateComputePipeline( pipelineDesc.CS.pShaderBytecode = bytecode; pipelineDesc.CS.BytecodeLength = bytecodeSize; pipelineDesc.pRootSignature = rootSignature->handle; + + if (pipelineCache != NULL && pipelineCache->cacheBlob != NULL) { + pipelineDesc.CachedPSO.CachedBlobSizeInBytes = pipelineCache->cacheBlobSize; + pipelineDesc.CachedPSO.pCachedBlob = pipelineCache->cacheBlob; + } + pipelineDesc.CachedPSO.CachedBlobSizeInBytes = 0; pipelineDesc.CachedPSO.pCachedBlob = NULL; pipelineDesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE; @@ -2567,6 +2584,12 @@ static SDL_GPUComputePipeline *D3D12_CreateComputePipeline( D3D_GUID(D3D_IID_ID3D12PipelineState), (void **)&pipelineState); + if (pipelineCache != NULL) + { + ID3D12PipelineState_GetCachedBlob(pipelineState, &pipelineCache->pipelineCache); + pipelineCache->cacheBlobSize = ID3D10Blob_GetBufferSize(pipelineCache->pipelineCache); + } + if (FAILED(res)) { D3D12_INTERNAL_SetError(renderer, "Could not create compute pipeline state", res); SDL_free(bytecode); @@ -2775,6 +2798,8 @@ static SDL_GPUGraphicsPipeline *D3D12_CreateGraphicsPipeline( D3D12Shader *vertShader = (D3D12Shader *)createinfo->vertex_shader; D3D12Shader *fragShader = (D3D12Shader *)createinfo->fragment_shader; + D3D12PipelineCache* pipelineCache = SDL_GetPointerProperty(createinfo->props, SDL_PROP_GPU_PIPELINE_USE_CACHE, NULL); + D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc; SDL_zero(psoDesc); psoDesc.VS.pShaderBytecode = vertShader->bytecode; @@ -2819,12 +2844,14 @@ static SDL_GPUGraphicsPipeline *D3D12_CreateGraphicsPipeline( for (uint32_t i = 0; i < createinfo->target_info.num_color_targets; i += 1) { psoDesc.RTVFormats[i] = SDLToD3D12_TextureFormat[createinfo->target_info.color_target_descriptions[i].format]; } - - // Assuming some default values or further initialization + psoDesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE; - psoDesc.CachedPSO.CachedBlobSizeInBytes = 0; - psoDesc.CachedPSO.pCachedBlob = NULL; + if (pipelineCache != NULL && pipelineCache->cacheBlob != NULL) { + psoDesc.CachedPSO.CachedBlobSizeInBytes = pipelineCache->cacheBlobSize; + psoDesc.CachedPSO.pCachedBlob = pipelineCache->cacheBlob; + } + psoDesc.NodeMask = 0; D3D12GraphicsRootSignature *rootSignature = D3D12_INTERNAL_CreateGraphicsRootSignature( @@ -2852,6 +2879,12 @@ static SDL_GPUGraphicsPipeline *D3D12_CreateGraphicsPipeline( return NULL; } + if (pipelineCache != NULL) + { + ID3D12PipelineState_GetCachedBlob(pipelineState, &pipelineCache->pipelineCache); + pipelineCache->cacheBlobSize = ID3D10Blob_GetBufferSize(pipelineCache->pipelineCache); + } + pipeline->pipelineState = pipelineState; for (Uint32 i = 0; i < createinfo->vertex_input_state.num_vertex_buffers; i += 1) { @@ -2879,8 +2912,33 @@ static SDL_GPUPipelineCache* D3D12_CreatePipelineCache( SDL_GPURenderer* driverData, const SDL_GPUPipelineCacheCreateInfo* createinfo) { - // Not yet implemented - return NULL; + D3D12Renderer* renderer = (D3D12Renderer*)driverData; + D3D12PipelineCache* d3d12PipelineCache = (D3D12PipelineCache*)SDL_malloc(sizeof(D3D12PipelineCache)); + + if (createinfo->cache_size != 0 && createinfo->cache_data != NULL) + { + d3d12PipelineCache->cacheBlobSize = createinfo->cache_size; + d3d12PipelineCache->cacheBlob = SDL_malloc(createinfo->cache_size); + SDL_memcpy(d3d12PipelineCache->cacheBlob, createinfo->cache_data, createinfo->cache_size); + } + else + { + d3d12PipelineCache->cacheBlobSize = 0; + d3d12PipelineCache->cacheBlob = NULL; + } + if (createinfo->checksum_size != 0 && createinfo->checksum_data != NULL) + { + d3d12PipelineCache->checksumSize = createinfo->checksum_size; + d3d12PipelineCache->checksumData = SDL_malloc(createinfo->checksum_size); + SDL_memcpy(d3d12PipelineCache->checksumData, createinfo->checksum_data, createinfo->checksum_size); + } + else + { + d3d12PipelineCache->checksumSize = 0; + d3d12PipelineCache->checksumData = NULL; + } + + return (SDL_GPUPipelineCache*)d3d12PipelineCache; } static bool D3D12_FetchPipelineCacheData( @@ -2888,8 +2946,12 @@ static bool D3D12_FetchPipelineCacheData( SDL_GPUPipelineCache* pipelineCache, SDL_GPUPipelineCacheCreateInfo* createinfo) { - // Not yet implemented - return false; + D3D12PipelineCache* d3d12PipelineCache = (D3D12PipelineCache*)pipelineCache; + createinfo->checksum_size = d3d12PipelineCache->checksumSize; + createinfo->checksum_data = d3d12PipelineCache->checksumData; + createinfo->cache_size = d3d12PipelineCache->cacheBlobSize; + createinfo->cache_data = ID3D10Blob_GetBufferPointer(d3d12PipelineCache->pipelineCache); + return true; } static SDL_GPUSampler *D3D12_CreateSampler( From 26443ec66bc5ebe458b5320e7762bcb8d01a3212 Mon Sep 17 00:00:00 2001 From: DeltaW0x Date: Fri, 13 Dec 2024 19:37:30 +0100 Subject: [PATCH 3/5] Added SDL_PROP_GPU_PIPELINE_STORE_CACHE --- include/SDL3/SDL_gpu.h | 1 + src/gpu/d3d12/SDL_gpu_d3d12.c | 7 ++++--- src/gpu/vulkan/SDL_gpu_vulkan.c | 6 ++++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/include/SDL3/SDL_gpu.h b/include/SDL3/SDL_gpu.h index 6611f4366d05f..633c1c3c1ac25 100644 --- a/include/SDL3/SDL_gpu.h +++ b/include/SDL3/SDL_gpu.h @@ -2038,6 +2038,7 @@ extern SDL_DECLSPEC SDL_GPUDevice *SDLCALL SDL_CreateGPUDeviceWithProperties( #define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_MSL_BOOLEAN "SDL.gpu.device.create.shaders.msl" #define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_METALLIB_BOOLEAN "SDL.gpu.device.create.shaders.metallib" #define SDL_PROP_GPU_DEVICE_CREATE_D3D12_SEMANTIC_NAME_STRING "SDL.gpu.device.create.d3d12.semantic" +#define SDL_PROP_GPU_PIPELINE_STORE_CACHE "SDL.gpu.pipeline.store.cache" #define SDL_PROP_GPU_PIPELINE_USE_CACHE "SDL.gpu.pipeline.use.cache" /** diff --git a/src/gpu/d3d12/SDL_gpu_d3d12.c b/src/gpu/d3d12/SDL_gpu_d3d12.c index 0c3ed84c43e40..7bdd6f50b141a 100644 --- a/src/gpu/d3d12/SDL_gpu_d3d12.c +++ b/src/gpu/d3d12/SDL_gpu_d3d12.c @@ -2541,6 +2541,7 @@ static SDL_GPUComputePipeline *D3D12_CreateComputePipeline( ID3D12PipelineState *pipelineState; D3D12PipelineCache* pipelineCache = SDL_GetPointerProperty(createinfo->props, SDL_PROP_GPU_PIPELINE_USE_CACHE, NULL); + bool storeCache = SDL_GetBooleanProperty(createinfo->props, SDL_PROP_GPU_PIPELINE_STORE_CACHE, false); if (!D3D12_INTERNAL_CreateShaderBytecode( renderer, @@ -2584,7 +2585,7 @@ static SDL_GPUComputePipeline *D3D12_CreateComputePipeline( D3D_GUID(D3D_IID_ID3D12PipelineState), (void **)&pipelineState); - if (pipelineCache != NULL) + if (pipelineCache != NULL && storeCache) { ID3D12PipelineState_GetCachedBlob(pipelineState, &pipelineCache->pipelineCache); pipelineCache->cacheBlobSize = ID3D10Blob_GetBufferSize(pipelineCache->pipelineCache); @@ -2799,6 +2800,7 @@ static SDL_GPUGraphicsPipeline *D3D12_CreateGraphicsPipeline( D3D12Shader *fragShader = (D3D12Shader *)createinfo->fragment_shader; D3D12PipelineCache* pipelineCache = SDL_GetPointerProperty(createinfo->props, SDL_PROP_GPU_PIPELINE_USE_CACHE, NULL); + bool storeCache = SDL_GetBooleanProperty(createinfo->props, SDL_PROP_GPU_PIPELINE_STORE_CACHE, false); D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc; SDL_zero(psoDesc); @@ -2879,7 +2881,7 @@ static SDL_GPUGraphicsPipeline *D3D12_CreateGraphicsPipeline( return NULL; } - if (pipelineCache != NULL) + if (pipelineCache != NULL && storeCache) { ID3D12PipelineState_GetCachedBlob(pipelineState, &pipelineCache->pipelineCache); pipelineCache->cacheBlobSize = ID3D10Blob_GetBufferSize(pipelineCache->pipelineCache); @@ -2912,7 +2914,6 @@ static SDL_GPUPipelineCache* D3D12_CreatePipelineCache( SDL_GPURenderer* driverData, const SDL_GPUPipelineCacheCreateInfo* createinfo) { - D3D12Renderer* renderer = (D3D12Renderer*)driverData; D3D12PipelineCache* d3d12PipelineCache = (D3D12PipelineCache*)SDL_malloc(sizeof(D3D12PipelineCache)); if (createinfo->cache_size != 0 && createinfo->cache_data != NULL) diff --git a/src/gpu/vulkan/SDL_gpu_vulkan.c b/src/gpu/vulkan/SDL_gpu_vulkan.c index 7c7a7f3a018e6..3e7772a9425a1 100644 --- a/src/gpu/vulkan/SDL_gpu_vulkan.c +++ b/src/gpu/vulkan/SDL_gpu_vulkan.c @@ -6163,6 +6163,7 @@ static SDL_GPUGraphicsPipeline *VULKAN_CreateGraphicsPipeline( VkGraphicsPipelineCreateInfo vkPipelineCreateInfo; VulkanPipelineCache* pipelineCache = SDL_GetPointerProperty(createinfo->props, SDL_PROP_GPU_PIPELINE_USE_CACHE, NULL); + bool storeCache = SDL_GetBooleanProperty(createinfo->props, SDL_PROP_GPU_PIPELINE_STORE_CACHE, false); VkPipelineShaderStageCreateInfo shaderStageCreateInfos[2]; @@ -6467,7 +6468,7 @@ static SDL_GPUGraphicsPipeline *VULKAN_CreateGraphicsPipeline( NULL, &graphicsPipeline->pipeline); - if (pipelineCache != NULL) + if (pipelineCache != NULL && storeCache) { renderer->vkGetPipelineCacheData(renderer->logicalDevice, pipelineCache->pipelineCache, &pipelineCache->cacheBlobSize, NULL); pipelineCache->cacheBlob = SDL_realloc(pipelineCache->cacheBlob, pipelineCache->cacheBlobSize); @@ -6506,6 +6507,7 @@ static SDL_GPUComputePipeline *VULKAN_CreateComputePipeline( VulkanComputePipeline *vulkanComputePipeline; VulkanPipelineCache* pipelineCache = SDL_GetPointerProperty(createinfo->props, SDL_PROP_GPU_PIPELINE_USE_CACHE, NULL); + bool storeCache = SDL_GetBooleanProperty(createinfo->props, SDL_PROP_GPU_PIPELINE_STORE_CACHE, false); if (createinfo->format != SDL_GPU_SHADERFORMAT_SPIRV) { SET_STRING_ERROR_AND_RETURN("Incompatible shader format for Vulkan!", NULL); @@ -6566,7 +6568,7 @@ static SDL_GPUComputePipeline *VULKAN_CreateComputePipeline( NULL, &vulkanComputePipeline->pipeline); - if (pipelineCache != NULL) + if (pipelineCache != NULL && storeCache) { renderer->vkGetPipelineCacheData(renderer->logicalDevice, pipelineCache->pipelineCache, &pipelineCache->cacheBlobSize, NULL); SDL_realloc(pipelineCache->cacheBlob, pipelineCache->cacheBlobSize); From d1963dced88486a90a89b2176a1c722d7ff4048e Mon Sep 17 00:00:00 2001 From: DeltaW0x Date: Fri, 13 Dec 2024 19:37:45 +0100 Subject: [PATCH 4/5] Removed metal implementation --- src/gpu/metal/SDL_gpu_metal.m | 90 ++--------------------------------- 1 file changed, 3 insertions(+), 87 deletions(-) diff --git a/src/gpu/metal/SDL_gpu_metal.m b/src/gpu/metal/SDL_gpu_metal.m index 2dc3cdb5ac5a1..0eefc1d2a2480 100644 --- a/src/gpu/metal/SDL_gpu_metal.m +++ b/src/gpu/metal/SDL_gpu_metal.m @@ -513,17 +513,6 @@ static MTLDepthClipMode SDLToMetal_DepthClipMode( Uint32 threadcountZ; } MetalComputePipeline; -/* -typedef struct MetalPipelineCache -{ - id pipelineCache; - size_t checksumSize; - void* checksumData; - size_t cacheBlobSize; - void* cacheBlob; -} MetalPipelineCache; -*/ - typedef struct MetalBuffer { id handle; @@ -1033,20 +1022,7 @@ static void METAL_ReleasePipelineCache( SDL_GPURenderer* driverData, SDL_GPUPipelineCache* pipelineCache) { - /* - @autoreleasepool { - MetalRenderer* renderer = (MetalRenderer*)driverData; - MetalPipelineCache* metalPipelineCache = (MetalPipelineCache*)pipelineCache; - - if (metalPipelineCache->checksumData != NULL) - { - SDL_free(metalPipelineCache->checksumData); - metalPipelineCache->checksumSize = 0; - } - metalPipelineCache->pipelineCache = nil; - SDL_free(metalPipelineCache); - } - */ + // Not yet supported } // Pipeline Creation @@ -1103,10 +1079,6 @@ static void METAL_ReleasePipelineCache( MetalShader *vertexShader = (MetalShader *)createinfo->vertex_shader; MetalShader *fragmentShader = (MetalShader *)createinfo->fragment_shader; - /* - MetalPipelineCache* pipelineCache = SDL_GetPointerProperty_REAL(createinfo->props,SDL_PROP_GPU_PIPELINE_USE_CACHE,NULL); - */ - MTLRenderPipelineDescriptor *pipelineDescriptor; const SDL_GPUColorTargetBlendState *blendState; MTLVertexDescriptor *vertexDescriptor; @@ -1121,16 +1093,6 @@ static void METAL_ReleasePipelineCache( pipelineDescriptor = [MTLRenderPipelineDescriptor new]; - /* - if(@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) - { - if(pipelineCache->pipelineCache != nil) - { - pipelineDescriptor.binaryArchives = @[pipelineCache->pipelineCache]; - } - } - */ - // Blend for (Uint32 i = 0; i < createinfo->target_info.num_color_targets; i += 1) { @@ -1218,15 +1180,6 @@ static void METAL_ReleasePipelineCache( pipelineDescriptor.vertexDescriptor = vertexDescriptor; } - /* - if(@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) - { - if(pipelineCache != NULL){ - [pipelineCache->pipelineCache addRenderPipelineFunctionsWithDescriptor:pipelineDescriptor error:&error]; - } - } - */ - // Create the graphics pipeline pipelineState = [renderer->device newRenderPipelineStateWithDescriptor:pipelineDescriptor error:&error]; @@ -1260,38 +1213,7 @@ static void METAL_ReleasePipelineCache( SDL_GPURenderer* driverData, const SDL_GPUPipelineCacheCreateInfo* createinfo) { - // Implementing it is easy, but there's not way to get the binary data out of MTLBinaryArchive without bouncing it to a file first - /* - if(@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)){ - @autoreleasepool { - MetalRenderer* renderer = (MetalRenderer*)driverData; - MetalPipelineCache* pipelineCache = (MetalPipelineCache*)SDL_malloc(sizeof(MetalPipelineCache)); - - MTLBinaryArchiveDescriptor* archiveDescriptor = [[MTLBinaryArchiveDescriptor alloc] init]; - NSError* error; - pipelineCache->pipelineCache = [renderer->device newBinaryArchiveWithDescriptor:archiveDescriptor error:&error]; - - if (error != NULL) { - SET_ERROR_AND_RETURN("Creating pipeline cache failed: %s", [[error description] UTF8String], NULL); - } - if (createinfo->checksum_size != 0 && createinfo->checksum_data != NULL) - { - pipelineCache->checksumSize = createinfo->checksum_size; - pipelineCache->checksumData = SDL_malloc(createinfo->checksum_size); - SDL_memcpy(pipelineCache->checksumData, createinfo->checksum_data, createinfo->checksum_size); - } - else - { - pipelineCache->checksumSize = 0; - pipelineCache->checksumData = NULL; - } - return (SDL_GPUPipelineCache*)pipelineCache; - } - } - else{ - return NULL; - } - */ + // Not yet supported return NULL; } @@ -1300,13 +1222,7 @@ static bool METAL_FetchPipelineCacheData( SDL_GPUPipelineCache* pipelineCache, SDL_GPUPipelineCacheCreateInfo* createinfo) { - /* - MetalRenderer* renderer = (MetalRenderer*)driverData; - MetalPipelineCache* metalPipelineCache = (MetalPipelineCache*)pipelineCache; - createinfo->checksum_size = metalPipelineCache->checksumSize; - createinfo->checksum_data = metalPipelineCache->checksumData; - return true; - */ + // Not yet supported return false; } From 8f7863fc4612b124df45e72bc0cde15bb26281c7 Mon Sep 17 00:00:00 2001 From: Delta <98419797+DeltaW0x@users.noreply.github.com> Date: Wed, 29 Jan 2025 17:46:37 +0100 Subject: [PATCH 5/5] Streamlined checksum implementation --- include/SDL3/SDL_gpu.h | 7 +++--- src/gpu/d3d12/SDL_gpu_d3d12.c | 36 ++++++++++++++------------- src/gpu/vulkan/SDL_gpu_vulkan.c | 43 ++++++++++++++------------------- 3 files changed, 40 insertions(+), 46 deletions(-) diff --git a/include/SDL3/SDL_gpu.h b/include/SDL3/SDL_gpu.h index cdfe1c853a81d..de7d20cc33566 100644 --- a/include/SDL3/SDL_gpu.h +++ b/include/SDL3/SDL_gpu.h @@ -1717,10 +1717,9 @@ typedef struct SDL_GPUComputePipelineCreateInfo */ typedef struct SDL_GPUPipelineCacheCreateInfo { - size_t checksum_size; /**< The size in bytes of the cache checksum. */ - void* checksum_data; /**< A pointer to the checksum data. */ - size_t cache_size; /**< The size in bytes of the pipeline cache. */ - void* cache_data; /**< A pointer to the cache data. */ + Uint64 cache_checksum[4]; + size_t cache_size; /**< The size in bytes of the pipeline cache. */ + void* cache_data; /**< A pointer to the cache data. */ } SDL_GPUPipelineCacheCreateInfo; /** diff --git a/src/gpu/d3d12/SDL_gpu_d3d12.c b/src/gpu/d3d12/SDL_gpu_d3d12.c index 1c03ee6d9a082..ff0241577c77d 100644 --- a/src/gpu/d3d12/SDL_gpu_d3d12.c +++ b/src/gpu/d3d12/SDL_gpu_d3d12.c @@ -1020,8 +1020,7 @@ struct D3D12ComputePipeline typedef struct D3D12PipelineCache { ID3DBlob* pipelineCache; - size_t checksumSize; - void* checksumData; + Uint64 cacheChecksum[4]; size_t cacheBlobSize; void* cacheBlob; } D3D12PipelineCache; @@ -2914,9 +2913,24 @@ static SDL_GPUPipelineCache* D3D12_CreatePipelineCache( SDL_GPURenderer* driverData, const SDL_GPUPipelineCacheCreateInfo* createinfo) { + D3D12Renderer *renderer = (D3D12Renderer *)driverData; D3D12PipelineCache* d3d12PipelineCache = (D3D12PipelineCache*)SDL_malloc(sizeof(D3D12PipelineCache)); - if (createinfo->cache_size != 0 && createinfo->cache_data != NULL) + LUID uuid; + LARGE_INTEGER umdVersion; + Uint64 computedCache[4]; + + ID3D12Device_GetAdapterLuid(renderer->device,&uuid); + IDXGIAdapter1_CheckInterfaceSupport(renderer->adapter, D3D_GUID(D3D_IID_IDXGIDevice), &umdVersion); + + computedCache[0] = uuid.LowPart; + computedCache[1] = uuid.HighPart; + computedCache[2] = umdVersion.QuadPart; + computedCache[3] = 0; + + if (createinfo->cache_size != 0 && + createinfo->cache_data != NULL && + (SDL_memcmp(computedCache, createinfo->cache_checksum, sizeof(Uint64) * 4) == 0)) { d3d12PipelineCache->cacheBlobSize = createinfo->cache_size; d3d12PipelineCache->cacheBlob = SDL_malloc(createinfo->cache_size); @@ -2927,18 +2941,7 @@ static SDL_GPUPipelineCache* D3D12_CreatePipelineCache( d3d12PipelineCache->cacheBlobSize = 0; d3d12PipelineCache->cacheBlob = NULL; } - if (createinfo->checksum_size != 0 && createinfo->checksum_data != NULL) - { - d3d12PipelineCache->checksumSize = createinfo->checksum_size; - d3d12PipelineCache->checksumData = SDL_malloc(createinfo->checksum_size); - SDL_memcpy(d3d12PipelineCache->checksumData, createinfo->checksum_data, createinfo->checksum_size); - } - else - { - d3d12PipelineCache->checksumSize = 0; - d3d12PipelineCache->checksumData = NULL; - } - + SDL_memcpy(d3d12PipelineCache->cacheChecksum,createinfo->cache_checksum,sizeof(Uint64) * 4); return (SDL_GPUPipelineCache*)d3d12PipelineCache; } @@ -2948,8 +2951,7 @@ static bool D3D12_FetchPipelineCacheData( SDL_GPUPipelineCacheCreateInfo* createinfo) { D3D12PipelineCache* d3d12PipelineCache = (D3D12PipelineCache*)pipelineCache; - createinfo->checksum_size = d3d12PipelineCache->checksumSize; - createinfo->checksum_data = d3d12PipelineCache->checksumData; + SDL_memcpy(createinfo->cache_checksum,d3d12PipelineCache->cacheChecksum,sizeof(Uint64)*4); createinfo->cache_size = d3d12PipelineCache->cacheBlobSize; createinfo->cache_data = ID3D10Blob_GetBufferPointer(d3d12PipelineCache->pipelineCache); return true; diff --git a/src/gpu/vulkan/SDL_gpu_vulkan.c b/src/gpu/vulkan/SDL_gpu_vulkan.c index fc9f8938c7697..32b60720e89d3 100644 --- a/src/gpu/vulkan/SDL_gpu_vulkan.c +++ b/src/gpu/vulkan/SDL_gpu_vulkan.c @@ -909,8 +909,7 @@ typedef struct VulkanComputePipeline typedef struct VulkanPipelineCache { VkPipelineCache pipelineCache; - size_t checksumSize; - void* checksumData; + Uint64 cacheChecksum[4]; size_t cacheBlobSize; void* cacheBlob; } VulkanPipelineCache; @@ -6592,10 +6591,11 @@ static SDL_GPUPipelineCache* VULKAN_CreatePipelineCache( { VulkanRenderer* renderer = (VulkanRenderer*)driverData; VulkanPipelineCache* pipelineCache = (VulkanPipelineCache*)SDL_malloc(sizeof(VulkanPipelineCache)); + VkPhysicalDeviceProperties deviceProperties; VkPipelineCache vkPipelineCache; + Uint64 computedChecksum[4]; VkResult vulkanResult; - - // Here I'll eventually need to implement the checksum control + VkPipelineCacheCreateInfo vkPipelineCacheInfo; vkPipelineCacheInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO; vkPipelineCacheInfo.pNext = NULL; @@ -6617,8 +6617,14 @@ static SDL_GPUPipelineCache* VULKAN_CreatePipelineCache( } pipelineCache->pipelineCache = vkPipelineCache; - - if (createinfo->cache_size != 0 && createinfo->cache_data != NULL) + renderer->vkGetPhysicalDeviceProperties(renderer->physicalDevice,&deviceProperties); + computedChecksum[0] = deviceProperties.deviceID; + computedChecksum[1] = deviceProperties.driverVersion; + SDL_memcpy(&computedChecksum[2],deviceProperties.pipelineCacheUUID,sizeof(deviceProperties.pipelineCacheUUID)); + + if (createinfo->cache_size != 0 && + createinfo->cache_data != NULL && + (SDL_memcmp(computedChecksum,createinfo->cache_data,sizeof(computedChecksum)) == 0)) { pipelineCache->cacheBlobSize = createinfo->cache_size; pipelineCache->cacheBlob = SDL_malloc(createinfo->cache_size); @@ -6629,18 +6635,7 @@ static SDL_GPUPipelineCache* VULKAN_CreatePipelineCache( pipelineCache->cacheBlobSize = 0; pipelineCache->cacheBlob = NULL; } - if (createinfo->checksum_size != 0 && createinfo->checksum_data != NULL) - { - pipelineCache->checksumSize = createinfo->checksum_size; - pipelineCache->checksumData = SDL_malloc(createinfo->checksum_size); - SDL_memcpy(pipelineCache->checksumData, createinfo->checksum_data, createinfo->checksum_size); - } - else - { - pipelineCache->checksumSize = 0; - pipelineCache->checksumData = NULL; - } - + SDL_memcpy(pipelineCache->cacheChecksum,createinfo->cache_checksum,sizeof(Uint64)*4); return (SDL_GPUPipelineCache*)pipelineCache; } @@ -6650,8 +6645,7 @@ static bool VULKAN_FetchPipelineCacheData( SDL_GPUPipelineCacheCreateInfo* createinfo) { VulkanPipelineCache* vulkanPipelineCache = (VulkanPipelineCache*)pipelineCache; - createinfo->checksum_size = vulkanPipelineCache->checksumSize; - createinfo->checksum_data = vulkanPipelineCache->checksumData; + SDL_memcpy(createinfo->cache_checksum,vulkanPipelineCache->cacheChecksum,sizeof(Uint64)*4); createinfo->cache_size = vulkanPipelineCache->cacheBlobSize; createinfo->cache_data = vulkanPipelineCache->cacheBlob; @@ -7057,11 +7051,10 @@ static void VULKAN_ReleasePipelineCache( SDL_free(vulkanPipelineCache->cacheBlob); vulkanPipelineCache->cacheBlobSize = 0; } - if (vulkanPipelineCache->checksumData != NULL) - { - SDL_free(vulkanPipelineCache->checksumData); - vulkanPipelineCache->checksumSize = 0; - } + vulkanPipelineCache->cacheChecksum[0] = 0; + vulkanPipelineCache->cacheChecksum[1] = 0; + vulkanPipelineCache->cacheChecksum[2] = 0; + vulkanPipelineCache->cacheChecksum[3] = 0; renderer->vkDestroyPipelineCache(renderer->logicalDevice, vulkanPipelineCache->pipelineCache, NULL); SDL_free(vulkanPipelineCache); }