diff --git a/CMakeLists.txt b/CMakeLists.txt index 1c87504..5b38fa4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,6 +41,12 @@ add_definitions( -DREFRESH_DRIVER_VULKAN ) +if (WIN32) + add_definitions( + -DREFRESH_DRIVER_D3D11 + ) +endif() + # Source lists add_library(Refresh # Public Headers @@ -51,6 +57,7 @@ add_library(Refresh src/Refresh_Driver_Vulkan_vkfuncs.h # Source Files src/Refresh.c + src/Refresh_Driver_D3D11.c src/Refresh_Driver_Vulkan.c src/Refresh_Image.c ) diff --git a/include/Refresh.h b/include/Refresh.h index 801c95e..19c98ed 100644 --- a/include/Refresh.h +++ b/include/Refresh.h @@ -330,6 +330,7 @@ typedef enum Refresh_Backend { REFRESH_BACKEND_DONTCARE, REFRESH_BACKEND_VULKAN, + REFRESH_BACKEND_D3D11, REFRESH_BACKEND_PS5, REFRESH_BACKEND_INVALID } Refresh_Backend; diff --git a/src/Refresh.c b/src/Refresh.c index ec8d7cd..b495fd2 100644 --- a/src/Refresh.c +++ b/src/Refresh.c @@ -39,6 +39,12 @@ #define VULKAN_DRIVER NULL #endif +#ifdef REFRESH_DRIVER_D3D11 + #define D3D11_DRIVER &D3D11Driver +#else + #define D3D11_DRIVER NULL +#endif + #ifdef REFRESH_DRIVER_PS5 #define PS5_DRIVER &PS5Driver #else @@ -47,6 +53,7 @@ static const Refresh_Driver *backends[] = { NULL, + D3D11_DRIVER, VULKAN_DRIVER, PS5_DRIVER }; diff --git a/src/Refresh_Driver.h b/src/Refresh_Driver.h index 5605d86..679539d 100644 --- a/src/Refresh_Driver.h +++ b/src/Refresh_Driver.h @@ -597,6 +597,7 @@ typedef struct Refresh_Driver } Refresh_Driver; extern Refresh_Driver VulkanDriver; +extern Refresh_Driver D3D11Driver; extern Refresh_Driver PS5Driver; #endif /* REFRESH_DRIVER_H */ diff --git a/src/Refresh_Driver_D3D11.c b/src/Refresh_Driver_D3D11.c new file mode 100644 index 0000000..5d5e8b9 --- /dev/null +++ b/src/Refresh_Driver_D3D11.c @@ -0,0 +1,1083 @@ +/* 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 + +#include "Refresh_Driver.h" +#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)) \ + { \ + 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; \ + } + +/* 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[] = +{ + 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_UINT, /* UINT */ + DXGI_FORMAT_R32_FLOAT, /* FLOAT */ + 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 */ +}; + +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 D3D11Texture +{ + /* 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 D3D11Buffer +{ + ID3D11Buffer *handle; +} D3D11Buffer; + +typedef struct D3D11SwapchainData +{ + IDXGISwapChain* swapchain; + D3D11Texture refreshTexture; + void* windowHandle; +} 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; +} D3D11CommandBuffer; + +typedef struct D3D11CommandBufferPool +{ + D3D11CommandBuffer **elements; + uint32_t count; + uint32_t capacity; +} D3D11CommandBufferPool; + +typedef struct D3D11ShaderModule +{ + ID3D11DeviceChild *shader; /* ID3D11VertexShader, ID3D11PixelShader, ID3D11ComputeShader */ + ID3D10Blob *blob; + char *shaderSource; + size_t shaderSourceLength; +} 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; + ID3D11DeviceContext *immediateContext; + IDXGIFactory1 *factory; + IDXGIAdapter1* adapter; + void *d3d11_dll; + void *dxgi_dll; + void *d3dcompiler_dll; + SDL_mutex *contextLock; + + D3D11CommandBufferPool *commandBufferPool; + SDL_mutex *commandBufferAcquisitionMutex; + + D3D11SwapchainData** swapchainDatas; + uint32_t swapchainDataCount; + uint32_t swapchainDataCapacity; + + Refresh_Vec4 blendFactor; + + uint8_t debugMode; + D3D_FEATURE_LEVEL featureLevel; + PFN_D3DCOMPILE D3DCompileFunc; +} 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 +) { + NOT_IMPLEMENTED +} + +/* Drawing */ + +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_DrawPrimitivesIndirect( + Refresh_Renderer *driverData, + Refresh_CommandBuffer *commandBuffer, + Refresh_Buffer *buffer, + uint32_t offsetInBytes, + uint32_t drawCount, + uint32_t stride, + 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 + return NULL; +} + +static Refresh_GraphicsPipeline* D3D11_CreateGraphicsPipeline( + Refresh_Renderer *driverData, + Refresh_GraphicsPipelineCreateInfo *pipelineCreateInfo +) { + NOT_IMPLEMENTED + return NULL; +} + +static Refresh_Sampler* D3D11_CreateSampler( + Refresh_Renderer *driverData, + Refresh_SamplerStateCreateInfo *samplerStateCreateInfo +) { + NOT_IMPLEMENTED + return NULL; +} + +static Refresh_ShaderModule* D3D11_CreateShaderModule( + Refresh_Renderer *driverData, + Refresh_ShaderModuleCreateInfo *shaderModuleCreateInfo +) { + NOT_IMPLEMENTED + return NULL; +} + +static Refresh_Texture* D3D11_CreateTexture( + Refresh_Renderer *driverData, + Refresh_TextureCreateInfo *textureCreateInfo +) { + NOT_IMPLEMENTED + return NULL; +} + +static Refresh_Buffer* D3D11_CreateBuffer( + Refresh_Renderer *driverData, + Refresh_BufferUsageFlags usageFlags, + uint32_t sizeInBytes +) { + NOT_IMPLEMENTED + return NULL; +} + +/* 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 *yDataPtr, + void *uDataPtr, + void *vDataPtr, + uint32_t yDataLength, + uint32_t uvDataLength, + uint32_t yStride, + uint32_t uvStride +) { + 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 + return 0; +} + +static uint32_t D3D11_PushFragmentShaderUniforms( + Refresh_Renderer *driverData, + Refresh_CommandBuffer *commandBuffer, + void *data, + uint32_t dataLengthInBytes +) { + NOT_IMPLEMENTED + return 0; +} + +static uint32_t D3D11_PushComputeShaderUniforms( + Refresh_Renderer *driverData, + Refresh_CommandBuffer *commandBuffer, + void *data, + uint32_t dataLengthInBytes +) { + NOT_IMPLEMENTED + return 0; +} + +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 Refresh_CommandBuffer* D3D11_AcquireCommandBuffer( + Refresh_Renderer *driverData +) { + NOT_IMPLEMENTED + return NULL; +} + +static void D3D11_BeginRenderPass( + Refresh_Renderer *driverData, + Refresh_CommandBuffer *commandBuffer, + 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 +} + +/* Compute State */ + +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 +} + +/* Window and Swapchain Management */ + +static uint8_t D3D11_ClaimWindow( + Refresh_Renderer *driverData, + void *windowHandle, + Refresh_PresentMode presentMode +) { + NOT_IMPLEMENTED + return 0; +} + +static uint8_t D3D11_UnclaimWindow( + Refresh_Renderer *driverData, + void *windowHandle +) { + NOT_IMPLEMENTED + return 0; +} + +static Refresh_Texture* D3D11_AcquireSwapchainTexture( + Refresh_Renderer *driverData, + Refresh_CommandBuffer *commandBuffer, + void *windowHandle, + uint32_t *pWidth, + uint32_t *pHeight +) { + NOT_IMPLEMENTED + return NULL; +} + +static Refresh_TextureFormat D3D11_GetSwapchainFormat( + Refresh_Renderer *driverData, + void *windowHandle +) { + NOT_IMPLEMENTED + return REFRESH_TEXTUREFORMAT_R8G8B8A8; +} + +static void D3D11_SetSwapchainPresentMode( + Refresh_Renderer *driverData, + void *windowHandle, + Refresh_PresentMode presentMode +) { + NOT_IMPLEMENTED +} + +/* Submission and Fences */ + +static void D3D11_Submit( + Refresh_Renderer *driverData, + Refresh_CommandBuffer *commandBuffer +) { + NOT_IMPLEMENTED +} + +static Refresh_Fence* D3D11_SubmitAndAcquireFence( + Refresh_Renderer *driverData, + Refresh_CommandBuffer *commandBuffer +) { + NOT_IMPLEMENTED + return NULL; +} + +static void D3D11_Wait( + Refresh_Renderer *driverData +) { + NOT_IMPLEMENTED +} + +static void D3D11_WaitForFences( + Refresh_Renderer *driverData, + uint8_t waitAll, + uint32_t fenceCount, + Refresh_Fence **pFences +) { + NOT_IMPLEMENTED +} + +static int D3D11_QueryFence( + Refresh_Renderer *driverData, + Refresh_Fence *fence +) { + NOT_IMPLEMENTED + return 0; +} + +static void D3D11_ReleaseFence( + Refresh_Renderer *driverData, + Refresh_Fence *fence +) { + NOT_IMPLEMENTED +} + +/* Device Creation */ + +static uint8_t D3D11_PrepareDriver( + uint32_t *flags +) { + /* Nothing to do here. */ + return 1; +} + +static Refresh_Device* D3D11_CreateDevice( + 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_calloc(1, 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) + { + 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_calloc( + 1, + sizeof(D3D11CommandBufferPool) + ); + + /* Create mutexes */ + renderer->contextLock = SDL_CreateMutex(); + renderer->commandBufferAcquisitionMutex = SDL_CreateMutex(); + + /* Initialize miscellaneous renderer members */ + renderer->debugMode = (flags & D3D11_CREATE_DEVICE_DEBUG); + 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_PrepareDriver, + 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..e269212 --- /dev/null +++ b/src/Refresh_Driver_D3D11_cdefines.h @@ -0,0 +1,215 @@ +/* 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} }; +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 +{ + 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..52fd6af 100644 --- a/visualc/Refresh.vcxproj +++ b/visualc/Refresh.vcxproj @@ -61,7 +61,7 @@ Level3 Disabled - REFRESH_DRIVER_VULKAN;%(PreprocessorDefinitions) + REFRESH_DRIVER_VULKAN;REFRESH_DRIVER_D3D11;%(PreprocessorDefinitions) DebugFull @@ -72,7 +72,7 @@ Level3 MaxSpeed - REFRESH_DRIVER_VULKAN;%(PreprocessorDefinitions) + REFRESH_DRIVER_VULKAN;REFRESH_DRIVER_D3D11;%(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 +