From 4dc3d4c45c954b91aa3983fce1336807005b28c9 Mon Sep 17 00:00:00 2001 From: Caleb Cornett Date: Sat, 5 Mar 2022 21:58:34 -0500 Subject: [PATCH 01/13] Device setup/teardown + Command buffer acquisition and submission --- CMakeLists.txt | 7 + src/Refresh.c | 40 +- src/Refresh_Driver.h | 1 + src/Refresh_Driver_D3D11.c | 1009 +++++++++++++++++++++++++++ src/Refresh_Driver_D3D11_cdefines.h | 214 ++++++ visualc/Refresh.vcxproj | 6 +- visualc/Refresh.vcxproj.filters | 6 + 7 files changed, 1274 insertions(+), 9 deletions(-) create mode 100644 src/Refresh_Driver_D3D11.c create mode 100644 src/Refresh_Driver_D3D11_cdefines.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 2beff84..e561d42 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,6 +40,11 @@ endif() add_definitions( -DREFRESH_DRIVER_VULKAN ) +if (WIN32) + add_definitions( + -DREFRESH_DRIVER_D3D11 + ) +endif() # Source lists add_library(Refresh @@ -49,8 +54,10 @@ add_library(Refresh # Internal Headers src/Refresh_Driver.h src/Refresh_Driver_Vulkan_vkfuncs.h + src/Refresh_Driver_D3D11_cdefines.h # Source Files src/Refresh.c + src/Refresh_Driver_D3D11.c src/Refresh_Driver_Vulkan.c src/Refresh_Image.c ) diff --git a/src/Refresh.c b/src/Refresh.c index e12c387..2ce2a96 100644 --- a/src/Refresh.c +++ b/src/Refresh.c @@ -34,7 +34,12 @@ /* Drivers */ static const Refresh_Driver *drivers[] = { +#if REFRESH_DRIVER_VULKAN &VulkanDriver, +#endif +#if REFRESH_DRIVER_D3D11 + &D3D11Driver, +#endif NULL }; @@ -124,21 +129,42 @@ uint32_t Refresh_LinkedVersion(void) /* Driver Functions */ -static int32_t selectedDriver = 0; +static int32_t selectedDriver = -1; Refresh_Device* Refresh_CreateDevice( Refresh_PresentationParameters *presentationParameters, uint8_t debugMode ) { - if (selectedDriver < 0) + uint32_t result = 0; + uint32_t i; + const char *hint = SDL_GetHint("REFRESH_FORCE_DRIVER"); + for (i = 0; drivers[i] != NULL; i += 1) { - return NULL; + if (hint != NULL) + { + if (SDL_strcmp(hint, drivers[i]->Name) != 0) + { + continue; + } + } + + /* FIXME: add fallback driver handling */ + break; } - return drivers[selectedDriver]->CreateDevice( - presentationParameters, - debugMode - ); + if (drivers[i] == NULL) + { + Refresh_LogError("No supported Refresh driver found!"); + return NULL; + } + else + { + selectedDriver = i; + return drivers[selectedDriver]->CreateDevice( + presentationParameters, + debugMode + ); + } } void Refresh_DestroyDevice(Refresh_Device *device) diff --git a/src/Refresh_Driver.h b/src/Refresh_Driver.h index a46270d..c99241e 100644 --- a/src/Refresh_Driver.h +++ b/src/Refresh_Driver.h @@ -522,6 +522,7 @@ typedef struct Refresh_Driver } Refresh_Driver; extern Refresh_Driver VulkanDriver; +extern Refresh_Driver D3D11Driver; #endif /* REFRESH_DRIVER_H */ diff --git a/src/Refresh_Driver_D3D11.c b/src/Refresh_Driver_D3D11.c new file mode 100644 index 0000000..d4aa718 --- /dev/null +++ b/src/Refresh_Driver_D3D11.c @@ -0,0 +1,1009 @@ +/* Refresh - XNA-inspired 3D Graphics Library with modern capabilities + * + * Copyright (c) 2020 Evan Hemsley + * + * This software is provided 'as-is', without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from + * the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software in a + * product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source distribution. + * + * Evan "cosmonaut" Hemsley + * + */ + +#if REFRESH_DRIVER_D3D11 + +#define D3D11_NO_HELPERS +#define CINTERFACE +#define COBJMACROS +#include +#include + +#include "Refresh_Driver.h" +#include "Refresh_Driver_D3D11_cdefines.h" + +#include + +#define D3D11_DLL "d3d11.dll" +#define DXGI_DLL "dxgi.dll" + +#define ERROR_CHECK(msg) \ + if (FAILED(res)) \ + { \ + D3D11_INTERNAL_LogError(renderer->device, msg, res); \ + } + +#define ERROR_CHECK_RETURN(msg, ret) \ + if (FAILED(res)) \ + { \ + D3D11_INTERNAL_LogError(renderer->device, msg, res); \ + return ret; \ + } + +#define ERROR_CHECK_UNLOCK_RETURN(msg, ret) \ + if (FAILED(res)) \ + { \ + D3D11_INTERNAL_LogError(renderer->device, msg, res); \ + SDL_UnlockMutex(renderer->ctxLock); \ + return ret; \ + } + +#define EXPAND_ELEMENTS_IF_NEEDED(arr, initialValue, type) \ + if (arr->count == arr->capacity) \ + { \ + if (arr->capacity == 0) \ + { \ + arr->capacity = initialValue; \ + } \ + else \ + { \ + arr->capacity *= 2; \ + } \ + arr->elements = (type*) SDL_realloc( \ + arr->elements, \ + arr->capacity * sizeof(type) \ + ); \ + } + +#define NOT_IMPLEMENTED SDL_assert(0 && "Not implemented!"); + + /* Conversions */ + +static DXGI_FORMAT RefreshToD3D11_SurfaceFormat[] = +{ + DXGI_FORMAT_R8G8B8A8_UNORM, /* R8G8B8A8 */ + DXGI_FORMAT_B8G8R8A8_UNORM, /* B8G8R8A8 */ + DXGI_FORMAT_B5G6R5_UNORM, /* R5G6B5 */ + DXGI_FORMAT_B5G5R5A1_UNORM, /* A1R5G5B5 */ + DXGI_FORMAT_B4G4R4A4_UNORM, /* B4G4R4A4 */ + DXGI_FORMAT_BC1_UNORM, /* BC1 */ + DXGI_FORMAT_BC3_UNORM, /* BC3 */ + DXGI_FORMAT_BC5_UNORM, /* BC5 */ + DXGI_FORMAT_R8G8_SNORM, /* R8G8_SNORM */ + DXGI_FORMAT_R8G8B8A8_SNORM, /* R8G8B8A8_SNORM */ + DXGI_FORMAT_R10G10B10A2_UNORM, /* A2R10G10B10 */ + DXGI_FORMAT_R16G16_UNORM, /* R16G16 */ + DXGI_FORMAT_R16G16B16A16_UNORM, /* R16G16B16A16 */ + DXGI_FORMAT_R8_UNORM, /* R8 */ + DXGI_FORMAT_R32_FLOAT, /* R32_SFLOAT */ + DXGI_FORMAT_R32G32_FLOAT, /* R32G32_SFLOAT */ + DXGI_FORMAT_R32G32B32A32_FLOAT, /* R32G32B32A32_SFLOAT */ + DXGI_FORMAT_R16_FLOAT, /* R16_SFLOAT */ + DXGI_FORMAT_R16G16_FLOAT, /* R16G16_SFLOAT */ + DXGI_FORMAT_R16G16B16A16_FLOAT, /* R16G16B16A16_SFLOAT */ + DXGI_FORMAT_D16_UNORM, /* D16 */ + DXGI_FORMAT_D32_FLOAT, /* D32 */ + DXGI_FORMAT_D24_UNORM_S8_UINT, /* D16S8 */ + DXGI_FORMAT_D32_FLOAT_S8X24_UINT /* D32S8 */ +}; + +static DXGI_FORMAT RefreshToD3D11_VertexFormat[] = +{ + DXGI_FORMAT_R32_FLOAT, /* SINGLE */ + DXGI_FORMAT_R32G32_FLOAT, /* VECTOR2 */ + DXGI_FORMAT_R32G32B32_FLOAT, /* VECTOR3 */ + DXGI_FORMAT_R32G32B32A32_FLOAT, /* VECTOR4 */ + DXGI_FORMAT_R8G8B8A8_UNORM, /* COLOR */ + DXGI_FORMAT_R8G8B8A8_UINT, /* BYTE4 */ + DXGI_FORMAT_R16G16_SINT, /* SHORT2 */ + DXGI_FORMAT_R16G16B16A16_SINT, /* SHORT4 */ + DXGI_FORMAT_R16G16_SNORM, /* NORMALIZEDSHORT2 */ + DXGI_FORMAT_R16G16B16A16_SNORM, /* NORMALIZEDSHORT4 */ + DXGI_FORMAT_R16G16_FLOAT, /* HALFVECTOR2 */ + DXGI_FORMAT_R16G16B16A16_FLOAT /* HALFVECTOR4 */ +}; + +static DXGI_FORMAT RefreshToD3D11_IndexType[] = +{ + DXGI_FORMAT_R16_UINT, /* 16BIT */ + DXGI_FORMAT_R32_UINT /* 32BIT */ +}; + +static D3D11_PRIMITIVE_TOPOLOGY RefreshToD3D11_PrimitiveType[] = +{ + D3D_PRIMITIVE_TOPOLOGY_POINTLIST, /* POINTLIST */ + D3D_PRIMITIVE_TOPOLOGY_LINELIST, /* LINELIST */ + D3D_PRIMITIVE_TOPOLOGY_LINESTRIP, /* LINESTRIP */ + D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST, /* TRIANGLELIST */ + D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP /* TRIANGLESTRIP */ +}; + +static D3D11_FILL_MODE RefreshToD3D11_PolygonMode[] = +{ + D3D11_FILL_SOLID, /* FILL */ + D3D11_FILL_WIREFRAME, /* LINE */ +}; + +static D3D11_CULL_MODE RefreshToD3D11_CullMode[] = +{ + D3D11_CULL_NONE, /* NONE */ + D3D11_CULL_FRONT, /* FRONT */ + D3D11_CULL_BACK /* BACK */ +}; + +static D3D11_BLEND RefreshToD3D11_BlendFactor[] = +{ + D3D11_BLEND_ZERO, /* ZERO */ + D3D11_BLEND_ONE, /* ONE */ + D3D11_BLEND_SRC_COLOR, /* SRC_COLOR */ + D3D11_BLEND_INV_SRC_COLOR, /* ONE_MINUS_SRC_COLOR */ + D3D11_BLEND_DEST_COLOR, /* DST_COLOR */ + D3D11_BLEND_INV_DEST_COLOR, /* ONE_MINUS_DST_COLOR */ + D3D11_BLEND_SRC_ALPHA, /* SRC_ALPHA */ + D3D11_BLEND_INV_SRC_ALPHA, /* ONE_MINUS_SRC_ALPHA */ + D3D11_BLEND_DEST_ALPHA, /* DST_ALPHA */ + D3D11_BLEND_INV_DEST_ALPHA, /* ONE_MINUS_DST_ALPHA */ + D3D11_BLEND_BLEND_FACTOR, /* CONSTANT_COLOR */ + D3D11_BLEND_INV_BLEND_FACTOR, /* ONE_MINUS_CONSTANT_COLOR */ + D3D11_BLEND_SRC_ALPHA_SAT, /* SRC_ALPHA_SATURATE */ + D3D11_BLEND_SRC1_COLOR, /* SRC1_COLOR */ + D3D11_BLEND_INV_SRC1_COLOR, /* ONE_MINUS_SRC1_COLOR */ + D3D11_BLEND_SRC1_ALPHA, /* SRC1_ALPHA */ + D3D11_BLEND_INV_SRC1_ALPHA /* ONE_MINUS_SRC1_ALPHA */ +}; + +static D3D11_BLEND_OP RefreshToD3D11_BlendOp[] = +{ + D3D11_BLEND_OP_ADD, /* ADD */ + D3D11_BLEND_OP_SUBTRACT, /* SUBTRACT */ + D3D11_BLEND_OP_REV_SUBTRACT, /* REVERSE_SUBTRACT */ + D3D11_BLEND_OP_MIN, /* MIN */ + D3D11_BLEND_OP_MAX /* MAX */ +}; + +static D3D11_COMPARISON_FUNC RefreshToD3D11_CompareOp[] = +{ + D3D11_COMPARISON_NEVER, /* NEVER */ + D3D11_COMPARISON_LESS, /* LESS */ + D3D11_COMPARISON_EQUAL, /* EQUAL */ + D3D11_COMPARISON_LESS_EQUAL, /* LESS_OR_EQUAL */ + D3D11_COMPARISON_GREATER, /* GREATER */ + D3D11_COMPARISON_NOT_EQUAL, /* NOT_EQUAL */ + D3D11_COMPARISON_GREATER_EQUAL, /* GREATER_OR_EQUAL */ + D3D11_COMPARISON_ALWAYS /* ALWAYS */ +}; + +static D3D11_STENCIL_OP RefreshToD3D11_StencilOp[] = +{ + D3D11_STENCIL_OP_KEEP, /* KEEP */ + D3D11_STENCIL_OP_ZERO, /* ZERO */ + D3D11_STENCIL_OP_REPLACE, /* REPLACE */ + D3D11_STENCIL_OP_INCR_SAT, /* INCREMENT_AND_CLAMP */ + D3D11_STENCIL_OP_DECR_SAT, /* DECREMENT_AND_CLAMP */ + D3D11_STENCIL_OP_INVERT, /* INVERT */ + D3D11_STENCIL_OP_INCR, /* INCREMENT_AND_WRAP */ + D3D11_STENCIL_OP_DECR /* DECREMENT_AND_WRAP */ +}; + +static int32_t RefreshToD3D11_SampleCount[] = +{ + 1, /* 1 */ + 2, /* 2 */ + 4, /* 4 */ + 8, /* 8 */ + 16, /* 16 */ + 32, /* 32 */ + 64 /* 64 */ +}; + +static D3D11_INPUT_CLASSIFICATION RefreshToD3D11_VertexInputRate[] = +{ + D3D11_INPUT_PER_VERTEX_DATA, /* VERTEX */ + D3D11_INPUT_PER_INSTANCE_DATA /* INSTANCE */ +}; + +static D3D11_TEXTURE_ADDRESS_MODE RefreshToD3D11_SamplerAddressMode[] = +{ + D3D11_TEXTURE_ADDRESS_WRAP, /* REPEAT */ + D3D11_TEXTURE_ADDRESS_MIRROR, /* MIRRORED_REPEAT */ + D3D11_TEXTURE_ADDRESS_CLAMP, /* CLAMP_TO_EDGE */ + D3D11_TEXTURE_ADDRESS_BORDER /* CLAMP_TO_BORDER */ +}; + +/* Structs */ + +typedef struct D3D11CommandBuffer +{ + ID3D11DeviceContext *context; + SDL_threadID threadID; + uint8_t recording; + uint8_t fixed; + ID3D11CommandList *commandList; +} D3D11CommandBuffer; + +typedef struct D3D11CommandBufferPool +{ + D3D11CommandBuffer **elements; + uint32_t count; + uint32_t capacity; +} D3D11CommandBufferPool; + +typedef struct D3D11Renderer +{ + /* Persistent D3D11 Objects*/ + ID3D11Device *device; + ID3D11DeviceContext *immediateContext; + IDXGIFactory1 *factory; + IDXGIAdapter1* adapter; + void *d3d11_dll; + void *dxgi_dll; + + /* Deferred Contexts */ + D3D11CommandBufferPool *commandBufferPool; + + /* Blend State */ + Refresh_Vec4 blendFactor; + + /* Capabilities */ + uint8_t debugMode; + D3D_FEATURE_LEVEL featureLevel; + +} D3D11Renderer; + +/* Logging */ + +static void D3D11_INTERNAL_LogError( + ID3D11Device *device, + const char *msg, + HRESULT res +) { + #define MAX_ERROR_LEN 1024 /* FIXME: Arbitrary! */ + + /* Buffer for text, ensure space for \0 terminator after buffer */ + char wszMsgBuff[MAX_ERROR_LEN + 1]; + DWORD dwChars; /* Number of chars returned. */ + + if (res == DXGI_ERROR_DEVICE_REMOVED) + { + res = ID3D11Device_GetDeviceRemovedReason(device); + } + + /* Try to get the message from the system errors. */ + dwChars = FormatMessage( + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + res, + 0, + wszMsgBuff, + MAX_ERROR_LEN, + NULL + ); + + /* No message? Screw it, just post the code. */ + if (dwChars == 0) + { + Refresh_LogError("%s! Error Code: 0x%08X", msg, res); + return; + } + + /* Ensure valid range */ + dwChars = SDL_min(dwChars, MAX_ERROR_LEN); + + /* Trim whitespace from tail of message */ + while (dwChars > 0) + { + if (wszMsgBuff[dwChars - 1] <= ' ') + { + dwChars--; + } + else + { + break; + } + } + + /* Ensure null-terminated string */ + wszMsgBuff[dwChars] = '\0'; + + Refresh_LogError("%s! Error Code: %s (0x%08X)", msg, wszMsgBuff, res); +} + +/* Quit */ + +static void D3D11_DestroyDevice( + Refresh_Device* device +) { + D3D11Renderer *renderer = (D3D11Renderer*) device->driverData; + D3D11CommandBuffer *commandBuffer; + uint32_t i; + + /* Free the command buffer pool */ + for (i = 0; i < renderer->commandBufferPool->count; i += 1) + { + commandBuffer = renderer->commandBufferPool->elements[i]; + if (commandBuffer->commandList != NULL) + { + ID3D11CommandList_Release(commandBuffer->commandList); + } + ID3D11DeviceContext_Release(commandBuffer->context); + SDL_free(commandBuffer); + } + SDL_free(renderer->commandBufferPool->elements); + SDL_free(renderer->commandBufferPool); + + /* Release persistent D3D11 objects */ + ID3D11DeviceContext_Release(renderer->immediateContext); + ID3D11Device_Release(renderer->device); + + /* Release DXGI objects */ + IDXGIAdapter1_Release(renderer->adapter); + IDXGIFactory1_Release(renderer->factory); + + /* Release the DLLs */ + SDL_UnloadObject(renderer->d3d11_dll); + SDL_UnloadObject(renderer->dxgi_dll); +} + +/* Drawing */ + +static void D3D11_Clear( + Refresh_Renderer* driverData, + Refresh_CommandBuffer* commandBuffer, + Refresh_Rect* clearRect, + Refresh_ClearOptions options, + Refresh_Vec4* colors, + uint32_t colorCount, + Refresh_DepthStencilValue depthStencil +) { + NOT_IMPLEMENTED +} + +static void D3D11_DrawInstancedPrimitives( + Refresh_Renderer* driverData, + Refresh_CommandBuffer* commandBuffer, + uint32_t baseVertex, + uint32_t startIndex, + uint32_t primitiveCount, + uint32_t instanceCount, + uint32_t vertexParamOffset, + uint32_t fragmentParamOffset +) { + NOT_IMPLEMENTED +} + +static void D3D11_DrawIndexedPrimitives( + Refresh_Renderer* driverData, + Refresh_CommandBuffer* commandBuffer, + uint32_t baseVertex, + uint32_t startIndex, + uint32_t primitiveCount, + uint32_t vertexParamOffset, + uint32_t fragmentParamOffset +) { + NOT_IMPLEMENTED +} + +static void D3D11_DrawPrimitives( + Refresh_Renderer* driverData, + Refresh_CommandBuffer* commandBuffer, + uint32_t vertexStart, + uint32_t primitiveCount, + uint32_t vertexParamOffset, + uint32_t fragmentParamOffset +) { + NOT_IMPLEMENTED +} + +static void D3D11_DispatchCompute( + Refresh_Renderer* device, + Refresh_CommandBuffer* commandBuffer, + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ, + uint32_t computeParamOffset +) { + NOT_IMPLEMENTED +} + +/* State Creation */ + +static Refresh_ComputePipeline* D3D11_CreateComputePipeline( + Refresh_Renderer* driverData, + Refresh_ComputeShaderInfo* computeShaderInfo +) { + NOT_IMPLEMENTED +} + +static Refresh_GraphicsPipeline* D3D11_CreateGraphicsPipeline( + Refresh_Renderer* driverData, + Refresh_GraphicsPipelineCreateInfo* pipelineCreateInfo +) { + NOT_IMPLEMENTED +} + +static Refresh_Sampler* D3D11_CreateSampler( + Refresh_Renderer* driverData, + Refresh_SamplerStateCreateInfo* samplerStateCreateInfo +) { + NOT_IMPLEMENTED +} + +static Refresh_ShaderModule* D3D11_CreateShaderModule( + Refresh_Renderer* driverData, + Refresh_ShaderModuleCreateInfo* shaderModuleCreateInfo +) { + NOT_IMPLEMENTED +} + +static Refresh_Texture* D3D11_CreateTexture( + Refresh_Renderer* driverData, + Refresh_TextureCreateInfo* textureCreateInfo +) { + NOT_IMPLEMENTED +} + +static Refresh_Buffer* D3D11_CreateBuffer( + Refresh_Renderer* driverData, + Refresh_BufferUsageFlags usageFlags, + uint32_t sizeInBytes +) { + NOT_IMPLEMENTED +} + +/* Setters */ + +static void D3D11_SetTextureData( + Refresh_Renderer* driverData, + Refresh_CommandBuffer* commandBuffer, + Refresh_TextureSlice* textureSlice, + void* data, + uint32_t dataLengthInBytes +) { + NOT_IMPLEMENTED +} + +static void D3D11_SetTextureDataYUV( + Refresh_Renderer* driverData, + Refresh_CommandBuffer* commandBuffer, + Refresh_Texture* y, + Refresh_Texture* u, + Refresh_Texture* v, + uint32_t yWidth, + uint32_t yHeight, + uint32_t uvWidth, + uint32_t uvHeight, + void* data, + uint32_t dataLength +) { + NOT_IMPLEMENTED +} + +static void D3D11_CopyTextureToTexture( + Refresh_Renderer* driverData, + Refresh_CommandBuffer* commandBuffer, + Refresh_TextureSlice* sourceTextureSlice, + Refresh_TextureSlice* destinationTextureSlice, + Refresh_Filter filter +) { + NOT_IMPLEMENTED +} + +static void D3D11_CopyTextureToBuffer( + Refresh_Renderer* driverData, + Refresh_CommandBuffer* commandBuffer, + Refresh_TextureSlice* textureSlice, + Refresh_Buffer* buffer +) { + NOT_IMPLEMENTED +} + +static void D3D11_SetBufferData( + Refresh_Renderer* driverData, + Refresh_CommandBuffer* commandBuffer, + Refresh_Buffer* buffer, + uint32_t offsetInBytes, + void* data, + uint32_t dataLength +) { + NOT_IMPLEMENTED +} + +static uint32_t D3D11_PushVertexShaderUniforms( + Refresh_Renderer* driverData, + Refresh_CommandBuffer* commandBuffer, + void* data, + uint32_t dataLengthInBytes +) { + NOT_IMPLEMENTED +} + +static uint32_t D3D11_PushFragmentShaderUniforms( + Refresh_Renderer* driverData, + Refresh_CommandBuffer* commandBuffer, + void* data, + uint32_t dataLengthInBytes +) { + NOT_IMPLEMENTED +} + +static uint32_t D3D11_PushComputeShaderUniforms( + Refresh_Renderer* driverData, + Refresh_CommandBuffer* commandBuffer, + void* data, + uint32_t dataLengthInBytes +) { + NOT_IMPLEMENTED +} + +static void D3D11_BindVertexSamplers( + Refresh_Renderer* driverData, + Refresh_CommandBuffer* commandBuffer, + Refresh_Texture** pTextures, + Refresh_Sampler** pSamplers +) { + NOT_IMPLEMENTED +} + +static void D3D11_BindFragmentSamplers( + Refresh_Renderer* driverData, + Refresh_CommandBuffer* commandBuffer, + Refresh_Texture** pTextures, + Refresh_Sampler** pSamplers +) { + NOT_IMPLEMENTED +} + +/* Getters */ + +static void D3D11_GetBufferData( + Refresh_Renderer* driverData, + Refresh_Buffer* buffer, + void* data, + uint32_t dataLengthInBytes +) { + NOT_IMPLEMENTED +} + +/* Disposal */ + +static void D3D11_QueueDestroyTexture( + Refresh_Renderer* driverData, + Refresh_Texture* texture +) { + NOT_IMPLEMENTED +} + +static void D3D11_QueueDestroySampler( + Refresh_Renderer* driverData, + Refresh_Sampler* sampler +) { + NOT_IMPLEMENTED +} + +static void D3D11_QueueDestroyBuffer( + Refresh_Renderer* driverData, + Refresh_Buffer* buffer +) { + NOT_IMPLEMENTED +} + +static void D3D11_QueueDestroyShaderModule( + Refresh_Renderer* driverData, + Refresh_ShaderModule* shaderModule +) { + NOT_IMPLEMENTED +} + +static void D3D11_QueueDestroyComputePipeline( + Refresh_Renderer* driverData, + Refresh_ComputePipeline* computePipeline +) { + NOT_IMPLEMENTED +} + +static void D3D11_QueueDestroyGraphicsPipeline( + Refresh_Renderer* driverData, + Refresh_GraphicsPipeline* graphicsPipeline +) { + NOT_IMPLEMENTED +} + +/* Graphics State */ + +static void D3D11_BeginRenderPass( + Refresh_Renderer* driverData, + Refresh_CommandBuffer* commandBuffer, + Refresh_Rect* renderArea, + Refresh_ColorAttachmentInfo* colorAttachmentInfos, + uint32_t colorAttachmentCount, + Refresh_DepthStencilAttachmentInfo* depthStencilAttachmentInfo +) { + NOT_IMPLEMENTED +} + +static void D3D11_EndRenderPass( + Refresh_Renderer* driverData, + Refresh_CommandBuffer* commandBuffer +) { + NOT_IMPLEMENTED +} + +static void D3D11_BindGraphicsPipeline( + Refresh_Renderer* driverData, + Refresh_CommandBuffer* commandBuffer, + Refresh_GraphicsPipeline* graphicsPipeline +) { + NOT_IMPLEMENTED +} + +static void D3D11_SetViewport( + Refresh_Renderer* driverData, + Refresh_CommandBuffer* commandBuffer, + Refresh_Viewport* viewport +) { + NOT_IMPLEMENTED +} + +static void D3D11_SetScissor( + Refresh_Renderer* driverData, + Refresh_CommandBuffer* commandBuffer, + Refresh_Rect* scissor +) { + NOT_IMPLEMENTED +} + +static void D3D11_BindVertexBuffers( + Refresh_Renderer* driverData, + Refresh_CommandBuffer* commandBuffer, + uint32_t firstBinding, + uint32_t bindingCount, + Refresh_Buffer** pBuffers, + uint64_t* pOffsets +) { + NOT_IMPLEMENTED +} + +static void D3D11_BindIndexBuffer( + Refresh_Renderer* driverData, + Refresh_CommandBuffer* commandBuffer, + Refresh_Buffer* buffer, + uint64_t offset, + Refresh_IndexElementSize indexElementSize +) { + NOT_IMPLEMENTED +} + +static void D3D11_BindComputePipeline( + Refresh_Renderer* driverData, + Refresh_CommandBuffer* commandBuffer, + Refresh_ComputePipeline* computePipeline +) { + NOT_IMPLEMENTED +} + +static void D3D11_BindComputeBuffers( + Refresh_Renderer* driverData, + Refresh_CommandBuffer* commandBuffer, + Refresh_Buffer** pBuffers +) { + NOT_IMPLEMENTED +} + +static void D3D11_BindComputeTextures( + Refresh_Renderer* driverData, + Refresh_CommandBuffer* commandBuffer, + Refresh_Texture** pTextures +) { + NOT_IMPLEMENTED +} + +static Refresh_CommandBuffer* D3D11_AcquireCommandBuffer( + Refresh_Renderer* driverData, + uint8_t fixed +) { + D3D11Renderer *renderer = (D3D11Renderer*) driverData; + D3D11CommandBuffer *commandBuffer = NULL; + uint32_t i; + HRESULT res; + + /* Try to use an existing command buffer, if one is available. */ + for (i = 0; i < renderer->commandBufferPool->count; i += 1) + { + /* Search for a command buffer in the pool that is not fixed, and is not recording. */ + if (!renderer->commandBufferPool->elements[i]->fixed && !renderer->commandBufferPool->elements[i]->recording) + { + commandBuffer = renderer->commandBufferPool->elements[i]; + break; + } + } + + /* If there are no free command buffers, make a new one. */ + if (commandBuffer == NULL) + { + /* Expand the capacity as needed. */ + EXPAND_ELEMENTS_IF_NEEDED( + renderer->commandBufferPool, + 2, + D3D11CommandBuffer* + ); + + /* Create a new command buffer */ + renderer->commandBufferPool->elements[i] = (D3D11CommandBuffer*) SDL_malloc( + sizeof(D3D11CommandBuffer) + ); + + /* Assign it a new deferred context */ + res = ID3D11Device_CreateDeferredContext( + renderer->device, + 0, + &renderer->commandBufferPool->elements[i]->context + ); + ERROR_CHECK_RETURN("Could not create deferred context for command buffer", NULL); + + /* Now we have a new command buffer we can use! */ + commandBuffer = renderer->commandBufferPool->elements[i]; + renderer->commandBufferPool->count += 1; + } + + /* Set up the command buffer */ + commandBuffer->threadID = SDL_ThreadID(); + commandBuffer->recording = 1; + commandBuffer->fixed = fixed; + commandBuffer->commandList = NULL; + + return (Refresh_CommandBuffer*) commandBuffer; +} + +Refresh_Texture* D3D11_AcquireSwapchainTexture( + Refresh_Renderer* driverData, + Refresh_CommandBuffer* commandBuffer, + void* windowHandle +) { + NOT_IMPLEMENTED +} + +Refresh_TextureFormat D3D11_GetSwapchainFormat( + Refresh_Renderer* driverData, + void* windowHandle +) { + NOT_IMPLEMENTED +} + +static void D3D11_Submit( + Refresh_Renderer* driverData, + uint32_t commandBufferCount, + Refresh_CommandBuffer** pCommandBuffers +) { + D3D11Renderer *renderer = (D3D11Renderer*) driverData; + ID3D11CommandList *commandList; + uint32_t i; + HRESULT res; + + for (i = 0; i < commandBufferCount; i += 1) + { + D3D11CommandBuffer *commandBuffer = (D3D11CommandBuffer*) pCommandBuffers[i]; + + /* FIXME: Should add sanity check that current thread ID matches the command buffer's threadID. */ + + if (commandBuffer->fixed && !commandBuffer->recording) + { + commandList = commandBuffer->commandList; + } + else + { + /* Serialize the commands into a command list */ + res = ID3D11DeviceContext_FinishCommandList( + commandBuffer->context, + 0, + &commandList + ); + ERROR_CHECK("Could not finish command list recording"); + } + + /* Submit the command list to the immediate context */ + /* FIXME: Mutex lock me! */ + ID3D11DeviceContext_ExecuteCommandList( + renderer->immediateContext, + commandList, + 0 + ); + + /* Now that we're done, either save the command list or release it. */ + if (commandBuffer->fixed) + { + commandBuffer->commandList = commandList; + } + else + { + ID3D11CommandList_Release(commandList); + } + + /* Mark the command buffer as not-recording so that it can be used to record again. */ + commandBuffer->recording = 0; + } +} + +static void D3D11_Wait( + Refresh_Renderer* driverData +) { + NOT_IMPLEMENTED +} + +static Refresh_Device* D3D11_CreateDevice( + Refresh_PresentationParameters* presentationParameters, + uint8_t debugMode +) { + D3D11Renderer *renderer; + PFN_CREATE_DXGI_FACTORY CreateDXGIFactoryFunc; + PFN_D3D11_CREATE_DEVICE D3D11CreateDeviceFunc; + D3D_FEATURE_LEVEL levels[] = { D3D_FEATURE_LEVEL_11_0 }; + void* factory6; + uint32_t flags; + DXGI_ADAPTER_DESC1 adapterDesc; + HRESULT res; + Refresh_Device* result; + + /* Allocate and zero out the renderer */ + renderer = (D3D11Renderer*) SDL_malloc(sizeof(D3D11Renderer)); + SDL_memset(renderer, 0, sizeof(D3D11Renderer)); + + /* Load the DXGI library */ + renderer->dxgi_dll = SDL_LoadObject(DXGI_DLL); + if (renderer->dxgi_dll == NULL) + { + Refresh_LogError("Could not find " DXGI_DLL); + return NULL; + } + + /* Load the CreateDXGIFactory function */ + CreateDXGIFactoryFunc = (PFN_CREATE_DXGI_FACTORY) SDL_LoadFunction( + renderer->dxgi_dll, + "CreateDXGIFactory1" + ); + if (CreateDXGIFactoryFunc == NULL) + { + Refresh_LogError("Could not load CreateDXGIFactory1 function!"); + return NULL; + } + + /* Create the DXGI factory */ + res = CreateDXGIFactoryFunc( + &D3D_IID_IDXGIFactory1, + &renderer->factory + ); + ERROR_CHECK_RETURN("Could not create DXGIFactory", NULL); + + /* Get the default adapter */ + res = IDXGIAdapter1_QueryInterface( + renderer->factory, + &D3D_IID_IDXGIFactory6, + (void**) &factory6 + ); + if (SUCCEEDED(res)) + { + IDXGIFactory6_EnumAdapterByGpuPreference( + (IDXGIFactory6*) factory6, + 0, + DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE, + &D3D_IID_IDXGIAdapter1, + &renderer->adapter + ); + } + else + { + IDXGIFactory1_EnumAdapters1( + renderer->factory, + 0, + &renderer->adapter + ); + } + + /* Get information about the selected adapter. Used for logging info. */ + IDXGIAdapter1_GetDesc1(renderer->adapter, &adapterDesc); + + /* Load the D3D library */ + renderer->d3d11_dll = SDL_LoadObject(D3D11_DLL); + if (renderer->d3d11_dll == NULL) + { + Refresh_LogError("Could not find " D3D11_DLL); + return NULL; + } + + /* Load the CreateDevice function */ + D3D11CreateDeviceFunc = (PFN_D3D11_CREATE_DEVICE) SDL_LoadFunction( + renderer->d3d11_dll, + "D3D11CreateDevice" + ); + if (D3D11CreateDeviceFunc == NULL) + { + Refresh_LogError("Could not load D3D11CreateDevice function!"); + return NULL; + } + + /* Set up device flags */ + flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; + if (debugMode) + { + flags |= D3D11_CREATE_DEVICE_DEBUG; + } + + /* Create the device */ +tryCreateDevice: + res = D3D11CreateDeviceFunc( + (IDXGIAdapter*) renderer->adapter, + D3D_DRIVER_TYPE_UNKNOWN, /* Must be UNKNOWN if adapter is non-null according to spec */ + NULL, + flags, + levels, + SDL_arraysize(levels), + D3D11_SDK_VERSION, + &renderer->device, + &renderer->featureLevel, + &renderer->immediateContext + ); + if (FAILED(res) && debugMode) + { + /* If device creation failed, and we're in debug mode, remove the debug flag and try again. */ + Refresh_LogWarn("Creating device in debug mode failed with error %08X. Trying non-debug.", res); + flags &= ~D3D11_CREATE_DEVICE_DEBUG; + debugMode = 0; + goto tryCreateDevice; + } + + ERROR_CHECK_RETURN("Could not create D3D11 device", NULL); + + /* Print driver info */ + Refresh_LogInfo("Refresh Driver: D3D11"); + Refresh_LogInfo("D3D11 Adapter: %S", adapterDesc.Description); + + /* Create the command buffer pool */ + renderer->commandBufferPool = (D3D11CommandBufferPool*) SDL_malloc( + sizeof(D3D11CommandBufferPool) + ); + SDL_memset(renderer->commandBufferPool, 0, sizeof(D3D11CommandBufferPool)); + + /* Initialize miscellaneous renderer members */ + renderer->debugMode = (flags & D3D11_CREATE_DEVICE_DEBUG) != 0; + renderer->blendFactor.x = 1.0f; + renderer->blendFactor.y = 1.0f; + renderer->blendFactor.z = 1.0f; + renderer->blendFactor.w = 1.0f; + + /* Create the Refresh Device */ + result = (Refresh_Device*) SDL_malloc(sizeof(Refresh_Device)); + ASSIGN_DRIVER(D3D11) + + result->driverData = (Refresh_Renderer*) renderer; + + return result; +} + +Refresh_Driver D3D11Driver = { + "D3D11", + D3D11_CreateDevice +}; + +#endif //REFRESH_DRIVER_D3D11 diff --git a/src/Refresh_Driver_D3D11_cdefines.h b/src/Refresh_Driver_D3D11_cdefines.h new file mode 100644 index 0000000..16f8b5d --- /dev/null +++ b/src/Refresh_Driver_D3D11_cdefines.h @@ -0,0 +1,214 @@ +/* Refresh - XNA-inspired 3D Graphics Library with modern capabilities + * + * Copyright (c) 2020 Evan Hemsley + * + * This software is provided 'as-is', without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from + * the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software in a + * product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source distribution. + * + * Evan "cosmonaut" Hemsley + * + */ + +/* Function Pointer Signatures */ +typedef HRESULT(WINAPI* PFN_CREATE_DXGI_FACTORY)(const GUID* riid, void** ppFactory); + + /* IIDs (from https://magnumdb.com) */ + +static const IID D3D_IID_IDXGIFactory1 = { 0x770aae78,0xf26f,0x4dba,{0xa8,0x29,0x25,0x3c,0x83,0xd1,0xb3,0x87} }; +static const IID D3D_IID_IDXGIFactory6 = { 0xc1b6694f,0xff09,0x44a9,{0xb0,0x3c,0x77,0x90,0x0a,0x0a,0x1d,0x17} }; +static const IID D3D_IID_IDXGIAdapter1 = { 0x29038f61,0x3839,0x4626,{0x91,0xfd,0x08,0x68,0x79,0x01,0x1a,0x05} }; + +/* IDXGIFactory6 (taken from dxgi1_6.h, cleaned up a bit) */ +typedef enum +{ + DXGI_FEATURE_PRESENT_ALLOW_TEARING = 0 +} DXGI_FEATURE; + +typedef enum +{ + DXGI_GPU_PREFERENCE_UNSPECIFIED = 0, + DXGI_GPU_PREFERENCE_MINIMUM_POWER = (DXGI_GPU_PREFERENCE_UNSPECIFIED + 1), + DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE = (DXGI_GPU_PREFERENCE_MINIMUM_POWER + 1) +} DXGI_GPU_PREFERENCE; + +typedef struct IDXGIFactory6 IDXGIFactory6; +typedef struct IDXGIFactory6Vtbl +{ + HRESULT(STDMETHODCALLTYPE* QueryInterface)( + IDXGIFactory6* This, + REFIID riid, + void** ppvObject); + + ULONG(STDMETHODCALLTYPE* AddRef)( + IDXGIFactory6* This); + + ULONG(STDMETHODCALLTYPE* Release)( + IDXGIFactory6* This); + + HRESULT(STDMETHODCALLTYPE* SetPrivateData)( + IDXGIFactory6* This, + REFGUID Name, + UINT DataSize, + const void* pData); + + HRESULT(STDMETHODCALLTYPE* SetPrivateDataInterface)( + IDXGIFactory6* This, + REFGUID Name, + const IUnknown* pUnknown); + + HRESULT(STDMETHODCALLTYPE* GetPrivateData)( + IDXGIFactory6* This, + REFGUID Name, + UINT* pDataSize, + void* pData); + + HRESULT(STDMETHODCALLTYPE* GetParent)( + IDXGIFactory6* This, + REFIID riid, + void** ppParent); + + HRESULT(STDMETHODCALLTYPE* EnumAdapters)( + IDXGIFactory6* This, + UINT Adapter, + IDXGIAdapter** ppAdapter); + + HRESULT(STDMETHODCALLTYPE* MakeWindowAssociation)( + IDXGIFactory6* This, + HWND WindowHandle, + UINT Flags); + + HRESULT(STDMETHODCALLTYPE* GetWindowAssociation)( + IDXGIFactory6* This, + HWND* pWindowHandle); + + HRESULT(STDMETHODCALLTYPE* CreateSwapChain)( + IDXGIFactory6* This, + IUnknown* pDevice, + DXGI_SWAP_CHAIN_DESC* pDesc, + IDXGISwapChain** ppSwapChain); + + HRESULT(STDMETHODCALLTYPE* CreateSoftwareAdapter)( + IDXGIFactory6* This, + HMODULE Module, + IDXGIAdapter** ppAdapter); + + HRESULT(STDMETHODCALLTYPE* EnumAdapters1)( + IDXGIFactory6* This, + UINT Adapter, + IDXGIAdapter1** ppAdapter); + + BOOL(STDMETHODCALLTYPE* IsCurrent)( + IDXGIFactory6* This); + + BOOL(STDMETHODCALLTYPE* IsWindowedStereoEnabled)( + IDXGIFactory6* This); + + HRESULT(STDMETHODCALLTYPE* CreateSwapChainForHwnd)( + IDXGIFactory6* This, + IUnknown* pDevice, + HWND hWnd, + void* pDesc, + void* pFullscreenDesc, + void* pRestrictToOutput, + void** ppSwapChain); + + HRESULT(STDMETHODCALLTYPE* CreateSwapChainForCoreWindow)( + IDXGIFactory6* This, + IUnknown* pDevice, + IUnknown* pWindow, + void* pDesc, + void* pRestrictToOutput, + void** ppSwapChain); + + HRESULT(STDMETHODCALLTYPE* GetSharedResourceAdapterLuid)( + IDXGIFactory6* This, + HANDLE hResource, + LUID* pLuid); + + HRESULT(STDMETHODCALLTYPE* RegisterStereoStatusWindow)( + IDXGIFactory6* This, + HWND WindowHandle, + UINT wMsg, + DWORD* pdwCookie); + + HRESULT(STDMETHODCALLTYPE* RegisterStereoStatusEvent)( + IDXGIFactory6* This, + HANDLE hEvent, + DWORD* pdwCookie); + + void (STDMETHODCALLTYPE* UnregisterStereoStatus)( + IDXGIFactory6* This, + DWORD dwCookie); + + HRESULT(STDMETHODCALLTYPE* RegisterOcclusionStatusWindow)( + IDXGIFactory6* This, + HWND WindowHandle, + UINT wMsg, + DWORD* pdwCookie); + + HRESULT(STDMETHODCALLTYPE* RegisterOcclusionStatusEvent)( + IDXGIFactory6* This, + HANDLE hEvent, + DWORD* pdwCookie); + + void (STDMETHODCALLTYPE* UnregisterOcclusionStatus)( + IDXGIFactory6* This, + DWORD dwCookie); + + HRESULT(STDMETHODCALLTYPE* CreateSwapChainForComposition)( + IDXGIFactory6* This, + IUnknown* pDevice, + void* pDesc, + void* pRestrictToOutput, + void** ppSwapChain); + + UINT(STDMETHODCALLTYPE* GetCreationFlags)( + IDXGIFactory6* This); + + HRESULT(STDMETHODCALLTYPE* EnumAdapterByLuid)( + IDXGIFactory6* This, + LUID AdapterLuid, + REFIID riid, + void** ppvAdapter); + + HRESULT(STDMETHODCALLTYPE* EnumWarpAdapter)( + IDXGIFactory6* This, + REFIID riid, + void** ppvAdapter); + + HRESULT(STDMETHODCALLTYPE* CheckFeatureSupport)( + IDXGIFactory6* This, + DXGI_FEATURE Feature, + void* pFeatureSupportData, + UINT FeatureSupportDataSize); + + HRESULT(STDMETHODCALLTYPE* EnumAdapterByGpuPreference)( + IDXGIFactory6* This, + UINT Adapter, + DXGI_GPU_PREFERENCE GpuPreference, + REFIID riid, + void** ppvAdapter); +} IDXGIFactory6Vtbl; + +struct IDXGIFactory6 +{ + struct IDXGIFactory6Vtbl* lpVtbl; +}; + +#define IDXGIFactory6_EnumAdapterByGpuPreference(This,Adapter,GpuPreference,riid,ppvAdapter) \ + ( (This)->lpVtbl -> EnumAdapterByGpuPreference(This,Adapter,GpuPreference,riid,ppvAdapter) ) diff --git a/visualc/Refresh.vcxproj b/visualc/Refresh.vcxproj index d73b03c..33b52ee 100644 --- a/visualc/Refresh.vcxproj +++ b/visualc/Refresh.vcxproj @@ -61,7 +61,7 @@ Level3 Disabled - REFRESH_DRIVER_VULKAN;%(PreprocessorDefinitions) + REFRESH_DRIVER_D3D11;REFRESH_DRIVER_VULKAN;%(PreprocessorDefinitions) DebugFull @@ -72,7 +72,7 @@ Level3 MaxSpeed - REFRESH_DRIVER_VULKAN;%(PreprocessorDefinitions) + REFRESH_DRIVER_D3D11;REFRESH_DRIVER_VULKAN;%(PreprocessorDefinitions) true true @@ -84,6 +84,7 @@ + @@ -91,6 +92,7 @@ + diff --git a/visualc/Refresh.vcxproj.filters b/visualc/Refresh.vcxproj.filters index 67135bd..769e63a 100644 --- a/visualc/Refresh.vcxproj.filters +++ b/visualc/Refresh.vcxproj.filters @@ -10,6 +10,9 @@ Source Files + + Source Files + @@ -24,6 +27,9 @@ Header Files + + Header Files + -- 2.25.1 From 387addd67dc6a36b5870515ca29624f88ece9cc3 Mon Sep 17 00:00:00 2001 From: Caleb Cornett Date: Sat, 5 Mar 2022 22:03:03 -0500 Subject: [PATCH 02/13] Free the actual renderer and Refresh device when destroying the device --- src/Refresh_Driver_D3D11.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Refresh_Driver_D3D11.c b/src/Refresh_Driver_D3D11.c index d4aa718..2723bf7 100644 --- a/src/Refresh_Driver_D3D11.c +++ b/src/Refresh_Driver_D3D11.c @@ -362,9 +362,13 @@ static void D3D11_DestroyDevice( IDXGIAdapter1_Release(renderer->adapter); IDXGIFactory1_Release(renderer->factory); - /* Release the DLLs */ + /* Unload the DLLs */ SDL_UnloadObject(renderer->d3d11_dll); SDL_UnloadObject(renderer->dxgi_dll); + + /* Free the renderer and Refresh Device */ + SDL_free(renderer); + SDL_free(device); } /* Drawing */ -- 2.25.1 From 9bdad47a36fff2a47b1271c38052d809208489cb Mon Sep 17 00:00:00 2001 From: Caleb Cornett Date: Mon, 7 Mar 2022 21:26:08 -0500 Subject: [PATCH 03/13] Swapchain creation, resizing, and destruction --- src/Refresh_Driver_D3D11.c | 318 ++++++++++++++++++++++++++-- src/Refresh_Driver_D3D11_cdefines.h | 1 + 2 files changed, 305 insertions(+), 14 deletions(-) diff --git a/src/Refresh_Driver_D3D11.c b/src/Refresh_Driver_D3D11.c index 2723bf7..1d895ae 100644 --- a/src/Refresh_Driver_D3D11.c +++ b/src/Refresh_Driver_D3D11.c @@ -36,9 +36,17 @@ #include "Refresh_Driver_D3D11_cdefines.h" #include +#include + +/* Defines */ #define D3D11_DLL "d3d11.dll" #define DXGI_DLL "dxgi.dll" +#define WINDOW_SWAPCHAIN_DATA "Refresh_D3D11Swapchain" + +#define NOT_IMPLEMENTED SDL_assert(0 && "Not implemented!"); + +/* Macros */ #define ERROR_CHECK(msg) \ if (FAILED(res)) \ @@ -78,9 +86,7 @@ ); \ } -#define NOT_IMPLEMENTED SDL_assert(0 && "Not implemented!"); - - /* Conversions */ +/* Conversions */ static DXGI_FORMAT RefreshToD3D11_SurfaceFormat[] = { @@ -235,13 +241,26 @@ static D3D11_TEXTURE_ADDRESS_MODE RefreshToD3D11_SamplerAddressMode[] = /* Structs */ +typedef struct D3D11Texture +{ + ID3D11RenderTargetView *rtv; +} D3D11Texture; + +typedef struct D3D11SwapchainData +{ + IDXGISwapChain* swapchain; + D3D11Texture refreshTexture; + void* windowHandle; +} D3D11SwapchainData; + typedef struct D3D11CommandBuffer { ID3D11DeviceContext *context; + ID3D11CommandList *commandList; + D3D11SwapchainData *swapchainData; SDL_threadID threadID; uint8_t recording; uint8_t fixed; - ID3D11CommandList *commandList; } D3D11CommandBuffer; typedef struct D3D11CommandBufferPool @@ -253,7 +272,6 @@ typedef struct D3D11CommandBufferPool typedef struct D3D11Renderer { - /* Persistent D3D11 Objects*/ ID3D11Device *device; ID3D11DeviceContext *immediateContext; IDXGIFactory1 *factory; @@ -261,18 +279,22 @@ typedef struct D3D11Renderer void *d3d11_dll; void *dxgi_dll; - /* Deferred Contexts */ D3D11CommandBufferPool *commandBufferPool; - /* Blend State */ + D3D11SwapchainData** swapchainDatas; + uint32_t swapchainDataCount; + uint32_t swapchainDataCapacity; + Refresh_Vec4 blendFactor; - /* Capabilities */ uint8_t debugMode; D3D_FEATURE_LEVEL featureLevel; - } D3D11Renderer; +/* Predeclarations */ + +static void D3D11_Wait(Refresh_Renderer* driverData); + /* Logging */ static void D3D11_INTERNAL_LogError( @@ -331,6 +353,187 @@ static void D3D11_INTERNAL_LogError( Refresh_LogError("%s! Error Code: %s (0x%08X)", msg, wszMsgBuff, res); } +/* Swapchain Management */ + +static uint8_t D3D11_INTERNAL_CreateSwapchain( + D3D11Renderer *renderer, + void *windowHandle +) { + IDXGIFactory1 *pParent; + DXGI_MODE_DESC swapchainBufferDesc; + DXGI_SWAP_CHAIN_DESC swapchainDesc; + IDXGISwapChain *swapchain; + D3D11SwapchainData *swapchainData; + SDL_SysWMinfo info; + HWND dxgiHandle; + ID3D11Texture2D *swapchainTexture; + D3D11_RENDER_TARGET_VIEW_DESC swapchainViewDesc; + HRESULT res; + + SDL_VERSION(&info.version); + SDL_GetWindowWMInfo((SDL_Window*) windowHandle, &info); + dxgiHandle = info.info.win.window; + + /* Initialize swapchain buffer descriptor */ + swapchainBufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + swapchainBufferDesc.Width = 0; + swapchainBufferDesc.Height = 0; + swapchainBufferDesc.RefreshRate.Numerator = 0; + swapchainBufferDesc.RefreshRate.Denominator = 0; + swapchainBufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; + swapchainBufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; + + /* Initialize the swapchain descriptor */ + swapchainDesc.BufferDesc = swapchainBufferDesc; + swapchainDesc.BufferCount = 3; + swapchainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + swapchainDesc.OutputWindow = dxgiHandle; + swapchainDesc.Flags = 0; + swapchainDesc.SampleDesc.Count = 1; + swapchainDesc.SampleDesc.Quality = 0; + swapchainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; + swapchainDesc.Windowed = 1; + + /* Create the swapchain! */ + res = IDXGIFactory1_CreateSwapChain( + renderer->factory, + (IUnknown*) renderer->device, + &swapchainDesc, + &swapchain + ); + ERROR_CHECK_RETURN("Could not create swap chain", 0); + + /* + * The swapchain's parent is a separate factory from the factory that + * we used to create the swapchain, and only that parent can be used to + * set the window association. Trying to set an association on our factory + * will silently fail and doesn't even verify arguments or return errors. + * See https://gamedev.net/forums/topic/634235-dxgidisabling-altenter/4999955/ + */ + res = IDXGISwapChain_GetParent( + swapchain, + &D3D_IID_IDXGIFactory1, + (void**) &pParent + ); + if (FAILED(res)) + { + Refresh_LogWarn( + "Could not get swapchain parent! Error Code: %08X", + res + ); + } + else + { + /* Disable DXGI window crap */ + res = IDXGIFactory1_MakeWindowAssociation( + pParent, + dxgiHandle, + DXGI_MWA_NO_WINDOW_CHANGES + ); + if (FAILED(res)) + { + Refresh_LogWarn( + "MakeWindowAssociation failed! Error Code: %08X", + res + ); + } + } + + /* Set up the swapchain data */ + swapchainData = (D3D11SwapchainData*) SDL_malloc(sizeof(D3D11SwapchainData)); + swapchainData->swapchain = swapchain; + swapchainData->windowHandle = windowHandle; + swapchainData->refreshTexture.rtv = NULL; + SDL_SetWindowData((SDL_Window*) windowHandle, WINDOW_SWAPCHAIN_DATA, swapchainData); + if (renderer->swapchainDataCount >= renderer->swapchainDataCapacity) + { + renderer->swapchainDataCapacity *= 2; + renderer->swapchainDatas = SDL_realloc( + renderer->swapchainDatas, + renderer->swapchainDataCapacity * sizeof(D3D11SwapchainData*) + ); + } + renderer->swapchainDatas[renderer->swapchainDataCount] = swapchainData; + renderer->swapchainDataCount += 1; + + /* Create the RTV for the swapchain */ + swapchainViewDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + swapchainViewDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + swapchainViewDesc.Texture2D.MipSlice = 0; + + res = IDXGISwapChain_GetBuffer( + swapchainData->swapchain, + 0, + &D3D_IID_ID3D11Texture2D, + (void**) &swapchainTexture + ); + ERROR_CHECK_RETURN("Could not get buffer from swapchain", 0); + + res = ID3D11Device_CreateRenderTargetView( + renderer->device, + (ID3D11Resource*) swapchainTexture, + &swapchainViewDesc, + &swapchainData->refreshTexture.rtv + ); + ERROR_CHECK_RETURN("Swapchain RT view creation failed", 0); + + /* Cleanup */ + ID3D11Texture2D_Release(swapchainTexture); + + return 1; +} + +static uint8_t D3D11_INTERNAL_ResizeSwapchain( + D3D11Renderer *renderer, + D3D11SwapchainData *swapchainData +) { + ID3D11Texture2D *swapchainTexture; + D3D11_RENDER_TARGET_VIEW_DESC swapchainViewDesc; + int w, h; + HRESULT res; + + /* Release the old RTV */ + ID3D11RenderTargetView_Release(swapchainData->refreshTexture.rtv); + + /* Resize the swapchain */ + SDL_GetWindowSize((SDL_Window*) swapchainData->windowHandle, &w, &h); + res = IDXGISwapChain_ResizeBuffers( + swapchainData->swapchain, + 0, /* Keep buffer count the same */ + w, + h, + DXGI_FORMAT_UNKNOWN, /* Keep the old format */ + 0 + ); + ERROR_CHECK_RETURN("Could not resize swapchain buffers", 0); + + /* Recreate the RTV using the new swapchain buffer */ + swapchainViewDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + swapchainViewDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + swapchainViewDesc.Texture2D.MipSlice = 0; + + res = IDXGISwapChain_GetBuffer( + swapchainData->swapchain, + 0, + &D3D_IID_ID3D11Texture2D, + &swapchainTexture + ); + ERROR_CHECK_RETURN("Could not get buffer from swapchain", 0); + + res = ID3D11Device_CreateRenderTargetView( + renderer->device, + (ID3D11Resource*) swapchainTexture, + &swapchainViewDesc, + &swapchainData->refreshTexture.rtv + ); + ERROR_CHECK_RETURN("Could not create render target view for swapchain", 0); + + /* Cleanup */ + ID3D11Texture2D_Release(swapchainTexture); + + return 1; +} + /* Quit */ static void D3D11_DestroyDevice( @@ -354,6 +557,15 @@ static void D3D11_DestroyDevice( SDL_free(renderer->commandBufferPool->elements); SDL_free(renderer->commandBufferPool); + /* Release swapchain */ + for (i = 0; i < renderer->swapchainDataCount; i += 1) + { + ID3D11RenderTargetView_Release(renderer->swapchainDatas[i]->refreshTexture.rtv); + IDXGISwapChain_Release(renderer->swapchainDatas[i]->swapchain); + SDL_free(renderer->swapchainDatas[i]); + } + SDL_free(renderer->swapchainDatas); + /* Release persistent D3D11 objects */ ID3D11DeviceContext_Release(renderer->immediateContext); ID3D11Device_Release(renderer->device); @@ -776,24 +988,79 @@ static Refresh_CommandBuffer* D3D11_AcquireCommandBuffer( commandBuffer->threadID = SDL_ThreadID(); commandBuffer->recording = 1; commandBuffer->fixed = fixed; + commandBuffer->swapchainData = NULL; commandBuffer->commandList = NULL; return (Refresh_CommandBuffer*) commandBuffer; } -Refresh_Texture* D3D11_AcquireSwapchainTexture( - Refresh_Renderer* driverData, - Refresh_CommandBuffer* commandBuffer, +static D3D11SwapchainData* D3D11_INTERNAL_FetchSwapchainData( + D3D11Renderer* renderer, void* windowHandle ) { - NOT_IMPLEMENTED + D3D11SwapchainData* swapchainData = NULL; + + swapchainData = (D3D11SwapchainData*) SDL_GetWindowData(windowHandle, WINDOW_SWAPCHAIN_DATA); + + if (swapchainData == NULL) + { + if (D3D11_INTERNAL_CreateSwapchain(renderer, windowHandle)) + { + swapchainData = (D3D11SwapchainData*) SDL_GetWindowData(windowHandle, WINDOW_SWAPCHAIN_DATA); + } + } + + return swapchainData; +} + +Refresh_Texture* D3D11_AcquireSwapchainTexture( + Refresh_Renderer *driverData, + Refresh_CommandBuffer *commandBuffer, + void *windowHandle +) { + D3D11Renderer *renderer = (D3D11Renderer*) driverData; + D3D11CommandBuffer *cmdbuf = (D3D11CommandBuffer*) commandBuffer; + D3D11SwapchainData *swapchainData; + DXGI_SWAP_CHAIN_DESC swapchainDesc; + int w, h; + HRESULT res; + + /* Fetch the swapchain data, creating a new swapchain if needed. */ + swapchainData = D3D11_INTERNAL_FetchSwapchainData(renderer, windowHandle); + if (swapchainData == NULL) + { + return NULL; + } + + /* Check for window size changes and resize the swapchain if needed. */ + IDXGISwapChain_GetDesc(swapchainData->swapchain, &swapchainDesc); + SDL_GetWindowSize((SDL_Window*) windowHandle, &w, &h); + + if (w != swapchainDesc.BufferDesc.Width || h != swapchainDesc.BufferDesc.Height) + { + res = D3D11_INTERNAL_ResizeSwapchain(renderer, swapchainData); + ERROR_CHECK_RETURN("Could not resize swapchain", NULL); + } + + /* Let's try this again... */ + swapchainData = D3D11_INTERNAL_FetchSwapchainData(renderer, windowHandle); + if (swapchainData == NULL) + { + return NULL; + } + + /* Let the command buffer know it's associated with this swapchain. */ + cmdbuf->swapchainData = swapchainData; + + /* Return the swapchain texture */ + return (Refresh_Texture*) &swapchainData->refreshTexture; } Refresh_TextureFormat D3D11_GetSwapchainFormat( Refresh_Renderer* driverData, void* windowHandle ) { - NOT_IMPLEMENTED + return DXGI_FORMAT_R8G8B8A8_UNORM; } static void D3D11_Submit( @@ -814,6 +1081,7 @@ static void D3D11_Submit( if (commandBuffer->fixed && !commandBuffer->recording) { + /* Grab the prerecorded command list. */ commandList = commandBuffer->commandList; } else @@ -847,6 +1115,16 @@ static void D3D11_Submit( /* Mark the command buffer as not-recording so that it can be used to record again. */ commandBuffer->recording = 0; + + /* Present, if applicable */ + if (commandBuffer->swapchainData) + { + IDXGISwapChain_Present( + commandBuffer->swapchainData->swapchain, + 1, /* FIXME: Assumes vsync! */ + 0 + ); + } } } @@ -1002,6 +1280,18 @@ tryCreateDevice: result->driverData = (Refresh_Renderer*) renderer; + /* Create the initial swapchain */ + renderer->swapchainDataCapacity = 1; + renderer->swapchainDataCount = 0; + renderer->swapchainDatas = SDL_malloc( + renderer->swapchainDataCapacity * sizeof(D3D11SwapchainData*) + ); + + if (!D3D11_INTERNAL_CreateSwapchain(renderer, presentationParameters->deviceWindowHandle)) + { + return NULL; + } + return result; } diff --git a/src/Refresh_Driver_D3D11_cdefines.h b/src/Refresh_Driver_D3D11_cdefines.h index 16f8b5d..e269212 100644 --- a/src/Refresh_Driver_D3D11_cdefines.h +++ b/src/Refresh_Driver_D3D11_cdefines.h @@ -32,6 +32,7 @@ typedef HRESULT(WINAPI* PFN_CREATE_DXGI_FACTORY)(const GUID* riid, void** ppFact static const IID D3D_IID_IDXGIFactory1 = { 0x770aae78,0xf26f,0x4dba,{0xa8,0x29,0x25,0x3c,0x83,0xd1,0xb3,0x87} }; static const IID D3D_IID_IDXGIFactory6 = { 0xc1b6694f,0xff09,0x44a9,{0xb0,0x3c,0x77,0x90,0x0a,0x0a,0x1d,0x17} }; static const IID D3D_IID_IDXGIAdapter1 = { 0x29038f61,0x3839,0x4626,{0x91,0xfd,0x08,0x68,0x79,0x01,0x1a,0x05} }; +static const IID D3D_IID_ID3D11Texture2D = { 0x6f15aaf2,0xd208,0x4e89,{0x9a,0xb4,0x48,0x95,0x35,0xd3,0x4f,0x9c} }; /* IDXGIFactory6 (taken from dxgi1_6.h, cleaned up a bit) */ typedef enum -- 2.25.1 From 3175f20db6470a913c785a5e596f474508335cd8 Mon Sep 17 00:00:00 2001 From: Caleb Cornett Date: Mon, 7 Mar 2022 21:47:07 -0500 Subject: [PATCH 04/13] Started work on BeginRenderPass, enough to get a clear screen! --- src/Refresh_Driver_D3D11.c | 62 +++++++++++++++++++++++++++++++++----- 1 file changed, 55 insertions(+), 7 deletions(-) diff --git a/src/Refresh_Driver_D3D11.c b/src/Refresh_Driver_D3D11.c index 1d895ae..b49903c 100644 --- a/src/Refresh_Driver_D3D11.c +++ b/src/Refresh_Driver_D3D11.c @@ -850,21 +850,69 @@ static void D3D11_QueueDestroyGraphicsPipeline( /* Graphics State */ static void D3D11_BeginRenderPass( - Refresh_Renderer* driverData, - Refresh_CommandBuffer* commandBuffer, - Refresh_Rect* renderArea, - Refresh_ColorAttachmentInfo* colorAttachmentInfos, + Refresh_Renderer *driverData, + Refresh_CommandBuffer *commandBuffer, + Refresh_Rect *renderArea, + Refresh_ColorAttachmentInfo *colorAttachmentInfos, uint32_t colorAttachmentCount, - Refresh_DepthStencilAttachmentInfo* depthStencilAttachmentInfo + Refresh_DepthStencilAttachmentInfo *depthStencilAttachmentInfo ) { - NOT_IMPLEMENTED + D3D11Renderer *renderer = (D3D11Renderer*) driverData; + D3D11CommandBuffer *cmdbuf = (D3D11CommandBuffer*) commandBuffer; + D3D11Texture *texture; + float clearColors[4]; + ID3D11RenderTargetView *rtViews[MAX_COLOR_TARGET_BINDINGS]; + ID3D11DepthStencilView *dsView = NULL; + D3D11_VIEWPORT viewports[1]; + D3D11_RECT scissorRects[1]; + uint8_t i; + + /* Get the RTVs for each color attachment. */ + for (i = 0; i < colorAttachmentCount; i += 1) + { + rtViews[i] = ((D3D11Texture*) colorAttachmentInfos[i].texture)->rtv; + } + + /* FIXME: Get the DSV for the depth stencil attachment, if one exists! */ + + /* Set the render targets. */ + ID3D11DeviceContext_OMSetRenderTargets( + cmdbuf->context, + colorAttachmentCount, + rtViews, + NULL + ); + + /* Perform load ops on those render targets. */ + for (i = 0; i < colorAttachmentCount; i += 1) + { + texture = (D3D11Texture*) colorAttachmentInfos[i].texture; + + if (colorAttachmentInfos[i].loadOp == REFRESH_LOADOP_CLEAR) + { + clearColors[0] = colorAttachmentInfos[i].clearColor.x; + clearColors[1] = colorAttachmentInfos[i].clearColor.y; + clearColors[2] = colorAttachmentInfos[i].clearColor.z; + clearColors[3] = colorAttachmentInfos[i].clearColor.w; + + ID3D11DeviceContext_ClearRenderTargetView( + cmdbuf->context, + texture->rtv, + clearColors + ); + } + } + + /* FIXME: Set viewport and scissor state */ + + /* FIXME: What should we do with render area? */ } static void D3D11_EndRenderPass( Refresh_Renderer* driverData, Refresh_CommandBuffer* commandBuffer ) { - NOT_IMPLEMENTED + /* FIXME: What should we do here? */ } static void D3D11_BindGraphicsPipeline( -- 2.25.1 From d6ccca3dc3ae48567f1df30256e9ff0325440ded Mon Sep 17 00:00:00 2001 From: Caleb Cornett Date: Mon, 7 Mar 2022 22:30:06 -0500 Subject: [PATCH 05/13] Added mutexes for command buffer acquisition and command list execution --- src/Refresh_Driver_D3D11.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/Refresh_Driver_D3D11.c b/src/Refresh_Driver_D3D11.c index b49903c..5d8c0d0 100644 --- a/src/Refresh_Driver_D3D11.c +++ b/src/Refresh_Driver_D3D11.c @@ -61,14 +61,6 @@ return ret; \ } -#define ERROR_CHECK_UNLOCK_RETURN(msg, ret) \ - if (FAILED(res)) \ - { \ - D3D11_INTERNAL_LogError(renderer->device, msg, res); \ - SDL_UnlockMutex(renderer->ctxLock); \ - return ret; \ - } - #define EXPAND_ELEMENTS_IF_NEEDED(arr, initialValue, type) \ if (arr->count == arr->capacity) \ { \ @@ -278,8 +270,10 @@ typedef struct D3D11Renderer IDXGIAdapter1* adapter; void *d3d11_dll; void *dxgi_dll; + SDL_mutex *immediateContextMutex; D3D11CommandBufferPool *commandBufferPool; + SDL_mutex *commandBufferAcquisitionMutex; D3D11SwapchainData** swapchainDatas; uint32_t swapchainDataCount; @@ -993,6 +987,9 @@ static Refresh_CommandBuffer* D3D11_AcquireCommandBuffer( uint32_t i; HRESULT res; + /* Make sure multiple threads can't acquire the same command buffer. */ + SDL_LockMutex(renderer->commandBufferAcquisitionMutex); + /* Try to use an existing command buffer, if one is available. */ for (i = 0; i < renderer->commandBufferPool->count; i += 1) { @@ -1025,7 +1022,11 @@ static Refresh_CommandBuffer* D3D11_AcquireCommandBuffer( 0, &renderer->commandBufferPool->elements[i]->context ); - ERROR_CHECK_RETURN("Could not create deferred context for command buffer", NULL); + if (FAILED(res)) + { + SDL_UnlockMutex(renderer->commandBufferAcquisitionMutex); + ERROR_CHECK_RETURN("Could not create deferred context for command buffer", NULL); + } /* Now we have a new command buffer we can use! */ commandBuffer = renderer->commandBufferPool->elements[i]; @@ -1039,6 +1040,8 @@ static Refresh_CommandBuffer* D3D11_AcquireCommandBuffer( commandBuffer->swapchainData = NULL; commandBuffer->commandList = NULL; + SDL_UnlockMutex(renderer->commandBufferAcquisitionMutex); + return (Refresh_CommandBuffer*) commandBuffer; } @@ -1144,12 +1147,13 @@ static void D3D11_Submit( } /* Submit the command list to the immediate context */ - /* FIXME: Mutex lock me! */ + SDL_LockMutex(renderer->immediateContextMutex); ID3D11DeviceContext_ExecuteCommandList( renderer->immediateContext, commandList, 0 ); + SDL_UnlockMutex(renderer->immediateContextMutex); /* Now that we're done, either save the command list or release it. */ if (commandBuffer->fixed) @@ -1315,6 +1319,10 @@ tryCreateDevice: ); SDL_memset(renderer->commandBufferPool, 0, sizeof(D3D11CommandBufferPool)); + /* Create mutexes */ + renderer->immediateContextMutex = SDL_CreateMutex(); + renderer->commandBufferAcquisitionMutex = SDL_CreateMutex(); + /* Initialize miscellaneous renderer members */ renderer->debugMode = (flags & D3D11_CREATE_DEVICE_DEBUG) != 0; renderer->blendFactor.x = 1.0f; -- 2.25.1 From 5315e1c435d1dc42da1916365422b613867caffe Mon Sep 17 00:00:00 2001 From: Caleb Cornett Date: Thu, 10 Mar 2022 00:30:28 -0500 Subject: [PATCH 06/13] Implemented Clear, fleshed out D3D11Texture, added depth-stencil clear support in BeginRenderPass --- src/Refresh_Driver_D3D11.c | 266 ++++++++++++++++++++++++++++--------- 1 file changed, 202 insertions(+), 64 deletions(-) diff --git a/src/Refresh_Driver_D3D11.c b/src/Refresh_Driver_D3D11.c index 5d8c0d0..c6d2c95 100644 --- a/src/Refresh_Driver_D3D11.c +++ b/src/Refresh_Driver_D3D11.c @@ -235,7 +235,39 @@ static D3D11_TEXTURE_ADDRESS_MODE RefreshToD3D11_SamplerAddressMode[] = typedef struct D3D11Texture { - ID3D11RenderTargetView *rtv; + /* D3D Handles */ + ID3D11Resource *handle; /* ID3D11Texture2D* or ID3D11Texture3D* */ + ID3D11ShaderResourceView *shaderView; + + /* Basic Info */ + int32_t levelCount; + uint8_t isRenderTarget; + + /* Dimensions */ + #define REFRESH_D3D11_RENDERTARGET_2D 0 + #define REFRESH_D3D11_RENDERTARGET_3D 1 + #define REFRESH_D3D11_RENDERTARGET_CUBE 2 + uint8_t rtType; + REFRESHNAMELESS union + { + struct + { + int32_t width; + int32_t height; + ID3D11View *targetView; /* ID3D11RenderTargetView* or ID3D11DepthStencilView* */ + } twod; + struct + { + int32_t width; + int32_t height; + int32_t depth; + } threed; + struct + { + int32_t size; + ID3D11RenderTargetView **rtViews; + } cube; + }; } D3D11Texture; typedef struct D3D11SwapchainData @@ -247,9 +279,17 @@ typedef struct D3D11SwapchainData typedef struct D3D11CommandBuffer { + /* D3D11 Object References */ ID3D11DeviceContext *context; ID3D11CommandList *commandList; D3D11SwapchainData *swapchainData; + + /* Render Pass */ + uint8_t numBoundColorAttachments; + ID3D11RenderTargetView *rtViews[MAX_COLOR_TARGET_BINDINGS]; + ID3D11DepthStencilView* dsView; + + /* State */ SDL_threadID threadID; uint8_t recording; uint8_t fixed; @@ -349,6 +389,57 @@ static void D3D11_INTERNAL_LogError( /* Swapchain Management */ +static uint8_t D3D11_INTERNAL_InitializeSwapchainTexture( + D3D11Renderer *renderer, + D3D11Texture *resultTexture, + IDXGISwapChain *swapchain +) { + ID3D11Texture2D *swapchainTexture; + D3D11_RENDER_TARGET_VIEW_DESC swapchainViewDesc; + D3D11_TEXTURE2D_DESC textureDesc; + HRESULT res; + + /* Clear all the texture data. */ + SDL_memset(resultTexture, 0, sizeof(D3D11Texture)); + + /* Grab the buffer from the swapchain */ + res = IDXGISwapChain_GetBuffer( + swapchain, + 0, + &D3D_IID_ID3D11Texture2D, + (void**) &swapchainTexture + ); + ERROR_CHECK_RETURN("Could not get buffer from swapchain", 0); + + /* Create the RTV for the swapchain */ + swapchainViewDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + swapchainViewDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + swapchainViewDesc.Texture2D.MipSlice = 0; + + res = ID3D11Device_CreateRenderTargetView( + renderer->device, + (ID3D11Resource*) swapchainTexture, + &swapchainViewDesc, + (ID3D11RenderTargetView**) &resultTexture->twod.targetView + ); + ERROR_CHECK_RETURN("Swapchain RT view creation failed", 0); + + /* Fill out the rest of the texture struct */ + resultTexture->handle = NULL; /* FIXME: Is drawing the backbuffer to an offscreen RT allowed? If so we'll need to fill in this and shaderView. */ + resultTexture->shaderView = NULL; + resultTexture->isRenderTarget = 1; + + ID3D11Texture2D_GetDesc(swapchainTexture, &textureDesc); + resultTexture->levelCount = textureDesc.MipLevels; + resultTexture->twod.width = textureDesc.Width; + resultTexture->twod.height = textureDesc.Height; + + /* Cleanup */ + ID3D11Texture2D_Release(swapchainTexture); + + return 1; +} + static uint8_t D3D11_INTERNAL_CreateSwapchain( D3D11Renderer *renderer, void *windowHandle @@ -360,8 +451,6 @@ static uint8_t D3D11_INTERNAL_CreateSwapchain( D3D11SwapchainData *swapchainData; SDL_SysWMinfo info; HWND dxgiHandle; - ID3D11Texture2D *swapchainTexture; - D3D11_RENDER_TARGET_VIEW_DESC swapchainViewDesc; HRESULT res; SDL_VERSION(&info.version); @@ -437,7 +526,8 @@ static uint8_t D3D11_INTERNAL_CreateSwapchain( swapchainData = (D3D11SwapchainData*) SDL_malloc(sizeof(D3D11SwapchainData)); swapchainData->swapchain = swapchain; swapchainData->windowHandle = windowHandle; - swapchainData->refreshTexture.rtv = NULL; + + /* Add the swapchain data to the window data */ SDL_SetWindowData((SDL_Window*) windowHandle, WINDOW_SWAPCHAIN_DATA, swapchainData); if (renderer->swapchainDataCount >= renderer->swapchainDataCapacity) { @@ -450,44 +540,23 @@ static uint8_t D3D11_INTERNAL_CreateSwapchain( renderer->swapchainDatas[renderer->swapchainDataCount] = swapchainData; renderer->swapchainDataCount += 1; - /* Create the RTV for the swapchain */ - swapchainViewDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - swapchainViewDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; - swapchainViewDesc.Texture2D.MipSlice = 0; - - res = IDXGISwapChain_GetBuffer( - swapchainData->swapchain, - 0, - &D3D_IID_ID3D11Texture2D, - (void**) &swapchainTexture + /* Create the Refresh-side texture for the swapchain */ + return D3D11_INTERNAL_InitializeSwapchainTexture( + renderer, + &swapchainData->refreshTexture, + swapchainData->swapchain ); - ERROR_CHECK_RETURN("Could not get buffer from swapchain", 0); - - res = ID3D11Device_CreateRenderTargetView( - renderer->device, - (ID3D11Resource*) swapchainTexture, - &swapchainViewDesc, - &swapchainData->refreshTexture.rtv - ); - ERROR_CHECK_RETURN("Swapchain RT view creation failed", 0); - - /* Cleanup */ - ID3D11Texture2D_Release(swapchainTexture); - - return 1; } static uint8_t D3D11_INTERNAL_ResizeSwapchain( D3D11Renderer *renderer, D3D11SwapchainData *swapchainData ) { - ID3D11Texture2D *swapchainTexture; - D3D11_RENDER_TARGET_VIEW_DESC swapchainViewDesc; int w, h; HRESULT res; /* Release the old RTV */ - ID3D11RenderTargetView_Release(swapchainData->refreshTexture.rtv); + ID3D11RenderTargetView_Release(swapchainData->refreshTexture.twod.targetView); /* Resize the swapchain */ SDL_GetWindowSize((SDL_Window*) swapchainData->windowHandle, &w, &h); @@ -501,31 +570,12 @@ static uint8_t D3D11_INTERNAL_ResizeSwapchain( ); ERROR_CHECK_RETURN("Could not resize swapchain buffers", 0); - /* Recreate the RTV using the new swapchain buffer */ - swapchainViewDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - swapchainViewDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; - swapchainViewDesc.Texture2D.MipSlice = 0; - - res = IDXGISwapChain_GetBuffer( - swapchainData->swapchain, - 0, - &D3D_IID_ID3D11Texture2D, - &swapchainTexture + /* Create the Refresh-side texture for the swapchain */ + return D3D11_INTERNAL_InitializeSwapchainTexture( + renderer, + &swapchainData->refreshTexture, + swapchainData->swapchain ); - ERROR_CHECK_RETURN("Could not get buffer from swapchain", 0); - - res = ID3D11Device_CreateRenderTargetView( - renderer->device, - (ID3D11Resource*) swapchainTexture, - &swapchainViewDesc, - &swapchainData->refreshTexture.rtv - ); - ERROR_CHECK_RETURN("Could not create render target view for swapchain", 0); - - /* Cleanup */ - ID3D11Texture2D_Release(swapchainTexture); - - return 1; } /* Quit */ @@ -554,7 +604,7 @@ static void D3D11_DestroyDevice( /* Release swapchain */ for (i = 0; i < renderer->swapchainDataCount; i += 1) { - ID3D11RenderTargetView_Release(renderer->swapchainDatas[i]->refreshTexture.rtv); + ID3D11RenderTargetView_Release(renderer->swapchainDatas[i]->refreshTexture.twod.targetView); IDXGISwapChain_Release(renderer->swapchainDatas[i]->swapchain); SDL_free(renderer->swapchainDatas[i]); } @@ -588,7 +638,54 @@ static void D3D11_Clear( uint32_t colorCount, Refresh_DepthStencilValue depthStencil ) { - NOT_IMPLEMENTED + D3D11Renderer *renderer = (D3D11Renderer*) driverData; + D3D11CommandBuffer *cmdbuf = (D3D11CommandBuffer*) commandBuffer; + D3D11_CLEAR_FLAG dsClearFlags; + float clearColors[4]; + uint32_t i; + + /* FIXME: What should we do about clearRect? */ + /* FIXME: Do we need to use colorCount or is it always the number of bound RTs? */ + + if (options & REFRESH_CLEAROPTIONS_COLOR) + { + /* Clear color attachments */ + for (i = 0; i < cmdbuf->numBoundColorAttachments; i += 1) + { + clearColors[0] = colors[i].x; + clearColors[1] = colors[i].y; + clearColors[2] = colors[i].z; + clearColors[3] = colors[i].w; + + ID3D11DeviceContext_ClearRenderTargetView( + cmdbuf->context, + cmdbuf->rtViews[i], + clearColors + ); + } + } + + /* Check which of depth/stencil need to be cleared (if either) */ + dsClearFlags = 0; + if (options & REFRESH_CLEAROPTIONS_DEPTH) + { + dsClearFlags |= D3D11_CLEAR_DEPTH; + } + if (options & REFRESH_CLEAROPTIONS_STENCIL) + { + dsClearFlags |= D3D11_CLEAR_STENCIL; + } + + if (dsClearFlags != 0) + { + ID3D11DeviceContext_ClearDepthStencilView( + cmdbuf->context, + cmdbuf->dsView, + dsClearFlags, + depthStencil.depth, + (uint8_t) depthStencil.stencil + ); + } } static void D3D11_DrawInstancedPrimitives( @@ -855,26 +952,37 @@ static void D3D11_BeginRenderPass( D3D11CommandBuffer *cmdbuf = (D3D11CommandBuffer*) commandBuffer; D3D11Texture *texture; float clearColors[4]; - ID3D11RenderTargetView *rtViews[MAX_COLOR_TARGET_BINDINGS]; - ID3D11DepthStencilView *dsView = NULL; + D3D11_CLEAR_FLAG dsClearFlags; D3D11_VIEWPORT viewports[1]; D3D11_RECT scissorRects[1]; uint8_t i; + /* Clear the list of attachments for the command buffer */ + for (i = 0; i < MAX_COLOR_TARGET_BINDINGS; i += 1) + { + cmdbuf->rtViews[i] = NULL; + } + cmdbuf->dsView = NULL; + /* Get the RTVs for each color attachment. */ + cmdbuf->numBoundColorAttachments = colorAttachmentCount; for (i = 0; i < colorAttachmentCount; i += 1) { - rtViews[i] = ((D3D11Texture*) colorAttachmentInfos[i].texture)->rtv; + cmdbuf->rtViews[i] = (ID3D11RenderTargetView*) ((D3D11Texture*) colorAttachmentInfos[i].texture)->twod.targetView; } - /* FIXME: Get the DSV for the depth stencil attachment, if one exists! */ + /* Get the DSV for the depth stencil attachment, if one exists */ + if (depthStencilAttachmentInfo != NULL) + { + cmdbuf->dsView = (ID3D11DepthStencilView*) ((D3D11Texture*) depthStencilAttachmentInfo->texture)->twod.targetView; + } /* Set the render targets. */ ID3D11DeviceContext_OMSetRenderTargets( cmdbuf->context, colorAttachmentCount, - rtViews, - NULL + cmdbuf->rtViews, + cmdbuf->dsView ); /* Perform load ops on those render targets. */ @@ -891,12 +999,36 @@ static void D3D11_BeginRenderPass( ID3D11DeviceContext_ClearRenderTargetView( cmdbuf->context, - texture->rtv, + (ID3D11RenderTargetView*) texture->twod.targetView, clearColors ); } } + if (cmdbuf->dsView != NULL) + { + dsClearFlags = 0; + if (depthStencilAttachmentInfo->loadOp == REFRESH_LOADOP_CLEAR) + { + dsClearFlags |= D3D11_CLEAR_DEPTH; + } + if (depthStencilAttachmentInfo->stencilLoadOp == REFRESH_LOADOP_CLEAR) + { + dsClearFlags |= D3D11_CLEAR_STENCIL; + } + + if (dsClearFlags != 0) + { + ID3D11DeviceContext_ClearDepthStencilView( + cmdbuf->context, + (ID3D11DepthStencilView*) ((D3D11Texture*) depthStencilAttachmentInfo->texture)->twod.targetView, + dsClearFlags, + depthStencilAttachmentInfo->depthStencilClearValue.depth, + (uint8_t) depthStencilAttachmentInfo->depthStencilClearValue.stencil + ); + } + } + /* FIXME: Set viewport and scissor state */ /* FIXME: What should we do with render area? */ @@ -1039,6 +1171,12 @@ static Refresh_CommandBuffer* D3D11_AcquireCommandBuffer( commandBuffer->fixed = fixed; commandBuffer->swapchainData = NULL; commandBuffer->commandList = NULL; + commandBuffer->dsView = NULL; + commandBuffer->numBoundColorAttachments = 0; + for (i = 0; i < MAX_COLOR_TARGET_BINDINGS; i += 1) + { + commandBuffer->rtViews[i] = NULL; + } SDL_UnlockMutex(renderer->commandBufferAcquisitionMutex); -- 2.25.1 From 107c94b6e9acff5311de7254505d5cab70bb2c84 Mon Sep 17 00:00:00 2001 From: Caleb Cornett Date: Fri, 11 Mar 2022 18:17:35 -0500 Subject: [PATCH 07/13] Removed D3D11_Clear, added pWidth/pHeight to AcquireSwapchainImage, fixed(?) threading crash with swapchain Present --- src/Refresh_Driver_D3D11.c | 79 +++++++------------------------------- 1 file changed, 14 insertions(+), 65 deletions(-) diff --git a/src/Refresh_Driver_D3D11.c b/src/Refresh_Driver_D3D11.c index c6d2c95..32c84e3 100644 --- a/src/Refresh_Driver_D3D11.c +++ b/src/Refresh_Driver_D3D11.c @@ -310,7 +310,7 @@ typedef struct D3D11Renderer IDXGIAdapter1* adapter; void *d3d11_dll; void *dxgi_dll; - SDL_mutex *immediateContextMutex; + SDL_mutex *contextLock; D3D11CommandBufferPool *commandBufferPool; SDL_mutex *commandBufferAcquisitionMutex; @@ -629,65 +629,6 @@ static void D3D11_DestroyDevice( /* Drawing */ -static void D3D11_Clear( - Refresh_Renderer* driverData, - Refresh_CommandBuffer* commandBuffer, - Refresh_Rect* clearRect, - Refresh_ClearOptions options, - Refresh_Vec4* colors, - uint32_t colorCount, - Refresh_DepthStencilValue depthStencil -) { - D3D11Renderer *renderer = (D3D11Renderer*) driverData; - D3D11CommandBuffer *cmdbuf = (D3D11CommandBuffer*) commandBuffer; - D3D11_CLEAR_FLAG dsClearFlags; - float clearColors[4]; - uint32_t i; - - /* FIXME: What should we do about clearRect? */ - /* FIXME: Do we need to use colorCount or is it always the number of bound RTs? */ - - if (options & REFRESH_CLEAROPTIONS_COLOR) - { - /* Clear color attachments */ - for (i = 0; i < cmdbuf->numBoundColorAttachments; i += 1) - { - clearColors[0] = colors[i].x; - clearColors[1] = colors[i].y; - clearColors[2] = colors[i].z; - clearColors[3] = colors[i].w; - - ID3D11DeviceContext_ClearRenderTargetView( - cmdbuf->context, - cmdbuf->rtViews[i], - clearColors - ); - } - } - - /* Check which of depth/stencil need to be cleared (if either) */ - dsClearFlags = 0; - if (options & REFRESH_CLEAROPTIONS_DEPTH) - { - dsClearFlags |= D3D11_CLEAR_DEPTH; - } - if (options & REFRESH_CLEAROPTIONS_STENCIL) - { - dsClearFlags |= D3D11_CLEAR_STENCIL; - } - - if (dsClearFlags != 0) - { - ID3D11DeviceContext_ClearDepthStencilView( - cmdbuf->context, - cmdbuf->dsView, - dsClearFlags, - depthStencil.depth, - (uint8_t) depthStencil.stencil - ); - } -} - static void D3D11_DrawInstancedPrimitives( Refresh_Renderer* driverData, Refresh_CommandBuffer* commandBuffer, @@ -1202,10 +1143,12 @@ static D3D11SwapchainData* D3D11_INTERNAL_FetchSwapchainData( return swapchainData; } -Refresh_Texture* D3D11_AcquireSwapchainTexture( +static Refresh_Texture* D3D11_AcquireSwapchainTexture( Refresh_Renderer *driverData, Refresh_CommandBuffer *commandBuffer, - void *windowHandle + void *windowHandle, + uint32_t *pWidth, + uint32_t *pHeight ) { D3D11Renderer *renderer = (D3D11Renderer*) driverData; D3D11CommandBuffer *cmdbuf = (D3D11CommandBuffer*) commandBuffer; @@ -1241,6 +1184,10 @@ Refresh_Texture* D3D11_AcquireSwapchainTexture( /* Let the command buffer know it's associated with this swapchain. */ cmdbuf->swapchainData = swapchainData; + /* Send the dimensions to the out parameters. */ + *pWidth = swapchainData->refreshTexture.twod.width; + *pHeight = swapchainData->refreshTexture.twod.height; + /* Return the swapchain texture */ return (Refresh_Texture*) &swapchainData->refreshTexture; } @@ -1285,13 +1232,13 @@ static void D3D11_Submit( } /* Submit the command list to the immediate context */ - SDL_LockMutex(renderer->immediateContextMutex); + SDL_LockMutex(renderer->contextLock); ID3D11DeviceContext_ExecuteCommandList( renderer->immediateContext, commandList, 0 ); - SDL_UnlockMutex(renderer->immediateContextMutex); + SDL_UnlockMutex(renderer->contextLock); /* Now that we're done, either save the command list or release it. */ if (commandBuffer->fixed) @@ -1309,11 +1256,13 @@ static void D3D11_Submit( /* Present, if applicable */ if (commandBuffer->swapchainData) { + SDL_LockMutex(renderer->contextLock); IDXGISwapChain_Present( commandBuffer->swapchainData->swapchain, 1, /* FIXME: Assumes vsync! */ 0 ); + SDL_UnlockMutex(renderer->contextLock); } } } @@ -1458,7 +1407,7 @@ tryCreateDevice: SDL_memset(renderer->commandBufferPool, 0, sizeof(D3D11CommandBufferPool)); /* Create mutexes */ - renderer->immediateContextMutex = SDL_CreateMutex(); + renderer->contextLock = SDL_CreateMutex(); renderer->commandBufferAcquisitionMutex = SDL_CreateMutex(); /* Initialize miscellaneous renderer members */ -- 2.25.1 From bb98f42839ae9236aad9c5d98bd4d8eb8a21aad3 Mon Sep 17 00:00:00 2001 From: Caleb Cornett Date: Sat, 12 Mar 2022 01:18:31 -0500 Subject: [PATCH 08/13] Added SPIRV-Cross as a submodule. Implemented CreateShaderModule and QueueDestroyShaderModule --- .gitmodules | 3 + SPIRV-Cross | 1 + src/Refresh_Driver_D3D11.c | 258 +++++++++++++++++- visualc/Refresh.sln | 28 ++ visualc/Refresh.vcxproj | 7 + visualc/SPIRV-Cross/SPIRV-Cross.vcxproj | 164 +++++++++++ .../SPIRV-Cross/SPIRV-Cross.vcxproj.filters | 43 +++ 7 files changed, 500 insertions(+), 4 deletions(-) create mode 160000 SPIRV-Cross create mode 100644 visualc/SPIRV-Cross/SPIRV-Cross.vcxproj create mode 100644 visualc/SPIRV-Cross/SPIRV-Cross.vcxproj.filters diff --git a/.gitmodules b/.gitmodules index bf4fac3..1da3b2f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "Vulkan-Headers"] path = Vulkan-Headers url = https://github.com/KhronosGroup/Vulkan-Headers.git +[submodule "SPIRV-Cross"] + path = SPIRV-Cross + url = https://github.com/KhronosGroup/SPIRV-Cross diff --git a/SPIRV-Cross b/SPIRV-Cross new file mode 160000 index 0000000..d5c3bd8 --- /dev/null +++ b/SPIRV-Cross @@ -0,0 +1 @@ +Subproject commit d5c3bd8b5e7db9e2d7fe809944b47b8f88e1c732 diff --git a/src/Refresh_Driver_D3D11.c b/src/Refresh_Driver_D3D11.c index 32c84e3..c3075be 100644 --- a/src/Refresh_Driver_D3D11.c +++ b/src/Refresh_Driver_D3D11.c @@ -31,6 +31,7 @@ #define COBJMACROS #include #include +#include #include "Refresh_Driver.h" #include "Refresh_Driver_D3D11_cdefines.h" @@ -38,6 +39,8 @@ #include #include +#include + /* Defines */ #define D3D11_DLL "d3d11.dll" @@ -78,6 +81,22 @@ ); \ } +/* D3DCompile signature */ + +typedef HRESULT(WINAPI *PFN_D3DCOMPILE)( + LPCVOID pSrcData, + SIZE_T SrcDataSize, + LPCSTR pSourceName, + const D3D_SHADER_MACRO* pDefines, + ID3DInclude* pInclude, + LPCSTR pEntrypoint, + LPCSTR pTarget, + UINT Flags1, + UINT Flags2, + ID3DBlob **ppCode, + ID3DBlob **ppErrorMsgs +); + /* Conversions */ static DXGI_FORMAT RefreshToD3D11_SurfaceFormat[] = @@ -302,6 +321,14 @@ typedef struct D3D11CommandBufferPool uint32_t capacity; } D3D11CommandBufferPool; +typedef struct D3D11ShaderModule +{ + spvc_context context; + size_t numEntryPoints; + const spvc_entry_point *entryPoints; + ID3D11DeviceChild **shaders; /* ID3D11VertexShader, ID3D11PixelShader, ID3D11ComputeShader */ +} D3D11ShaderModule; + typedef struct D3D11Renderer { ID3D11Device *device; @@ -310,6 +337,7 @@ typedef struct D3D11Renderer IDXGIAdapter1* adapter; void *d3d11_dll; void *dxgi_dll; + void *d3dcompiler_dll; SDL_mutex *contextLock; D3D11CommandBufferPool *commandBufferPool; @@ -323,6 +351,8 @@ typedef struct D3D11Renderer uint8_t debugMode; D3D_FEATURE_LEVEL featureLevel; + + PFN_D3DCOMPILE D3DCompileFunc; } D3D11Renderer; /* Predeclarations */ @@ -621,6 +651,7 @@ static void D3D11_DestroyDevice( /* Unload the DLLs */ SDL_UnloadObject(renderer->d3d11_dll); SDL_UnloadObject(renderer->dxgi_dll); + SDL_UnloadObject(renderer->d3dcompiler_dll); /* Free the renderer and Refresh Device */ SDL_free(renderer); @@ -700,10 +731,197 @@ static Refresh_Sampler* D3D11_CreateSampler( } static Refresh_ShaderModule* D3D11_CreateShaderModule( - Refresh_Renderer* driverData, - Refresh_ShaderModuleCreateInfo* shaderModuleCreateInfo + Refresh_Renderer *driverData, + Refresh_ShaderModuleCreateInfo *shaderModuleCreateInfo ) { - NOT_IMPLEMENTED + D3D11Renderer *renderer = (D3D11Renderer*) driverData; + spvc_context context; + spvc_result result; + spvc_parsed_ir parsedIR; + spvc_compiler compiler; + const spvc_entry_point *entryPoints; + size_t numEntryPoints; + spvc_compiler_options compilerOptions; + char *hlslSource; + const char *shaderModel; + ID3DBlob *blob; + ID3DBlob *errorBlob = NULL; + ID3D11DeviceChild **shaders; + D3D11ShaderModule *shaderModule; + uint32_t i; + HRESULT res; + + /* Create the context */ + result = spvc_context_create(&context); + if (result != SPVC_SUCCESS) + { + Refresh_LogError("Could not create SPIRV Cross context! Error: %X", result); + return NULL; + } + + /* Parse the SPIRV input */ + result = spvc_context_parse_spirv( + context, + shaderModuleCreateInfo->byteCode, + shaderModuleCreateInfo->codeSize / sizeof(uint32_t), /* word count, not byte length */ + &parsedIR + ); + if (result != SPVC_SUCCESS) + { + Refresh_LogError("Could not parse SPIRV! Error: %X", result); + spvc_context_destroy(context); /* free all context-related memory */ + return NULL; + } + + /* Create the cross compiler */ + result = spvc_context_create_compiler( + context, + SPVC_BACKEND_HLSL, + parsedIR, + SPVC_CAPTURE_MODE_TAKE_OWNERSHIP, + &compiler + ); + if (result != SPVC_SUCCESS) + { + Refresh_LogError("Could not create SPIRV to HLSL cross compiler! Error: %X", result); + spvc_context_destroy(context); /* free all context-related memory */ + return NULL; + } + + /* Get entry points from the source bytecode */ + result = spvc_compiler_get_entry_points(compiler, &entryPoints, &numEntryPoints); + if (result != SPVC_SUCCESS) + { + Refresh_LogError("Could not get SPIRV entry points! Error: %X", result); + spvc_context_destroy(context); /* free all context-related memory */ + return NULL; + } + + /* Set HLSL cross-compile options (target SM5.0) */ + spvc_compiler_create_compiler_options(compiler, &compilerOptions); + spvc_compiler_options_set_uint( + compilerOptions, + SPVC_COMPILER_OPTION_HLSL_SHADER_MODEL, + 50 /* shader model 5.0 */ + ); + spvc_compiler_install_compiler_options(compiler, compilerOptions); + + /* Cross compile to HLSL */ + result = spvc_compiler_compile(compiler, &hlslSource); + if (result != SPVC_SUCCESS) + { + Refresh_LogError("Could not cross-compile SPIRV to HLSL! Error: %X", result); + spvc_context_destroy(context); /* free all context-related memory */ + return NULL; + } + + /* Allocate memory for the D3D11 shader list */ + shaders = (ID3D11DeviceChild**) SDL_malloc(numEntryPoints * sizeof(ID3D11DeviceChild*)); + + /* Compile each HLSL entry point into a D3D shader */ + for (i = 0; i < numEntryPoints; i += 1) + { + /* Determine the exact shader model to use */ + switch (entryPoints[i].execution_model) + { + case SpvExecutionModelVertex: + shaderModel = "vs_5_0"; + break; + + case SpvExecutionModelFragment: + shaderModel = "ps_5_0"; + break; + + case SpvExecutionModelGLCompute: + shaderModel = "cs_5_0"; + break; + + default: + Refresh_LogError( + "Attempting to compile a shader with an unknown execution model: %X", + entryPoints[i].execution_model + ); + spvc_context_destroy(context); /* free all context-related memory */ + SDL_free(shaders); + return NULL; + } + + /* Compile the shader blob */ + res = renderer->D3DCompileFunc( + hlslSource, + SDL_strlen(hlslSource), + NULL, + NULL, + NULL, + entryPoints[i].name, + shaderModel, + 0, + 0, + &blob, + &errorBlob + ); + if (FAILED(res)) + { + Refresh_LogError( + "D3DCompile failed on HLSL shader with entry point '%s'! Error: %X\nCompiler error message: %s", + entryPoints[i].name, + res, + errorBlob ? (const char*) ID3D10Blob_GetBufferPointer(errorBlob) : "" + ); + spvc_context_destroy(context); /* free all context-related memory */ + SDL_free(shaders); + return NULL; + } + + /* Create the shader from the blob */ + switch (entryPoints[i].execution_model) + { + case SpvExecutionModelVertex: + res = ID3D11Device_CreateVertexShader( + renderer->device, + ID3D10Blob_GetBufferPointer(blob), + ID3D10Blob_GetBufferSize(blob), + NULL, + (ID3D11VertexShader**) &shaders[i] + ); + break; + + case SpvExecutionModelFragment: + res = ID3D11Device_CreatePixelShader( + renderer->device, + ID3D10Blob_GetBufferPointer(blob), + ID3D10Blob_GetBufferSize(blob), + NULL, + (ID3D11PixelShader**) &shaders[i] + ); + break; + + case SpvExecutionModelGLCompute: + res = ID3D11Device_CreateComputeShader( + renderer->device, + ID3D10Blob_GetBufferPointer(blob), + ID3D10Blob_GetBufferSize(blob), + NULL, + (ID3D11ComputeShader**) &shaders[i] + ); + break; + } + if (FAILED(res)) + { + Refresh_LogError("D3D11 shader creation failed! Error code: %X", res); + spvc_context_destroy(context); /* free all context-related memory */ + SDL_free(shaders); + return NULL; + } + } + + /* Create the final shader module object to return */ + shaderModule = (D3D11ShaderModule*) SDL_malloc(sizeof(D3D11ShaderModule)); + shaderModule->context = context; + shaderModule->entryPoints = entryPoints; + shaderModule->numEntryPoints = numEntryPoints; + shaderModule->shaders = shaders; + return (Refresh_ShaderModule*) shaderModule; } static Refresh_Texture* D3D11_CreateTexture( @@ -862,7 +1080,20 @@ static void D3D11_QueueDestroyShaderModule( Refresh_Renderer* driverData, Refresh_ShaderModule* shaderModule ) { - NOT_IMPLEMENTED + D3D11ShaderModule *d3dShaderModule = (D3D11ShaderModule*) shaderModule; + uint32_t i; + + /* Release the D3D11 shader objects and free the array */ + for (i = 0; i < d3dShaderModule->numEntryPoints; i += 1) + { + ID3D11DeviceChild_Release(d3dShaderModule->shaders[i]); + } + SDL_free(d3dShaderModule->shaders); + + /* Destroy the SPIRV-Cross context. + * This should destroy the entryPoints list as well. + */ + spvc_context_destroy(d3dShaderModule->context); } static void D3D11_QueueDestroyComputePipeline( @@ -1291,6 +1522,25 @@ static Refresh_Device* D3D11_CreateDevice( renderer = (D3D11Renderer*) SDL_malloc(sizeof(D3D11Renderer)); SDL_memset(renderer, 0, sizeof(D3D11Renderer)); + /* Load the D3DCompiler library */ + renderer->d3dcompiler_dll = SDL_LoadObject(D3DCOMPILER_DLL); + if (renderer->d3dcompiler_dll == NULL) + { + Refresh_LogError("Could not find " D3DCOMPILER_DLL); + return NULL; + } + + /* Load the D3DCompile function pointer */ + renderer->D3DCompileFunc = (PFN_D3DCOMPILE) SDL_LoadFunction( + renderer->d3dcompiler_dll, + "D3DCompile" + ); + if (renderer->D3DCompileFunc == NULL) + { + Refresh_LogError("Could not load D3DCompile function!"); + return NULL; + } + /* Load the DXGI library */ renderer->dxgi_dll = SDL_LoadObject(DXGI_DLL); if (renderer->dxgi_dll == NULL) diff --git a/visualc/Refresh.sln b/visualc/Refresh.sln index e69634a..b65b0a0 100644 --- a/visualc/Refresh.sln +++ b/visualc/Refresh.sln @@ -5,22 +5,50 @@ VisualStudioVersion = 16.0.30717.126 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Refresh", "Refresh.vcxproj", "{6DB15344-E000-45CB-A48A-1D72F7D6E945}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SPIRV-Cross", "SPIRV-Cross\SPIRV-Cross.vcxproj", "{C9462931-41A4-4E61-B145-F2D2CDE43C69}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 MinSizeRel|x64 = MinSizeRel|x64 + MinSizeRel|x86 = MinSizeRel|x86 Release|x64 = Release|x64 + Release|x86 = Release|x86 RelWithDebInfo|x64 = RelWithDebInfo|x64 + RelWithDebInfo|x86 = RelWithDebInfo|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {6DB15344-E000-45CB-A48A-1D72F7D6E945}.Debug|x64.ActiveCfg = Debug|x64 {6DB15344-E000-45CB-A48A-1D72F7D6E945}.Debug|x64.Build.0 = Debug|x64 + {6DB15344-E000-45CB-A48A-1D72F7D6E945}.Debug|x86.ActiveCfg = Debug|Win32 + {6DB15344-E000-45CB-A48A-1D72F7D6E945}.Debug|x86.Build.0 = Debug|Win32 {6DB15344-E000-45CB-A48A-1D72F7D6E945}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64 {6DB15344-E000-45CB-A48A-1D72F7D6E945}.MinSizeRel|x64.Build.0 = MinSizeRel|x64 + {6DB15344-E000-45CB-A48A-1D72F7D6E945}.MinSizeRel|x86.ActiveCfg = MinSizeRel|x64 {6DB15344-E000-45CB-A48A-1D72F7D6E945}.Release|x64.ActiveCfg = Release|x64 {6DB15344-E000-45CB-A48A-1D72F7D6E945}.Release|x64.Build.0 = Release|x64 + {6DB15344-E000-45CB-A48A-1D72F7D6E945}.Release|x86.ActiveCfg = Release|Win32 + {6DB15344-E000-45CB-A48A-1D72F7D6E945}.Release|x86.Build.0 = Release|Win32 {6DB15344-E000-45CB-A48A-1D72F7D6E945}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 {6DB15344-E000-45CB-A48A-1D72F7D6E945}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {6DB15344-E000-45CB-A48A-1D72F7D6E945}.RelWithDebInfo|x86.ActiveCfg = RelWithDebInfo|x64 + {C9462931-41A4-4E61-B145-F2D2CDE43C69}.Debug|x64.ActiveCfg = Debug|x64 + {C9462931-41A4-4E61-B145-F2D2CDE43C69}.Debug|x64.Build.0 = Debug|x64 + {C9462931-41A4-4E61-B145-F2D2CDE43C69}.Debug|x86.ActiveCfg = Debug|Win32 + {C9462931-41A4-4E61-B145-F2D2CDE43C69}.Debug|x86.Build.0 = Debug|Win32 + {C9462931-41A4-4E61-B145-F2D2CDE43C69}.MinSizeRel|x64.ActiveCfg = Debug|x64 + {C9462931-41A4-4E61-B145-F2D2CDE43C69}.MinSizeRel|x64.Build.0 = Debug|x64 + {C9462931-41A4-4E61-B145-F2D2CDE43C69}.MinSizeRel|x86.ActiveCfg = Debug|Win32 + {C9462931-41A4-4E61-B145-F2D2CDE43C69}.MinSizeRel|x86.Build.0 = Debug|Win32 + {C9462931-41A4-4E61-B145-F2D2CDE43C69}.Release|x64.ActiveCfg = Release|x64 + {C9462931-41A4-4E61-B145-F2D2CDE43C69}.Release|x64.Build.0 = Release|x64 + {C9462931-41A4-4E61-B145-F2D2CDE43C69}.Release|x86.ActiveCfg = Release|Win32 + {C9462931-41A4-4E61-B145-F2D2CDE43C69}.Release|x86.Build.0 = Release|Win32 + {C9462931-41A4-4E61-B145-F2D2CDE43C69}.RelWithDebInfo|x64.ActiveCfg = Release|x64 + {C9462931-41A4-4E61-B145-F2D2CDE43C69}.RelWithDebInfo|x64.Build.0 = Release|x64 + {C9462931-41A4-4E61-B145-F2D2CDE43C69}.RelWithDebInfo|x86.ActiveCfg = Release|Win32 + {C9462931-41A4-4E61-B145-F2D2CDE43C69}.RelWithDebInfo|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/visualc/Refresh.vcxproj b/visualc/Refresh.vcxproj index 33b52ee..dd0053c 100644 --- a/visualc/Refresh.vcxproj +++ b/visualc/Refresh.vcxproj @@ -62,6 +62,7 @@ Level3 Disabled REFRESH_DRIVER_D3D11;REFRESH_DRIVER_VULKAN;%(PreprocessorDefinitions) + ..\SPIRV-Cross;%(AdditionalIncludeDirectories) DebugFull @@ -75,6 +76,7 @@ REFRESH_DRIVER_D3D11;REFRESH_DRIVER_VULKAN;%(PreprocessorDefinitions) true true + ..\SPIRV-Cross;%(AdditionalIncludeDirectories) true @@ -95,6 +97,11 @@ + + + {c9462931-41a4-4e61-b145-f2d2cde43c69} + + diff --git a/visualc/SPIRV-Cross/SPIRV-Cross.vcxproj b/visualc/SPIRV-Cross/SPIRV-Cross.vcxproj new file mode 100644 index 0000000..8fd6f23 --- /dev/null +++ b/visualc/SPIRV-Cross/SPIRV-Cross.vcxproj @@ -0,0 +1,164 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + + + + + + + + 16.0 + Win32Proj + {c9462931-41a4-4e61-b145-f2d2cde43c69} + SPIRVCross + 10.0 + + + + StaticLibrary + true + v142 + Unicode + + + StaticLibrary + false + v142 + true + Unicode + + + StaticLibrary + true + v142 + Unicode + + + StaticLibrary + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + false + + + true + + + false + + + + Level3 + true + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + Use + pch.h + + + + + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + Use + pch.h + + + + + true + true + true + + + + + Level3 + true + _DEBUG;_LIB;%(PreprocessorDefinitions);SPIRV_CROSS_C_API_HLSL=1;SPIRV_CROSS_C_API_GLSL=1;SPIRV_CROSS_C_API_REFLECT=1 + true + + + + + true + + + + + Level3 + true + true + true + NDEBUG;_LIB;%(PreprocessorDefinitions);SPIRV_CROSS_C_API_HLSL=1;SPIRV_CROSS_C_API_REFLECT=1 + true + Use + pch.h + + + + + true + true + true + + + + + + \ No newline at end of file diff --git a/visualc/SPIRV-Cross/SPIRV-Cross.vcxproj.filters b/visualc/SPIRV-Cross/SPIRV-Cross.vcxproj.filters new file mode 100644 index 0000000..95cf63a --- /dev/null +++ b/visualc/SPIRV-Cross/SPIRV-Cross.vcxproj.filters @@ -0,0 +1,43 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file -- 2.25.1 From 67ac5987af30192a4d2bd42bbcf2f7b2f65862e7 Mon Sep 17 00:00:00 2001 From: Caleb Cornett Date: Sat, 12 Mar 2022 01:22:19 -0500 Subject: [PATCH 09/13] Actually, just bake the spirv-cross source files into the Refresh VS project directly --- visualc/Refresh.sln | 18 -- visualc/Refresh.vcxproj | 17 +- visualc/Refresh.vcxproj.filters | 27 +++ visualc/SPIRV-Cross/SPIRV-Cross.vcxproj | 164 ------------------ .../SPIRV-Cross/SPIRV-Cross.vcxproj.filters | 43 ----- 5 files changed, 37 insertions(+), 232 deletions(-) delete mode 100644 visualc/SPIRV-Cross/SPIRV-Cross.vcxproj delete mode 100644 visualc/SPIRV-Cross/SPIRV-Cross.vcxproj.filters diff --git a/visualc/Refresh.sln b/visualc/Refresh.sln index b65b0a0..0cec952 100644 --- a/visualc/Refresh.sln +++ b/visualc/Refresh.sln @@ -5,8 +5,6 @@ VisualStudioVersion = 16.0.30717.126 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Refresh", "Refresh.vcxproj", "{6DB15344-E000-45CB-A48A-1D72F7D6E945}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SPIRV-Cross", "SPIRV-Cross\SPIRV-Cross.vcxproj", "{C9462931-41A4-4E61-B145-F2D2CDE43C69}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -33,22 +31,6 @@ Global {6DB15344-E000-45CB-A48A-1D72F7D6E945}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 {6DB15344-E000-45CB-A48A-1D72F7D6E945}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 {6DB15344-E000-45CB-A48A-1D72F7D6E945}.RelWithDebInfo|x86.ActiveCfg = RelWithDebInfo|x64 - {C9462931-41A4-4E61-B145-F2D2CDE43C69}.Debug|x64.ActiveCfg = Debug|x64 - {C9462931-41A4-4E61-B145-F2D2CDE43C69}.Debug|x64.Build.0 = Debug|x64 - {C9462931-41A4-4E61-B145-F2D2CDE43C69}.Debug|x86.ActiveCfg = Debug|Win32 - {C9462931-41A4-4E61-B145-F2D2CDE43C69}.Debug|x86.Build.0 = Debug|Win32 - {C9462931-41A4-4E61-B145-F2D2CDE43C69}.MinSizeRel|x64.ActiveCfg = Debug|x64 - {C9462931-41A4-4E61-B145-F2D2CDE43C69}.MinSizeRel|x64.Build.0 = Debug|x64 - {C9462931-41A4-4E61-B145-F2D2CDE43C69}.MinSizeRel|x86.ActiveCfg = Debug|Win32 - {C9462931-41A4-4E61-B145-F2D2CDE43C69}.MinSizeRel|x86.Build.0 = Debug|Win32 - {C9462931-41A4-4E61-B145-F2D2CDE43C69}.Release|x64.ActiveCfg = Release|x64 - {C9462931-41A4-4E61-B145-F2D2CDE43C69}.Release|x64.Build.0 = Release|x64 - {C9462931-41A4-4E61-B145-F2D2CDE43C69}.Release|x86.ActiveCfg = Release|Win32 - {C9462931-41A4-4E61-B145-F2D2CDE43C69}.Release|x86.Build.0 = Release|Win32 - {C9462931-41A4-4E61-B145-F2D2CDE43C69}.RelWithDebInfo|x64.ActiveCfg = Release|x64 - {C9462931-41A4-4E61-B145-F2D2CDE43C69}.RelWithDebInfo|x64.Build.0 = Release|x64 - {C9462931-41A4-4E61-B145-F2D2CDE43C69}.RelWithDebInfo|x86.ActiveCfg = Release|Win32 - {C9462931-41A4-4E61-B145-F2D2CDE43C69}.RelWithDebInfo|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/visualc/Refresh.vcxproj b/visualc/Refresh.vcxproj index dd0053c..a757695 100644 --- a/visualc/Refresh.vcxproj +++ b/visualc/Refresh.vcxproj @@ -61,7 +61,7 @@ Level3 Disabled - REFRESH_DRIVER_D3D11;REFRESH_DRIVER_VULKAN;%(PreprocessorDefinitions) + REFRESH_DRIVER_D3D11;REFRESH_DRIVER_VULKAN;SPIRV_CROSS_C_API_GLSL;SPIRV_CROSS_C_API_HLSL;SPIRV_CROSS_C_API_REFLECT;%(PreprocessorDefinitions) ..\SPIRV-Cross;%(AdditionalIncludeDirectories) @@ -73,7 +73,7 @@ Level3 MaxSpeed - REFRESH_DRIVER_D3D11;REFRESH_DRIVER_VULKAN;%(PreprocessorDefinitions) + REFRESH_DRIVER_D3D11;REFRESH_DRIVER_VULKAN;SPIRV_CROSS_C_API_GLSL;SPIRV_CROSS_C_API_HLSL;SPIRV_CROSS_C_API_REFLECT;%(PreprocessorDefinitions) true true ..\SPIRV-Cross;%(AdditionalIncludeDirectories) @@ -85,6 +85,14 @@ + + + + + + + + @@ -97,11 +105,6 @@ - - - {c9462931-41a4-4e61-b145-f2d2cde43c69} - - diff --git a/visualc/Refresh.vcxproj.filters b/visualc/Refresh.vcxproj.filters index 769e63a..e4cb70c 100644 --- a/visualc/Refresh.vcxproj.filters +++ b/visualc/Refresh.vcxproj.filters @@ -13,6 +13,30 @@ Source Files + + Source Files\spirv-cross + + + Source Files\spirv-cross + + + Source Files\spirv-cross + + + Source Files\spirv-cross + + + Source Files\spirv-cross + + + Source Files\spirv-cross + + + Source Files\spirv-cross + + + Source Files\spirv-cross + @@ -38,5 +62,8 @@ {B2BA146C-CAA1-30BE-B7A9-F8D02673EA0C} + + {4764626f-fd8b-4a1c-8c20-fd92a1f3cb4b} + \ No newline at end of file diff --git a/visualc/SPIRV-Cross/SPIRV-Cross.vcxproj b/visualc/SPIRV-Cross/SPIRV-Cross.vcxproj deleted file mode 100644 index 8fd6f23..0000000 --- a/visualc/SPIRV-Cross/SPIRV-Cross.vcxproj +++ /dev/null @@ -1,164 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - - - - - - - - - - - 16.0 - Win32Proj - {c9462931-41a4-4e61-b145-f2d2cde43c69} - SPIRVCross - 10.0 - - - - StaticLibrary - true - v142 - Unicode - - - StaticLibrary - false - v142 - true - Unicode - - - StaticLibrary - true - v142 - Unicode - - - StaticLibrary - false - v142 - true - Unicode - - - - - - - - - - - - - - - - - - - - - true - - - false - - - true - - - false - - - - Level3 - true - WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) - true - Use - pch.h - - - - - true - - - - - Level3 - true - true - true - WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) - true - Use - pch.h - - - - - true - true - true - - - - - Level3 - true - _DEBUG;_LIB;%(PreprocessorDefinitions);SPIRV_CROSS_C_API_HLSL=1;SPIRV_CROSS_C_API_GLSL=1;SPIRV_CROSS_C_API_REFLECT=1 - true - - - - - true - - - - - Level3 - true - true - true - NDEBUG;_LIB;%(PreprocessorDefinitions);SPIRV_CROSS_C_API_HLSL=1;SPIRV_CROSS_C_API_REFLECT=1 - true - Use - pch.h - - - - - true - true - true - - - - - - \ No newline at end of file diff --git a/visualc/SPIRV-Cross/SPIRV-Cross.vcxproj.filters b/visualc/SPIRV-Cross/SPIRV-Cross.vcxproj.filters deleted file mode 100644 index 95cf63a..0000000 --- a/visualc/SPIRV-Cross/SPIRV-Cross.vcxproj.filters +++ /dev/null @@ -1,43 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - \ No newline at end of file -- 2.25.1 From bd8276b0ea2ad33a797d705a10062b67ce49482d Mon Sep 17 00:00:00 2001 From: Caleb Cornett Date: Sun, 13 Mar 2022 23:42:35 -0400 Subject: [PATCH 10/13] First pass at CreateBuffer, SetBufferData, QueueDestroyBuffer, CreateGraphicsPipeline, QueueDestroyGraphicsPipeline, DrawPrimitives, and setting default viewport/scissor rects on render passes --- src/Refresh_Driver_D3D11.c | 586 +++++++++++++++++++++++++++++++++++-- 1 file changed, 562 insertions(+), 24 deletions(-) diff --git a/src/Refresh_Driver_D3D11.c b/src/Refresh_Driver_D3D11.c index c3075be..3a86ab0 100644 --- a/src/Refresh_Driver_D3D11.c +++ b/src/Refresh_Driver_D3D11.c @@ -158,7 +158,7 @@ static D3D11_PRIMITIVE_TOPOLOGY RefreshToD3D11_PrimitiveType[] = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP /* TRIANGLESTRIP */ }; -static D3D11_FILL_MODE RefreshToD3D11_PolygonMode[] = +static D3D11_FILL_MODE RefreshToD3D11_FillMode[] = { D3D11_FILL_SOLID, /* FILL */ D3D11_FILL_WIREFRAME, /* LINE */ @@ -289,6 +289,11 @@ typedef struct D3D11Texture }; } D3D11Texture; +typedef struct D3D11Buffer +{ + ID3D11Buffer *handle; +} D3D11Buffer; + typedef struct D3D11SwapchainData { IDXGISwapChain* swapchain; @@ -327,8 +332,32 @@ typedef struct D3D11ShaderModule size_t numEntryPoints; const spvc_entry_point *entryPoints; ID3D11DeviceChild **shaders; /* ID3D11VertexShader, ID3D11PixelShader, ID3D11ComputeShader */ + ID3D10Blob **blobs; } D3D11ShaderModule; +typedef struct D3D11GraphicsPipeline +{ + float blendConstants[4]; + + int32_t numColorAttachments; + int32_t colorAttachmentSampleCounts[MAX_COLOR_TARGET_BINDINGS]; + DXGI_FORMAT colorAttachmentFormats[MAX_COLOR_TARGET_BINDINGS]; + ID3D11BlendState *colorAttachmentBlendState; + + uint8_t hasDepthStencilAttachment; + DXGI_FORMAT depthStencilAttachmentFormat; + + D3D11_PRIMITIVE_TOPOLOGY primitiveTopology; + uint32_t stencilRef; + ID3D11DepthStencilState *depthStencilState; + ID3D11RasterizerState *rasterizerState; + ID3D11InputLayout *inputLayout; + + Refresh_MultisampleState multisampleState; + ID3D11VertexShader *vertexShader; + ID3D11PixelShader *fragmentShader; +} D3D11GraphicsPipeline; + typedef struct D3D11Renderer { ID3D11Device *device; @@ -351,7 +380,6 @@ typedef struct D3D11Renderer uint8_t debugMode; D3D_FEATURE_LEVEL featureLevel; - PFN_D3DCOMPILE D3DCompileFunc; } D3D11Renderer; @@ -693,7 +721,14 @@ static void D3D11_DrawPrimitives( uint32_t vertexParamOffset, uint32_t fragmentParamOffset ) { - NOT_IMPLEMENTED + D3D11CommandBuffer *cmdbuf = (D3D11CommandBuffer*) commandBuffer; + ID3D11DeviceContext_Draw( + cmdbuf->context, + primitiveCount * 3, /* FIXME: Needs to use a primitive lookup table! */ + vertexStart + ); + + /* FIXME: vertex/fragment param offsets */ } static void D3D11_DispatchCompute( @@ -709,6 +744,224 @@ static void D3D11_DispatchCompute( /* State Creation */ +static ID3D11BlendState* D3D11_INTERNAL_FetchBlendState( + D3D11Renderer *renderer, + uint32_t numColorAttachments, + Refresh_ColorAttachmentDescription *colorAttachments +) { + ID3D11BlendState *result; + D3D11_BLEND_DESC blendDesc; + uint32_t i; + HRESULT res; + + /* Create a new blend state. + * The spec says the driver will not create duplicate states, so there's no need to cache. + */ + SDL_zero(blendDesc); /* needed for any unused RT entries */ + + blendDesc.AlphaToCoverageEnable = FALSE; + blendDesc.IndependentBlendEnable = TRUE; + + for (i = 0; i < numColorAttachments; i += 1) + { + blendDesc.RenderTarget[i].BlendEnable = colorAttachments[i].blendState.blendEnable; + blendDesc.RenderTarget[i].BlendOp = RefreshToD3D11_BlendOp[ + colorAttachments[i].blendState.colorBlendOp + ]; + blendDesc.RenderTarget[i].BlendOpAlpha = RefreshToD3D11_BlendOp[ + colorAttachments[i].blendState.alphaBlendOp + ]; + blendDesc.RenderTarget[i].DestBlend = RefreshToD3D11_BlendFactor[ + colorAttachments[i].blendState.dstColorBlendFactor + ]; + blendDesc.RenderTarget[i].DestBlendAlpha = RefreshToD3D11_BlendFactor[ + colorAttachments[i].blendState.dstAlphaBlendFactor + ]; + blendDesc.RenderTarget[i].RenderTargetWriteMask = colorAttachments[i].blendState.colorWriteMask; + blendDesc.RenderTarget[i].SrcBlend = RefreshToD3D11_BlendFactor[ + colorAttachments[i].blendState.srcColorBlendFactor + ]; + blendDesc.RenderTarget[i].SrcBlendAlpha = RefreshToD3D11_BlendFactor[ + colorAttachments[i].blendState.srcAlphaBlendFactor + ]; + } + + res = ID3D11Device_CreateBlendState( + renderer->device, + &blendDesc, + &result + ); + ERROR_CHECK_RETURN("Could not create blend state", NULL); + + return result; +} + +static ID3D11DepthStencilState* D3D11_INTERNAL_FetchDepthStencilState( + D3D11Renderer *renderer, + Refresh_DepthStencilState depthStencilState +) { + ID3D11DepthStencilState *result; + D3D11_DEPTH_STENCIL_DESC dsDesc; + HRESULT res; + + /* Create a new depth-stencil state. + * The spec says the driver will not create duplicate states, so there's no need to cache. + */ + dsDesc.DepthEnable = depthStencilState.depthTestEnable; + dsDesc.StencilEnable = depthStencilState.stencilTestEnable; + dsDesc.DepthFunc = depthStencilState.compareOp; + dsDesc.DepthWriteMask = ( + depthStencilState.depthWriteEnable ? + D3D11_DEPTH_WRITE_MASK_ALL : + D3D11_DEPTH_WRITE_MASK_ZERO + ); + + dsDesc.BackFace.StencilFunc = depthStencilState.backStencilState.compareOp; + dsDesc.BackFace.StencilDepthFailOp = depthStencilState.backStencilState.depthFailOp; + dsDesc.BackFace.StencilFailOp = depthStencilState.backStencilState.failOp; + dsDesc.BackFace.StencilPassOp = depthStencilState.backStencilState.passOp; + + dsDesc.FrontFace.StencilFunc = depthStencilState.frontStencilState.compareOp; + dsDesc.FrontFace.StencilDepthFailOp = depthStencilState.frontStencilState.depthFailOp; + dsDesc.FrontFace.StencilFailOp = depthStencilState.frontStencilState.failOp; + dsDesc.FrontFace.StencilPassOp = depthStencilState.frontStencilState.passOp; + + /* FIXME: D3D11 doesn't have separate read/write masks for each stencil side. What should we do? */ + dsDesc.StencilReadMask = depthStencilState.backStencilState.compareMask; + dsDesc.StencilWriteMask = depthStencilState.backStencilState.writeMask; + + /* FIXME: What do we do with these? + * depthStencilState.depthBoundsTestEnable + * depthStencilState.maxDepthBounds + * depthStencilState.minDepthBounds + */ + + res = ID3D11Device_CreateDepthStencilState( + renderer->device, + &dsDesc, + &result + ); + ERROR_CHECK_RETURN("Could not create depth-stencil state", NULL); + + return result; +} + +static ID3D11RasterizerState* D3D11_INTERNAL_FetchRasterizerState( + D3D11Renderer *renderer, + Refresh_RasterizerState rasterizerState +) { + ID3D11RasterizerState *result; + D3D11_RASTERIZER_DESC rasterizerDesc; + HRESULT res; + + /* Create a new rasterizer state. + * The spec says the driver will not create duplicate states, so there's no need to cache. + */ + rasterizerDesc.AntialiasedLineEnable = FALSE; + rasterizerDesc.CullMode = RefreshToD3D11_CullMode[rasterizerState.cullMode]; + rasterizerDesc.DepthBias = (INT) rasterizerState.depthBiasConstantFactor; /* FIXME: Is this cast correct? */ + rasterizerDesc.DepthBiasClamp = rasterizerState.depthBiasClamp; + rasterizerDesc.DepthClipEnable = TRUE; /* FIXME: Do we want this...? */ + rasterizerDesc.FillMode = RefreshToD3D11_FillMode[rasterizerState.fillMode]; + rasterizerDesc.FrontCounterClockwise = (rasterizerState.frontFace == REFRESH_FRONTFACE_COUNTER_CLOCKWISE); + rasterizerDesc.MultisampleEnable = TRUE; /* only applies to MSAA render targets */ + rasterizerDesc.ScissorEnable = TRUE; + rasterizerDesc.SlopeScaledDepthBias = rasterizerState.depthBiasSlopeFactor; + + res = ID3D11Device_CreateRasterizerState( + renderer->device, + &rasterizerDesc, + &result + ); + ERROR_CHECK_RETURN("Could not create rasterizer state", NULL); + + return result; +} + +static uint32_t D3D11_INTERNAL_FindIndexOfVertexBinding( + uint32_t targetBinding, + const Refresh_VertexBinding *bindings, + uint32_t numBindings +) { + uint32_t i; + for (i = 0; i < numBindings; i += 1) + { + if (bindings[i].binding == targetBinding) + { + return i; + } + } + + Refresh_LogError("Could not find vertex binding %d!", targetBinding); + return 0; +} + +static ID3D11InputLayout* D3D11_INTERNAL_FetchInputLayout( + D3D11Renderer *renderer, + Refresh_VertexInputState inputState, + ID3D10Blob *shaderBlob +) { + ID3D11InputLayout *result = NULL; + D3D11_INPUT_ELEMENT_DESC *elementDescs; + uint32_t i, bindingIndex; + HRESULT res; + + /* Allocate an array of vertex elements */ + elementDescs = SDL_stack_alloc( + D3D11_INPUT_ELEMENT_DESC, + inputState.vertexAttributeCount + ); + + /* Create the array of input elements */ + for (i = 0; i < inputState.vertexAttributeCount; i += 1) + { + elementDescs[i].AlignedByteOffset = inputState.vertexAttributes[i].offset; + elementDescs[i].Format = RefreshToD3D11_VertexFormat[ + inputState.vertexAttributes[i].format + ]; + elementDescs[i].InputSlot = inputState.vertexAttributes[i].binding; + + bindingIndex = D3D11_INTERNAL_FindIndexOfVertexBinding( + elementDescs[i].InputSlot, + inputState.vertexBindings, + inputState.vertexBindingCount + ); + elementDescs[i].InputSlotClass = RefreshToD3D11_VertexInputRate[ + inputState.vertexBindings[bindingIndex].inputRate + ]; + /* The spec requires this to be 0 for per-vertex data */ + elementDescs[i].InstanceDataStepRate = ( + elementDescs[i].InputSlotClass == D3D11_INPUT_PER_INSTANCE_DATA ? 1 : 0 + ); + + elementDescs[i].SemanticIndex = inputState.vertexAttributes[i].location; + elementDescs[i].SemanticName = "TEXCOORD"; + } + + res = ID3D11Device_CreateInputLayout( + renderer->device, + elementDescs, + inputState.vertexAttributeCount, + (void*) ID3D10Blob_GetBufferPointer(shaderBlob), + ID3D10Blob_GetBufferSize(shaderBlob), + &result + ); + if (FAILED(res)) + { + Refresh_LogError("Could not create input layout! Error: %X", res); + SDL_stack_free(elementDescs); + return NULL; + } + + /* FIXME: + * These are not cached by the driver! Should we cache them, or allow duplicates? + * If we have one input layout per graphics pipeline maybe that wouldn't be so bad...? + */ + + SDL_stack_free(elementDescs); + return result; +} + static Refresh_ComputePipeline* D3D11_CreateComputePipeline( Refresh_Renderer* driverData, Refresh_ComputeShaderInfo* computeShaderInfo @@ -720,7 +973,109 @@ static Refresh_GraphicsPipeline* D3D11_CreateGraphicsPipeline( Refresh_Renderer* driverData, Refresh_GraphicsPipelineCreateInfo* pipelineCreateInfo ) { - NOT_IMPLEMENTED + D3D11Renderer *renderer = (D3D11Renderer*) driverData; + D3D11GraphicsPipeline *pipeline = (D3D11GraphicsPipeline*) SDL_malloc(sizeof(D3D11GraphicsPipeline)); + D3D11ShaderModule* vertShaderModule = (D3D11ShaderModule*) pipelineCreateInfo->vertexShaderInfo.shaderModule; + D3D11ShaderModule* fragShaderModule = (D3D11ShaderModule*) pipelineCreateInfo->fragmentShaderInfo.shaderModule; + int32_t vertexShaderIndex, fragmentShaderIndex; + int32_t i; + + /* Color attachments */ + pipeline->numColorAttachments = pipelineCreateInfo->attachmentInfo.colorAttachmentCount; + for (i = 0; i < pipeline->numColorAttachments; i += 1) + { + pipeline->colorAttachmentSampleCounts[i] = RefreshToD3D11_SampleCount[ + pipelineCreateInfo->attachmentInfo.colorAttachmentDescriptions[i].sampleCount + ]; + + pipeline->colorAttachmentFormats[i] = RefreshToD3D11_SurfaceFormat[ + pipelineCreateInfo->attachmentInfo.colorAttachmentDescriptions[i].format + ]; + } + + pipeline->blendConstants[0] = pipelineCreateInfo->blendConstants[0]; + pipeline->blendConstants[1] = pipelineCreateInfo->blendConstants[1]; + pipeline->blendConstants[2] = pipelineCreateInfo->blendConstants[2]; + pipeline->blendConstants[3] = pipelineCreateInfo->blendConstants[3]; + pipeline->multisampleState = pipelineCreateInfo->multisampleState; + + pipeline->colorAttachmentBlendState = D3D11_INTERNAL_FetchBlendState( + renderer, + pipelineCreateInfo->attachmentInfo.colorAttachmentCount, + pipelineCreateInfo->attachmentInfo.colorAttachmentDescriptions + ); + + /* Depth stencil */ + pipeline->hasDepthStencilAttachment = pipelineCreateInfo->attachmentInfo.hasDepthStencilAttachment; + pipeline->depthStencilAttachmentFormat = RefreshToD3D11_SurfaceFormat[ + pipelineCreateInfo->attachmentInfo.depthStencilFormat + ]; + pipeline->stencilRef = pipelineCreateInfo->depthStencilState.backStencilState.reference; /* FIXME: Should we use front or back? */ + + pipeline->depthStencilState = D3D11_INTERNAL_FetchDepthStencilState( + renderer, + pipelineCreateInfo->depthStencilState + ); + + /* Rasterizer state */ + pipeline->primitiveTopology = RefreshToD3D11_PrimitiveType[pipelineCreateInfo->primitiveType]; + pipeline->rasterizerState = D3D11_INTERNAL_FetchRasterizerState( + renderer, + pipelineCreateInfo->rasterizerState + ); + + /* Vertex Shader + Input Layout */ + vertexShaderIndex = -1; + for (i = 0; i < vertShaderModule->numEntryPoints; i += 1) + { + if ( vertShaderModule->entryPoints[i].execution_model == SpvExecutionModelVertex && + SDL_strcmp(vertShaderModule->entryPoints[i].name, pipelineCreateInfo->vertexShaderInfo.entryPointName) == 0 ) + { + vertexShaderIndex = i; + break; + } + } + if (vertexShaderIndex == -1) + { + Refresh_LogError( + "Graphics pipeline creation failed! No entry point '%s' exists for the vertex shader!", + pipelineCreateInfo->vertexShaderInfo.entryPointName + ); + return NULL; + } + + pipeline->inputLayout = D3D11_INTERNAL_FetchInputLayout( + renderer, + pipelineCreateInfo->vertexInputState, + vertShaderModule->blobs[vertexShaderIndex] + ); + pipeline->vertexShader = (ID3D11VertexShader*) vertShaderModule->shaders[vertexShaderIndex]; + + /* Fragment Shader */ + fragmentShaderIndex = -1; + for (i = 0; i < fragShaderModule->numEntryPoints; i += 1) + { + if ( fragShaderModule->entryPoints[i].execution_model == SpvExecutionModelFragment && + SDL_strcmp(fragShaderModule->entryPoints[i].name, pipelineCreateInfo->fragmentShaderInfo.entryPointName) == 0 ) + { + fragmentShaderIndex = i; + break; + } + } + if (fragmentShaderIndex == -1) + { + Refresh_LogError( + "Graphics pipeline creation failed! No entry point '%s' exists for the fragment shader!", + pipelineCreateInfo->vertexShaderInfo.entryPointName + ); + return NULL; + } + + pipeline->fragmentShader = (ID3D11PixelShader*) fragShaderModule->shaders[fragmentShaderIndex]; + + /* FIXME: Need to create uniform buffers for the shaders */ + + return (Refresh_GraphicsPipeline*) pipeline; } static Refresh_Sampler* D3D11_CreateSampler( @@ -744,7 +1099,7 @@ static Refresh_ShaderModule* D3D11_CreateShaderModule( spvc_compiler_options compilerOptions; char *hlslSource; const char *shaderModel; - ID3DBlob *blob; + ID3DBlob **blobs; ID3DBlob *errorBlob = NULL; ID3D11DeviceChild **shaders; D3D11ShaderModule *shaderModule; @@ -804,6 +1159,11 @@ static Refresh_ShaderModule* D3D11_CreateShaderModule( SPVC_COMPILER_OPTION_HLSL_SHADER_MODEL, 50 /* shader model 5.0 */ ); + spvc_compiler_options_set_bool( + compilerOptions, + SPVC_COMPILER_OPTION_FLIP_VERTEX_Y, + SPVC_TRUE + ); spvc_compiler_install_compiler_options(compiler, compilerOptions); /* Cross compile to HLSL */ @@ -817,6 +1177,7 @@ static Refresh_ShaderModule* D3D11_CreateShaderModule( /* Allocate memory for the D3D11 shader list */ shaders = (ID3D11DeviceChild**) SDL_malloc(numEntryPoints * sizeof(ID3D11DeviceChild*)); + blobs = (ID3D10Blob**) SDL_malloc(numEntryPoints * sizeof(ID3D10Blob*)); /* Compile each HLSL entry point into a D3D shader */ for (i = 0; i < numEntryPoints; i += 1) @@ -857,7 +1218,7 @@ static Refresh_ShaderModule* D3D11_CreateShaderModule( shaderModel, 0, 0, - &blob, + &blobs[i], &errorBlob ); if (FAILED(res)) @@ -879,8 +1240,8 @@ static Refresh_ShaderModule* D3D11_CreateShaderModule( case SpvExecutionModelVertex: res = ID3D11Device_CreateVertexShader( renderer->device, - ID3D10Blob_GetBufferPointer(blob), - ID3D10Blob_GetBufferSize(blob), + ID3D10Blob_GetBufferPointer(blobs[i]), + ID3D10Blob_GetBufferSize(blobs[i]), NULL, (ID3D11VertexShader**) &shaders[i] ); @@ -889,8 +1250,8 @@ static Refresh_ShaderModule* D3D11_CreateShaderModule( case SpvExecutionModelFragment: res = ID3D11Device_CreatePixelShader( renderer->device, - ID3D10Blob_GetBufferPointer(blob), - ID3D10Blob_GetBufferSize(blob), + ID3D10Blob_GetBufferPointer(blobs[i]), + ID3D10Blob_GetBufferSize(blobs[i]), NULL, (ID3D11PixelShader**) &shaders[i] ); @@ -899,8 +1260,8 @@ static Refresh_ShaderModule* D3D11_CreateShaderModule( case SpvExecutionModelGLCompute: res = ID3D11Device_CreateComputeShader( renderer->device, - ID3D10Blob_GetBufferPointer(blob), - ID3D10Blob_GetBufferSize(blob), + ID3D10Blob_GetBufferPointer(blobs[i]), + ID3D10Blob_GetBufferSize(blobs[i]), NULL, (ID3D11ComputeShader**) &shaders[i] ); @@ -921,6 +1282,7 @@ static Refresh_ShaderModule* D3D11_CreateShaderModule( shaderModule->entryPoints = entryPoints; shaderModule->numEntryPoints = numEntryPoints; shaderModule->shaders = shaders; + shaderModule->blobs = blobs; return (Refresh_ShaderModule*) shaderModule; } @@ -936,7 +1298,45 @@ static Refresh_Buffer* D3D11_CreateBuffer( Refresh_BufferUsageFlags usageFlags, uint32_t sizeInBytes ) { - NOT_IMPLEMENTED + D3D11Renderer *renderer = (D3D11Renderer*) driverData; + ID3D11Buffer *bufferHandle; + D3D11_BUFFER_DESC bufferDesc; + uint32_t bindFlags = 0; + D3D11Buffer *result; + HRESULT res; + + if (usageFlags & REFRESH_BUFFERUSAGE_INDEX_BIT) + { + bindFlags |= D3D11_BIND_INDEX_BUFFER; + } + if (usageFlags & REFRESH_BUFFERUSAGE_VERTEX_BIT) + { + bindFlags |= D3D11_BIND_VERTEX_BUFFER; + } + if (usageFlags & REFRESH_BUFFERUSAGE_COMPUTE_BIT) + { + bindFlags |= D3D11_BIND_UNORDERED_ACCESS; + bindFlags |= D3D11_BIND_SHADER_RESOURCE; + } + + bufferDesc.BindFlags = bindFlags; + bufferDesc.ByteWidth = sizeInBytes; + bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + bufferDesc.MiscFlags = 0; + bufferDesc.StructureByteStride = 0; /* FIXME: Is this right...? */ + bufferDesc.Usage = D3D11_USAGE_DYNAMIC; + + res = ID3D11Device_CreateBuffer( + renderer->device, + &bufferDesc, + NULL, + &bufferHandle + ); + ERROR_CHECK_RETURN("Could not create buffer", NULL); + + result = (D3D11Buffer*) SDL_malloc(sizeof(D3D11Buffer)); + result->handle = bufferHandle; + return (Refresh_Buffer*) result; } /* Setters */ @@ -987,14 +1387,45 @@ static void D3D11_CopyTextureToBuffer( } static void D3D11_SetBufferData( - Refresh_Renderer* driverData, - Refresh_CommandBuffer* commandBuffer, - Refresh_Buffer* buffer, + Refresh_Renderer *driverData, + Refresh_CommandBuffer *commandBuffer, + Refresh_Buffer *buffer, uint32_t offsetInBytes, - void* data, + void *data, uint32_t dataLength ) { - NOT_IMPLEMENTED + D3D11Renderer *renderer = (D3D11Renderer*) driverData; + D3D11CommandBuffer *cmdbuf = (D3D11CommandBuffer*) commandBuffer; + D3D11Buffer *buf = (D3D11Buffer*) buffer; + D3D11_MAPPED_SUBRESOURCE mappedSubresource; + HRESULT res; + + /* FIXME: How should we handle partial updates? */ + + /* Map the buffer */ + res = ID3D11DeviceContext_Map( + cmdbuf->context, + (ID3D11Resource*) buf->handle, + 0, + D3D11_MAP_WRITE_DISCARD, + 0, + &mappedSubresource + ); + ERROR_CHECK_RETURN("Could not map buffer",); + + /* Copy in the data */ + SDL_memcpy( + (uint8_t*) mappedSubresource.pData + offsetInBytes, + data, + dataLength + ); + + /* Unmap the buffer */ + ID3D11DeviceContext_Unmap( + cmdbuf->context, + (ID3D11Resource*) buf->handle, + 0 + ); } static uint32_t D3D11_PushVertexShaderUniforms( @@ -1073,7 +1504,9 @@ static void D3D11_QueueDestroyBuffer( Refresh_Renderer* driverData, Refresh_Buffer* buffer ) { - NOT_IMPLEMENTED + D3D11Buffer *d3dBuffer = (D3D11Buffer*) buffer; + ID3D11Buffer_Release(d3dBuffer->handle); + SDL_free(d3dBuffer); } static void D3D11_QueueDestroyShaderModule( @@ -1083,12 +1516,14 @@ static void D3D11_QueueDestroyShaderModule( D3D11ShaderModule *d3dShaderModule = (D3D11ShaderModule*) shaderModule; uint32_t i; - /* Release the D3D11 shader objects and free the array */ + /* Release the D3D11 shader objects and free the arrays */ for (i = 0; i < d3dShaderModule->numEntryPoints; i += 1) { ID3D11DeviceChild_Release(d3dShaderModule->shaders[i]); + ID3D10Blob_Release(d3dShaderModule->blobs[i]); } SDL_free(d3dShaderModule->shaders); + SDL_free(d3dShaderModule->blobs); /* Destroy the SPIRV-Cross context. * This should destroy the entryPoints list as well. @@ -1107,7 +1542,17 @@ static void D3D11_QueueDestroyGraphicsPipeline( Refresh_Renderer* driverData, Refresh_GraphicsPipeline* graphicsPipeline ) { - NOT_IMPLEMENTED + D3D11Renderer *renderer = (D3D11Renderer*) driverData; + D3D11GraphicsPipeline *d3dGraphicsPipeline = (D3D11GraphicsPipeline*) graphicsPipeline; + + ID3D11BlendState_Release(d3dGraphicsPipeline->colorAttachmentBlendState); + ID3D11DepthStencilState_Release(d3dGraphicsPipeline->depthStencilState); + ID3D11RasterizerState_Release(d3dGraphicsPipeline->rasterizerState); + ID3D11InputLayout_Release(d3dGraphicsPipeline->inputLayout); + + /* FIXME: Release uniform buffers, once that's written in */ + + SDL_free(d3dGraphicsPipeline); } /* Graphics State */ @@ -1201,7 +1646,31 @@ static void D3D11_BeginRenderPass( } } - /* FIXME: Set viewport and scissor state */ + /* Set default viewport and scissor state */ + /* FIXME: Check how Vulkan sets these defaults */ + viewports[0].TopLeftX = 0; + viewports[0].TopLeftY = 0; + viewports[0].Width = (float) ((D3D11Texture*) colorAttachmentInfos[0].texture)->twod.width; + viewports[0].Height = (float) ((D3D11Texture*) colorAttachmentInfos[0].texture)->twod.height; + viewports[0].MinDepth = 0; /* FIXME: Check what Vulkan does for these. */ + viewports[0].MaxDepth = 1; + + ID3D11DeviceContext_RSSetViewports( + cmdbuf->context, + 1, + viewports + ); + + scissorRects[0].left = 0; + scissorRects[0].right = (LONG) viewports[0].Width; + scissorRects[0].top = 0; + scissorRects[0].bottom = (LONG) viewports[0].Height; + + ID3D11DeviceContext_RSSetScissorRects( + cmdbuf->context, + 1, + scissorRects + ); /* FIXME: What should we do with render area? */ } @@ -1218,7 +1687,51 @@ static void D3D11_BindGraphicsPipeline( Refresh_CommandBuffer* commandBuffer, Refresh_GraphicsPipeline* graphicsPipeline ) { - NOT_IMPLEMENTED + D3D11Renderer *renderer = (D3D11Renderer*) driverData; + D3D11CommandBuffer *cmdbuf = (D3D11CommandBuffer*) commandBuffer; + D3D11GraphicsPipeline *pipeline = (D3D11GraphicsPipeline*) graphicsPipeline; + + ID3D11DeviceContext_OMSetBlendState( + cmdbuf->context, + pipeline->colorAttachmentBlendState, + pipeline->blendConstants, + 0xffffffff + ); + + ID3D11DeviceContext_OMSetDepthStencilState( + cmdbuf->context, + pipeline->depthStencilState, + pipeline->stencilRef + ); + + ID3D11DeviceContext_IASetPrimitiveTopology( + cmdbuf->context, + pipeline->primitiveTopology + ); + + ID3D11DeviceContext_IASetInputLayout( + cmdbuf->context, + pipeline->inputLayout + ); + + ID3D11DeviceContext_RSSetState( + cmdbuf->context, + pipeline->rasterizerState + ); + + ID3D11DeviceContext_VSSetShader( + cmdbuf->context, + pipeline->vertexShader, + NULL, + 0 + ); + + ID3D11DeviceContext_PSSetShader( + cmdbuf->context, + pipeline->fragmentShader, + NULL, + 0 + ); } static void D3D11_SetViewport( @@ -1245,7 +1758,32 @@ static void D3D11_BindVertexBuffers( Refresh_Buffer** pBuffers, uint64_t* pOffsets ) { - NOT_IMPLEMENTED + D3D11CommandBuffer *cmdbuf = (D3D11CommandBuffer*) commandBuffer; + ID3D11Buffer **buffers; + uint32_t *strides; + uint32_t i; + + buffers = SDL_stack_alloc(ID3D11Buffer*, bindingCount); + strides = SDL_stack_alloc(uint32_t, bindingCount); + for (i = 0; i < bindingCount; i += 1) + { + buffers[i] = ((D3D11Buffer*) pBuffers[i])->handle; + strides[i] = 20; + /* FIXME: Strides! Will probably need to get this from InputLayout somehow. */ + } + + /* FIXME: State shadowing? */ + ID3D11DeviceContext_IASetVertexBuffers( + cmdbuf->context, + firstBinding, + bindingCount, + buffers, + strides, + (const UINT*) pOffsets + ); + + SDL_stack_free(buffers); + SDL_stack_free(strides); } static void D3D11_BindIndexBuffer( -- 2.25.1 From bca9d1e533afb12858495a90555eda08f6bd6af3 Mon Sep 17 00:00:00 2001 From: Caleb Cornett Date: Mon, 14 Mar 2022 19:07:26 -0400 Subject: [PATCH 11/13] Update CMakeLists to include SPIRV-Cross --- CMakeLists.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index e561d42..480d055 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,10 +39,13 @@ endif() # Defines add_definitions( -DREFRESH_DRIVER_VULKAN + -DSPIRV_CROSS_C_API_GLSL + -DSPIRV_CROSS_C_API_REFLECT ) if (WIN32) add_definitions( -DREFRESH_DRIVER_D3D11 + -DSPIRV_CROSS_C_API_HLSL ) endif() @@ -72,6 +75,7 @@ target_include_directories(Refresh PUBLIC $ $ $ + $ ) # MinGW builds should statically link libgcc @@ -85,6 +89,10 @@ set_target_properties(Refresh PROPERTIES OUTPUT_NAME "Refresh" SOVERSION ${LIB_MAJOR_VERSION} ) +# Internal Dependencies +add_subdirectory(SPIRV-Cross EXCLUDE_FROM_ALL) +target_link_libraries(Refresh PRIVATE spirv-cross-c) + # SDL2 Dependency if (DEFINED SDL2_INCLUDE_DIRS AND DEFINED SDL2_LIBRARIES) message(STATUS "using pre-defined SDL2 variables SDL2_INCLUDE_DIRS and SDL2_LIBRARIES") -- 2.25.1 From 0d8e1590d5b46b71f20e2b4f3d4826eb7d843e4c Mon Sep 17 00:00:00 2001 From: cosmonaut Date: Mon, 14 Mar 2022 17:40:09 -0700 Subject: [PATCH 12/13] conditional spirv cross build --- CMakeLists.txt | 29 +++++++++++++++++++++++------ src/Refresh_Driver_D3D11.c | 4 ++++ src/Refresh_Driver_Vulkan.c | 4 ++++ 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 480d055..eb46dee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,16 +36,20 @@ elseif(WIN32) set(CMAKE_SHARED_LIBRARY_PREFIX "") endif() +set(BUILD_D3D11 OFF) + +if (WIN32) + set(BUILD_D3D11 ON) +endif() + # Defines add_definitions( -DREFRESH_DRIVER_VULKAN - -DSPIRV_CROSS_C_API_GLSL - -DSPIRV_CROSS_C_API_REFLECT ) -if (WIN32) + +if (BUILD_D3D11) add_definitions( -DREFRESH_DRIVER_D3D11 - -DSPIRV_CROSS_C_API_HLSL ) endif() @@ -90,8 +94,21 @@ set_target_properties(Refresh PROPERTIES OUTPUT_NAME "Refresh" ) # Internal Dependencies -add_subdirectory(SPIRV-Cross EXCLUDE_FROM_ALL) -target_link_libraries(Refresh PRIVATE spirv-cross-c) +if (BUILD_D3D11) + set(SPIRV_CROSS_ENABLE_TESTS OFF CACHE "" INTERNAL FORCE) + set(SPIRV_CROSS_CLI OFF CACHE "" INTERNAL FORCE) + set(SPIRV_CROSS_SHARED ON CACHE "" INTERNAL FORCE) + set(SPIRV_CROSS_STATIC OFF CACHE "" INTERNAL FORCE) + set(SPIRV_CROSS_ENABLE_C_API ON CACHE "" INTERNAL FORCE) + set(SPIRV_CROSS_ENABLE_HLSL ON CACHE "" INTERNAL FORCE) + set(SPIRV_CROSS_ENABLE_GLSL ON CACHE "" INTERNAL FORCE) + set(SPIRV_CROSS_ENABLE_REFLECT ON CACHE "" INTERNAL FORCE) + set(SPIRV_CROSS_ENABLE_MSL OFF CACHE "" INTERNAL FORCE) + set(SPIRV_CROSS_ENABLE_CPP OFF CACHE "" INTERNAL FORCE) + + add_subdirectory(SPIRV-Cross EXCLUDE_FROM_ALL) + target_link_libraries(Refresh PUBLIC spirv-cross-c-shared) +endif() # SDL2 Dependency if (DEFINED SDL2_INCLUDE_DIRS AND DEFINED SDL2_LIBRARIES) diff --git a/src/Refresh_Driver_D3D11.c b/src/Refresh_Driver_D3D11.c index 3a86ab0..17d47ae 100644 --- a/src/Refresh_Driver_D3D11.c +++ b/src/Refresh_Driver_D3D11.c @@ -2231,4 +2231,8 @@ Refresh_Driver D3D11Driver = { D3D11_CreateDevice }; +#else + +extern int this_tu_is_empty; + #endif //REFRESH_DRIVER_D3D11 diff --git a/src/Refresh_Driver_Vulkan.c b/src/Refresh_Driver_Vulkan.c index 72c2a5c..b5fb204 100644 --- a/src/Refresh_Driver_Vulkan.c +++ b/src/Refresh_Driver_Vulkan.c @@ -10642,4 +10642,8 @@ Refresh_Driver VulkanDriver = { VULKAN_CreateDevice }; +#else + +extern int this_tu_is_empty; + #endif //REFRESH_DRIVER_VULKAN -- 2.25.1 From 2a9dbc963a958e82e7b3c27e601a9029aad8eafe Mon Sep 17 00:00:00 2001 From: Caleb Cornett Date: Sun, 20 Mar 2022 18:24:08 -0400 Subject: [PATCH 13/13] Remove spirv-cross, take HLSL files as shader module input, update vertex format ABI --- .gitmodules | 3 - CMakeLists.txt | 18 -- SPIRV-Cross | 1 - src/Refresh_Driver_D3D11.c | 341 ++++++++------------------------ visualc/Refresh.vcxproj | 18 +- visualc/Refresh.vcxproj.filters | 27 --- 6 files changed, 91 insertions(+), 317 deletions(-) delete mode 160000 SPIRV-Cross diff --git a/.gitmodules b/.gitmodules index 1da3b2f..bf4fac3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ [submodule "Vulkan-Headers"] path = Vulkan-Headers url = https://github.com/KhronosGroup/Vulkan-Headers.git -[submodule "SPIRV-Cross"] - path = SPIRV-Cross - url = https://github.com/KhronosGroup/SPIRV-Cross diff --git a/CMakeLists.txt b/CMakeLists.txt index eb46dee..a22ec80 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -79,7 +79,6 @@ target_include_directories(Refresh PUBLIC $ $ $ - $ ) # MinGW builds should statically link libgcc @@ -93,23 +92,6 @@ set_target_properties(Refresh PROPERTIES OUTPUT_NAME "Refresh" SOVERSION ${LIB_MAJOR_VERSION} ) -# Internal Dependencies -if (BUILD_D3D11) - set(SPIRV_CROSS_ENABLE_TESTS OFF CACHE "" INTERNAL FORCE) - set(SPIRV_CROSS_CLI OFF CACHE "" INTERNAL FORCE) - set(SPIRV_CROSS_SHARED ON CACHE "" INTERNAL FORCE) - set(SPIRV_CROSS_STATIC OFF CACHE "" INTERNAL FORCE) - set(SPIRV_CROSS_ENABLE_C_API ON CACHE "" INTERNAL FORCE) - set(SPIRV_CROSS_ENABLE_HLSL ON CACHE "" INTERNAL FORCE) - set(SPIRV_CROSS_ENABLE_GLSL ON CACHE "" INTERNAL FORCE) - set(SPIRV_CROSS_ENABLE_REFLECT ON CACHE "" INTERNAL FORCE) - set(SPIRV_CROSS_ENABLE_MSL OFF CACHE "" INTERNAL FORCE) - set(SPIRV_CROSS_ENABLE_CPP OFF CACHE "" INTERNAL FORCE) - - add_subdirectory(SPIRV-Cross EXCLUDE_FROM_ALL) - target_link_libraries(Refresh PUBLIC spirv-cross-c-shared) -endif() - # SDL2 Dependency if (DEFINED SDL2_INCLUDE_DIRS AND DEFINED SDL2_LIBRARIES) message(STATUS "using pre-defined SDL2 variables SDL2_INCLUDE_DIRS and SDL2_LIBRARIES") diff --git a/SPIRV-Cross b/SPIRV-Cross deleted file mode 160000 index d5c3bd8..0000000 --- a/SPIRV-Cross +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d5c3bd8b5e7db9e2d7fe809944b47b8f88e1c732 diff --git a/src/Refresh_Driver_D3D11.c b/src/Refresh_Driver_D3D11.c index 17d47ae..c3c8ec8 100644 --- a/src/Refresh_Driver_D3D11.c +++ b/src/Refresh_Driver_D3D11.c @@ -39,8 +39,6 @@ #include #include -#include - /* Defines */ #define D3D11_DLL "d3d11.dll" @@ -129,7 +127,8 @@ static DXGI_FORMAT RefreshToD3D11_SurfaceFormat[] = static DXGI_FORMAT RefreshToD3D11_VertexFormat[] = { - DXGI_FORMAT_R32_FLOAT, /* SINGLE */ + DXGI_FORMAT_R32_UINT, /* UINT */ + DXGI_FORMAT_R32_FLOAT, /* FLOAT */ DXGI_FORMAT_R32G32_FLOAT, /* VECTOR2 */ DXGI_FORMAT_R32G32B32_FLOAT, /* VECTOR3 */ DXGI_FORMAT_R32G32B32A32_FLOAT, /* VECTOR4 */ @@ -328,11 +327,10 @@ typedef struct D3D11CommandBufferPool typedef struct D3D11ShaderModule { - spvc_context context; - size_t numEntryPoints; - const spvc_entry_point *entryPoints; - ID3D11DeviceChild **shaders; /* ID3D11VertexShader, ID3D11PixelShader, ID3D11ComputeShader */ - ID3D10Blob **blobs; + ID3D11DeviceChild *shader; /* ID3D11VertexShader, ID3D11PixelShader, ID3D11ComputeShader */ + ID3D10Blob *blob; + char *shaderSource; + size_t shaderSourceLength; } D3D11ShaderModule; typedef struct D3D11GraphicsPipeline @@ -899,7 +897,8 @@ static uint32_t D3D11_INTERNAL_FindIndexOfVertexBinding( static ID3D11InputLayout* D3D11_INTERNAL_FetchInputLayout( D3D11Renderer *renderer, Refresh_VertexInputState inputState, - ID3D10Blob *shaderBlob + void *shaderBytes, + size_t shaderByteLength ) { ID3D11InputLayout *result = NULL; D3D11_INPUT_ELEMENT_DESC *elementDescs; @@ -942,8 +941,8 @@ static ID3D11InputLayout* D3D11_INTERNAL_FetchInputLayout( renderer->device, elementDescs, inputState.vertexAttributeCount, - (void*) ID3D10Blob_GetBufferPointer(shaderBlob), - ID3D10Blob_GetBufferSize(shaderBlob), + shaderBytes, + shaderByteLength, &result ); if (FAILED(res)) @@ -975,10 +974,11 @@ static Refresh_GraphicsPipeline* D3D11_CreateGraphicsPipeline( ) { D3D11Renderer *renderer = (D3D11Renderer*) driverData; D3D11GraphicsPipeline *pipeline = (D3D11GraphicsPipeline*) SDL_malloc(sizeof(D3D11GraphicsPipeline)); - D3D11ShaderModule* vertShaderModule = (D3D11ShaderModule*) pipelineCreateInfo->vertexShaderInfo.shaderModule; - D3D11ShaderModule* fragShaderModule = (D3D11ShaderModule*) pipelineCreateInfo->fragmentShaderInfo.shaderModule; - int32_t vertexShaderIndex, fragmentShaderIndex; + D3D11ShaderModule *vertShaderModule = (D3D11ShaderModule*) pipelineCreateInfo->vertexShaderInfo.shaderModule; + D3D11ShaderModule *fragShaderModule = (D3D11ShaderModule*) pipelineCreateInfo->fragmentShaderInfo.shaderModule; + ID3D10Blob *errorBlob; int32_t i; + HRESULT res; /* Color attachments */ pipeline->numColorAttachments = pipelineCreateInfo->attachmentInfo.colorAttachmentCount; @@ -1024,54 +1024,79 @@ static Refresh_GraphicsPipeline* D3D11_CreateGraphicsPipeline( pipelineCreateInfo->rasterizerState ); - /* Vertex Shader + Input Layout */ - vertexShaderIndex = -1; - for (i = 0; i < vertShaderModule->numEntryPoints; i += 1) + /* Vertex Shader */ + if (vertShaderModule->shader == NULL) { - if ( vertShaderModule->entryPoints[i].execution_model == SpvExecutionModelVertex && - SDL_strcmp(vertShaderModule->entryPoints[i].name, pipelineCreateInfo->vertexShaderInfo.entryPointName) == 0 ) - { - vertexShaderIndex = i; - break; - } - } - if (vertexShaderIndex == -1) - { - Refresh_LogError( - "Graphics pipeline creation failed! No entry point '%s' exists for the vertex shader!", - pipelineCreateInfo->vertexShaderInfo.entryPointName + res = renderer->D3DCompileFunc( + vertShaderModule->shaderSource, + vertShaderModule->shaderSourceLength, + NULL, + NULL, + NULL, + "main", + "vs_5_0", + 0, + 0, + &vertShaderModule->blob, + &errorBlob ); - return NULL; - } + if (FAILED(res)) + { + Refresh_LogError("Vertex Shader Compile Error: %s", ID3D10Blob_GetBufferPointer(errorBlob)); + return NULL; + } + res = ID3D11Device_CreateVertexShader( + renderer->device, + ID3D10Blob_GetBufferPointer(vertShaderModule->blob), + ID3D10Blob_GetBufferSize(vertShaderModule->blob), + NULL, + (ID3D11VertexShader**) &vertShaderModule->shader + ); + ERROR_CHECK_RETURN("Could not create vertex shader", NULL); + } + pipeline->vertexShader = (ID3D11VertexShader*)vertShaderModule->shader; + + /* Input Layout */ pipeline->inputLayout = D3D11_INTERNAL_FetchInputLayout( renderer, pipelineCreateInfo->vertexInputState, - vertShaderModule->blobs[vertexShaderIndex] + ID3D10Blob_GetBufferPointer(vertShaderModule->blob), + ID3D10Blob_GetBufferSize(vertShaderModule->blob) ); - pipeline->vertexShader = (ID3D11VertexShader*) vertShaderModule->shaders[vertexShaderIndex]; /* Fragment Shader */ - fragmentShaderIndex = -1; - for (i = 0; i < fragShaderModule->numEntryPoints; i += 1) + if (fragShaderModule->shader == NULL) { - if ( fragShaderModule->entryPoints[i].execution_model == SpvExecutionModelFragment && - SDL_strcmp(fragShaderModule->entryPoints[i].name, pipelineCreateInfo->fragmentShaderInfo.entryPointName) == 0 ) - { - fragmentShaderIndex = i; - break; - } - } - if (fragmentShaderIndex == -1) - { - Refresh_LogError( - "Graphics pipeline creation failed! No entry point '%s' exists for the fragment shader!", - pipelineCreateInfo->vertexShaderInfo.entryPointName + res = renderer->D3DCompileFunc( + fragShaderModule->shaderSource, + fragShaderModule->shaderSourceLength, + NULL, + NULL, + NULL, + "main", + "ps_5_0", + 0, + 0, + &fragShaderModule->blob, + &errorBlob ); - return NULL; - } + if (FAILED(res)) + { + Refresh_LogError("Fragment Shader Compile Error: %s", ID3D10Blob_GetBufferPointer(errorBlob)); + return NULL; + } - pipeline->fragmentShader = (ID3D11PixelShader*) fragShaderModule->shaders[fragmentShaderIndex]; + res = ID3D11Device_CreatePixelShader( + renderer->device, + ID3D10Blob_GetBufferPointer(fragShaderModule->blob), + ID3D10Blob_GetBufferSize(fragShaderModule->blob), + NULL, + (ID3D11PixelShader**) &fragShaderModule->shader + ); + ERROR_CHECK_RETURN("Could not create pixel shader", NULL); + } + pipeline->fragmentShader = (ID3D11PixelShader*) fragShaderModule->shader; /* FIXME: Need to create uniform buffers for the shaders */ @@ -1090,199 +1115,14 @@ static Refresh_ShaderModule* D3D11_CreateShaderModule( Refresh_ShaderModuleCreateInfo *shaderModuleCreateInfo ) { D3D11Renderer *renderer = (D3D11Renderer*) driverData; - spvc_context context; - spvc_result result; - spvc_parsed_ir parsedIR; - spvc_compiler compiler; - const spvc_entry_point *entryPoints; - size_t numEntryPoints; - spvc_compiler_options compilerOptions; - char *hlslSource; - const char *shaderModel; - ID3DBlob **blobs; - ID3DBlob *errorBlob = NULL; - ID3D11DeviceChild **shaders; - D3D11ShaderModule *shaderModule; - uint32_t i; - HRESULT res; - /* Create the context */ - result = spvc_context_create(&context); - if (result != SPVC_SUCCESS) - { - Refresh_LogError("Could not create SPIRV Cross context! Error: %X", result); - return NULL; - } + D3D11ShaderModule *shaderModule = (D3D11ShaderModule*) SDL_malloc(sizeof(D3D11ShaderModule)); + shaderModule->shader = NULL; /* created when binding to a pipeline */ + shaderModule->blob = NULL; /* created when binding to a pipeline */ + shaderModule->shaderSourceLength = shaderModuleCreateInfo->codeSize; + shaderModule->shaderSource = (char*) SDL_malloc(shaderModule->shaderSourceLength); + SDL_memcpy(shaderModule->shaderSource, shaderModuleCreateInfo->byteCode, shaderModuleCreateInfo->codeSize); - /* Parse the SPIRV input */ - result = spvc_context_parse_spirv( - context, - shaderModuleCreateInfo->byteCode, - shaderModuleCreateInfo->codeSize / sizeof(uint32_t), /* word count, not byte length */ - &parsedIR - ); - if (result != SPVC_SUCCESS) - { - Refresh_LogError("Could not parse SPIRV! Error: %X", result); - spvc_context_destroy(context); /* free all context-related memory */ - return NULL; - } - - /* Create the cross compiler */ - result = spvc_context_create_compiler( - context, - SPVC_BACKEND_HLSL, - parsedIR, - SPVC_CAPTURE_MODE_TAKE_OWNERSHIP, - &compiler - ); - if (result != SPVC_SUCCESS) - { - Refresh_LogError("Could not create SPIRV to HLSL cross compiler! Error: %X", result); - spvc_context_destroy(context); /* free all context-related memory */ - return NULL; - } - - /* Get entry points from the source bytecode */ - result = spvc_compiler_get_entry_points(compiler, &entryPoints, &numEntryPoints); - if (result != SPVC_SUCCESS) - { - Refresh_LogError("Could not get SPIRV entry points! Error: %X", result); - spvc_context_destroy(context); /* free all context-related memory */ - return NULL; - } - - /* Set HLSL cross-compile options (target SM5.0) */ - spvc_compiler_create_compiler_options(compiler, &compilerOptions); - spvc_compiler_options_set_uint( - compilerOptions, - SPVC_COMPILER_OPTION_HLSL_SHADER_MODEL, - 50 /* shader model 5.0 */ - ); - spvc_compiler_options_set_bool( - compilerOptions, - SPVC_COMPILER_OPTION_FLIP_VERTEX_Y, - SPVC_TRUE - ); - spvc_compiler_install_compiler_options(compiler, compilerOptions); - - /* Cross compile to HLSL */ - result = spvc_compiler_compile(compiler, &hlslSource); - if (result != SPVC_SUCCESS) - { - Refresh_LogError("Could not cross-compile SPIRV to HLSL! Error: %X", result); - spvc_context_destroy(context); /* free all context-related memory */ - return NULL; - } - - /* Allocate memory for the D3D11 shader list */ - shaders = (ID3D11DeviceChild**) SDL_malloc(numEntryPoints * sizeof(ID3D11DeviceChild*)); - blobs = (ID3D10Blob**) SDL_malloc(numEntryPoints * sizeof(ID3D10Blob*)); - - /* Compile each HLSL entry point into a D3D shader */ - for (i = 0; i < numEntryPoints; i += 1) - { - /* Determine the exact shader model to use */ - switch (entryPoints[i].execution_model) - { - case SpvExecutionModelVertex: - shaderModel = "vs_5_0"; - break; - - case SpvExecutionModelFragment: - shaderModel = "ps_5_0"; - break; - - case SpvExecutionModelGLCompute: - shaderModel = "cs_5_0"; - break; - - default: - Refresh_LogError( - "Attempting to compile a shader with an unknown execution model: %X", - entryPoints[i].execution_model - ); - spvc_context_destroy(context); /* free all context-related memory */ - SDL_free(shaders); - return NULL; - } - - /* Compile the shader blob */ - res = renderer->D3DCompileFunc( - hlslSource, - SDL_strlen(hlslSource), - NULL, - NULL, - NULL, - entryPoints[i].name, - shaderModel, - 0, - 0, - &blobs[i], - &errorBlob - ); - if (FAILED(res)) - { - Refresh_LogError( - "D3DCompile failed on HLSL shader with entry point '%s'! Error: %X\nCompiler error message: %s", - entryPoints[i].name, - res, - errorBlob ? (const char*) ID3D10Blob_GetBufferPointer(errorBlob) : "" - ); - spvc_context_destroy(context); /* free all context-related memory */ - SDL_free(shaders); - return NULL; - } - - /* Create the shader from the blob */ - switch (entryPoints[i].execution_model) - { - case SpvExecutionModelVertex: - res = ID3D11Device_CreateVertexShader( - renderer->device, - ID3D10Blob_GetBufferPointer(blobs[i]), - ID3D10Blob_GetBufferSize(blobs[i]), - NULL, - (ID3D11VertexShader**) &shaders[i] - ); - break; - - case SpvExecutionModelFragment: - res = ID3D11Device_CreatePixelShader( - renderer->device, - ID3D10Blob_GetBufferPointer(blobs[i]), - ID3D10Blob_GetBufferSize(blobs[i]), - NULL, - (ID3D11PixelShader**) &shaders[i] - ); - break; - - case SpvExecutionModelGLCompute: - res = ID3D11Device_CreateComputeShader( - renderer->device, - ID3D10Blob_GetBufferPointer(blobs[i]), - ID3D10Blob_GetBufferSize(blobs[i]), - NULL, - (ID3D11ComputeShader**) &shaders[i] - ); - break; - } - if (FAILED(res)) - { - Refresh_LogError("D3D11 shader creation failed! Error code: %X", res); - spvc_context_destroy(context); /* free all context-related memory */ - SDL_free(shaders); - return NULL; - } - } - - /* Create the final shader module object to return */ - shaderModule = (D3D11ShaderModule*) SDL_malloc(sizeof(D3D11ShaderModule)); - shaderModule->context = context; - shaderModule->entryPoints = entryPoints; - shaderModule->numEntryPoints = numEntryPoints; - shaderModule->shaders = shaders; - shaderModule->blobs = blobs; return (Refresh_ShaderModule*) shaderModule; } @@ -1514,21 +1354,10 @@ static void D3D11_QueueDestroyShaderModule( Refresh_ShaderModule* shaderModule ) { D3D11ShaderModule *d3dShaderModule = (D3D11ShaderModule*) shaderModule; - uint32_t i; - - /* Release the D3D11 shader objects and free the arrays */ - for (i = 0; i < d3dShaderModule->numEntryPoints; i += 1) - { - ID3D11DeviceChild_Release(d3dShaderModule->shaders[i]); - ID3D10Blob_Release(d3dShaderModule->blobs[i]); - } - SDL_free(d3dShaderModule->shaders); - SDL_free(d3dShaderModule->blobs); - - /* Destroy the SPIRV-Cross context. - * This should destroy the entryPoints list as well. - */ - spvc_context_destroy(d3dShaderModule->context); + ID3D11DeviceChild_Release(d3dShaderModule->shader); + ID3D10Blob_Release(d3dShaderModule->blob); + SDL_free(d3dShaderModule->shaderSource); + SDL_free(d3dShaderModule); } static void D3D11_QueueDestroyComputePipeline( diff --git a/visualc/Refresh.vcxproj b/visualc/Refresh.vcxproj index a757695..6a37b21 100644 --- a/visualc/Refresh.vcxproj +++ b/visualc/Refresh.vcxproj @@ -61,8 +61,9 @@ Level3 Disabled - REFRESH_DRIVER_D3D11;REFRESH_DRIVER_VULKAN;SPIRV_CROSS_C_API_GLSL;SPIRV_CROSS_C_API_HLSL;SPIRV_CROSS_C_API_REFLECT;%(PreprocessorDefinitions) - ..\SPIRV-Cross;%(AdditionalIncludeDirectories) + REFRESH_DRIVER_D3D11;REFRESH_DRIVER_VULKAN;%(PreprocessorDefinitions) + + DebugFull @@ -73,10 +74,11 @@ Level3 MaxSpeed - REFRESH_DRIVER_D3D11;REFRESH_DRIVER_VULKAN;SPIRV_CROSS_C_API_GLSL;SPIRV_CROSS_C_API_HLSL;SPIRV_CROSS_C_API_REFLECT;%(PreprocessorDefinitions) + REFRESH_DRIVER_D3D11;REFRESH_DRIVER_VULKAN;%(PreprocessorDefinitions) true true - ..\SPIRV-Cross;%(AdditionalIncludeDirectories) + + true @@ -85,14 +87,6 @@ - - - - - - - - diff --git a/visualc/Refresh.vcxproj.filters b/visualc/Refresh.vcxproj.filters index e4cb70c..769e63a 100644 --- a/visualc/Refresh.vcxproj.filters +++ b/visualc/Refresh.vcxproj.filters @@ -13,30 +13,6 @@ Source Files - - Source Files\spirv-cross - - - Source Files\spirv-cross - - - Source Files\spirv-cross - - - Source Files\spirv-cross - - - Source Files\spirv-cross - - - Source Files\spirv-cross - - - Source Files\spirv-cross - - - Source Files\spirv-cross - @@ -62,8 +38,5 @@ {B2BA146C-CAA1-30BE-B7A9-F8D02673EA0C} - - {4764626f-fd8b-4a1c-8c20-fd92a1f3cb4b} - \ No newline at end of file -- 2.25.1