diff --git a/Examples/D3D11/main.c b/Examples/D3D11/main.c new file mode 100644 index 0000000..28875b8 --- /dev/null +++ b/Examples/D3D11/main.c @@ -0,0 +1,29 @@ +#include + +#include +#include + +void DebugCallBack(PulseDebugMessageSeverity severity, const char* message) +{ + if(severity == PULSE_DEBUG_MESSAGE_SEVERITY_ERROR) + { + fprintf(stderr, "Pulse Error: %s\n", message); + exit(1); + } + else if(severity == PULSE_DEBUG_MESSAGE_SEVERITY_WARNING) + fprintf(stderr, "Pulse Warning: %s\n", message); + else + printf("Pulse: %s\n", message); +} + +#define BUFFER_SIZE (256 * sizeof(uint32_t)) + +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); + PulseUnloadBackend(backend); + puts("Successfully executed Pulse example using D3D11 !"); + return 0; +} diff --git a/Examples/D3D11/xmake.lua b/Examples/D3D11/xmake.lua new file mode 100644 index 0000000..8643b60 --- /dev/null +++ b/Examples/D3D11/xmake.lua @@ -0,0 +1,7 @@ +target("D3D11Example") + add_deps("pulse_gpu") + if is_plat("linux") then + set_extension(".x86_64") + end + add_files("*.c") +target_end() diff --git a/Examples/xmake.lua b/Examples/xmake.lua index 8f95e8e..4c58db6 100644 --- a/Examples/xmake.lua +++ b/Examples/xmake.lua @@ -14,4 +14,7 @@ if has_config("examples") then if has_config("software") then includes("Software/xmake.lua") end + if has_config("d3d11") then + includes("D3D11/xmake.lua") + end end diff --git a/Includes/Pulse.h b/Includes/Pulse.h index aa0df77..13f9da9 100644 --- a/Includes/Pulse.h +++ b/Includes/Pulse.h @@ -42,6 +42,7 @@ typedef enum PulseBackendBits PULSE_BACKEND_SOFTWARE = PULSE_BIT(6), PULSE_BACKEND_OPENGL = PULSE_BIT(7), PULSE_BACKEND_OPENGL_ES = PULSE_BIT(8), + PULSE_BACKEND_D3D11 = PULSE_BIT(9), } PulseBackendBits; typedef PulseFlags PulseBackendFlags; @@ -75,6 +76,7 @@ typedef enum PulseShaderFormatsBits PULSE_SHADER_FORMAT_METALLIB_BIT = PULSE_BIT(3), // Can be used by Metal backend 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 // More to come } PulseShaderFormatsBits; typedef PulseFlags PulseShaderFormatsFlags; diff --git a/Includes/PulseProfile.h b/Includes/PulseProfile.h index 8320408..a2fe0d7 100644 --- a/Includes/PulseProfile.h +++ b/Includes/PulseProfile.h @@ -83,6 +83,14 @@ extern "C" { #define PULSE_API #endif +#ifdef PULSE_COMPILER_MSVC + #define PULSE_IMPORT_API __declspec(dllimport) +#elif defined(PULSE_COMPILER_MINGW) + #define PULSE_IMPORT_API __attribute__((dllimport)) +#else + #define PULSE_IMPORT_API +#endif + #ifndef __cplusplus // if we compile in C #ifdef __STDC__ #ifdef __STDC_VERSION__ diff --git a/Sources/Backends/D3D11/D3D11.c b/Sources/Backends/D3D11/D3D11.c new file mode 100644 index 0000000..8ce44e1 --- /dev/null +++ b/Sources/Backends/D3D11/D3D11.c @@ -0,0 +1,37 @@ +// Copyright (C) 2025 kanel +// This file is part of "Pulse" +// For conditions of distribution and use, see copyright notice in LICENSE + +#include +#include "../../PulseInternal.h" + +#include "D3D11.h" +#include "D3D11Device.h" + +PulseBackendFlags PuD3D11CheckSupport(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) + return PULSE_BACKEND_INVALID; + return PULSE_BACKEND_D3D11; +} + +bool PuD3D11LoadBackend(PulseBackend backend, PulseDebugLevel debug_level) +{ + return true; +} + +void PuD3D11UnloadBackend(PulseBackend backend) +{ +} + +PulseBackendHandler D3D11Driver = { + .PFN_LoadBackend = PuD3D11LoadBackend, + .PFN_UnloadBackend = PuD3D11UnloadBackend, + .PFN_CreateDevice = PuD3D11CreateDevice, + .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 new file mode 100644 index 0000000..7998a96 --- /dev/null +++ b/Sources/Backends/D3D11/D3D11.h @@ -0,0 +1,21 @@ +// Copyright (C) 2025 kanel +// This file is part of "Pulse" +// For conditions of distribution and use, see copyright notice in LICENSE + +#ifdef PULSE_ENABLE_D3D11_BACKEND + +#ifndef PULSE_D3D11_H_ +#define PULSE_D3D11_H_ + +#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 + +#endif // PULSE_D3D11_H_ + +#endif // PULSE_ENABLE_D3D11_BACKEND diff --git a/Sources/Backends/D3D11/D3D11Device.c b/Sources/Backends/D3D11/D3D11Device.c new file mode 100644 index 0000000..925c8b5 --- /dev/null +++ b/Sources/Backends/D3D11/D3D11Device.c @@ -0,0 +1,61 @@ +// Copyright (C) 2025 kanel +// This file is part of "Pulse" +// For conditions of distribution and use, see copyright notice in LICENSE + +#include + +#include + +#include "../../PulseInternal.h" +#include "D3D11.h" +#include "D3D11Device.h" + +bool PuD3D11IsDedicatedAdapter(IDXGIAdapter1* adapter) +{ + DXGI_ADAPTER_DESC1 desc; + if(FAILED(adapter->lpVtbl->GetDesc1(adapter, &desc))) + return false; + bool has_dedicated_memory = desc.DedicatedVideoMemory > 0; + bool is_software_adapter = wcsstr(desc.Description, L"Microsoft Basic Render") != PULSE_NULLPTR; + + // Known vendor IDs + const uint32_t NVIDIA = 0x10DE; + const uint32_t AMD = 0x1002; + + bool is_known_vendor = (desc.VendorId == NVIDIA || desc.VendorId == AMD); + + return has_dedicated_memory && is_known_vendor && !is_software_adapter; +} + +static uint64_t PuD3D11ScoreAdapter(ID3D11Device* device, IDXGIAdapter1* adapter) +{ +} + +PulseDevice PuD3D11CreateDevice(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)); + 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); + return pulse_device; +} + +void PuD3D11DestroyDevice(PulseDevice device) +{ +} diff --git a/Sources/Backends/D3D11/D3D11Device.h b/Sources/Backends/D3D11/D3D11Device.h new file mode 100644 index 0000000..1ed7726 --- /dev/null +++ b/Sources/Backends/D3D11/D3D11Device.h @@ -0,0 +1,26 @@ +// Copyright (C) 2025 kanel +// This file is part of "Pulse" +// For conditions of distribution and use, see copyright notice in LICENSE + +#ifdef PULSE_ENABLE_D3D11_BACKEND + +#ifndef PULSE_D3D11_DEVICE_H_ +#define PULSE_D3D11_DEVICE_H_ + +#include +#include "D3D11.h" + +typedef struct D3D11Device +{ + ID3D11Device* device; + ID3D11DeviceContext* context; + IDXGIFactory1* factory; + IDXGIAdapter1* adapter; +} D3D11Device; + +PulseDevice PuD3D11CreateDevice(PulseBackend backend, PulseDevice* forbiden_devices, uint32_t forbiden_devices_count); +void PuD3D11DestroyDevice(PulseDevice device); + +#endif // PULSE_D3D11_DEVICE_H_ + +#endif // PULSE_ENABLE_D3D11_BACKEND diff --git a/Sources/PulseBackend.c b/Sources/PulseBackend.c index 54f4a48..2fc919e 100644 --- a/Sources/PulseBackend.c +++ b/Sources/PulseBackend.c @@ -23,6 +23,9 @@ #ifdef PULSE_ENABLE_OPENGL_BACKEND #include "Backends/OpenGL/OpenGL.h" #endif +#ifdef PULSE_ENABLE_D3D11_BACKEND + #include "Backends/D3D11/D3D11.h" +#endif // Ordered by default preference static const PulseCheckBackendSupportPFN backends_supports[] = { @@ -35,6 +38,9 @@ static const PulseCheckBackendSupportPFN backends_supports[] = { #ifdef PULSE_ENABLE_WEBGPU_BACKEND WebGPUCheckSupport, #endif + #ifdef PULSE_ENABLE_D3D11_BACKEND + PuD3D11CheckSupport, + #endif #ifdef PULSE_ENABLE_OPENGL_BACKEND OpenGLCheckSupport, OpenGLESCheckSupport, @@ -115,6 +121,9 @@ static PulseBackend PulseGetBackendFromFlag(PulseBackendBits flag) #ifdef PULSE_ENABLE_WEBGPU_BACKEND case PULSE_BACKEND_WEBGPU: return &WebGPUDriver; #endif + #ifdef PULSE_ENABLE_D3D11_BACKEND + case PULSE_BACKEND_D3D11: return &D3D11Driver; + #endif #ifdef PULSE_ENABLE_OPENGL_BACKEND case PULSE_BACKEND_OPENGL: return &OpenGLDriver; case PULSE_BACKEND_OPENGL_ES: return &OpenGLESDriver; diff --git a/Sources/PulseInternal.c b/Sources/PulseInternal.c index 8686088..9dfb960 100644 --- a/Sources/PulseInternal.c +++ b/Sources/PulseInternal.c @@ -123,7 +123,7 @@ char* PulseStrtokR(char* str, const char* delim, char** saveptr) return token; } -static int isspace(int x) +static int PulseIsSpace(int x) { return ((x) == ' ') || ((x) == '\t') || ((x) == '\r') || ((x) == '\n') || ((x) == '\f') || ((x) == '\v'); } @@ -131,10 +131,10 @@ static int isspace(int x) void PulseTrimString(char* str) { char* start = str; - while(*start && isspace((unsigned char)*start)) + while(*start && PulseIsSpace((unsigned char)*start)) start++; char* end = start + strlen(start) - 1; - while(end > start && isspace((unsigned char)*end)) + while(end > start && PulseIsSpace((unsigned char)*end)) end--; *(end + 1) = '\0'; if(start != str) diff --git a/Sources/PulseInternal.h b/Sources/PulseInternal.h index a3b197f..48e7801 100644 --- a/Sources/PulseInternal.h +++ b/Sources/PulseInternal.h @@ -11,6 +11,10 @@ #include "PulseDefs.h" #include "PulseEnums.h" +#ifdef PULSE_COMPILER_MINGW + #include +#endif + #define PULSE_MAX_READ_TEXTURES_BOUND 8 #define PULSE_MAX_READ_BUFFERS_BOUND 8 #define PULSE_MAX_WRITE_TEXTURES_BOUND 8 @@ -222,5 +226,8 @@ void PulseLogBackend(PulseBackend backend, PulseDebugMessageSeverity type, const extern PulseBackendHandler OpenGLDriver; extern PulseBackendHandler OpenGLESDriver; #endif // PULSE_ENABLE_OPENGL_BACKEND +#ifdef PULSE_ENABLE_D3D11_BACKEND + extern PulseBackendHandler D3D11Driver; +#endif // PULSE_ENABLE_D3D11_BACKEND #endif // PULSE_INTERNAL_H_ diff --git a/xmake.lua b/xmake.lua index bff8a10..750ebf8 100644 --- a/xmake.lua +++ b/xmake.lua @@ -30,6 +30,18 @@ local backends = { end end }, + D3D11 = { + 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 + end + }, Software = { option = "software", default = true,