Created
July 27, 2025 14:28
-
-
Save nickav/9be8dfe77dfcde223720d6b5e2e10999 to your computer and use it in GitHub Desktop.
DirectX12 Textured Quad, Vertex, Index and Constants Buffer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // | |
| // Compile with: | |
| // > cl /I . /D"BUILD_DEBUG=1" /D"BUILD_ARCH64=1" /D"BUILD_WIN=1" /Z7 /W4 /sdl /MT /GR- /EHa /WX /nologo /Oi /Gm- /MP d3d12_textured_quad.c /link /opt:ref /DEBUG "kernel32.lib" "user32.lib" "gdi32.lib" "d3d12.lib" "dxguid.lib" "dxgi.lib" "d3dcompiler.lib" /OUT:d3d12_textured_quad.exe | |
| // | |
| #pragma warning(disable:4221) | |
| #pragma warning(disable:4204) | |
| #pragma warning(disable:4201) | |
| #define NOMINMAX | |
| #include <windows.h> | |
| #define COBJMACROS | |
| #pragma warning(push) | |
| #pragma warning(disable:4115) | |
| #include <d3d12.h> | |
| #include <d3dcompiler.h> | |
| #include <dxgi1_6.h> | |
| #pragma warning(pop) | |
| #undef COBJMACROS | |
| #include <stdio.h> | |
| #include <stdbool.h> | |
| #include <stdint.h> | |
| #define STATIC_ARRAY_LENGTH(array) (sizeof(array) / sizeof(*(array))) | |
| #if defined(_DEBUG) || defined(DEBUG) | |
| #if !defined(BUILD_DEBUG) | |
| #define BUILD_DEBUG 1 | |
| #endif | |
| #endif | |
| //////////////////////////////////////////////////////////////////////////////// | |
| D3D12_CPU_DESCRIPTOR_HANDLE get_descriptor_handle_d3d12(ID3D12DescriptorHeap* heap, D3D12_DESCRIPTOR_HEAP_TYPE heapType, size_t index, ID3D12Device* device) { | |
| typedef void(GetCpuHandleHack)(ID3D12DescriptorHeap*, D3D12_CPU_DESCRIPTOR_HANDLE*); | |
| GetCpuHandleHack* func = (GetCpuHandleHack*)heap->lpVtbl->GetCPUDescriptorHandleForHeapStart; | |
| D3D12_CPU_DESCRIPTOR_HANDLE handle = { 0 }; | |
| func(heap, &handle); | |
| if (index > 0) { | |
| const UINT size = ID3D12Device_GetDescriptorHandleIncrementSize(device, heapType); | |
| handle.ptr += index * size; | |
| } | |
| return handle; | |
| } | |
| D3D12_GPU_DESCRIPTOR_HANDLE get_gpu_descriptor_handle_d3d12(ID3D12DescriptorHeap* heap, D3D12_DESCRIPTOR_HEAP_TYPE heapType, size_t index, ID3D12Device* device) { | |
| typedef void(GetGpuHandleHack)(ID3D12DescriptorHeap*, D3D12_GPU_DESCRIPTOR_HANDLE*); | |
| GetGpuHandleHack* func = (GetGpuHandleHack*)heap->lpVtbl->GetGPUDescriptorHandleForHeapStart; | |
| D3D12_GPU_DESCRIPTOR_HANDLE handle = { 0 }; | |
| func(heap, &handle); | |
| if (index > 0) { | |
| const UINT size = ID3D12Device_GetDescriptorHandleIncrementSize(device, heapType); | |
| handle.ptr += index * size; | |
| } | |
| return handle; | |
| } | |
| //////////////////////////////////////////////////////////////////////////////// | |
| struct windowsize { | |
| uint32_t width; | |
| uint32_t height; | |
| }; | |
| enum { NUM_RENDERTARGETS = 2 }; | |
| struct renderer_d3d12 { | |
| ID3D12Debug* debug; | |
| IDXGIFactory4* factory; | |
| IDXGIAdapter1* adapter; | |
| ID3D12Device* device; | |
| ID3D12CommandQueue* queue; | |
| IDXGISwapChain4* swapchain; | |
| ID3D12DescriptorHeap* rtvDescriptorHeap; | |
| ID3D12DescriptorHeap* srvDescriptorHeap; | |
| ID3D12CommandAllocator* commandAllocator; | |
| ID3D12RootSignature* rootSignature; | |
| ID3D12PipelineState* pipeline; | |
| ID3D12GraphicsCommandList* cmdlist; | |
| }; | |
| struct resources_d3d12 { | |
| ID3D12Resource* targets[NUM_RENDERTARGETS]; | |
| ID3D12Resource* vertexBuffer; | |
| ID3D12Resource* indexBuffer; | |
| ID3D12Resource* constantBuffer; | |
| ID3D12Resource* texture; | |
| ID3D12Resource* textureUpload; | |
| D3D12_VERTEX_BUFFER_VIEW vertexBufferView; | |
| D3D12_INDEX_BUFFER_VIEW indexBufferView; | |
| ID3D12Fence* fence; | |
| HANDLE fenceEvent; | |
| uint32_t fenceValue; | |
| UINT frameIndex; | |
| }; | |
| struct app_state { | |
| struct renderer_d3d12* renderer; | |
| struct resources_d3d12* resources; | |
| struct windowsize windowsize; | |
| }; | |
| void wait_for_frame(struct renderer_d3d12* renderer, struct resources_d3d12* resources) { | |
| uint32_t value = resources->fenceValue; | |
| HRESULT hr = ID3D12CommandQueue_Signal(renderer->queue, resources->fence, value); | |
| if (!SUCCEEDED(hr)) { | |
| printf("Failed to signal fence: %d\n", hr); | |
| return; | |
| } | |
| ++resources->fenceValue; | |
| uint64_t completed = ID3D12Fence_GetCompletedValue(resources->fence); | |
| if (completed < value) { | |
| hr = ID3D12Fence_SetEventOnCompletion(resources->fence, value, resources->fenceEvent); | |
| if (!SUCCEEDED(hr)) { | |
| printf("Failed to set event on completion flag: %d\n", hr); | |
| } | |
| WaitForSingleObject(resources->fenceEvent, INFINITE); | |
| } | |
| resources->frameIndex = IDXGISwapChain3_GetCurrentBackBufferIndex(renderer->swapchain); | |
| } | |
| void draw(struct renderer_d3d12* renderer, struct resources_d3d12* resources, struct windowsize ws) { | |
| HRESULT hr = ID3D12CommandAllocator_Reset(renderer->commandAllocator); | |
| if (!SUCCEEDED(hr)) { | |
| printf("Failed to reset command allocator: %d\n", hr); | |
| return; | |
| } | |
| hr = ID3D12GraphicsCommandList_Reset(renderer->cmdlist, renderer->commandAllocator, renderer->pipeline); | |
| if (!SUCCEEDED(hr)) { | |
| printf("Failed to reset command list: %d\n", hr); | |
| return; | |
| } | |
| const D3D12_VIEWPORT viewport = { | |
| .TopLeftX = 0.0f, | |
| .TopLeftY = 0.0f, | |
| .Width = (float)ws.width, | |
| .Height = (float)ws.height, | |
| .MinDepth = 0.0f, | |
| .MaxDepth = 1.0f, | |
| }; | |
| const D3D12_RECT scissorRect = { | |
| .left = 0, .right = ws.width, | |
| .top = 0, .bottom = ws.height, | |
| }; | |
| ID3D12GraphicsCommandList_SetPipelineState(renderer->cmdlist, renderer->pipeline); | |
| ID3D12GraphicsCommandList_SetGraphicsRootSignature(renderer->cmdlist, renderer->rootSignature); | |
| ID3D12DescriptorHeap* heaps[] = { renderer->srvDescriptorHeap }; | |
| ID3D12GraphicsCommandList_SetDescriptorHeaps(renderer->cmdlist, STATIC_ARRAY_LENGTH(heaps), heaps); | |
| D3D12_GPU_DESCRIPTOR_HANDLE cbvHandle = get_gpu_descriptor_handle_d3d12(renderer->srvDescriptorHeap, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 0, renderer->device); | |
| D3D12_GPU_DESCRIPTOR_HANDLE srvHandle = get_gpu_descriptor_handle_d3d12(renderer->srvDescriptorHeap, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 1, renderer->device); | |
| ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(renderer->cmdlist, 0, cbvHandle); | |
| ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(renderer->cmdlist, 1, srvHandle); | |
| ID3D12GraphicsCommandList_RSSetViewports(renderer->cmdlist, 1, &viewport); | |
| ID3D12GraphicsCommandList_RSSetScissorRects(renderer->cmdlist, 1, &scissorRect); | |
| const D3D12_RESOURCE_BARRIER toRenderTargetBarrier = { | |
| .Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, | |
| .Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE, | |
| .Transition = { | |
| .pResource = resources->targets[resources->frameIndex], | |
| .StateBefore = D3D12_RESOURCE_STATE_PRESENT, | |
| .StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET, | |
| .Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, | |
| }, | |
| }; | |
| ID3D12GraphicsCommandList_ResourceBarrier(renderer->cmdlist, 1, &toRenderTargetBarrier); | |
| D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = get_descriptor_handle_d3d12(renderer->rtvDescriptorHeap, | |
| D3D12_DESCRIPTOR_HEAP_TYPE_RTV, | |
| resources->frameIndex, | |
| renderer->device); | |
| ID3D12GraphicsCommandList_OMSetRenderTargets(renderer->cmdlist, 1, &rtvHandle, FALSE, NULL); | |
| const float clearcolor[] = { 0.05f, 0.05f, 0.05f, 1.0f }; | |
| ID3D12GraphicsCommandList_ClearRenderTargetView(renderer->cmdlist, rtvHandle, clearcolor, 0, NULL); | |
| ID3D12GraphicsCommandList_IASetPrimitiveTopology(renderer->cmdlist, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); | |
| ID3D12GraphicsCommandList_IASetVertexBuffers(renderer->cmdlist, 0, 1, &resources->vertexBufferView); | |
| ID3D12GraphicsCommandList_IASetIndexBuffer(renderer->cmdlist, &resources->indexBufferView); | |
| ID3D12GraphicsCommandList_DrawIndexedInstanced(renderer->cmdlist, 6, 1, 0, 0, 0); | |
| D3D12_RESOURCE_BARRIER toPresentBarrier = toRenderTargetBarrier; | |
| toPresentBarrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET; | |
| toPresentBarrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT; | |
| ID3D12GraphicsCommandList_ResourceBarrier(renderer->cmdlist, 1, &toPresentBarrier); | |
| hr = ID3D12GraphicsCommandList_Close(renderer->cmdlist); | |
| if (!SUCCEEDED(hr)) { | |
| printf("Failed to close command list: %d\n", hr); | |
| } | |
| ID3D12GraphicsCommandList* cmdlists[] = { renderer->cmdlist }; | |
| ID3D12CommandQueue_ExecuteCommandLists(renderer->queue, STATIC_ARRAY_LENGTH(cmdlists), (ID3D12CommandList**)cmdlists); | |
| { | |
| UINT flags = 0; | |
| DXGI_PRESENT_PARAMETERS params = {0}; | |
| hr = IDXGISwapChain1_Present1(renderer->swapchain, 1, flags, ¶ms); | |
| if (!SUCCEEDED(hr)) { | |
| printf("Failed to present backbuffer: %u\n", hr); | |
| } | |
| } | |
| } | |
| LRESULT CALLBACK WindowProc(HWND hWindow, UINT msg, WPARAM wparam, LPARAM lparam) { | |
| switch (msg) | |
| { | |
| case WM_CREATE: | |
| { | |
| CREATESTRUCT* info = (CREATESTRUCT*)lparam; | |
| LONG_PTR userdata = (LONG_PTR)info->lpCreateParams; | |
| if (!SetWindowLongPtr(hWindow, GWLP_USERDATA, userdata)) { | |
| printf("Something went wrong setting window's userdata: %d\n", GetLastError()); | |
| } | |
| } | |
| return 0; | |
| case WM_DESTROY: | |
| case WM_CLOSE: | |
| PostQuitMessage(0); | |
| return 0; | |
| case WM_PAINT: | |
| { | |
| struct app_state* params = (struct app_state*)GetWindowLongPtr(hWindow, GWLP_USERDATA); | |
| draw(params->renderer, params->resources, params->windowsize); | |
| wait_for_frame(params->renderer, params->resources); | |
| } | |
| return 0; | |
| } | |
| return DefWindowProc(hWindow, msg, wparam, lparam); | |
| } | |
| int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR cmdline, int nCmdShow) { | |
| (void)hPrevInstance; | |
| (void)cmdline; | |
| (void)nCmdShow; | |
| //////////////////////////////////////////////////////////////////////////////// | |
| // Create window | |
| WNDCLASSEX win_class = {0}; | |
| win_class.cbSize = sizeof(WNDCLASSEX); | |
| win_class.style = CS_HREDRAW | CS_VREDRAW; | |
| win_class.lpfnWndProc = WindowProc; | |
| win_class.hInstance = hInstance; | |
| win_class.lpszClassName = "TexturedQuadWindow"; | |
| if (!RegisterClassEx(&win_class)) | |
| { | |
| printf("Failed to create window class."); | |
| return 1; | |
| } | |
| const uint32_t WINDOW_WIDTH = 1280; | |
| const uint32_t WINDOW_HEIGHT = 720; | |
| struct app_state app = {0}; | |
| HWND window = CreateWindowEx(0, | |
| "TexturedQuadWindow", | |
| "Textured Quad (Index + Constants)", | |
| WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_SYSMENU, | |
| 100, 100, | |
| WINDOW_WIDTH, WINDOW_HEIGHT, | |
| NULL, | |
| NULL, | |
| hInstance, | |
| &app); | |
| if (!window) | |
| { | |
| printf("Failed to create window."); | |
| return 1; | |
| } | |
| struct windowsize ws = { .width = WINDOW_WIDTH, .height = WINDOW_HEIGHT }; | |
| struct renderer_d3d12 renderer = {0}; | |
| struct resources_d3d12 resources = { 0 }; | |
| //////////////////////////////////////////////////////////////////////////////// | |
| // debug reporting | |
| #if BUILD_DEBUG | |
| { | |
| if (SUCCEEDED(D3D12GetDebugInterface(&IID_ID3D12Debug, &renderer.debug))) { | |
| ID3D12Debug_EnableDebugLayer(renderer.debug); | |
| } else { | |
| printf("Failed to get debug interface\n"); | |
| return false; | |
| } | |
| } | |
| #endif | |
| //////////////////////////////////////////////////////////////////////////////// | |
| // create pipeline objects | |
| { | |
| UINT flags = 0; | |
| #if BUILD_DEBUG | |
| flags |= DXGI_CREATE_FACTORY_DEBUG; | |
| #endif | |
| HRESULT hr = CreateDXGIFactory2(flags, &IID_IDXGIFactory4, &renderer.factory); | |
| if (!SUCCEEDED(hr)) { | |
| printf("Failed to create factory: %u\n", hr); | |
| return false; | |
| } | |
| } | |
| for (UINT i = 0; DXGI_ERROR_NOT_FOUND != IDXGIFactory1_EnumAdapters1(renderer.factory, i, &renderer.adapter); ++i) { | |
| DXGI_ADAPTER_DESC1 desc; | |
| IDXGIAdapter1_GetDesc1(renderer.adapter, &desc); | |
| if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) { | |
| continue; | |
| } | |
| HRESULT hr = D3D12CreateDevice((IUnknown*)renderer.adapter, D3D_FEATURE_LEVEL_11_0, &IID_ID3D12Device, NULL); | |
| if (SUCCEEDED(hr)) { | |
| break; | |
| } else { | |
| printf("Failed to create device: %u\n", hr); | |
| } | |
| } | |
| if (renderer.adapter == NULL) { | |
| printf("No hardware adapter found. This system does not support D3D12.\n"); | |
| return false; | |
| } | |
| { | |
| HRESULT hr = D3D12CreateDevice((IUnknown*)renderer.adapter, | |
| D3D_FEATURE_LEVEL_11_0, | |
| &IID_ID3D12Device, | |
| &renderer.device); | |
| if (!SUCCEEDED(hr)) { | |
| printf("Failed to create device: %u\n", hr); | |
| return false; | |
| } | |
| } | |
| { | |
| D3D12_COMMAND_QUEUE_DESC desc = {.Type = D3D12_COMMAND_LIST_TYPE_DIRECT}; | |
| HRESULT hr = ID3D12Device_CreateCommandQueue(renderer.device, &desc, &IID_ID3D12CommandQueue, &renderer.queue); | |
| if (!SUCCEEDED(hr)) { | |
| printf("Failed to create command queue: %u", hr); | |
| return false; | |
| } | |
| } | |
| { | |
| DXGI_SWAP_CHAIN_DESC1 desc = { | |
| .Width = ws.width, | |
| .Height = ws.height, | |
| .Format = DXGI_FORMAT_R8G8B8A8_UNORM, | |
| .SampleDesc = { | |
| .Count = 1, | |
| .Quality = 0, | |
| }, | |
| .BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT, | |
| .BufferCount = NUM_RENDERTARGETS, | |
| .Scaling = DXGI_SCALING_NONE, | |
| .SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD, | |
| .AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED, | |
| }; | |
| HRESULT hr = IDXGIFactory4_CreateSwapChainForHwnd( | |
| renderer.factory, (IUnknown*)renderer.queue, window, &desc, NULL, NULL, (IDXGISwapChain1**)&renderer.swapchain); | |
| if (!SUCCEEDED(hr)) { | |
| printf("Failed to create swap chain: %u\n", hr); | |
| return false; | |
| } | |
| } | |
| IDXGIFactory4_MakeWindowAssociation(renderer.factory, window, DXGI_MWA_NO_ALT_ENTER); | |
| resources.frameIndex = IDXGISwapChain3_GetCurrentBackBufferIndex(renderer.swapchain); | |
| { | |
| D3D12_DESCRIPTOR_HEAP_DESC desc = { | |
| .NumDescriptors = NUM_RENDERTARGETS, | |
| .Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV, | |
| .Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE, | |
| }; | |
| HRESULT hr = ID3D12Device_CreateDescriptorHeap( | |
| renderer.device, &desc, &IID_ID3D12DescriptorHeap, &renderer.rtvDescriptorHeap); | |
| if (!SUCCEEDED(hr)) { | |
| printf("Failed to create descriptor heap: %u\n", hr); | |
| return false; | |
| } | |
| } | |
| { | |
| D3D12_DESCRIPTOR_HEAP_DESC desc = { | |
| .NumDescriptors = 2, | |
| .Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, | |
| .Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE, | |
| }; | |
| HRESULT hr = ID3D12Device_CreateDescriptorHeap( | |
| renderer.device, &desc, &IID_ID3D12DescriptorHeap, &renderer.srvDescriptorHeap); | |
| if (!SUCCEEDED(hr)) { | |
| printf("Failed to create SRV descriptor heap: %u\n", hr); | |
| return false; | |
| } | |
| } | |
| { | |
| const UINT rtvDescriptorSize = | |
| ID3D12Device_GetDescriptorHandleIncrementSize(renderer.device, D3D12_DESCRIPTOR_HEAP_TYPE_RTV); | |
| D3D12_CPU_DESCRIPTOR_HANDLE rtvDescriptorHandle = | |
| get_descriptor_handle_d3d12(renderer.rtvDescriptorHeap, D3D12_DESCRIPTOR_HEAP_TYPE_RTV, 0, renderer.device); | |
| for (size_t i = 0; i < NUM_RENDERTARGETS; ++i) { | |
| HRESULT hr = IDXGISwapChain1_GetBuffer(renderer.swapchain, (UINT)i, &IID_ID3D12Resource, &resources.targets[i]); | |
| if (!SUCCEEDED(hr)) { | |
| return false; | |
| } | |
| ID3D12Device_CreateRenderTargetView(renderer.device, resources.targets[i], NULL, rtvDescriptorHandle); | |
| rtvDescriptorHandle.ptr += rtvDescriptorSize; | |
| } | |
| } | |
| { | |
| HRESULT hr = | |
| ID3D12Device_CreateCommandAllocator(renderer.device, | |
| D3D12_COMMAND_LIST_TYPE_DIRECT, | |
| &IID_ID3D12CommandAllocator, | |
| &renderer.commandAllocator); | |
| if (!SUCCEEDED(hr)) { | |
| printf("Failed to create command allocator: %u\n", hr); | |
| return false; | |
| } | |
| } | |
| //////////////////////////////////////////////////////////////////////////////// | |
| // create pipeline assets | |
| { | |
| D3D12_DESCRIPTOR_RANGE ranges[2] = { | |
| { | |
| .RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_CBV, | |
| .NumDescriptors = 1, | |
| .BaseShaderRegister = 0, | |
| .RegisterSpace = 0, | |
| .OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND, | |
| }, | |
| { | |
| .RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV, | |
| .NumDescriptors = 1, | |
| .BaseShaderRegister = 0, | |
| .RegisterSpace = 0, | |
| .OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND, | |
| }, | |
| }; | |
| D3D12_ROOT_PARAMETER params[2] = { | |
| { | |
| .ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, | |
| .ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL, | |
| .DescriptorTable = { | |
| .NumDescriptorRanges = 1, | |
| .pDescriptorRanges = &ranges[0], | |
| }, | |
| }, | |
| { | |
| .ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, | |
| .ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL, | |
| .DescriptorTable = { | |
| .NumDescriptorRanges = 1, | |
| .pDescriptorRanges = &ranges[1], | |
| }, | |
| }, | |
| }; | |
| D3D12_STATIC_SAMPLER_DESC sampler = { | |
| .Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR, | |
| .AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP, | |
| .AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP, | |
| .AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP, | |
| .MipLODBias = 0, | |
| .MaxAnisotropy = 0, | |
| .ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER, | |
| .BorderColor = D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK, | |
| .MinLOD = 0.0f, | |
| .MaxLOD = D3D12_FLOAT32_MAX, | |
| .ShaderRegister = 0, | |
| .RegisterSpace = 0, | |
| .ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL, | |
| }; | |
| D3D12_VERSIONED_ROOT_SIGNATURE_DESC desc = { | |
| .Version = D3D_ROOT_SIGNATURE_VERSION_1_0, | |
| .Desc_1_0 = { | |
| .NumParameters = 2, | |
| .pParameters = params, | |
| .NumStaticSamplers = 1, | |
| .pStaticSamplers = &sampler, | |
| .Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT, | |
| }, | |
| }; | |
| ID3DBlob* serializedDesc = NULL; | |
| HRESULT hr = D3D12SerializeVersionedRootSignature(&desc, &serializedDesc, NULL); | |
| if (!SUCCEEDED(hr)) { | |
| printf("Failed to serialize root signature: %u\n", hr); | |
| return false; | |
| } | |
| hr = ID3D12Device_CreateRootSignature(renderer.device, 0, | |
| ID3D10Blob_GetBufferPointer(serializedDesc), | |
| ID3D10Blob_GetBufferSize(serializedDesc), | |
| &IID_ID3D12RootSignature, | |
| &renderer.rootSignature); | |
| if (!SUCCEEDED(hr)) { | |
| printf("Failed to create root signature: %u\n", hr); | |
| return false; | |
| } | |
| ID3D10Blob_Release(serializedDesc); | |
| } | |
| { | |
| const char data[] = | |
| "cbuffer Constants : register(b0) {\n" | |
| " float4x4 mvpMatrix;\n" | |
| " float4 tintColor;\n" | |
| "};\n" | |
| "struct PSInput {\n" | |
| " float4 position : SV_POSITION;\n" | |
| " float2 uv : TEXCOORD0;\n" | |
| "};\n" | |
| "PSInput VSMain(float3 position : POSITION0, float2 uv : TEXCOORD0) {\n" | |
| " PSInput result;\n" | |
| " result.position = mul(mvpMatrix, float4(position, 1.0));\n" | |
| " result.uv = uv;\n" | |
| " return result;\n" | |
| "}\n" | |
| "Texture2D g_texture : register(t0);\n" | |
| "SamplerState g_sampler : register(s0);\n" | |
| "float4 PSMain(PSInput input) : SV_TARGET {\n" | |
| " return g_texture.Sample(g_sampler, input.uv) * tintColor;\n" | |
| "}\n"; | |
| const size_t data_size = STATIC_ARRAY_LENGTH(data); | |
| UINT compileFlags = 0; | |
| #if BUILD_DEBUG | |
| compileFlags |= D3DCOMPILE_DEBUG; | |
| compileFlags |= D3DCOMPILE_SKIP_OPTIMIZATION; | |
| #endif | |
| ID3DBlob* vs = NULL; | |
| ID3DBlob* ps = NULL; | |
| HRESULT hr = D3DCompile(data, data_size, NULL, NULL, NULL, "VSMain", "vs_4_0", compileFlags, 0, &vs, NULL); | |
| if (!SUCCEEDED(hr)) { | |
| printf("Failed to compile vertex shader: %u\n", hr); | |
| return false; | |
| } | |
| hr = D3DCompile(data, data_size, NULL, NULL, NULL, "PSMain", "ps_4_0", compileFlags, 0, &ps, NULL); | |
| if (!SUCCEEDED(hr)) { | |
| printf("Failed to compile pixel shader: %u\n", hr); | |
| return false; | |
| } | |
| D3D12_INPUT_ELEMENT_DESC vertexFormat[] = { | |
| { | |
| .SemanticName = "POSITION", | |
| .Format = DXGI_FORMAT_R32G32B32_FLOAT, | |
| .InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, | |
| }, | |
| { | |
| .SemanticName = "TEXCOORD", | |
| .Format = DXGI_FORMAT_R32G32_FLOAT, | |
| .AlignedByteOffset = sizeof(float) * 3, | |
| .InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, | |
| }, | |
| }; | |
| const D3D12_RENDER_TARGET_BLEND_DESC defaultBlendState = { | |
| .BlendEnable = FALSE, | |
| .LogicOpEnable = FALSE, | |
| .SrcBlend = D3D12_BLEND_ONE, | |
| .DestBlend = D3D12_BLEND_ZERO, | |
| .BlendOp = D3D12_BLEND_OP_ADD, | |
| .SrcBlendAlpha = D3D12_BLEND_ONE, | |
| .DestBlendAlpha = D3D12_BLEND_ZERO, | |
| .BlendOpAlpha = D3D12_BLEND_OP_ADD, | |
| .LogicOp = D3D12_LOGIC_OP_NOOP, | |
| .RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL, | |
| }; | |
| D3D12_GRAPHICS_PIPELINE_STATE_DESC pipelineStateDesc = { | |
| .pRootSignature = renderer.rootSignature, | |
| .VS = { | |
| .pShaderBytecode = ID3D10Blob_GetBufferPointer(vs), | |
| .BytecodeLength = ID3D10Blob_GetBufferSize(vs), | |
| }, | |
| .PS = { | |
| .pShaderBytecode = ID3D10Blob_GetBufferPointer(ps), | |
| .BytecodeLength = ID3D10Blob_GetBufferSize(ps), | |
| }, | |
| .StreamOutput = {0}, | |
| .BlendState = { | |
| .AlphaToCoverageEnable = FALSE, | |
| .IndependentBlendEnable = FALSE, | |
| .RenderTarget = { defaultBlendState }, | |
| }, | |
| .SampleMask = 0xFFFFFFFF, | |
| .RasterizerState = { | |
| .FillMode = D3D12_FILL_MODE_SOLID, | |
| .CullMode = D3D12_CULL_MODE_BACK, | |
| .FrontCounterClockwise = FALSE, | |
| .DepthBias = 0, | |
| .DepthBiasClamp = 0, | |
| .SlopeScaledDepthBias = 0, | |
| .DepthClipEnable = TRUE, | |
| .MultisampleEnable = FALSE, | |
| .AntialiasedLineEnable = FALSE, | |
| .ForcedSampleCount = 0, | |
| .ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF, | |
| }, | |
| .DepthStencilState = { | |
| .DepthEnable = FALSE, | |
| .StencilEnable = FALSE, | |
| }, | |
| .InputLayout = { | |
| .pInputElementDescs = vertexFormat, | |
| .NumElements = STATIC_ARRAY_LENGTH(vertexFormat), | |
| }, | |
| .PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE, | |
| .NumRenderTargets = 1, | |
| .RTVFormats = { DXGI_FORMAT_R8G8B8A8_UNORM }, | |
| .DSVFormat = DXGI_FORMAT_UNKNOWN, | |
| .SampleDesc = { | |
| .Count = 1, | |
| .Quality = 0, | |
| }, | |
| }; | |
| hr = ID3D12Device_CreateGraphicsPipelineState( | |
| renderer.device, &pipelineStateDesc, &IID_ID3D12PipelineState, &renderer.pipeline); | |
| if (!SUCCEEDED(hr)) { | |
| printf("Failed to create pipeline state: %u\n", hr); | |
| return false; | |
| } | |
| ID3D10Blob_Release(vs); | |
| ID3D10Blob_Release(ps); | |
| } | |
| { | |
| HRESULT hr = ID3D12Device_CreateCommandList(renderer.device, | |
| 0, | |
| D3D12_COMMAND_LIST_TYPE_DIRECT, | |
| renderer.commandAllocator, | |
| NULL, | |
| &IID_ID3D12CommandList, | |
| &renderer.cmdlist); | |
| if (!SUCCEEDED(hr)) { | |
| printf("Failed to create command list: %u\n", hr); | |
| return false; | |
| } | |
| hr = ID3D12GraphicsCommandList_Close(renderer.cmdlist); | |
| if (!SUCCEEDED(hr)) { | |
| printf("Failed to close command list: %u\n", hr); | |
| return false; | |
| } | |
| } | |
| { | |
| const float vertices[] = { | |
| // pos uv | |
| -0.5f, 0.5f, 0.0f, 0.0f, 0.0f, | |
| 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, | |
| 0.5f, -0.5f, 0.0f, 1.0f, 1.0f, | |
| -0.5f, -0.5f, 0.0f, 0.0f, 1.0f, | |
| }; | |
| const uint16_t indices[] = { | |
| 0, 1, 2, | |
| 2, 3, 0, | |
| }; | |
| const D3D12_HEAP_PROPERTIES heapProps = { | |
| .Type = D3D12_HEAP_TYPE_UPLOAD, | |
| }; | |
| const D3D12_RESOURCE_DESC vertexResourceDesc = { | |
| .Dimension = D3D12_RESOURCE_DIMENSION_BUFFER, | |
| .Alignment = 0, | |
| .Width = sizeof(vertices), | |
| .Height = 1, | |
| .DepthOrArraySize = 1, | |
| .MipLevels = 1, | |
| .Format = DXGI_FORMAT_UNKNOWN, | |
| .SampleDesc = { .Count = 1, .Quality = 0 }, | |
| .Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR, | |
| .Flags = D3D12_RESOURCE_FLAG_NONE, | |
| }; | |
| HRESULT hr = ID3D12Device_CreateCommittedResource( | |
| renderer.device, | |
| &heapProps, | |
| D3D12_HEAP_FLAG_NONE, | |
| &vertexResourceDesc, | |
| D3D12_RESOURCE_STATE_GENERIC_READ, | |
| NULL, | |
| &IID_ID3D12Resource, | |
| &resources.vertexBuffer); | |
| if (!SUCCEEDED(hr)) { | |
| printf("Failed to create vertex buffer resource: %d\n", hr); | |
| return false; | |
| } | |
| void* gpuData = NULL; | |
| D3D12_RANGE readRange = { 0 }; | |
| hr = ID3D12Resource_Map(resources.vertexBuffer, 0, &readRange, &gpuData); | |
| if (!SUCCEEDED(hr)) { | |
| printf("Failed to map vertex buffer resource: %d\n", hr); | |
| return false; | |
| } | |
| memcpy(gpuData, vertices, sizeof(vertices)); | |
| ID3D12Resource_Unmap(resources.vertexBuffer, 0, NULL); | |
| D3D12_VERTEX_BUFFER_VIEW vbView = { | |
| .BufferLocation = ID3D12Resource_GetGPUVirtualAddress(resources.vertexBuffer), | |
| .StrideInBytes = sizeof(float) * (3 + 2), | |
| .SizeInBytes = sizeof(vertices), | |
| }; | |
| resources.vertexBufferView = vbView; | |
| const D3D12_RESOURCE_DESC indexResourceDesc = { | |
| .Dimension = D3D12_RESOURCE_DIMENSION_BUFFER, | |
| .Alignment = 0, | |
| .Width = sizeof(indices), | |
| .Height = 1, | |
| .DepthOrArraySize = 1, | |
| .MipLevels = 1, | |
| .Format = DXGI_FORMAT_UNKNOWN, | |
| .SampleDesc = { .Count = 1, .Quality = 0 }, | |
| .Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR, | |
| .Flags = D3D12_RESOURCE_FLAG_NONE, | |
| }; | |
| hr = ID3D12Device_CreateCommittedResource( | |
| renderer.device, | |
| &heapProps, | |
| D3D12_HEAP_FLAG_NONE, | |
| &indexResourceDesc, | |
| D3D12_RESOURCE_STATE_GENERIC_READ, | |
| NULL, | |
| &IID_ID3D12Resource, | |
| &resources.indexBuffer); | |
| if (!SUCCEEDED(hr)) { | |
| printf("Failed to create index buffer resource: %d\n", hr); | |
| return false; | |
| } | |
| hr = ID3D12Resource_Map(resources.indexBuffer, 0, &readRange, &gpuData); | |
| if (!SUCCEEDED(hr)) { | |
| printf("Failed to map index buffer resource: %d\n", hr); | |
| return false; | |
| } | |
| memcpy(gpuData, indices, sizeof(indices)); | |
| ID3D12Resource_Unmap(resources.indexBuffer, 0, NULL); | |
| D3D12_INDEX_BUFFER_VIEW ibView = { | |
| .BufferLocation = ID3D12Resource_GetGPUVirtualAddress(resources.indexBuffer), | |
| .SizeInBytes = sizeof(indices), | |
| .Format = DXGI_FORMAT_R16_UINT, | |
| }; | |
| resources.indexBufferView = ibView; | |
| } | |
| { | |
| const uint32_t textureWidth = 4; | |
| const uint32_t textureHeight = 4; | |
| const uint32_t textureData[] = { | |
| 0xFFFF0000, 0xFF00FF00, 0xFFFF0000, 0xFF00FF00, | |
| 0xFF00FF00, 0xFFFF0000, 0xFF00FF00, 0xFFFF0000, | |
| 0xFFFF0000, 0xFF00FF00, 0xFFFF0000, 0xFF00FF00, | |
| 0xFF00FF00, 0xFFFF0000, 0xFF00FF00, 0xFFFF0000, | |
| }; | |
| const D3D12_HEAP_PROPERTIES defaultHeapProps = { | |
| .Type = D3D12_HEAP_TYPE_DEFAULT, | |
| }; | |
| const D3D12_RESOURCE_DESC textureDesc = { | |
| .Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D, | |
| .Alignment = 0, | |
| .Width = textureWidth, | |
| .Height = textureHeight, | |
| .DepthOrArraySize = 1, | |
| .MipLevels = 1, | |
| .Format = DXGI_FORMAT_R8G8B8A8_UNORM, | |
| .SampleDesc = { .Count = 1, .Quality = 0 }, | |
| .Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN, | |
| .Flags = D3D12_RESOURCE_FLAG_NONE, | |
| }; | |
| HRESULT hr = ID3D12Device_CreateCommittedResource( | |
| renderer.device, | |
| &defaultHeapProps, | |
| D3D12_HEAP_FLAG_NONE, | |
| &textureDesc, | |
| D3D12_RESOURCE_STATE_COPY_DEST, | |
| NULL, | |
| &IID_ID3D12Resource, | |
| &resources.texture); | |
| if (!SUCCEEDED(hr)) { | |
| printf("Failed to create texture resource: %d\n", hr); | |
| return false; | |
| } | |
| const UINT64 uploadBufferSize = ((sizeof(uint32_t) * textureWidth) + 255) & ~255; | |
| const D3D12_RESOURCE_DESC uploadBufferDesc = { | |
| .Dimension = D3D12_RESOURCE_DIMENSION_BUFFER, | |
| .Alignment = 0, | |
| .Width = uploadBufferSize * textureHeight, | |
| .Height = 1, | |
| .DepthOrArraySize = 1, | |
| .MipLevels = 1, | |
| .Format = DXGI_FORMAT_UNKNOWN, | |
| .SampleDesc = { .Count = 1, .Quality = 0 }, | |
| .Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR, | |
| .Flags = D3D12_RESOURCE_FLAG_NONE, | |
| }; | |
| const D3D12_HEAP_PROPERTIES uploadHeapProps = { | |
| .Type = D3D12_HEAP_TYPE_UPLOAD, | |
| }; | |
| hr = ID3D12Device_CreateCommittedResource( | |
| renderer.device, | |
| &uploadHeapProps, | |
| D3D12_HEAP_FLAG_NONE, | |
| &uploadBufferDesc, | |
| D3D12_RESOURCE_STATE_GENERIC_READ, | |
| NULL, | |
| &IID_ID3D12Resource, | |
| &resources.textureUpload); | |
| if (!SUCCEEDED(hr)) { | |
| printf("Failed to create texture upload resource: %d\n", hr); | |
| return false; | |
| } | |
| void* textureDataPtr = NULL; | |
| D3D12_RANGE readRange = { 0 }; | |
| hr = ID3D12Resource_Map(resources.textureUpload, 0, &readRange, &textureDataPtr); | |
| if (!SUCCEEDED(hr)) { | |
| printf("Failed to map texture upload resource: %d\n", hr); | |
| return false; | |
| } | |
| for (uint32_t y = 0; y < textureHeight; ++y) { | |
| uint8_t* destRow = (uint8_t*)textureDataPtr + y * uploadBufferSize; | |
| const uint32_t* srcRow = textureData + y * textureWidth; | |
| memcpy(destRow, srcRow, textureWidth * sizeof(uint32_t)); | |
| } | |
| ID3D12Resource_Unmap(resources.textureUpload, 0, NULL); | |
| hr = ID3D12CommandAllocator_Reset(renderer.commandAllocator); | |
| if (!SUCCEEDED(hr)) { | |
| printf("Failed to reset command allocator for texture upload: %d\n", hr); | |
| return false; | |
| } | |
| hr = ID3D12GraphicsCommandList_Reset(renderer.cmdlist, renderer.commandAllocator, NULL); | |
| if (!SUCCEEDED(hr)) { | |
| printf("Failed to reset command list for texture upload: %d\n", hr); | |
| return false; | |
| } | |
| D3D12_TEXTURE_COPY_LOCATION destLocation = { | |
| .pResource = resources.texture, | |
| .Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX, | |
| .SubresourceIndex = 0, | |
| }; | |
| D3D12_TEXTURE_COPY_LOCATION srcLocation = { | |
| .pResource = resources.textureUpload, | |
| .Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT, | |
| .PlacedFootprint = { | |
| .Offset = 0, | |
| .Footprint = { | |
| .Format = DXGI_FORMAT_R8G8B8A8_UNORM, | |
| .Width = textureWidth, | |
| .Height = textureHeight, | |
| .Depth = 1, | |
| .RowPitch = (UINT)uploadBufferSize, | |
| }, | |
| }, | |
| }; | |
| ID3D12GraphicsCommandList_CopyTextureRegion(renderer.cmdlist, &destLocation, 0, 0, 0, &srcLocation, NULL); | |
| D3D12_RESOURCE_BARRIER barrier = { | |
| .Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, | |
| .Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE, | |
| .Transition = { | |
| .pResource = resources.texture, | |
| .StateBefore = D3D12_RESOURCE_STATE_COPY_DEST, | |
| .StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, | |
| .Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, | |
| }, | |
| }; | |
| ID3D12GraphicsCommandList_ResourceBarrier(renderer.cmdlist, 1, &barrier); | |
| hr = ID3D12GraphicsCommandList_Close(renderer.cmdlist); | |
| if (!SUCCEEDED(hr)) { | |
| printf("Failed to close command list for texture upload: %d\n", hr); | |
| return false; | |
| } | |
| ID3D12GraphicsCommandList* cmdlists[] = { renderer.cmdlist }; | |
| ID3D12CommandQueue_ExecuteCommandLists(renderer.queue, STATIC_ARRAY_LENGTH(cmdlists), (ID3D12CommandList**)cmdlists); | |
| D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = { | |
| .Format = textureDesc.Format, | |
| .ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D, | |
| .Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING, | |
| .Texture2D = { | |
| .MipLevels = 1, | |
| }, | |
| }; | |
| D3D12_CPU_DESCRIPTOR_HANDLE srvHandle = get_descriptor_handle_d3d12(renderer.srvDescriptorHeap, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 1, renderer.device); | |
| ID3D12Device_CreateShaderResourceView(renderer.device, resources.texture, &srvDesc, srvHandle); | |
| } | |
| { | |
| const size_t constantBufferSize = 256; | |
| const D3D12_HEAP_PROPERTIES heapProps = { | |
| .Type = D3D12_HEAP_TYPE_UPLOAD, | |
| }; | |
| const D3D12_RESOURCE_DESC resourceDesc = { | |
| .Dimension = D3D12_RESOURCE_DIMENSION_BUFFER, | |
| .Alignment = 0, | |
| .Width = constantBufferSize, | |
| .Height = 1, | |
| .DepthOrArraySize = 1, | |
| .MipLevels = 1, | |
| .Format = DXGI_FORMAT_UNKNOWN, | |
| .SampleDesc = { .Count = 1, .Quality = 0 }, | |
| .Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR, | |
| .Flags = D3D12_RESOURCE_FLAG_NONE, | |
| }; | |
| HRESULT hr = ID3D12Device_CreateCommittedResource( | |
| renderer.device, | |
| &heapProps, | |
| D3D12_HEAP_FLAG_NONE, | |
| &resourceDesc, | |
| D3D12_RESOURCE_STATE_GENERIC_READ, | |
| NULL, | |
| &IID_ID3D12Resource, | |
| &resources.constantBuffer); | |
| if (!SUCCEEDED(hr)) { | |
| printf("Failed to create constant buffer: %d\n", hr); | |
| return false; | |
| } | |
| void* constantData = NULL; | |
| D3D12_RANGE readRange = { 0 }; | |
| hr = ID3D12Resource_Map(resources.constantBuffer, 0, &readRange, &constantData); | |
| if (!SUCCEEDED(hr)) { | |
| printf("Failed to map constant buffer: %d\n", hr); | |
| return false; | |
| } | |
| float* data = (float*)constantData; | |
| float mvpMatrix[16] = { | |
| 1.0f, 0.0f, 0.0f, 0.0f, | |
| 0.0f, 1.0f, 0.0f, 0.0f, | |
| 0.0f, 0.0f, 1.0f, 0.0f, | |
| 0.0f, 0.0f, 0.0f, 1.0f, | |
| }; | |
| float tintColor[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; | |
| memcpy(data, mvpMatrix, sizeof(mvpMatrix)); | |
| memcpy(data + 16, tintColor, sizeof(tintColor)); | |
| ID3D12Resource_Unmap(resources.constantBuffer, 0, NULL); | |
| D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = { | |
| .BufferLocation = ID3D12Resource_GetGPUVirtualAddress(resources.constantBuffer), | |
| .SizeInBytes = (UINT)constantBufferSize, | |
| }; | |
| D3D12_CPU_DESCRIPTOR_HANDLE cbvHandle = get_descriptor_handle_d3d12(renderer.srvDescriptorHeap, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 0, renderer.device); | |
| ID3D12Device_CreateConstantBufferView(renderer.device, &cbvDesc, cbvHandle); | |
| } | |
| { | |
| HRESULT hr = ID3D12Device_CreateFence( | |
| renderer.device, resources.fenceValue, D3D12_FENCE_FLAG_NONE, &IID_ID3D12Fence, &resources.fence); | |
| if (!SUCCEEDED(hr)) { | |
| printf("Failed to create fence: %d\n", hr); | |
| return false; | |
| } | |
| ++resources.fenceValue; | |
| BOOL manualReset = FALSE; | |
| BOOL initialState = FALSE; | |
| resources.fenceEvent = CreateEvent(0, manualReset, initialState, NULL); | |
| if (resources.fenceEvent == NULL) { | |
| hr = HRESULT_FROM_WIN32(GetLastError()); | |
| printf("Failed to create fence event: %d\n", hr); | |
| return false; | |
| } | |
| } | |
| wait_for_frame(&renderer, &resources); | |
| app = (struct app_state){ | |
| .renderer = &renderer, | |
| .resources = &resources, | |
| .windowsize = ws, | |
| }; | |
| //////////////////////////////////////////////////////////////////////////////// | |
| // main loop | |
| for (bool quit = false; !quit; ) | |
| { | |
| MSG msg; | |
| PeekMessage(&msg, NULL, 0, 0, PM_REMOVE); | |
| if (msg.message == WM_QUIT) | |
| { | |
| quit = true; | |
| } | |
| else | |
| { | |
| TranslateMessage(&msg); | |
| DispatchMessage(&msg); | |
| } | |
| } | |
| wait_for_frame(&renderer, &resources); | |
| // free resources | |
| ID3D12Resource_Release(resources.vertexBuffer); | |
| ID3D12Resource_Release(resources.indexBuffer); | |
| ID3D12Resource_Release(resources.constantBuffer); | |
| ID3D12Resource_Release(resources.texture); | |
| ID3D12Resource_Release(resources.textureUpload); | |
| ID3D12Fence_Release(resources.fence); | |
| CloseHandle(resources.fenceEvent); | |
| for (size_t i = 0; i < NUM_RENDERTARGETS; ++i) { | |
| ID3D12Resource_Release(resources.targets[i]); | |
| } | |
| // free renderer | |
| if (renderer.debug) | |
| { | |
| ID3D12Debug_Release(renderer.debug); | |
| } | |
| IDXGIFactory4_Release(renderer.factory); | |
| IDXGIAdapter1_Release(renderer.adapter); | |
| ID3D12Device_Release(renderer.device); | |
| ID3D12CommandQueue_Release(renderer.queue); | |
| IDXGISwapChain1_Release(renderer.swapchain); | |
| ID3D12DescriptorHeap_Release(renderer.rtvDescriptorHeap); | |
| ID3D12DescriptorHeap_Release(renderer.srvDescriptorHeap); | |
| ID3D12CommandAllocator_Release(renderer.commandAllocator); | |
| ID3D12RootSignature_Release(renderer.rootSignature); | |
| ID3D12PipelineState_Release(renderer.pipeline); | |
| ID3D12GraphicsCommandList_Release(renderer.cmdlist); | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment