Swapchain creation, resizing, and destruction
							parent
							
								
									387addd67d
								
							
						
					
					
						commit
						9bdad47a36
					
				|  | @ -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