diff --git a/Examples/D3D11/main.c b/Examples/D3D11/main.c index a350386..d08a317 100644 --- a/Examples/D3D11/main.c +++ b/Examples/D3D11/main.c @@ -2,6 +2,9 @@ #include #include +#include + +#define HLSL_SOURCE(...) #__VA_ARGS__ void DebugCallBack(PulseDebugMessageSeverity severity, const char* message) { @@ -18,12 +21,42 @@ void DebugCallBack(PulseDebugMessageSeverity severity, const char* message) #define BUFFER_SIZE (256 * sizeof(uint32_t)) +const char* hlsl_source = HLSL_SOURCE( + RWStructuredBuffer ssbo : register(u0); + + [numthreads(16, 16, 1)] + void CSMain(uint3 grid : SV_DispatchThreadID) + { + ssbo[grid.x * grid.y] = (int)(grid.x * grid.y); + } +); + int main(void) { - PulseBackend backend = PulseLoadBackend(PULSE_BACKEND_D3D11, PULSE_SHADER_FORMAT_DXBC_BIT, PULSE_HIGH_DEBUG); + PulseBackend backend = PulseLoadBackend(PULSE_BACKEND_D3D11, PULSE_SHADER_FORMAT_HLSL_BIT, PULSE_HIGH_DEBUG); PulseSetDebugCallback(backend, DebugCallBack); PulseDevice device = PulseCreateDevice(backend, NULL, 0); + PulseBufferCreateInfo buffer_create_info = { 0 }; + buffer_create_info.size = BUFFER_SIZE; + buffer_create_info.usage = PULSE_BUFFER_USAGE_STORAGE_READ | PULSE_BUFFER_USAGE_STORAGE_WRITE | PULSE_BUFFER_USAGE_TRANSFER_DOWNLOAD; + PulseBuffer buffer = PulseCreateBuffer(device, &buffer_create_info); + + // GPU computations + { + PulseComputePipelineCreateInfo info = { 0 }; + info.code_size = strlen(hlsl_source); + info.code = (const uint8_t*)hlsl_source; + info.entrypoint = "CSMain"; + info.format = PULSE_SHADER_FORMAT_HLSL_BIT; + info.num_readwrite_storage_buffers = 1; + PulseComputePipeline pipeline = PulseCreateComputePipeline(device, &info); + + PulseDestroyComputePipeline(device, pipeline); + } + + PulseDestroyBuffer(device, buffer); + PulseDestroyDevice(device); PulseUnloadBackend(backend); puts("Successfully executed Pulse example using D3D11 !"); diff --git a/Includes/Pulse.h b/Includes/Pulse.h index 48789f0..b24afe2 100644 --- a/Includes/Pulse.h +++ b/Includes/Pulse.h @@ -77,6 +77,7 @@ typedef enum PulseShaderFormatsBits PULSE_SHADER_FORMAT_WGSL_BIT = PULSE_BIT(4), // Can be used by WebGPU backend PULSE_SHADER_FORMAT_GLSL_BIT = PULSE_BIT(5), // Can be used by OpenGL / OpenGL_ES backend PULSE_SHADER_FORMAT_DXBC_BIT = PULSE_BIT(6), // Can be used by D3D11 backend + PULSE_SHADER_FORMAT_HLSL_BIT = PULSE_BIT(7), // Can be used by D3D11 backend // More to come } PulseShaderFormatsBits; typedef PulseFlags PulseShaderFormatsFlags; @@ -270,7 +271,7 @@ PULSE_API bool PulseDeviceSupportsShaderFormats(PulseDevice device, PulseShaderF PULSE_API void PulseDestroyDevice(PulseDevice device); PULSE_API PulseBuffer PulseCreateBuffer(PulseDevice device, const PulseBufferCreateInfo* create_infos); -PULSE_API bool PulseMapBuffer(PulseBuffer buffer, PulseMapMode mode, void** data); +PULSE_API bool PulseMapBuffer(PulseBuffer buffer, PulseMapMode mode, void** data); // Data writing may only apply when unmapping PULSE_API void PulseUnmapBuffer(PulseBuffer buffer); PULSE_API bool PulseCopyBufferToBuffer(PulseCommandList cmd, const PulseBufferRegion* src, const PulseBufferRegion* dst); PULSE_API bool PulseCopyBufferToImage(PulseCommandList cmd, const PulseBufferRegion* src, const PulseImageRegion* dst); diff --git a/Sources/Backends/D3D11/D3D11.c b/Sources/Backends/D3D11/D3D11.c index e491c46..04b494d 100644 --- a/Sources/Backends/D3D11/D3D11.c +++ b/Sources/Backends/D3D11/D3D11.c @@ -8,11 +8,14 @@ #include "D3D11.h" #include "D3D11Device.h" +#pragma comment(lib,"d3d11.lib") +#pragma comment(lib,"d3dcompiler.lib") + PulseBackendFlags Direct3D11CheckSupport(PulseBackendFlags candidates, PulseShaderFormatsFlags shader_formats_used) { if(candidates != PULSE_BACKEND_ANY && (candidates & PULSE_BACKEND_D3D11) == 0) return PULSE_BACKEND_INVALID; - if((shader_formats_used & PULSE_SHADER_FORMAT_DXBC_BIT) == 0) + if((shader_formats_used & PULSE_SHADER_FORMAT_DXBC_BIT) == 0 && (shader_formats_used & PULSE_SHADER_FORMAT_HLSL_BIT) == 0) return PULSE_BACKEND_INVALID; return PULSE_BACKEND_D3D11; } @@ -28,11 +31,58 @@ void Direct3D11UnloadBackend(PulseBackend backend) { } +#ifndef D3D11_ERROR_FILE_NOT_FOUND + #define D3D11_ERROR_FILE_NOT_FOUND 0x887C0002 +#endif + +#ifndef D3D11_ERROR_TOO_MANY_UNIQUE_STATE_OBJECTS + #define D3D11_ERROR_TOO_MANY_UNIQUE_STATE_OBJECTS 0x887C0001 +#endif + +#ifndef D3D11_ERROR_TOO_MANY_UNIQUE_VIEW_OBJECTS + #define D3D11_ERROR_TOO_MANY_UNIQUE_VIEW_OBJECTS 0x887C0003 +#endif + +#ifndef D3D11_ERROR_DEFERRED_CONTEXT_MAP_WITHOUT_INITIAL_DISCARD + #define D3D11_ERROR_DEFERRED_CONTEXT_MAP_WITHOUT_INITIAL_DISCARD 0x887C0004 +#endif + +#ifndef D3DERR_INVALIDCALL + #define D3DERR_INVALIDCALL 0x887A0001 +#endif + +#ifndef D3DERR_WASSTILLDRAWING + #define D3DERR_WASSTILLDRAWING 0x887A000A +#endif + +const char* D3D11VerbaliseResult(HRESULT res) +{ + switch(res) + { + case S_OK: + case S_FALSE: return "success"; + + case D3D11_ERROR_FILE_NOT_FOUND: return "a file was not found"; + case D3D11_ERROR_TOO_MANY_UNIQUE_STATE_OBJECTS: return "too many instances of a particular state objects"; + case D3D11_ERROR_TOO_MANY_UNIQUE_VIEW_OBJECTS: return "too many instances of a particular view objects"; + case D3D11_ERROR_DEFERRED_CONTEXT_MAP_WITHOUT_INITIAL_DISCARD: return "deffered context mapped without initial discard"; + case D3DERR_INVALIDCALL: return "invalid call"; + case D3DERR_WASSTILLDRAWING: return "was still drawing"; + case E_FAIL: return "attempted to create a device with the debug layer enabled and the layer is not installed"; + case E_INVALIDARG: return "an invalid parameter was passed to the returning function"; + case E_OUTOFMEMORY: return "could not allocate sufficient memory to complete the call"; + case E_NOTIMPL: return "method call isn't implemented with the passed parameter combination"; + + default: return "Unknown D3D11 error"; + } + return "Unknown D3D11 error"; // Just to avoid warnings +} + PulseBackendHandler D3D11Driver = { .PFN_LoadBackend = Direct3D11LoadBackend, .PFN_UnloadBackend = Direct3D11UnloadBackend, .PFN_CreateDevice = Direct3D11CreateDevice, .backend = PULSE_BACKEND_D3D11, - .supported_shader_formats = PULSE_SHADER_FORMAT_DXBC_BIT, + .supported_shader_formats = PULSE_SHADER_FORMAT_DXBC_BIT | PULSE_SHADER_FORMAT_HLSL_BIT, .driver_data = PULSE_NULLPTR }; diff --git a/Sources/Backends/D3D11/D3D11.h b/Sources/Backends/D3D11/D3D11.h index 7022e9a..53d6696 100644 --- a/Sources/Backends/D3D11/D3D11.h +++ b/Sources/Backends/D3D11/D3D11.h @@ -9,6 +9,10 @@ #ifndef PULSE_D3D11_H_ #define PULSE_D3D11_H_ +#define D3D11_NO_HELPERS +#define CINTERFACE +#define COBJMACROS + #ifdef PULSE_PLAT_WINDOWS #include #endif @@ -20,6 +24,21 @@ #define D3D11_RETRIEVE_DRIVER_DATA_AS(handle, cast) ((cast)handle->driver_data) +#define CHECK_D3D11_RETVAL(backend, res, error, retval) \ + do { \ + if((res) != S_OK && (res) != S_FALSE) \ + { \ + if(backend != PULSE_NULL_HANDLE && PULSE_IS_BACKEND_LOW_LEVEL_DEBUG(backend)) \ + PulseLogErrorFmt(backend, "(D3D11) call to a D3D11 function failed due to %s", D3D11VerbaliseResult(res)); \ + PulseSetInternalError(error); \ + return retval; \ + } \ + } while(0) \ + +#define CHECK_D3D11(backend, res, error) CHECK_D3D11_RETVAL(backend, res, error, ) + +const char* D3D11VerbaliseResult(HRESULT res); + PulseBackendFlags Direct3D11CheckSupport(PulseBackendFlags candidates, PulseShaderFormatsFlags shader_formats_used); // Returns corresponding PULSE_BACKEND enum in case of success and PULSE_BACKEND_INVALID otherwise #endif // PULSE_D3D11_H_ diff --git a/Sources/Backends/D3D11/D3D11Buffer.c b/Sources/Backends/D3D11/D3D11Buffer.c index 9f45ffb..9b0d7c0 100644 --- a/Sources/Backends/D3D11/D3D11Buffer.c +++ b/Sources/Backends/D3D11/D3D11Buffer.c @@ -2,18 +2,40 @@ // This file is part of "Pulse" // For conditions of distribution and use, see copyright notice in LICENSE -#include - #include +#include #include "../../PulseInternal.h" #include "D3D11.h" +#include "D3D11Device.h" #include "D3D11Buffer.h" #include "D3D11CommandList.h" PulseBuffer Direct3D11CreateBuffer(PulseDevice device, const PulseBufferCreateInfo* create_infos) { + Direct3D11Device* d3d11_device = D3D11_RETRIEVE_DRIVER_DATA_AS(device, Direct3D11Device*); + PulseBuffer buffer = (PulseBuffer)calloc(1, sizeof(PulseBufferHandler)); PULSE_CHECK_ALLOCATION_RETVAL(buffer, PULSE_NULL_HANDLE); + + Direct3D11Buffer* d3d11_buffer = (Direct3D11Buffer*)calloc(1, sizeof(Direct3D11Buffer)); + PULSE_CHECK_ALLOCATION_RETVAL(d3d11_buffer, PULSE_NULL_HANDLE); + + buffer->device = device; + buffer->driver_data = d3d11_buffer; + buffer->size = create_infos->size; + buffer->usage = create_infos->usage; + + D3D11_BUFFER_DESC description = { 0 }; + description.ByteWidth = create_infos->size; + description.Usage = D3D11_USAGE_DEFAULT; + if(create_infos->usage & (PULSE_BUFFER_USAGE_STORAGE_READ | PULSE_BUFFER_USAGE_STORAGE_WRITE)) + { + description.BindFlags |= D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE; + description.MiscFlags |= D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS; + } + + CHECK_D3D11_RETVAL(device->backend, ID3D11Device_CreateBuffer(d3d11_device->device, &description, PULSE_NULLPTR, &d3d11_buffer->buffer), PULSE_ERROR_INITIALIZATION_FAILED, PULSE_NULL_HANDLE); + return buffer; } @@ -38,4 +60,8 @@ bool Direct3D11CopyBufferToImage(PulseCommandList cmd, const PulseBufferRegion* void Direct3D11DestroyBuffer(PulseDevice device, PulseBuffer buffer) { + Direct3D11Buffer* d3d11_buffer = D3D11_RETRIEVE_DRIVER_DATA_AS(buffer, Direct3D11Buffer*); + ID3D11Buffer_Release(d3d11_buffer->buffer); + free(d3d11_buffer); + free(buffer); } diff --git a/Sources/Backends/D3D11/D3D11Buffer.h b/Sources/Backends/D3D11/D3D11Buffer.h index eb13ce5..dc8c5ea 100644 --- a/Sources/Backends/D3D11/D3D11Buffer.h +++ b/Sources/Backends/D3D11/D3D11Buffer.h @@ -13,7 +13,7 @@ typedef struct Direct3D11Buffer { - int dummy; + ID3D11Buffer* buffer; } Direct3D11Buffer; PulseBuffer Direct3D11CreateBuffer(PulseDevice device, const PulseBufferCreateInfo* create_infos); diff --git a/Sources/Backends/D3D11/D3D11ComputePipeline.c b/Sources/Backends/D3D11/D3D11ComputePipeline.c index 6238288..2ae44a4 100644 --- a/Sources/Backends/D3D11/D3D11ComputePipeline.c +++ b/Sources/Backends/D3D11/D3D11ComputePipeline.c @@ -8,10 +8,71 @@ #include "D3D11Device.h" #include "D3D11ComputePipeline.h" +#include +#include + +static HRESULT CompileComputeShader(PulseDevice device, const unsigned char* src, uint32_t src_size, const char* entry_point, ID3DBlob** blob) +{ + if(!src || !entry_point || !device || !blob) + return E_INVALIDARG; + + Direct3D11Device* d3d11_device = D3D11_RETRIEVE_DRIVER_DATA_AS(device, Direct3D11Device*); + *blob = PULSE_NULLPTR; + + UINT flags = D3DCOMPILE_ENABLE_STRICTNESS; + if(PULSE_IS_BACKEND_HIGH_LEVEL_DEBUG(device->backend)) + flags |= D3DCOMPILE_DEBUG; + + // We generally prefer to use the higher CS shader profile when possible as CS 5.0 is better performance on 11-class hardware + LPCSTR profile = (ID3D11Device_GetFeatureLevel(d3d11_device->device) >= D3D_FEATURE_LEVEL_11_0) ? "cs_5_0" : "cs_4_0"; + + ID3DBlob* shader_blob = PULSE_NULLPTR; + ID3DBlob* error_blob = PULSE_NULLPTR; + HRESULT hr = D3DCompile(src, src_size, PULSE_NULLPTR, PULSE_NULLPTR, PULSE_NULLPTR, entry_point, profile, flags, 0, &shader_blob, &error_blob); + + if(FAILED(hr)) + { + if(error_blob) + { + if(PULSE_IS_BACKEND_LOW_LEVEL_DEBUG(device->backend)) + PulseLogInfoFmt(device->backend, "(D3D11) failed to compile HLSL shader. %s", ID3D10Blob_GetBufferPointer(error_blob)); + ID3D10Blob_Release(error_blob); + } + if(shader_blob) + ID3D10Blob_Release(shader_blob); + return hr; + } + + *blob = shader_blob; + return hr; +} + PulseComputePipeline Direct3D11CreateComputePipeline(PulseDevice device, const PulseComputePipelineCreateInfo* info) { + Direct3D11Device* d3d11_device = D3D11_RETRIEVE_DRIVER_DATA_AS(device, Direct3D11Device*); + PulseComputePipelineHandler* pipeline = (PulseComputePipelineHandler*)calloc(1, sizeof(PulseComputePipelineHandler)); PULSE_CHECK_ALLOCATION_RETVAL(pipeline, PULSE_NULL_HANDLE); + + Direct3D11ComputePipeline* d3d11_pipeline = (Direct3D11ComputePipeline*)calloc(1, sizeof(Direct3D11ComputePipeline)); + PULSE_CHECK_ALLOCATION_RETVAL(d3d11_pipeline, PULSE_NULL_HANDLE); + + pipeline->driver_data = d3d11_pipeline; + + ID3D10Blob* blob = PULSE_NULLPTR; + if(info->format & PULSE_SHADER_FORMAT_HLSL_BIT) + CHECK_D3D11_RETVAL(device->backend, CompileComputeShader(device, info->code, info->code_size, info->entrypoint, &blob), PULSE_ERROR_INITIALIZATION_FAILED, PULSE_NULL_HANDLE); + + if(blob == PULSE_NULLPTR) + { + D3DCreateBlob(info->code_size, &blob); + memcpy(ID3D10Blob_GetBufferPointer(blob), (void*)info->code, info->code_size); + } + + CHECK_D3D11_RETVAL(device->backend, ID3D11Device_CreateComputeShader(d3d11_device->device, ID3D10Blob_GetBufferPointer(blob), ID3D10Blob_GetBufferSize(blob), PULSE_NULLPTR, &d3d11_pipeline->shader), PULSE_ERROR_INITIALIZATION_FAILED, PULSE_NULL_HANDLE);; + + ID3D10Blob_Release(blob); + if(PULSE_IS_BACKEND_HIGH_LEVEL_DEBUG(device->backend)) PulseLogInfoFmt(device->backend, "(D3D11) created new compute pipeline %p", pipeline); return pipeline; @@ -19,4 +80,16 @@ PulseComputePipeline Direct3D11CreateComputePipeline(PulseDevice device, const P void Direct3D11DestroyComputePipeline(PulseDevice device, PulseComputePipeline pipeline) { + if(pipeline == PULSE_NULL_HANDLE) + { + if(PULSE_IS_BACKEND_LOW_LEVEL_DEBUG(device->backend)) + PulseLogWarning(device->backend, "compute pipeline is NULL, this may be a bug in your application"); + return; + } + Direct3D11ComputePipeline* d3d11_pipeline = D3D11_RETRIEVE_DRIVER_DATA_AS(pipeline, Direct3D11ComputePipeline*); + ID3D11ComputeShader_Release(d3d11_pipeline->shader); + free(d3d11_pipeline); + if(PULSE_IS_BACKEND_HIGH_LEVEL_DEBUG(device->backend)) + PulseLogInfoFmt(device->backend, "(D3D11) destroyed compute pipeline %p", pipeline); + free(pipeline); } diff --git a/Sources/Backends/D3D11/D3D11ComputePipeline.h b/Sources/Backends/D3D11/D3D11ComputePipeline.h index 42a5870..0e162c6 100644 --- a/Sources/Backends/D3D11/D3D11ComputePipeline.h +++ b/Sources/Backends/D3D11/D3D11ComputePipeline.h @@ -13,7 +13,7 @@ typedef struct Direct3D11ComputePipeline { - int dummy; + ID3D11ComputeShader* shader; } Direct3D11ComputePipeline; PulseComputePipeline Direct3D11CreateComputePipeline(PulseDevice device, const PulseComputePipelineCreateInfo* info); diff --git a/Sources/Backends/D3D11/D3D11Device.c b/Sources/Backends/D3D11/D3D11Device.c index 277d2eb..855eb22 100644 --- a/Sources/Backends/D3D11/D3D11Device.c +++ b/Sources/Backends/D3D11/D3D11Device.c @@ -35,7 +35,7 @@ bool Direct3D11IsDedicatedAdapter(IDXGIAdapter1* adapter) static uint64_t Direct3D11ScoreAdapter(IDXGIAdapter1* adapter) { DXGI_ADAPTER_DESC1 desc; - adapter->lpVtbl->GetDesc1(adapter, &desc); + IDXGIAdapter1_GetDesc1(adapter, &desc); D3D_FEATURE_LEVEL feature_levels[] = { D3D_FEATURE_LEVEL_11_1, @@ -58,10 +58,19 @@ static uint64_t Direct3D11ScoreAdapter(IDXGIAdapter1* adapter) if(FAILED(hr)) return 0; - hr = base_device->lpVtbl->QueryInterface(base_device, &IID_ID3D11Device1, (void**)&d3d_device1); + hr = ID3D11Device_QueryInterface(base_device, &IID_ID3D11Device1, (void**)&d3d_device1); if(FAILED(hr) || out_feature_level < D3D_FEATURE_LEVEL_10_0) goto Cleanup; + // Verify compute shader support presence + if(ID3D11Device_GetFeatureLevel(base_device) < D3D_FEATURE_LEVEL_11_0) + { + D3D11_FEATURE_DATA_D3D10_X_HARDWARE_OPTIONS hwopts = { 0 }; + ID3D11Device_CheckFeatureSupport(base_device, D3D11_FEATURE_D3D10_X_HARDWARE_OPTIONS, &hwopts, sizeof(hwopts)); + if(!hwopts.ComputeShaders_Plus_RawAndStructuredBuffers_Via_Shader_4_x) + goto Cleanup; + } + if(Direct3D11IsDedicatedAdapter(adapter)) score += 50000; else if(!(desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE)) @@ -77,9 +86,9 @@ static uint64_t Direct3D11ScoreAdapter(IDXGIAdapter1* adapter) Cleanup: if(base_device) - base_device->lpVtbl->Release(base_device); + ID3D11Device_Release(base_device); if(base_context) - base_context->lpVtbl->Release(base_context); + ID3D11DeviceContext_Release(base_context); return score; } @@ -90,11 +99,11 @@ static bool Direct3D11IsAdapterForbidden(IDXGIAdapter1* adapter, PulseDevice* fo for(uint32_t i = 0; i < forbiden_devices_count; i++) { DXGI_ADAPTER_DESC1 desc1; - adapter->lpVtbl->GetDesc1(adapter, &desc1); + IDXGIAdapter1_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); + IDXGIAdapter1_GetDesc1(d3d11_device->adapter, &desc2); if(desc1.AdapterLuid.HighPart == desc2.AdapterLuid.HighPart && desc1.AdapterLuid.LowPart == desc2.AdapterLuid.LowPart) return true; @@ -118,9 +127,9 @@ static IDXGIAdapter1* Direct3D11SelectAdapter(IDXGIFactory1* factory, PulseDevic best_device_score = current_device_score; best_device_id = i; } - adapter->lpVtbl->Release(adapter); + IDXGIAdapter1_Release(adapter); } - if(factory->lpVtbl->EnumAdapters1(factory, best_device_id, &adapter) == DXGI_ERROR_NOT_FOUND) + if(IDXGIFactory1_EnumAdapters1(factory, best_device_id, &adapter) == DXGI_ERROR_NOT_FOUND) return PULSE_NULLPTR; return adapter; } @@ -141,7 +150,7 @@ PulseDevice Direct3D11CreateDevice(PulseBackend backend, PulseDevice* forbiden_d CreateDXGIFactory1(&IID_IDXGIFactory, (void**)&device->factory); device->adapter = Direct3D11SelectAdapter(device->factory, forbiden_devices, forbiden_devices_count); - device->adapter->lpVtbl->GetDesc1(device->adapter, &device->description); + IDXGIAdapter1_GetDesc1(device->adapter, &device->description); D3D_FEATURE_LEVEL feature_levels[] = { D3D_FEATURE_LEVEL_11_1, @@ -150,7 +159,11 @@ PulseDevice Direct3D11CreateDevice(PulseBackend backend, PulseDevice* forbiden_d 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); + UINT flags = 0; + if(PULSE_IS_BACKEND_HIGH_LEVEL_DEBUG(backend)) + flags |= D3D11_CREATE_DEVICE_DEBUG; + + D3D11CreateDevice((IDXGIAdapter*)device->adapter, D3D_DRIVER_TYPE_UNKNOWN, PULSE_NULLPTR, flags, feature_levels, PULSE_SIZEOF_ARRAY(feature_levels), D3D11_SDK_VERSION, &device->device, PULSE_NULLPTR, &device->context); PULSE_LOAD_DRIVER_DEVICE(Direct3D11); if(PULSE_IS_BACKEND_HIGH_LEVEL_DEBUG(backend)) @@ -163,10 +176,10 @@ 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); + ID3D11Device_Release(d3d11_device->device); + ID3D11DeviceContext_Release(d3d11_device->context); + IDXGIAdapter1_Release(d3d11_device->adapter); + IDXGIFactory1_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); diff --git a/Sources/Backends/OpenGL/OpenGLComputePipeline.c b/Sources/Backends/OpenGL/OpenGLComputePipeline.c index ddc5aad..f88d5ec 100644 --- a/Sources/Backends/OpenGL/OpenGLComputePipeline.c +++ b/Sources/Backends/OpenGL/OpenGLComputePipeline.c @@ -24,16 +24,6 @@ PulseComputePipeline OpenGLCreateComputePipeline(PulseDevice device, const Pulse pipeline->driver_data = opengl_pipeline; - if(PULSE_IS_BACKEND_LOW_LEVEL_DEBUG(device->backend)) - { - if(info->code == PULSE_NULLPTR) - PulseLogError(device->backend, "invalid code pointer passed to PulseComputePipelineCreateInfo"); - if(info->entrypoint == PULSE_NULLPTR) - PulseLogError(device->backend, "invalid entrypoint pointer passed to PulseComputePipelineCreateInfo"); - if(info->format == PULSE_SHADER_FORMAT_WGSL_BIT && (device->backend->supported_shader_formats & PULSE_SHADER_FORMAT_WGSL_BIT) == 0) - PulseLogError(device->backend, "invalid shader format passed to PulseComputePipelineCreateInfo"); - } - uint8_t* code = (uint8_t*)calloc(info->code_size + 1, 1); memcpy(code, info->code, info->code_size); diff --git a/Sources/Backends/Software/SoftComputePipeline.c b/Sources/Backends/Software/SoftComputePipeline.c index 741da1d..b627c05 100644 --- a/Sources/Backends/Software/SoftComputePipeline.c +++ b/Sources/Backends/Software/SoftComputePipeline.c @@ -119,16 +119,6 @@ PulseComputePipeline SoftCreateComputePipeline(PulseDevice device, const PulseCo SoftComputePipeline* soft_pipeline = (SoftComputePipeline*)calloc(1, sizeof(SoftComputePipeline)); PULSE_CHECK_ALLOCATION_RETVAL(soft_pipeline, PULSE_NULL_HANDLE); - if(PULSE_IS_BACKEND_LOW_LEVEL_DEBUG(device->backend)) - { - if(info->code == PULSE_NULLPTR) - PulseLogError(device->backend, "invalid code pointer passed to PulseComputePipelineCreateInfo"); - if(info->entrypoint == PULSE_NULLPTR) - PulseLogError(device->backend, "invalid entrypoint pointer passed to PulseComputePipelineCreateInfo"); - if(info->format == PULSE_SHADER_FORMAT_SPIRV_BIT && (device->backend->supported_shader_formats & PULSE_SHADER_FORMAT_SPIRV_BIT) == 0) - PulseLogError(device->backend, "invalid shader format passed to PulseComputePipelineCreateInfo"); - } - soft_pipeline->program = spvm_program_create(soft_device->spv_context, (spvm_source)info->code, info->code_size / sizeof(spvm_word)); soft_pipeline->entry_point = calloc(1, strlen(info->entrypoint)); PULSE_CHECK_ALLOCATION_RETVAL(soft_pipeline->entry_point, PULSE_NULL_HANDLE); diff --git a/Sources/Backends/Vulkan/VulkanComputePipeline.c b/Sources/Backends/Vulkan/VulkanComputePipeline.c index d82a429..b37d06a 100644 --- a/Sources/Backends/Vulkan/VulkanComputePipeline.c +++ b/Sources/Backends/Vulkan/VulkanComputePipeline.c @@ -19,16 +19,6 @@ PulseComputePipeline VulkanCreateComputePipeline(PulseDevice device, const Pulse pipeline->driver_data = vulkan_pipeline; - if(PULSE_IS_BACKEND_LOW_LEVEL_DEBUG(device->backend)) - { - if(info->code == PULSE_NULLPTR) - PulseLogError(device->backend, "invalid code pointer passed to PulseComputePipelineCreateInfo"); - if(info->entrypoint == PULSE_NULLPTR) - PulseLogError(device->backend, "invalid entrypoint pointer passed to PulseComputePipelineCreateInfo"); - if(info->format == PULSE_SHADER_FORMAT_SPIRV_BIT && (device->backend->supported_shader_formats & PULSE_SHADER_FORMAT_SPIRV_BIT) == 0) - PulseLogError(device->backend, "invalid shader format passed to PulseComputePipelineCreateInfo"); - } - VkShaderModuleCreateInfo shader_module_create_info = { 0 }; shader_module_create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; shader_module_create_info.codeSize = info->code_size; diff --git a/Sources/Backends/WebGPU/WebGPUComputePipeline.c b/Sources/Backends/WebGPU/WebGPUComputePipeline.c index 5c8f845..3023b6c 100644 --- a/Sources/Backends/WebGPU/WebGPUComputePipeline.c +++ b/Sources/Backends/WebGPU/WebGPUComputePipeline.c @@ -335,16 +335,6 @@ PulseComputePipeline WebGPUCreateComputePipeline(PulseDevice device, const Pulse pipeline->driver_data = webgpu_pipeline; - if(PULSE_IS_BACKEND_LOW_LEVEL_DEBUG(device->backend)) - { - if(info->code == PULSE_NULLPTR) - PulseLogError(device->backend, "invalid code pointer passed to PulseComputePipelineCreateInfo"); - if(info->entrypoint == PULSE_NULLPTR) - PulseLogError(device->backend, "invalid entrypoint pointer passed to PulseComputePipelineCreateInfo"); - if(info->format == PULSE_SHADER_FORMAT_WGSL_BIT && (device->backend->supported_shader_formats & PULSE_SHADER_FORMAT_WGSL_BIT) == 0) - PulseLogError(device->backend, "invalid shader format passed to PulseComputePipelineCreateInfo"); - } - WGPUShaderSourceWGSL source = { 0 }; source.chain.next = PULSE_NULLPTR; source.chain.sType = WGPUSType_ShaderSourceWGSL; diff --git a/Sources/PulseComputePipeline.c b/Sources/PulseComputePipeline.c index 6d64def..0c55163 100644 --- a/Sources/PulseComputePipeline.c +++ b/Sources/PulseComputePipeline.c @@ -11,6 +11,15 @@ PULSE_API PulseComputePipeline PulseCreateComputePipeline(PulseDevice device, co if(info == PULSE_NULLPTR && PULSE_IS_BACKEND_LOW_LEVEL_DEBUG(device->backend)) PulseLogError(device->backend, "null infos pointer"); PULSE_CHECK_PTR_RETVAL(info, PULSE_NULL_HANDLE); + if(PULSE_IS_BACKEND_LOW_LEVEL_DEBUG(device->backend)) + { + if(info->code == PULSE_NULLPTR) + PulseLogError(device->backend, "invalid code pointer passed to PulseComputePipelineCreateInfo"); + if(info->entrypoint == PULSE_NULLPTR) + PulseLogError(device->backend, "invalid entrypoint pointer passed to PulseComputePipelineCreateInfo"); + if((info->format & device->backend->supported_shader_formats) == 0) + PulseLogError(device->backend, "invalid shader format passed to PulseComputePipelineCreateInfo"); + } PulseComputePipeline pipeline = device->PFN_CreateComputePipeline(device, info); if(pipeline == PULSE_NULL_HANDLE) return PULSE_NULL_HANDLE; diff --git a/Tests/Device.c b/Tests/Device.c index 1df1b9e..63456e6 100644 --- a/Tests/Device.c +++ b/Tests/Device.c @@ -15,6 +15,27 @@ void TestDeviceSetup() CleanupPulse(backend); } +void TestMultipleDevices() +{ + PulseBackend backend; + SetupPulse(&backend); + + #define DEVICES_COUNT 10 + + PulseDevice devices[DEVICES_COUNT]; + for(int i = 0; i < DEVICES_COUNT; i++) + { + devices[i] = PulseCreateDevice(backend, NULL, 0); + TEST_ASSERT_NOT_EQUAL_MESSAGE(devices[i], PULSE_NULL_HANDLE, PulseVerbaliseErrorType(PulseGetLastErrorType())); + } + + for(int i = 0; i < DEVICES_COUNT; i++) + PulseDestroyDevice(devices[i]); + + #undef DEVICES_COUNT + CleanupPulse(backend); +} + void TestForbiddenDeviceSetup() { PulseBackend backend; @@ -78,6 +99,7 @@ void TestDevice() RUN_TEST(TestDeviceSetup); RUN_TEST(TestForbiddenDeviceSetup); RUN_TEST(TestInvalidBackendDeviceSetup); + RUN_TEST(TestMultipleDevices); RUN_TEST(TestBackendInUse); RUN_TEST(TestShaderFormatSupport); } diff --git a/xmake.lua b/xmake.lua index 084434f..5f75a2c 100644 --- a/xmake.lua +++ b/xmake.lua @@ -35,12 +35,7 @@ local backends = { option = "d3d11", default = is_plat("windows", "msys", "mingw"), custom = function() - if is_plat("linux") then - add_sysincludedirs("/usr/include/dxvk/") - add_syslinks("dxvk_d3d11", "dxvk_dxgi") - else - add_syslinks("d3d11", "dxgi", "windowscodecs") - end + add_syslinks("d3d11", "d3dcompiler_47", "dxgi", "windowscodecs") end }, Software = {