forked from MoonsideGames/Refresh
Swapchain creation, resizing, and destruction
parent
cd8f48c444
commit
a93d49a05e
|
@ -36,9 +36,17 @@
|
|||
#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)) \
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue