Skip to content

Instantly share code, notes, and snippets.

@akbyrd
Created July 30, 2020 19:31
Show Gist options
  • Save akbyrd/c9d312048b49c5bd607ceba084d95bd0 to your computer and use it in GitHub Desktop.
Save akbyrd/c9d312048b49c5bd607ceba084d95bd0 to your computer and use it in GitHub Desktop.
DirectX 11 Swap Chain Format Support
DXGI_FORMAT renderTextureFormat = DXGI_FORMAT_B5G6R5_UNORM;
// Device
hr = D3D11CreateDevice(
nullptr,
D3D_DRIVER_TYPE_HARDWARE,
nullptr,
D3D11_CREATE_DEVICE_SINGLETHREADED | D3D11_CREATE_DEVICE_DEBUG,
nullptr, 0,
D3D11_SDK_VERSION,
&d3dDevice,
&featureLevel,
&d3dContext
);
// Render Texture
D3D11_TEXTURE2D_DESC renderTextureDesc = {};
renderTextureDesc.Width = renderSize.x;
renderTextureDesc.Height = renderSize.y;
renderTextureDesc.MipLevels = 1;
renderTextureDesc.ArraySize = 1;
renderTextureDesc.Format = renderTextureFormat;
renderTextureDesc.SampleDesc.Count = 1;
renderTextureDesc.SampleDesc.Quality = 0;
renderTextureDesc.Usage = D3D11_USAGE_DEFAULT;
renderTextureDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
renderTextureDesc.CPUAccessFlags = 0;
renderTextureDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED;
hr = d3dDevice->CreateTexture2D(&renderTextureDesc, nullptr, &d3dRenderTexture);
// Swap Chain
DXGI_SWAP_CHAIN_DESC swapChainDesc = {};
swapChainDesc.BufferDesc.Width = renderSize.x;
swapChainDesc.BufferDesc.Height = renderSize.y;
swapChainDesc.BufferDesc.RefreshRate.Numerator = 60;
swapChainDesc.BufferDesc.RefreshRate.Denominator = 1;
swapChainDesc.BufferDesc.Format = renderTextureFormat;
swapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
swapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferCount = 1;
swapChainDesc.OutputWindow = hwnd;
swapChainDesc.Windowed = true;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
swapChainDesc.Flags = 0;
hr = dxgiFactory->CreateSwapChain(d3dDevice.Get(), &swapChainDesc, &swapChain);
#include <stdint.h>
#include <exception>
using u32 = uint32_t;
using i32 = int32_t;
using c8 = char;
using b8 = bool;
struct v2u { u32 x; u32 y; };
#define Assert(condition) if (!(condition)) { *((c8 *) 0) = 0; }
#pragma comment(lib, "D3D11.lib")
#pragma comment(lib, "DXGI.lib")
#pragma warning(push, 0)
#define D3D_DEBUG_INFO
#include <InitGuid.h>
#include <d3d11sdklayers.h>
#include <dxgidebug.h>
#include <dxgi1_3.h>
#include <d3d11.h>
#include <wrl\client.h>
using Microsoft::WRL::ComPtr;
#pragma warning(pop)
#if false
DXGI_FORMAT renderTextureFormat = DXGI_FORMAT_B8G8R8A8_UNORM;
#else
DXGI_FORMAT renderTextureFormat = DXGI_FORMAT_B5G6R5_UNORM;
#endif
const c8 previewWindowClass[] = "Preview Window Class";
const u32 WM_PREVIEWWINDOWCLOSED = WM_USER + 0;
i32 CALLBACK
WinMain(HINSTANCE hInstance, HINSTANCE, c8*, i32)
{
HRESULT hr;
b8 success;
v2u renderSize = { 320, 240 };
ComPtr<ID3D11Device> d3dDevice;
ComPtr<ID3D11DeviceContext> d3dContext;
ComPtr<IDXGIFactory1> dxgiFactory;
ComPtr<ID3D11Texture2D> d3dRenderTexture;;
HWND hwnd;
ComPtr<IDXGISwapChain> swapChain;
ComPtr<ID3D11Texture2D> backBuffer;
v2u nonClientSize;
// Renderer
// Create device
{
UINT createDeviceFlags = D3D11_CREATE_DEVICE_SINGLETHREADED;
createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
D3D_FEATURE_LEVEL featureLevel;
hr = D3D11CreateDevice(
nullptr,
D3D_DRIVER_TYPE_HARDWARE,
nullptr,
createDeviceFlags,
nullptr, 0,
D3D11_SDK_VERSION,
&d3dDevice,
&featureLevel,
&d3dContext
);
Assert(!FAILED(hr));
// Check feature level
Assert((featureLevel & D3D_FEATURE_LEVEL_11_0) == D3D_FEATURE_LEVEL_11_0);
// Obtain the DXGI factory used to create the current device.
ComPtr<IDXGIDevice1> dxgiDevice;
hr = d3dDevice.As(&dxgiDevice);
Assert(!FAILED(hr));
ComPtr<IDXGIAdapter> dxgiAdapter;
hr = dxgiDevice->GetAdapter(&dxgiAdapter);
Assert(!FAILED(hr));
hr = dxgiAdapter->GetParent(IID_PPV_ARGS(&dxgiFactory));
Assert(!FAILED(hr));
// Check for the WARP driver
DXGI_ADAPTER_DESC desc = {};
hr = dxgiAdapter->GetDesc(&desc);
Assert(!FAILED(hr));
Assert(!((desc.VendorId == 0x1414) && (desc.DeviceId == 0x8c)));
}
// Configure debugging
{
ComPtr<IDXGIDebug1> dxgiDebug;
hr = DXGIGetDebugInterface1(0, IID_PPV_ARGS(&dxgiDebug));
Assert(!FAILED(hr));
dxgiDebug->EnableLeakTrackingForThread();
ComPtr<IDXGIInfoQueue> dxgiInfoQueue;
hr = DXGIGetDebugInterface1(0, IID_PPV_ARGS(&dxgiInfoQueue));
Assert(!FAILED(hr));
hr = dxgiInfoQueue->SetBreakOnSeverity(DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_ERROR, true);
Assert(!FAILED(hr));
hr = dxgiInfoQueue->SetBreakOnSeverity(DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_CORRUPTION, true);
Assert(!FAILED(hr));
// Ignore warning for not using a flip-mode swap chain
DXGI_INFO_QUEUE_MESSAGE_ID ids[] = { 294 };
DXGI_INFO_QUEUE_FILTER filter = {};
filter.DenyList.NumIDs = 1;
filter.DenyList.pIDList = ids;
hr = dxgiInfoQueue->PushStorageFilter(DXGI_DEBUG_DXGI, &filter);
Assert(!FAILED(hr));
}
// Create render texture
{
D3D11_TEXTURE2D_DESC renderTextureDesc = {};
renderTextureDesc.Width = renderSize.x;
renderTextureDesc.Height = renderSize.y;
renderTextureDesc.MipLevels = 1;
renderTextureDesc.ArraySize = 1;
renderTextureDesc.Format = renderTextureFormat;
renderTextureDesc.SampleDesc.Count = 1;
renderTextureDesc.SampleDesc.Quality = 0;
renderTextureDesc.Usage = D3D11_USAGE_DEFAULT;
renderTextureDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
renderTextureDesc.CPUAccessFlags = 0;
renderTextureDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED;
hr = d3dDevice->CreateTexture2D(&renderTextureDesc, nullptr, &d3dRenderTexture);
Assert(!FAILED(hr));
}
// Preview Window
// Create Window
{
LRESULT CALLBACK
PreviewWndProc(HWND, u32, WPARAM, LPARAM);
WNDCLASSA windowClass = {};
windowClass.style = 0;
windowClass.lpfnWndProc = PreviewWndProc;
windowClass.cbClsExtra = 0;
windowClass.cbWndExtra = 0;
windowClass.hInstance = hInstance;
windowClass.hIcon = nullptr;
windowClass.hCursor = LoadCursorW(nullptr, IDC_ARROW);
windowClass.hbrBackground = nullptr;
windowClass.lpszMenuName = nullptr;
windowClass.lpszClassName = previewWindowClass;
ATOM classAtom = RegisterClassA(&windowClass);
Assert(classAtom != INVALID_ATOM);
u32 windowStyle = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_VISIBLE;
RECT windowRect = { 0, 0, (i32) renderSize.x, (i32) renderSize.y };
success = AdjustWindowRect(&windowRect, (u32) windowStyle, false);
Assert(success);
nonClientSize.x = (windowRect.right - windowRect.left) - renderSize.x;
nonClientSize.y = (windowRect.bottom - windowRect.top) - renderSize.y;
hwnd = CreateWindowA(
windowClass.lpszClassName,
"Preview",
(u32) windowStyle,
CW_USEDEFAULT, CW_USEDEFAULT,
(i32) (renderSize.x + nonClientSize.x),
(i32) (renderSize.y + nonClientSize.y),
nullptr,
nullptr,
hInstance,
nullptr
);
Assert(hwnd != INVALID_HANDLE_VALUE);
success = SetForegroundWindow(hwnd);
Assert(success);
}
// Attach Renderer
{
DXGI_SWAP_CHAIN_DESC swapChainDesc = {};
swapChainDesc.BufferDesc.Width = renderSize.x;
swapChainDesc.BufferDesc.Height = renderSize.y;
swapChainDesc.BufferDesc.RefreshRate.Numerator = 60;
swapChainDesc.BufferDesc.RefreshRate.Denominator = 1;
swapChainDesc.BufferDesc.Format = renderTextureFormat;
swapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
swapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferCount = 1;
swapChainDesc.OutputWindow = hwnd;
swapChainDesc.Windowed = true;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
swapChainDesc.Flags = 0;
// Create the swap chain
hr = dxgiFactory->CreateSwapChain(d3dDevice.Get(), &swapChainDesc, &swapChain);
Assert(!FAILED(hr));
// Get the back buffer
hr = swapChain->GetBuffer(0, IID_PPV_ARGS(&backBuffer));
Assert(!FAILED(hr));
// Associate the window
hr = dxgiFactory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_ALT_ENTER);
Assert(!FAILED(hr));
}
// Main loop
for(;;)
{
// Pump messages
MSG msg = {};
while (PeekMessageA(&msg, nullptr, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessageA(&msg);
switch (msg.message)
{
case WM_PREVIEWWINDOWCLOSED:
case WM_QUIT:
return (i32) msg.wParam;
}
}
}
return 0;
}
LRESULT CALLBACK
PreviewWndProc(HWND hwnd, u32 uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_KEYDOWN:
{
switch (wParam)
{
case VK_ESCAPE:
PostQuitMessage(0);
return 0;
}
break;
}
case WM_CLOSE:
{
b8 success = PostMessageA(nullptr, WM_PREVIEWWINDOWCLOSED, 0, 0);
Assert(success);
return 0;
}
}
return DefWindowProcA(hwnd, uMsg, wParam, lParam);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment