Refresh/src/Refresh_Driver_D3D11.c

1498 lines
38 KiB
C

/* 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 <evan@moonside.games>
*
*/
#if REFRESH_DRIVER_D3D11
#define D3D11_NO_HELPERS
#define CINTERFACE
#define COBJMACROS
#include <d3d11.h>
#include <dxgi.h>
#include "Refresh_Driver.h"
#include "Refresh_Driver_D3D11_cdefines.h"
#include <SDL.h>
#include <SDL_syswm.h>
/* 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; \
}
#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) \
); \
}
/* 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 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 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;
uint8_t fixed;
} D3D11CommandBuffer;
typedef struct D3D11CommandBufferPool
{
D3D11CommandBuffer **elements;
uint32_t count;
uint32_t capacity;
} D3D11CommandBufferPool;
typedef struct D3D11Renderer
{
ID3D11Device *device;
ID3D11DeviceContext *immediateContext;
IDXGIFactory1 *factory;
IDXGIAdapter1* adapter;
void *d3d11_dll;
void *dxgi_dll;
SDL_mutex *immediateContextMutex;
D3D11CommandBufferPool *commandBufferPool;
SDL_mutex *commandBufferAcquisitionMutex;
D3D11SwapchainData** swapchainDatas;
uint32_t swapchainDataCount;
uint32_t swapchainDataCapacity;
Refresh_Vec4 blendFactor;
uint8_t debugMode;
D3D_FEATURE_LEVEL featureLevel;
} D3D11Renderer;
/* Predeclarations */
static void D3D11_Wait(Refresh_Renderer* driverData);
/* 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);
}
/* 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
) {
IDXGIFactory1 *pParent;
DXGI_MODE_DESC swapchainBufferDesc;
DXGI_SWAP_CHAIN_DESC swapchainDesc;
IDXGISwapChain *swapchain;
D3D11SwapchainData *swapchainData;
SDL_SysWMinfo info;
HWND dxgiHandle;
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;
/* Add the swapchain data to the window data */
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 Refresh-side texture for the swapchain */
return D3D11_INTERNAL_InitializeSwapchainTexture(
renderer,
&swapchainData->refreshTexture,
swapchainData->swapchain
);
}
static uint8_t D3D11_INTERNAL_ResizeSwapchain(
D3D11Renderer *renderer,
D3D11SwapchainData *swapchainData
) {
int w, h;
HRESULT res;
/* Release the old RTV */
ID3D11RenderTargetView_Release(swapchainData->refreshTexture.twod.targetView);
/* 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);
/* Create the Refresh-side texture for the swapchain */
return D3D11_INTERNAL_InitializeSwapchainTexture(
renderer,
&swapchainData->refreshTexture,
swapchainData->swapchain
);
}
/* 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 swapchain */
for (i = 0; i < renderer->swapchainDataCount; i += 1)
{
ID3D11RenderTargetView_Release(renderer->swapchainDatas[i]->refreshTexture.twod.targetView);
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);
/* Release DXGI objects */
IDXGIAdapter1_Release(renderer->adapter);
IDXGIFactory1_Release(renderer->factory);
/* 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 */
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,
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
) {
D3D11Renderer *renderer = (D3D11Renderer*) driverData;
D3D11CommandBuffer *cmdbuf = (D3D11CommandBuffer*) commandBuffer;
D3D11Texture *texture;
float clearColors[4];
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)
{
cmdbuf->rtViews[i] = (ID3D11RenderTargetView*) ((D3D11Texture*) colorAttachmentInfos[i].texture)->twod.targetView;
}
/* 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,
cmdbuf->rtViews,
cmdbuf->dsView
);
/* 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,
(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? */
}
static void D3D11_EndRenderPass(
Refresh_Renderer* driverData,
Refresh_CommandBuffer* commandBuffer
) {
/* FIXME: What should we do here? */
}
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;
/* 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)
{
/* 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
);
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];
renderer->commandBufferPool->count += 1;
}
/* Set up the command buffer */
commandBuffer->threadID = SDL_ThreadID();
commandBuffer->recording = 1;
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);
return (Refresh_CommandBuffer*) commandBuffer;
}
static D3D11SwapchainData* D3D11_INTERNAL_FetchSwapchainData(
D3D11Renderer* renderer,
void* windowHandle
) {
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
) {
return DXGI_FORMAT_R8G8B8A8_UNORM;
}
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)
{
/* Grab the prerecorded command list. */
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 */
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)
{
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;
/* Present, if applicable */
if (commandBuffer->swapchainData)
{
IDXGISwapChain_Present(
commandBuffer->swapchainData->swapchain,
1, /* FIXME: Assumes vsync! */
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));
/* 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;
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;
/* 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;
}
Refresh_Driver D3D11Driver = {
"D3D11",
D3D11_CreateDevice
};
#endif //REFRESH_DRIVER_D3D11