Skip to content

Instantly share code, notes, and snippets.

@kayru
Last active November 29, 2020 11:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kayru/1537161 to your computer and use it in GitHub Desktop.
Save kayru/1537161 to your computer and use it in GitHub Desktop.
D3D11 Boilerplate code
// clang main.cpp
#include <tchar.h>
#include <stdint.h>
#include <stdio.h>
#include <windows.h>
#include <D3D11.h>
#include <D3Dcompiler.h>
#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "d3dcompiler.lib")
#pragma comment(lib, "dxguid.lib")
#pragma comment(lib, "dxgi.lib")
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "gdi32.lib")
static const uint32_t WindowWidth = 1280;
static const uint32_t WindowHeight = 720;
static const char* WindowName = "Boilerplate D3D11 App";
#define CHECKHR(hr) { if(FAILED(hr)){ printf("D3D Error: 0x%08x\n", (int)hr); DebugBreak();}}
struct Context
{
HWND hwnd;
bool finished;
ID3D11Device* device;
ID3D11DeviceContext* device_context;
IDXGISwapChain* swap_chain;
ID3D11Texture2D* backbuffer_tex;
ID3D11RenderTargetView* backbuffer_view;
ID3D11Texture2D* depthstencil_tex;
ID3D11DepthStencilView* depthstencil_view;
};
template <typename T>
inline void safe_release(T& x)
{
if(x)
{
x->Release();
x=NULL;
}
}
LRESULT APIENTRY wnd_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
{
Context* ctx = reinterpret_cast<Context*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
switch(msg)
{
case WM_CLOSE:
ctx->finished = true;
default:
return (LONG)DefWindowProc(hwnd, msg, wparam, lparam);
}
}
Context* Init()
{
Context* ctx = new Context;
ZeroMemory(ctx, sizeof(*ctx));
ctx->finished = false;
// register window class
WNDCLASSEX wc = {0};
HINSTANCE hInst = GetModuleHandle(NULL);
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_DBLCLKS | CS_OWNDC | CS_HREDRAW |CS_VREDRAW;
wc.lpfnWndProc = wnd_proc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInst;
wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor (NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = _T("BoilerplateWindowClass");
wc.hIconSm = wc.hIcon;
RegisterClassEx(&wc);
uint32_t window_style = WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
// find screen center and create our window there
int32_t pos_x = GetSystemMetrics(SM_CXSCREEN) / 2 - WindowWidth/2;
int32_t pos_y = GetSystemMetrics(SM_CYSCREEN) / 2 - WindowHeight/2;
// calculate window size for required client area
RECT client_rect = { pos_x, pos_y, LONG(pos_x+WindowWidth), LONG(pos_y+WindowHeight)};
AdjustWindowRect(&client_rect, window_style, FALSE);
// create window
ctx->hwnd = CreateWindowA("BoilerplateWindowClass", WindowName, window_style,
client_rect.left, client_rect.top,
client_rect.right-client_rect.left, client_rect.bottom-client_rect.top,
NULL, NULL, hInst, NULL);
// setup window owner for message handling
SetWindowLongPtr(ctx->hwnd, GWLP_USERDATA, (LONG_PTR)ctx);
ShowWindow(ctx->hwnd, SW_SHOWNORMAL);
UpdateWindow(ctx->hwnd);
// Create D3D11
DXGI_SWAP_CHAIN_DESC sd;
ZeroMemory( &sd, sizeof( sd ) );
sd.BufferCount = 1;
sd.BufferDesc.Width = WindowWidth;
sd.BufferDesc.Height = WindowHeight;
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
sd.BufferDesc.RefreshRate.Numerator = 60;
sd.BufferDesc.RefreshRate.Denominator = 1;
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
sd.OutputWindow = ctx->hwnd;
sd.SampleDesc.Count = 1;
sd.SampleDesc.Quality = 0;
sd.Windowed = TRUE;
uint32_t flags = D3D11_CREATE_DEVICE_SINGLETHREADED;
D3D_DRIVER_TYPE type = D3D_DRIVER_TYPE_HARDWARE;
IDXGIAdapter* adapter = NULL;
IDXGIAdapter* enumerated_adapter = NULL;
IDXGIFactory* factory = NULL;
CHECKHR(CreateDXGIFactory(__uuidof(IDXGIFactory),(void**)&factory));
for( uint32_t i=0; factory->EnumAdapters(i,&enumerated_adapter) != DXGI_ERROR_NOT_FOUND; ++i )
{
DXGI_ADAPTER_DESC adapter_desc;
if(enumerated_adapter->GetDesc(&adapter_desc) != S_OK)
{
continue;
}
if(wcsstr(adapter_desc.Description,L"PerfHUD") != 0)
{
type = D3D_DRIVER_TYPE_REFERENCE;
adapter = enumerated_adapter;
break;
}
}
safe_release(factory);
D3D_FEATURE_LEVEL features[] =
{
D3D_FEATURE_LEVEL_11_0
};
const uint32_t num_features = sizeof(features) / sizeof(features[0]);
// Create device
D3D_FEATURE_LEVEL supported_features;
CHECKHR(D3D11CreateDeviceAndSwapChain(adapter, type, NULL, flags, features, num_features,
D3D11_SDK_VERSION, &sd, &ctx->swap_chain, &ctx->device,
&supported_features, &ctx->device_context));
// Get default back buffer
CHECKHR(ctx->swap_chain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&ctx->backbuffer_tex));
CHECKHR(ctx->device->CreateRenderTargetView(ctx->backbuffer_tex, NULL, &ctx->backbuffer_view));
// Create default depth buffer
// create depth stencil
D3D11_TEXTURE2D_DESC depth_stencil_desc;
depth_stencil_desc.Width = WindowWidth;
depth_stencil_desc.Height = WindowHeight;
depth_stencil_desc.MipLevels = 1;
depth_stencil_desc.ArraySize = 1;
depth_stencil_desc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
depth_stencil_desc.SampleDesc.Count = 1;
depth_stencil_desc.SampleDesc.Quality = 0;
depth_stencil_desc.Usage = D3D11_USAGE_DEFAULT;
depth_stencil_desc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
depth_stencil_desc.CPUAccessFlags = 0;
depth_stencil_desc.MiscFlags = 0;
CHECKHR(ctx->device->CreateTexture2D(&depth_stencil_desc, NULL, &ctx->depthstencil_tex));
// create depth stencil view
D3D11_DEPTH_STENCIL_VIEW_DESC depth_stencil_view_desc = CD3D11_DEPTH_STENCIL_VIEW_DESC(D3D11_DSV_DIMENSION_TEXTURE2D, DXGI_FORMAT_D24_UNORM_S8_UINT);
CHECKHR(ctx->device->CreateDepthStencilView(ctx->depthstencil_tex, &depth_stencil_view_desc, &ctx->depthstencil_view));
// Set-up default Colour and Depth surfaces
ctx->device_context->OMSetRenderTargets(1, &ctx->backbuffer_view, ctx->depthstencil_view);
// All done, ready to rock
return ctx;
}
void Update(Context* ctx)
{
float colour_array[4] = { 0.1f, 0.2f, 0.3f, 1.0f };
ctx->device_context->ClearRenderTargetView(ctx->backbuffer_view, colour_array);
// [Do your rendering here]
// All done, now swap
CHECKHR(ctx->swap_chain->Present(0, 0));
}
void Shutdown(Context* ctx)
{
safe_release(ctx->depthstencil_view);
safe_release(ctx->depthstencil_tex);
safe_release(ctx->backbuffer_view);
safe_release(ctx->backbuffer_tex);
safe_release(ctx->swap_chain);
safe_release(ctx->device_context);
safe_release(ctx->device);
delete ctx;
}
int main()
{
Context* ctx = Init();
while(ctx->finished == false)
{
MSG msg;
while( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) )
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
Update(ctx);
}
Shutdown(ctx);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment