diff --git a/Examples/D3D11/main.c b/Examples/D3D11/main.c index 28875b8..a350386 100644 --- a/Examples/D3D11/main.c +++ b/Examples/D3D11/main.c @@ -23,6 +23,8 @@ int main(void) PulseBackend backend = PulseLoadBackend(PULSE_BACKEND_D3D11, PULSE_SHADER_FORMAT_DXBC_BIT, PULSE_HIGH_DEBUG); PulseSetDebugCallback(backend, DebugCallBack); PulseDevice device = PulseCreateDevice(backend, NULL, 0); + + PulseDestroyDevice(device); PulseUnloadBackend(backend); puts("Successfully executed Pulse example using D3D11 !"); return 0; diff --git a/Sources/Backends/D3D11/D3D11.c b/Sources/Backends/D3D11/D3D11.c index 8ce44e1..1105053 100644 --- a/Sources/Backends/D3D11/D3D11.c +++ b/Sources/Backends/D3D11/D3D11.c @@ -8,7 +8,7 @@ #include "D3D11.h" #include "D3D11Device.h" -PulseBackendFlags PuD3D11CheckSupport(PulseBackendFlags candidates, PulseShaderFormatsFlags shader_formats_used) +PulseBackendFlags Direct3D11CheckSupport(PulseBackendFlags candidates, PulseShaderFormatsFlags shader_formats_used) { if(candidates != PULSE_BACKEND_ANY && (candidates & PULSE_BACKEND_D3D11) == 0) return PULSE_BACKEND_INVALID; @@ -17,19 +17,19 @@ PulseBackendFlags PuD3D11CheckSupport(PulseBackendFlags candidates, PulseShaderF return PULSE_BACKEND_D3D11; } -bool PuD3D11LoadBackend(PulseBackend backend, PulseDebugLevel debug_level) +bool Direct3D11LoadBackend(PulseBackend backend, PulseDebugLevel debug_level) { return true; } -void PuD3D11UnloadBackend(PulseBackend backend) +void Direct3D11UnloadBackend(PulseBackend backend) { } PulseBackendHandler D3D11Driver = { - .PFN_LoadBackend = PuD3D11LoadBackend, - .PFN_UnloadBackend = PuD3D11UnloadBackend, - .PFN_CreateDevice = PuD3D11CreateDevice, + .PFN_LoadBackend = Direct3D11LoadBackend, + .PFN_UnloadBackend = Direct3D11UnloadBackend, + .PFN_CreateDevice = Direct3D11CreateDevice, .backend = PULSE_BACKEND_D3D11, .supported_shader_formats = PULSE_SHADER_FORMAT_DXBC_BIT, .driver_data = PULSE_NULLPTR diff --git a/Sources/Backends/D3D11/D3D11.h b/Sources/Backends/D3D11/D3D11.h index 7998a96..9b8e16e 100644 --- a/Sources/Backends/D3D11/D3D11.h +++ b/Sources/Backends/D3D11/D3D11.h @@ -8,13 +8,14 @@ #define PULSE_D3D11_H_ #include +#include #include #include "../../PulseInternal.h" #define D3D11_RETRIEVE_DRIVER_DATA_AS(handle, cast) ((cast)handle->driver_data) -PulseBackendFlags PuD3D11CheckSupport(PulseBackendFlags candidates, PulseShaderFormatsFlags shader_formats_used); // Return PULSE_BACKEND_D3D11 in case of success and PULSE_BACKEND_INVALID otherwise +PulseBackendFlags Direct3D11CheckSupport(PulseBackendFlags candidates, PulseShaderFormatsFlags shader_formats_used); // Return PULSE_BACKEND_D3D11 in case of success and PULSE_BACKEND_INVALID otherwise #endif // PULSE_D3D11_H_ diff --git a/Sources/Backends/D3D11/D3D11Device.c b/Sources/Backends/D3D11/D3D11Device.c index 925c8b5..a1bb6c6 100644 --- a/Sources/Backends/D3D11/D3D11Device.c +++ b/Sources/Backends/D3D11/D3D11Device.c @@ -4,13 +4,13 @@ #include -#include +#include #include "../../PulseInternal.h" #include "D3D11.h" #include "D3D11Device.h" -bool PuD3D11IsDedicatedAdapter(IDXGIAdapter1* adapter) +bool Direct3D11IsDedicatedAdapter(IDXGIAdapter1* adapter) { DXGI_ADAPTER_DESC1 desc; if(FAILED(adapter->lpVtbl->GetDesc1(adapter, &desc))) @@ -27,35 +27,144 @@ bool PuD3D11IsDedicatedAdapter(IDXGIAdapter1* adapter) return has_dedicated_memory && is_known_vendor && !is_software_adapter; } -static uint64_t PuD3D11ScoreAdapter(ID3D11Device* device, IDXGIAdapter1* adapter) +static uint64_t Direct3D11ScoreAdapter(IDXGIAdapter1* adapter) { + DXGI_ADAPTER_DESC1 desc; + adapter->lpVtbl->GetDesc1(adapter, &desc); + + D3D_FEATURE_LEVEL feature_levels[] = { + D3D_FEATURE_LEVEL_11_1, + D3D_FEATURE_LEVEL_11_0, + D3D_FEATURE_LEVEL_10_1, // :doubt: + D3D_FEATURE_LEVEL_10_0 + }; + + ID3D11Device* base_device = PULSE_NULLPTR; + ID3D11DeviceContext* base_context = PULSE_NULLPTR; + ID3D11Device1* d3d_device1 = PULSE_NULLPTR; + ID3D11DeviceContext1* d3d_context1 = PULSE_NULLPTR; + + D3D_FEATURE_LEVEL out_feature_level; + + uint64_t score = 0; + + HRESULT hr = D3D11CreateDevice((IDXGIAdapter*)adapter, D3D_DRIVER_TYPE_UNKNOWN, PULSE_NULLPTR, 0, feature_levels, PULSE_SIZEOF_ARRAY(feature_levels), D3D11_SDK_VERSION, &base_device, &out_feature_level, &base_context); + + if(FAILED(hr)) + return 0; + + hr = base_device->lpVtbl->QueryInterface(base_device, &IID_ID3D11Device1, (void**)&d3d_device1); + if(FAILED(hr) || out_feature_level < D3D_FEATURE_LEVEL_10_0) + goto Cleanup; + + if(Direct3D11IsDedicatedAdapter(adapter)) + score += 50000; + else if(!(desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE)) + { + // Often integrated GPUs are labeled "Intel(R)" in the description + if(wcsstr(desc.Description, L"Intel") != PULSE_NULLPTR) + score += 10000; + } + + score += desc.DedicatedVideoMemory; + score += desc.DedicatedSystemMemory; + score += desc.SharedSystemMemory; + +Cleanup: + if(base_device) + base_device->lpVtbl->Release(base_device); + if(base_context) + base_context->lpVtbl->Release(base_context); + return score; } -PulseDevice PuD3D11CreateDevice(PulseBackend backend, PulseDevice* forbiden_devices, uint32_t forbiden_devices_count) +static bool Direct3D11IsAdapterForbidden(IDXGIAdapter1* adapter, PulseDevice* forbiden_devices, uint32_t forbiden_devices_count) +{ + if(adapter == PULSE_NULLPTR) + return true; + for(uint32_t i = 0; i < forbiden_devices_count; i++) + { + DXGI_ADAPTER_DESC1 desc1; + adapter->lpVtbl->GetDesc1(adapter, &desc1); + + DXGI_ADAPTER_DESC1 desc2; + Direct3D11Device* d3d11_device = D3D11_RETRIEVE_DRIVER_DATA_AS(forbiden_devices[i], Direct3D11Device*); + d3d11_device->adapter->lpVtbl->GetDesc1(d3d11_device->adapter, &desc2); + + if(desc1.AdapterLuid.HighPart == desc2.AdapterLuid.HighPart && desc1.AdapterLuid.LowPart == desc2.AdapterLuid.LowPart) + return true; + } + return false; +} + +static IDXGIAdapter1* Direct3D11SelectAdapter(IDXGIFactory1* factory, PulseDevice* forbiden_devices, uint32_t forbiden_devices_count) +{ + IDXGIAdapter1* adapter = PULSE_NULLPTR; + uint64_t best_device_score = 0; + uint32_t best_device_id = 0; + + for(uint32_t i = 0; factory->lpVtbl->EnumAdapters1(factory, i, &adapter) != DXGI_ERROR_NOT_FOUND; i++) + { + if(Direct3D11IsAdapterForbidden(adapter, forbiden_devices, forbiden_devices_count)) + continue; + uint64_t current_device_score = Direct3D11ScoreAdapter(adapter); + if(current_device_score > best_device_score) + { + best_device_score = current_device_score; + best_device_id = i; + } + adapter->lpVtbl->Release(adapter); + } + if(factory->lpVtbl->EnumAdapters1(factory, best_device_id, &adapter) == DXGI_ERROR_NOT_FOUND) + return PULSE_NULLPTR; + return adapter; +} + +PulseDevice Direct3D11CreateDevice(PulseBackend backend, PulseDevice* forbiden_devices, uint32_t forbiden_devices_count) { PULSE_CHECK_HANDLE_RETVAL(backend, PULSE_NULLPTR); PulseDevice pulse_device = (PulseDeviceHandler*)calloc(1, sizeof(PulseDeviceHandler)); PULSE_CHECK_ALLOCATION_RETVAL(pulse_device, PULSE_NULL_HANDLE); - D3D11Device* device = (D3D11Device*)calloc(1, sizeof(D3D11Device)); + Direct3D11Device* device = (Direct3D11Device*)calloc(1, sizeof(Direct3D11Device)); PULSE_CHECK_ALLOCATION_RETVAL(device, PULSE_NULL_HANDLE); pulse_device->driver_data = device; pulse_device->backend = backend; CreateDXGIFactory1(&IID_IDXGIFactory, (void**)&device->factory); - for(uint32_t i = 0; device->factory->lpVtbl->EnumAdapters1(device->factory, i, &device->adapter) != DXGI_ERROR_NOT_FOUND; i++) - { - DXGI_ADAPTER_DESC1 desc; - device->adapter->lpVtbl->GetDesc1(device->adapter, &desc); - device->adapter->lpVtbl->Release(device->adapter); - } - device->factory->lpVtbl->Release(device->factory); + device->adapter = Direct3D11SelectAdapter(device->factory, forbiden_devices, forbiden_devices_count); + device->adapter->lpVtbl->GetDesc1(device->adapter, &device->description); + + D3D_FEATURE_LEVEL feature_levels[] = { + D3D_FEATURE_LEVEL_11_1, + D3D_FEATURE_LEVEL_11_0, + D3D_FEATURE_LEVEL_10_1, // :doubt: + D3D_FEATURE_LEVEL_10_0 + }; + + D3D11CreateDevice((IDXGIAdapter*)device->adapter, D3D_DRIVER_TYPE_UNKNOWN, PULSE_NULLPTR, 0, feature_levels, PULSE_SIZEOF_ARRAY(feature_levels), D3D11_SDK_VERSION, &device->device, PULSE_NULLPTR, &device->context); + + pulse_device->PFN_DestroyDevice = Direct3D11DestroyDevice; + + if(PULSE_IS_BACKEND_HIGH_LEVEL_DEBUG(backend)) + PulseLogInfoFmt(backend, "(D3D11) created device from %ls", device->description.Description); return pulse_device; } -void PuD3D11DestroyDevice(PulseDevice device) +void Direct3D11DestroyDevice(PulseDevice device) { + Direct3D11Device* d3d11_device = D3D11_RETRIEVE_DRIVER_DATA_AS(device, Direct3D11Device*); + if(d3d11_device == PULSE_NULLPTR || d3d11_device->device == PULSE_NULLPTR) + return; + d3d11_device->device->lpVtbl->Release(d3d11_device->device); + d3d11_device->context->lpVtbl->Release(d3d11_device->context); + d3d11_device->adapter->lpVtbl->Release(d3d11_device->adapter); + d3d11_device->factory->lpVtbl->Release(d3d11_device->factory); + if(PULSE_IS_BACKEND_HIGH_LEVEL_DEBUG(device->backend)) + PulseLogInfoFmt(device->backend, "(D3D11) destroyed device created from %ls", d3d11_device->description.Description); + free(d3d11_device); + free(device); } diff --git a/Sources/Backends/D3D11/D3D11Device.h b/Sources/Backends/D3D11/D3D11Device.h index 1ed7726..9fe22bb 100644 --- a/Sources/Backends/D3D11/D3D11Device.h +++ b/Sources/Backends/D3D11/D3D11Device.h @@ -10,16 +10,17 @@ #include #include "D3D11.h" -typedef struct D3D11Device +typedef struct Direct3D11Device { + DXGI_ADAPTER_DESC1 description; ID3D11Device* device; ID3D11DeviceContext* context; IDXGIFactory1* factory; IDXGIAdapter1* adapter; -} D3D11Device; +} Direct3D11Device; -PulseDevice PuD3D11CreateDevice(PulseBackend backend, PulseDevice* forbiden_devices, uint32_t forbiden_devices_count); -void PuD3D11DestroyDevice(PulseDevice device); +PulseDevice Direct3D11CreateDevice(PulseBackend backend, PulseDevice* forbiden_devices, uint32_t forbiden_devices_count); +void Direct3D11DestroyDevice(PulseDevice device); #endif // PULSE_D3D11_DEVICE_H_ diff --git a/Sources/Backends/Vulkan/VulkanDevice.c b/Sources/Backends/Vulkan/VulkanDevice.c index 4691025..08c1a55 100644 --- a/Sources/Backends/Vulkan/VulkanDevice.c +++ b/Sources/Backends/Vulkan/VulkanDevice.c @@ -128,8 +128,7 @@ PulseDevice VulkanCreateDevice(PulseBackend backend, PulseDevice* forbiden_devic const float queue_priority = 1.0f; - VkDeviceQueueCreateInfo queue_create_infos[VULKAN_QUEUE_END_ENUM * sizeof(VkDeviceQueueCreateInfo)] = { 0 }; - // No need to check allocation, it is allocated on the stack + VkDeviceQueueCreateInfo queue_create_infos[VULKAN_QUEUE_END_ENUM] = { 0 }; uint32_t unique_queues_count = 1; diff --git a/Sources/PulseBackend.c b/Sources/PulseBackend.c index 2fc919e..252d170 100644 --- a/Sources/PulseBackend.c +++ b/Sources/PulseBackend.c @@ -39,7 +39,7 @@ static const PulseCheckBackendSupportPFN backends_supports[] = { WebGPUCheckSupport, #endif #ifdef PULSE_ENABLE_D3D11_BACKEND - PuD3D11CheckSupport, + Direct3D11CheckSupport, #endif #ifdef PULSE_ENABLE_OPENGL_BACKEND OpenGLCheckSupport,