diff --git a/include/SDL3/SDL_gpu.h b/include/SDL3/SDL_gpu.h index 26901c8edb1c8..273a41e93ef0e 100644 --- a/include/SDL3/SDL_gpu.h +++ b/include/SDL3/SDL_gpu.h @@ -4177,6 +4177,26 @@ extern SDL_DECLSPEC Uint32 SDLCALL SDL_CalculateGPUTextureFormatSize( Uint32 height, Uint32 depth_or_layer_count); +/** + * Get readonly metadata properties of an existing GPU device. + * + * Currently available properties: + * + * - `SDL_PROP_GPU_DEVICE_PHYSICAL_NAME_STRING`: The physical name of the GPU device, as reported by the system driver. + * - `SDL_PROP_GPU_DEVICE_DRIVER_VERSION_STRING`: Version of the GPU driver as a string. May be NULL on some platforms, like MacOS. + * + * \param device GPU device to query + * + * \returns a SDL_PropertiesID containing various data regarding the device or 0 on error. Use SDL_GetError() to get more information. + * + * \since This function is available since SDL 3.2.0. + */ +extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetGPUDeviceProperties( + SDL_GPUDevice *device); + +#define SDL_PROP_GPU_DEVICE_PHYSICAL_NAME_STRING "SDL.gpu.device.physical.name" +#define SDL_PROP_GPU_DEVICE_DRIVER_VERSION_STRING "SDL.gpu.device.driver.version" + #ifdef SDL_PLATFORM_GDK /** diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym index 8b3c48170e680..cdbf7ea756e81 100644 --- a/src/dynapi/SDL_dynapi.sym +++ b/src/dynapi/SDL_dynapi.sym @@ -1242,6 +1242,7 @@ SDL3_0.0.0 { SDL_SetGPURenderStateFragmentUniforms; SDL_SetRenderGPUState; SDL_DestroyGPURenderState; + SDL_GetGPUDeviceProperties; # 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 df0848e280c5c..5b3f3821ea87d 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -1267,3 +1267,4 @@ #define SDL_SetGPURenderStateFragmentUniforms SDL_SetGPURenderStateFragmentUniforms_REAL #define SDL_SetRenderGPUState SDL_SetRenderGPUState_REAL #define SDL_DestroyGPURenderState SDL_DestroyGPURenderState_REAL +#define SDL_GetGPUDeviceProperties SDL_GetGPUDeviceProperties_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index 7be1e52219037..f3645f8fe8519 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -1275,3 +1275,4 @@ SDL_DYNAPI_PROC(SDL_GPURenderState*,SDL_CreateGPURenderState,(SDL_Renderer *a,SD SDL_DYNAPI_PROC(bool,SDL_SetGPURenderStateFragmentUniforms,(SDL_GPURenderState *a,Uint32 b,const void *c,Uint32 d),(a,b,c,d),return) SDL_DYNAPI_PROC(bool,SDL_SetRenderGPUState,(SDL_Renderer *a,SDL_GPURenderState *b),(a,b),return) SDL_DYNAPI_PROC(void,SDL_DestroyGPURenderState,(SDL_GPURenderState *a),(a),) +SDL_DYNAPI_PROC(SDL_PropertiesID,SDL_GetGPUDeviceProperties,(SDL_GPUDevice *a),(a),return) diff --git a/src/gpu/SDL_gpu.c b/src/gpu/SDL_gpu.c index 7ca2590ad810c..62c480ffc2c15 100644 --- a/src/gpu/SDL_gpu.c +++ b/src/gpu/SDL_gpu.c @@ -2970,3 +2970,12 @@ Uint32 SDL_CalculateGPUTextureFormatSize( Uint32 blocksPerColumn = (height + blockHeight - 1) / blockHeight; return depth_or_layer_count * blocksPerRow * blocksPerColumn * SDL_GPUTextureFormatTexelBlockSize(format); } + + +SDL_PropertiesID SDL_GetGPUDeviceProperties( + SDL_GPUDevice *device) +{ + CHECK_DEVICE_MAGIC(device, 0); + + return device->props; +} diff --git a/src/gpu/SDL_sysgpu.h b/src/gpu/SDL_sysgpu.h index 31e6b8d472bec..d3c5d8af95333 100644 --- a/src/gpu/SDL_sysgpu.h +++ b/src/gpu/SDL_sysgpu.h @@ -888,92 +888,95 @@ struct SDL_GPUDevice // Store this for SDL_gpu.c's debug layer bool debug_mode; + + // Various readonly properties for the device + SDL_PropertiesID props; }; #define ASSIGN_DRIVER_FUNC(func, name) \ result->func = name##_##func; -#define ASSIGN_DRIVER(name) \ - ASSIGN_DRIVER_FUNC(DestroyDevice, name) \ - ASSIGN_DRIVER_FUNC(CreateComputePipeline, name) \ - ASSIGN_DRIVER_FUNC(CreateGraphicsPipeline, name) \ - ASSIGN_DRIVER_FUNC(CreateSampler, name) \ - ASSIGN_DRIVER_FUNC(CreateShader, name) \ - ASSIGN_DRIVER_FUNC(CreateTexture, name) \ - ASSIGN_DRIVER_FUNC(CreateBuffer, name) \ - ASSIGN_DRIVER_FUNC(CreateTransferBuffer, name) \ - ASSIGN_DRIVER_FUNC(SetBufferName, name) \ - ASSIGN_DRIVER_FUNC(SetTextureName, name) \ - ASSIGN_DRIVER_FUNC(InsertDebugLabel, name) \ - ASSIGN_DRIVER_FUNC(PushDebugGroup, name) \ - ASSIGN_DRIVER_FUNC(PopDebugGroup, name) \ - ASSIGN_DRIVER_FUNC(ReleaseTexture, name) \ - ASSIGN_DRIVER_FUNC(ReleaseSampler, name) \ - ASSIGN_DRIVER_FUNC(ReleaseBuffer, name) \ - ASSIGN_DRIVER_FUNC(ReleaseTransferBuffer, name) \ - ASSIGN_DRIVER_FUNC(ReleaseShader, name) \ - ASSIGN_DRIVER_FUNC(ReleaseComputePipeline, name) \ - ASSIGN_DRIVER_FUNC(ReleaseGraphicsPipeline, name) \ - ASSIGN_DRIVER_FUNC(BeginRenderPass, name) \ - ASSIGN_DRIVER_FUNC(BindGraphicsPipeline, name) \ - ASSIGN_DRIVER_FUNC(SetViewport, name) \ - ASSIGN_DRIVER_FUNC(SetScissor, name) \ - ASSIGN_DRIVER_FUNC(SetBlendConstants, name) \ - ASSIGN_DRIVER_FUNC(SetStencilReference, name) \ - ASSIGN_DRIVER_FUNC(BindVertexBuffers, name) \ - ASSIGN_DRIVER_FUNC(BindIndexBuffer, name) \ - ASSIGN_DRIVER_FUNC(BindVertexSamplers, name) \ - ASSIGN_DRIVER_FUNC(BindVertexStorageTextures, name) \ - ASSIGN_DRIVER_FUNC(BindVertexStorageBuffers, name) \ - ASSIGN_DRIVER_FUNC(BindFragmentSamplers, name) \ - ASSIGN_DRIVER_FUNC(BindFragmentStorageTextures, name) \ - ASSIGN_DRIVER_FUNC(BindFragmentStorageBuffers, name) \ - ASSIGN_DRIVER_FUNC(PushVertexUniformData, name) \ - ASSIGN_DRIVER_FUNC(PushFragmentUniformData, name) \ - ASSIGN_DRIVER_FUNC(DrawIndexedPrimitives, name) \ - ASSIGN_DRIVER_FUNC(DrawPrimitives, name) \ - ASSIGN_DRIVER_FUNC(DrawPrimitivesIndirect, name) \ - ASSIGN_DRIVER_FUNC(DrawIndexedPrimitivesIndirect, name) \ - ASSIGN_DRIVER_FUNC(EndRenderPass, name) \ - ASSIGN_DRIVER_FUNC(BeginComputePass, name) \ - ASSIGN_DRIVER_FUNC(BindComputePipeline, name) \ - ASSIGN_DRIVER_FUNC(BindComputeSamplers, name) \ - ASSIGN_DRIVER_FUNC(BindComputeStorageTextures, name) \ - ASSIGN_DRIVER_FUNC(BindComputeStorageBuffers, name) \ - ASSIGN_DRIVER_FUNC(PushComputeUniformData, name) \ - ASSIGN_DRIVER_FUNC(DispatchCompute, name) \ - ASSIGN_DRIVER_FUNC(DispatchComputeIndirect, name) \ - ASSIGN_DRIVER_FUNC(EndComputePass, name) \ - ASSIGN_DRIVER_FUNC(MapTransferBuffer, name) \ - ASSIGN_DRIVER_FUNC(UnmapTransferBuffer, name) \ - ASSIGN_DRIVER_FUNC(BeginCopyPass, name) \ - ASSIGN_DRIVER_FUNC(UploadToTexture, name) \ - ASSIGN_DRIVER_FUNC(UploadToBuffer, name) \ - ASSIGN_DRIVER_FUNC(DownloadFromTexture, name) \ - ASSIGN_DRIVER_FUNC(DownloadFromBuffer, name) \ - ASSIGN_DRIVER_FUNC(CopyTextureToTexture, name) \ - ASSIGN_DRIVER_FUNC(CopyBufferToBuffer, name) \ - ASSIGN_DRIVER_FUNC(GenerateMipmaps, name) \ - ASSIGN_DRIVER_FUNC(EndCopyPass, name) \ - ASSIGN_DRIVER_FUNC(Blit, name) \ - ASSIGN_DRIVER_FUNC(SupportsSwapchainComposition, name) \ - ASSIGN_DRIVER_FUNC(SupportsPresentMode, name) \ - ASSIGN_DRIVER_FUNC(ClaimWindow, name) \ - ASSIGN_DRIVER_FUNC(ReleaseWindow, name) \ - ASSIGN_DRIVER_FUNC(SetSwapchainParameters, name) \ - ASSIGN_DRIVER_FUNC(SetAllowedFramesInFlight, name) \ - ASSIGN_DRIVER_FUNC(GetSwapchainTextureFormat, name) \ - ASSIGN_DRIVER_FUNC(AcquireCommandBuffer, name) \ - ASSIGN_DRIVER_FUNC(AcquireSwapchainTexture, name) \ - ASSIGN_DRIVER_FUNC(WaitForSwapchain, name) \ - ASSIGN_DRIVER_FUNC(WaitAndAcquireSwapchainTexture, name)\ - ASSIGN_DRIVER_FUNC(Submit, name) \ - ASSIGN_DRIVER_FUNC(SubmitAndAcquireFence, name) \ - ASSIGN_DRIVER_FUNC(Cancel, name) \ - ASSIGN_DRIVER_FUNC(Wait, name) \ - ASSIGN_DRIVER_FUNC(WaitForFences, name) \ - ASSIGN_DRIVER_FUNC(QueryFence, name) \ - ASSIGN_DRIVER_FUNC(ReleaseFence, name) \ - ASSIGN_DRIVER_FUNC(SupportsTextureFormat, name) \ +#define ASSIGN_DRIVER(name) \ + ASSIGN_DRIVER_FUNC(DestroyDevice, name) \ + ASSIGN_DRIVER_FUNC(CreateComputePipeline, name) \ + ASSIGN_DRIVER_FUNC(CreateGraphicsPipeline, name) \ + ASSIGN_DRIVER_FUNC(CreateSampler, name) \ + ASSIGN_DRIVER_FUNC(CreateShader, name) \ + ASSIGN_DRIVER_FUNC(CreateTexture, name) \ + ASSIGN_DRIVER_FUNC(CreateBuffer, name) \ + ASSIGN_DRIVER_FUNC(CreateTransferBuffer, name) \ + ASSIGN_DRIVER_FUNC(SetBufferName, name) \ + ASSIGN_DRIVER_FUNC(SetTextureName, name) \ + ASSIGN_DRIVER_FUNC(InsertDebugLabel, name) \ + ASSIGN_DRIVER_FUNC(PushDebugGroup, name) \ + ASSIGN_DRIVER_FUNC(PopDebugGroup, name) \ + ASSIGN_DRIVER_FUNC(ReleaseTexture, name) \ + ASSIGN_DRIVER_FUNC(ReleaseSampler, name) \ + ASSIGN_DRIVER_FUNC(ReleaseBuffer, name) \ + ASSIGN_DRIVER_FUNC(ReleaseTransferBuffer, name) \ + ASSIGN_DRIVER_FUNC(ReleaseShader, name) \ + ASSIGN_DRIVER_FUNC(ReleaseComputePipeline, name) \ + ASSIGN_DRIVER_FUNC(ReleaseGraphicsPipeline, name) \ + ASSIGN_DRIVER_FUNC(BeginRenderPass, name) \ + ASSIGN_DRIVER_FUNC(BindGraphicsPipeline, name) \ + ASSIGN_DRIVER_FUNC(SetViewport, name) \ + ASSIGN_DRIVER_FUNC(SetScissor, name) \ + ASSIGN_DRIVER_FUNC(SetBlendConstants, name) \ + ASSIGN_DRIVER_FUNC(SetStencilReference, name) \ + ASSIGN_DRIVER_FUNC(BindVertexBuffers, name) \ + ASSIGN_DRIVER_FUNC(BindIndexBuffer, name) \ + ASSIGN_DRIVER_FUNC(BindVertexSamplers, name) \ + ASSIGN_DRIVER_FUNC(BindVertexStorageTextures, name) \ + ASSIGN_DRIVER_FUNC(BindVertexStorageBuffers, name) \ + ASSIGN_DRIVER_FUNC(BindFragmentSamplers, name) \ + ASSIGN_DRIVER_FUNC(BindFragmentStorageTextures, name) \ + ASSIGN_DRIVER_FUNC(BindFragmentStorageBuffers, name) \ + ASSIGN_DRIVER_FUNC(PushVertexUniformData, name) \ + ASSIGN_DRIVER_FUNC(PushFragmentUniformData, name) \ + ASSIGN_DRIVER_FUNC(DrawIndexedPrimitives, name) \ + ASSIGN_DRIVER_FUNC(DrawPrimitives, name) \ + ASSIGN_DRIVER_FUNC(DrawPrimitivesIndirect, name) \ + ASSIGN_DRIVER_FUNC(DrawIndexedPrimitivesIndirect, name) \ + ASSIGN_DRIVER_FUNC(EndRenderPass, name) \ + ASSIGN_DRIVER_FUNC(BeginComputePass, name) \ + ASSIGN_DRIVER_FUNC(BindComputePipeline, name) \ + ASSIGN_DRIVER_FUNC(BindComputeSamplers, name) \ + ASSIGN_DRIVER_FUNC(BindComputeStorageTextures, name) \ + ASSIGN_DRIVER_FUNC(BindComputeStorageBuffers, name) \ + ASSIGN_DRIVER_FUNC(PushComputeUniformData, name) \ + ASSIGN_DRIVER_FUNC(DispatchCompute, name) \ + ASSIGN_DRIVER_FUNC(DispatchComputeIndirect, name) \ + ASSIGN_DRIVER_FUNC(EndComputePass, name) \ + ASSIGN_DRIVER_FUNC(MapTransferBuffer, name) \ + ASSIGN_DRIVER_FUNC(UnmapTransferBuffer, name) \ + ASSIGN_DRIVER_FUNC(BeginCopyPass, name) \ + ASSIGN_DRIVER_FUNC(UploadToTexture, name) \ + ASSIGN_DRIVER_FUNC(UploadToBuffer, name) \ + ASSIGN_DRIVER_FUNC(DownloadFromTexture, name) \ + ASSIGN_DRIVER_FUNC(DownloadFromBuffer, name) \ + ASSIGN_DRIVER_FUNC(CopyTextureToTexture, name) \ + ASSIGN_DRIVER_FUNC(CopyBufferToBuffer, name) \ + ASSIGN_DRIVER_FUNC(GenerateMipmaps, name) \ + ASSIGN_DRIVER_FUNC(EndCopyPass, name) \ + ASSIGN_DRIVER_FUNC(Blit, name) \ + ASSIGN_DRIVER_FUNC(SupportsSwapchainComposition, name) \ + ASSIGN_DRIVER_FUNC(SupportsPresentMode, name) \ + ASSIGN_DRIVER_FUNC(ClaimWindow, name) \ + ASSIGN_DRIVER_FUNC(ReleaseWindow, name) \ + ASSIGN_DRIVER_FUNC(SetSwapchainParameters, name) \ + ASSIGN_DRIVER_FUNC(SetAllowedFramesInFlight, name) \ + ASSIGN_DRIVER_FUNC(GetSwapchainTextureFormat, name) \ + ASSIGN_DRIVER_FUNC(AcquireCommandBuffer, name) \ + ASSIGN_DRIVER_FUNC(AcquireSwapchainTexture, name) \ + ASSIGN_DRIVER_FUNC(WaitForSwapchain, name) \ + ASSIGN_DRIVER_FUNC(WaitAndAcquireSwapchainTexture, name) \ + ASSIGN_DRIVER_FUNC(Submit, name) \ + ASSIGN_DRIVER_FUNC(SubmitAndAcquireFence, name) \ + ASSIGN_DRIVER_FUNC(Cancel, name) \ + ASSIGN_DRIVER_FUNC(Wait, name) \ + ASSIGN_DRIVER_FUNC(WaitForFences, name) \ + ASSIGN_DRIVER_FUNC(QueryFence, name) \ + ASSIGN_DRIVER_FUNC(ReleaseFence, name) \ + ASSIGN_DRIVER_FUNC(SupportsTextureFormat, name) \ ASSIGN_DRIVER_FUNC(SupportsSampleCount, name) typedef struct SDL_GPUBootstrap diff --git a/src/gpu/d3d12/SDL_gpu_d3d12.c b/src/gpu/d3d12/SDL_gpu_d3d12.c index 19601ff0b624e..91fbfc133435c 100644 --- a/src/gpu/d3d12/SDL_gpu_d3d12.c +++ b/src/gpu/d3d12/SDL_gpu_d3d12.c @@ -1619,6 +1619,9 @@ static void D3D12_DestroyDevice(SDL_GPUDevice *device) } D3D12_INTERNAL_DestroyRenderer(renderer); + + SDL_DestroyProperties(device->props); + SDL_free(device); } @@ -8994,6 +8997,16 @@ static SDL_GPUDevice *D3D12_CreateDevice(bool debugMode, bool preferLowPower, SD result->debug_mode = debugMode; renderer->sdlGPUDevice = result; + result->props = SDL_CreateProperties(); + + char *adapterDescUtf8 = SDL_iconv_wchar_utf8(&adapterDesc.Description[0]); + SDL_SetStringProperty(result->props, SDL_PROP_GPU_DEVICE_PHYSICAL_NAME_STRING, adapterDescUtf8); + SDL_free(adapterDescUtf8); + + char driverMetadataBuffer[256] = { 0 }; + SDL_snprintf(&driverMetadataBuffer[0], 256, "%d.%d.%d.%d", HIWORD(umdVersion.HighPart), LOWORD(umdVersion.HighPart), HIWORD(umdVersion.LowPart), LOWORD(umdVersion.LowPart)); + SDL_SetStringProperty(result->props, SDL_PROP_GPU_DEVICE_DRIVER_VERSION_STRING, driverMetadataBuffer); + return result; } diff --git a/src/gpu/metal/SDL_gpu_metal.m b/src/gpu/metal/SDL_gpu_metal.m index 250c03928b326..e00620b9f5514 100644 --- a/src/gpu/metal/SDL_gpu_metal.m +++ b/src/gpu/metal/SDL_gpu_metal.m @@ -765,6 +765,8 @@ static void METAL_DestroyDevice(SDL_GPUDevice *device) // Release the command queue renderer->queue = nil; + SDL_DestroyProperties(device->props); + // Free the primary structures SDL_free(renderer); SDL_free(device); @@ -4570,6 +4572,10 @@ static void METAL_INTERNAL_DestroyBlitResources( result->driverData = (SDL_GPURenderer *)renderer; renderer->sdlGPUDevice = result; + result->props = SDL_CreateProperties(); + + SDL_SetStringProperty(result->props, SDL_PROP_GPU_DEVICE_PHYSICAL_NAME_STRING, [device.name UTF8String]); + return result; } } diff --git a/src/gpu/vulkan/SDL_gpu_vulkan.c b/src/gpu/vulkan/SDL_gpu_vulkan.c index bd3910bd7ba0d..dd07287e28fc7 100644 --- a/src/gpu/vulkan/SDL_gpu_vulkan.c +++ b/src/gpu/vulkan/SDL_gpu_vulkan.c @@ -4895,6 +4895,8 @@ static void VULKAN_DestroyDevice( renderer->vkDestroyDevice(renderer->logicalDevice, NULL); renderer->vkDestroyInstance(renderer->instance, NULL); + SDL_DestroyProperties(device->props); + SDL_free(renderer); SDL_free(device); SDL_Vulkan_UnloadLibrary(); @@ -11590,6 +11592,10 @@ static SDL_GPUDevice *VULKAN_CreateDevice(bool debugMode, bool preferLowPower, S ASSIGN_DRIVER(VULKAN) result->driverData = (SDL_GPURenderer *)renderer; + + result->props = SDL_CreateProperties(); + SDL_SetStringProperty(result->props, SDL_PROP_GPU_DEVICE_PHYSICAL_NAME_STRING, renderer->physicalDeviceProperties.properties.deviceName); + SDL_SetStringProperty(result->props, SDL_PROP_GPU_DEVICE_DRIVER_VERSION_STRING, renderer->physicalDeviceDriverProperties.driverInfo); /* * Create initial swapchain array