Last active
December 1, 2023 06:47
-
-
Save oluigipo/e0ecb775031870933e7e610667f14731 to your computer and use it in GitHub Desktop.
learn-d3d12
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
/* | |
* fxc /nologo shader.hlsl /Fovs.bin /EVertex /Tvs_5_0 | |
* fxc /nologo shader.hlsl /Fops.bin /EPixel /Tps_5_0 | |
* clang learn-d3d12.c -o a.exe -g -Wall -fuse-ld=lld | |
*/ | |
#include <stddef.h> | |
#include <stdint.h> | |
#include <stdlib.h> | |
#include <stdio.h> | |
#include <stdbool.h> | |
#define COBJMACROS | |
#define WIN32_LEAN_AND_MEAN | |
#define INITGUID | |
#include <windows.h> | |
#include <d3d12.h> | |
#include <dxgi1_6.h> | |
#pragma comment(lib, "user32.lib") | |
#pragma comment(lib, "d3d12.lib") | |
#pragma comment(lib, "dxgi.lib") | |
#define ArrayLength(x) (sizeof(x)/sizeof*(x)) | |
#define SafeAssert(...) do { \ | |
if (!(__VA_ARGS__)) { \ | |
if (IsDebuggerPresent()) \ | |
__debugbreak(); \ | |
SafeAssertFailed(__FILE__, __LINE__, __func__, #__VA_ARGS__); \ | |
} \ | |
} \ | |
while (0) | |
static bool g_running = true; | |
static void | |
SafeAssertFailed(char const* file, int line, char const* func, char const* expr) | |
{ | |
wchar_t wstr[4096]; | |
wchar_t* head = wstr; | |
wchar_t* end = wstr + ArrayLength(wstr); | |
char linestr[32]; | |
snprintf(linestr, sizeof(linestr), "%i", line); | |
head += -1+MultiByteToWideChar(CP_UTF8, 0, "SafeAssert failure!\nFile: ", -1, head, end-head); | |
head += -1+MultiByteToWideChar(CP_UTF8, 0, file, -1, head, end-head); | |
head += -1+MultiByteToWideChar(CP_UTF8, 0, "\nLine: ", -1, head, end-head); | |
head += -1+MultiByteToWideChar(CP_UTF8, 0, linestr, -1, head, end-head); | |
head += -1+MultiByteToWideChar(CP_UTF8, 0, "\nFunction: ", -1, head, end-head); | |
head += -1+MultiByteToWideChar(CP_UTF8, 0, func, -1, head, end-head); | |
head += -1+MultiByteToWideChar(CP_UTF8, 0, "\nExpr: ", -1, head, end-head); | |
head += -1+MultiByteToWideChar(CP_UTF8, 0, expr, -1, head, end-head); | |
head[0] = L'\0'; | |
MessageBoxW(NULL, wstr, L"Fatal error", MB_OK); | |
ExitProcess(1); | |
} | |
struct LoadFileResult | |
{ | |
void* data; | |
size_t size; | |
} | |
typedef LoadFileResult; | |
static LoadFileResult | |
LoadFile(LPWSTR path) | |
{ | |
LoadFileResult result = { 0 }; | |
HANDLE handle = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL); | |
if (handle != INVALID_HANDLE_VALUE) | |
{ | |
LARGE_INTEGER size_largeint; | |
if (GetFileSizeEx(handle, &size_largeint)) | |
{ | |
size_t size = size_largeint.QuadPart; | |
uint8_t* buffer = HeapAlloc(GetProcessHeap(), 0, size); | |
size_t read = 0; | |
while (read < size) | |
{ | |
DWORD to_read = (size >= UINT32_MAX) ? UINT32_MAX : (DWORD)size; | |
DWORD did_read = 0; | |
if (!ReadFile(handle, buffer+read, to_read, &did_read, NULL)) | |
break; | |
read += did_read; | |
} | |
if (read == size) | |
{ | |
result.data = buffer; | |
result.size = size; | |
} | |
} | |
CloseHandle(handle); | |
} | |
return result; | |
} | |
LRESULT CALLBACK | |
WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) | |
{ | |
LRESULT result = 0; | |
switch (msg) | |
{ | |
case WM_CLOSE: g_running = false; break; | |
default: result = DefWindowProcW(hwnd, msg, wparam, lparam); | |
} | |
return result; | |
} | |
int WINAPI | |
wWinMain(HINSTANCE instance, HINSTANCE prev, LPWSTR wargs, int cmd_show) | |
{ | |
HRESULT hr; | |
//~ Win32 basics | |
WNDCLASSW wndclass = { | |
.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW, | |
.lpfnWndProc = WindowProc, | |
.lpszClassName = L"ClassName", | |
.hCursor = LoadCursorA(NULL, IDC_ARROW), | |
.hIcon = LoadIconA(instance, MAKEINTRESOURCE(101)), | |
}; | |
SafeAssert(RegisterClassW(&wndclass)); | |
UINT style = WS_OVERLAPPEDWINDOW; | |
style &= ~WS_MAXIMIZEBOX; | |
style &= ~WS_THICKFRAME; | |
HWND hwnd = CreateWindowExW(0, wndclass.lpszClassName, L"Title", style, CW_USEDEFAULT, CW_USEDEFAULT, 1280, 720, NULL, NULL, instance, NULL); | |
SafeAssert(hwnd); | |
int32_t window_width, window_height; | |
{ | |
RECT client_area; | |
SafeAssert(GetClientRect(hwnd, &client_area)); | |
window_width = client_area.right - client_area.left; | |
window_height = client_area.bottom - client_area.top; | |
} | |
//~ D3D12 basics | |
D3D12_VIEWPORT d3d12_viewport = { | |
.TopLeftX = 0.0f, | |
.TopLeftY = 0.0f, | |
.Width = (float)window_width, | |
.Height = (float)window_height, | |
.MinDepth = 0.0f, | |
.MaxDepth = 1.0f, | |
}; | |
D3D12_RECT d3d12_scissor_rect = { | |
.left = 0, | |
.top = 0, | |
.right = window_width, | |
.bottom = window_height, | |
}; | |
ID3D12Debug* d3d12_debug = NULL; | |
if (SUCCEEDED(D3D12GetDebugInterface(&IID_ID3D12Debug, (void**)&d3d12_debug))) | |
ID3D12Debug_EnableDebugLayer(d3d12_debug); | |
ID3D12Resource* d3d12_render_targets[2] = { 0 }; | |
IDXGIFactory4* dxgi_factory4 = NULL; | |
{ | |
hr = CreateDXGIFactory1(&IID_IDXGIFactory4, (void**)&dxgi_factory4); | |
SafeAssert(SUCCEEDED(hr)); | |
} | |
IDXGIAdapter1* dxgi_adapter1 = NULL; | |
for (UINT index = 0;; ++index) | |
{ | |
IDXGIAdapter1* adapter; | |
if (IDXGIFactory4_EnumAdapters1(dxgi_factory4, index, &adapter) == DXGI_ERROR_NOT_FOUND) | |
break; | |
hr = D3D12CreateDevice((IUnknown*)adapter, D3D_FEATURE_LEVEL_11_0, &IID_ID3D12Device, NULL); | |
if (SUCCEEDED(hr)) | |
{ | |
dxgi_adapter1 = adapter; | |
break; | |
} | |
IDXGIAdapter1_Release(adapter); | |
} | |
SafeAssert(dxgi_adapter1); | |
ID3D12Device* d3d12_device = NULL; | |
{ | |
hr = D3D12CreateDevice((IUnknown*)dxgi_adapter1, D3D_FEATURE_LEVEL_12_0, &IID_ID3D12Device, (void**)&d3d12_device); | |
SafeAssert(SUCCEEDED(hr)); | |
} | |
ID3D12CommandQueue* d3d12_cmdqueue = NULL; | |
{ | |
D3D12_COMMAND_QUEUE_DESC cmdqueue_desc = { | |
.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE, | |
.Type = D3D12_COMMAND_LIST_TYPE_DIRECT, | |
}; | |
hr = ID3D12Device_CreateCommandQueue(d3d12_device, &cmdqueue_desc, &IID_ID3D12CommandQueue, (void**)&d3d12_cmdqueue); | |
SafeAssert(SUCCEEDED(hr)); | |
} | |
IDXGISwapChain1* dxgi_swapchain1 = NULL; | |
{ | |
DXGI_SWAP_CHAIN_DESC1 swapchain_desc1 = { | |
.BufferCount = ArrayLength(d3d12_render_targets), | |
.Width = 0, | |
.Height = 0, | |
.Format = DXGI_FORMAT_R8G8B8A8_UNORM, | |
.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT, | |
.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD, | |
.SampleDesc.Count = 1, | |
}; | |
hr = IDXGIFactory4_CreateSwapChainForHwnd(dxgi_factory4, (IUnknown*)d3d12_cmdqueue, hwnd, &swapchain_desc1, NULL, NULL, &dxgi_swapchain1); | |
SafeAssert(SUCCEEDED(hr)); | |
} | |
IDXGISwapChain3* dxgi_swapchain3 = NULL; | |
hr = IDXGISwapChain1_QueryInterface(dxgi_swapchain1, &IID_IDXGISwapChain3, (void**)&dxgi_swapchain3); | |
SafeAssert(SUCCEEDED(hr)); | |
hr = IDXGIFactory4_MakeWindowAssociation(dxgi_factory4, hwnd, DXGI_MWA_NO_ALT_ENTER); | |
SafeAssert(SUCCEEDED(hr)); | |
UINT frame_index = IDXGISwapChain3_GetCurrentBackBufferIndex(dxgi_swapchain3); | |
ID3D12DescriptorHeap* d3d12_rtvheap = NULL; | |
{ | |
D3D12_DESCRIPTOR_HEAP_DESC rtvheap_desc = { | |
.NumDescriptors = ArrayLength(d3d12_render_targets), | |
.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV, | |
.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE, | |
}; | |
hr = ID3D12Device_CreateDescriptorHeap(d3d12_device, &rtvheap_desc, &IID_ID3D12DescriptorHeap, (void**)&d3d12_rtvheap); | |
SafeAssert(SUCCEEDED(hr)); | |
} | |
UINT rtv_descriptor_size = ID3D12Device_GetDescriptorHandleIncrementSize(d3d12_device, D3D12_DESCRIPTOR_HEAP_TYPE_RTV); | |
{ | |
D3D12_CPU_DESCRIPTOR_HANDLE rtvhandle; | |
ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(d3d12_rtvheap, &rtvhandle); | |
for (UINT i = 0; i < ArrayLength(d3d12_render_targets); ++i) | |
{ | |
hr = IDXGISwapChain3_GetBuffer(dxgi_swapchain3, i, &IID_ID3D12Resource, (void**)&d3d12_render_targets[i]); | |
SafeAssert(SUCCEEDED(hr)); | |
ID3D12Device_CreateRenderTargetView(d3d12_device, d3d12_render_targets[i], NULL, rtvhandle); | |
// https://github.com/microsoft/DirectX-Headers/blob/48f23952bc08a6dce0727339c07cedbc4797356c/include/directx/d3dx12_root_signature.h#L889 | |
rtvhandle.ptr = (SIZE_T)((INT64)rtvhandle.ptr + rtv_descriptor_size); | |
} | |
} | |
ID3D12CommandAllocator* d3d12_cmdallocator = NULL; | |
{ | |
hr = ID3D12Device_CreateCommandAllocator(d3d12_device, D3D12_COMMAND_LIST_TYPE_DIRECT, &IID_ID3D12CommandAllocator, (void**)&d3d12_cmdallocator); | |
SafeAssert(SUCCEEDED(hr)); | |
} | |
//~ D3D12 resources | |
ID3D12RootSignature* d3d12_rootsig = NULL; | |
{ | |
D3D12_ROOT_SIGNATURE_DESC rootsig_desc = { | |
.NumParameters = 0, | |
.pParameters = NULL, | |
.NumStaticSamplers = 0, | |
.pStaticSamplers = NULL, | |
.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT, | |
}; | |
ID3DBlob* signature = NULL; | |
ID3DBlob* error = NULL; | |
hr = D3D12SerializeRootSignature(&rootsig_desc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error); | |
SafeAssert(SUCCEEDED(hr)); | |
hr = ID3D12Device_CreateRootSignature(d3d12_device, 0, ID3D10Blob_GetBufferPointer(signature), ID3D10Blob_GetBufferSize(signature), &IID_ID3D12RootSignature, (void**)&d3d12_rootsig); | |
SafeAssert(SUCCEEDED(hr)); | |
if (signature) | |
ID3D10Blob_Release(signature); | |
if (error) | |
ID3D10Blob_Release(error); | |
} | |
ID3D12PipelineState* d3d12_pipeline_state = NULL; | |
{ | |
LoadFileResult vs_file = LoadFile(L"vs.bin"); | |
LoadFileResult ps_file = LoadFile(L"ps.bin"); | |
D3D12_INPUT_ELEMENT_DESC input_layout[] = { | |
{ "V0INPUT", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, | |
{ "V1INPUT", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, | |
}; | |
D3D12_GRAPHICS_PIPELINE_STATE_DESC pipeline_state_desc = { | |
.InputLayout = { input_layout, ArrayLength(input_layout) }, | |
.pRootSignature = d3d12_rootsig, | |
.VS = { vs_file.data, vs_file.size }, | |
.PS = { ps_file.data, ps_file.size }, | |
.RasterizerState = { | |
.FillMode = D3D12_FILL_MODE_SOLID, | |
.CullMode = D3D12_CULL_MODE_NONE, | |
.FrontCounterClockwise = true, | |
.DepthBias = D3D12_DEFAULT_DEPTH_BIAS, | |
.DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP, | |
.SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS, | |
.DepthClipEnable = true, | |
.MultisampleEnable = false, | |
.AntialiasedLineEnable = false, | |
.ForcedSampleCount = 0, | |
.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF, | |
}, | |
.DepthStencilState = { | |
.DepthEnable = false, | |
.StencilEnable = false, | |
}, | |
.BlendState = { | |
.RenderTarget[0] = { | |
.BlendEnable = true, | |
.LogicOpEnable = false, | |
.SrcBlend = D3D12_BLEND_SRC_ALPHA, | |
.DestBlend = D3D12_BLEND_INV_SRC_ALPHA, | |
.BlendOp = D3D12_BLEND_OP_ADD, | |
.SrcBlendAlpha = D3D12_BLEND_SRC_ALPHA, | |
.DestBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA, | |
.BlendOpAlpha = D3D12_BLEND_OP_ADD, | |
.LogicOp = D3D12_LOGIC_OP_NOOP, | |
.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL, | |
}, | |
}, | |
.SampleMask = UINT_MAX, | |
.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE, | |
.NumRenderTargets = 1, | |
.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM, | |
.SampleDesc.Count = 1, | |
}; | |
hr = ID3D12Device_CreateGraphicsPipelineState(d3d12_device, &pipeline_state_desc, &IID_ID3D12PipelineState, (void**)&d3d12_pipeline_state); | |
SafeAssert(SUCCEEDED(hr)); | |
} | |
ID3D12GraphicsCommandList* d3d12_cmdlist = NULL; | |
{ | |
hr = ID3D12Device_CreateCommandList(d3d12_device, 0, D3D12_COMMAND_LIST_TYPE_DIRECT, d3d12_cmdallocator, d3d12_pipeline_state, &IID_ID3D12GraphicsCommandList, (void**)&d3d12_cmdlist); | |
SafeAssert(SUCCEEDED(hr)); | |
hr = ID3D12GraphicsCommandList_Close(d3d12_cmdlist); | |
SafeAssert(SUCCEEDED(hr)); | |
} | |
ID3D12Resource* d3d12_vbuffer = NULL; | |
D3D12_VERTEX_BUFFER_VIEW d3d12_vbuffer_view = { 0 }; | |
{ | |
struct | |
{ | |
float position[3]; | |
float color[4]; | |
} | |
vertices[6] = { | |
{ { 0.0f, 0.5f, 0.0f }, { 1.0f, 0.0f, 0.0f, 1.0f } }, | |
{ { -0.5f, -0.5f, 0.0f }, { 0.0f, 1.0f, 0.0f, 1.0f } }, | |
{ { 0.5f, -0.5f, 0.0f }, { 0.0f, 0.0f, 1.0f, 1.0f } }, | |
}; | |
D3D12_HEAP_PROPERTIES heap_properties = { | |
.Type = D3D12_HEAP_TYPE_UPLOAD, | |
.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN, | |
.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN, | |
.CreationNodeMask = 1, | |
.VisibleNodeMask = 1, | |
}; | |
D3D12_RESOURCE_DESC resource_desc = { | |
.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, | |
}; | |
hr = ID3D12Device_CreateCommittedResource(d3d12_device, &heap_properties, D3D12_HEAP_FLAG_NONE, &resource_desc, D3D12_RESOURCE_STATE_GENERIC_READ, NULL, &IID_ID3D12Resource, (void**)&d3d12_vbuffer); | |
SafeAssert(SUCCEEDED(hr)); | |
uint8_t* data_begin = NULL; | |
D3D12_RANGE range = { 0 }; | |
hr = ID3D12Resource_Map(d3d12_vbuffer, 0, &range, (void**)&data_begin); | |
SafeAssert(SUCCEEDED(hr)); | |
memcpy(data_begin, vertices, sizeof(vertices)); | |
ID3D12Resource_Unmap(d3d12_vbuffer, 0, NULL); | |
d3d12_vbuffer_view.BufferLocation = ID3D12Resource_GetGPUVirtualAddress(d3d12_vbuffer); | |
d3d12_vbuffer_view.StrideInBytes = sizeof(vertices[0]); | |
d3d12_vbuffer_view.SizeInBytes = sizeof(vertices); | |
} | |
ID3D12Fence* d3d12_fence = NULL; | |
HANDLE fence_event = NULL; | |
UINT64 fence_value = 0; | |
{ | |
hr = ID3D12Device_CreateFence(d3d12_device, 0, D3D12_FENCE_FLAG_NONE, &IID_ID3D12Fence, (void**)&d3d12_fence); | |
SafeAssert(SUCCEEDED(hr)); | |
fence_event = CreateEventW(NULL, false, false, NULL); | |
SafeAssert(fence_event && fence_event != INVALID_HANDLE_VALUE); | |
} | |
//~ Message Loop | |
ShowWindow(hwnd, SW_SHOW); | |
while (true) | |
{ | |
//~ Wait for previous frame | |
{ | |
const UINT64 value = fence_value; | |
hr = ID3D12CommandQueue_Signal(d3d12_cmdqueue, d3d12_fence, fence_value); | |
SafeAssert(SUCCEEDED(hr)); | |
++fence_value; | |
if (ID3D12Fence_GetCompletedValue(d3d12_fence) < value) | |
{ | |
hr = ID3D12Fence_SetEventOnCompletion(d3d12_fence, value, fence_event); | |
SafeAssert(SUCCEEDED(hr)); | |
WaitForSingleObject(fence_event, INFINITE); | |
} | |
frame_index = IDXGISwapChain3_GetCurrentBackBufferIndex(dxgi_swapchain3); | |
} | |
//~ Update | |
{ | |
MSG message; | |
while (PeekMessageW(&message, 0, 0, 0, PM_REMOVE) > 0) | |
{ | |
TranslateMessage(&message); | |
DispatchMessageW(&message); | |
} | |
} | |
if (!g_running) | |
break; | |
//~ Render | |
{ | |
hr = ID3D12CommandAllocator_Reset(d3d12_cmdallocator); | |
SafeAssert(SUCCEEDED(hr)); | |
hr = ID3D12GraphicsCommandList_Reset(d3d12_cmdlist, d3d12_cmdallocator, d3d12_pipeline_state); | |
SafeAssert(SUCCEEDED(hr)); | |
ID3D12GraphicsCommandList_SetGraphicsRootSignature(d3d12_cmdlist, d3d12_rootsig); | |
ID3D12GraphicsCommandList_RSSetViewports(d3d12_cmdlist, 1, &d3d12_viewport); | |
ID3D12GraphicsCommandList_RSSetScissorRects(d3d12_cmdlist, 1, &d3d12_scissor_rect); | |
D3D12_RESOURCE_BARRIER barrier = { | |
.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, | |
.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE, | |
.Transition = { | |
.pResource = d3d12_render_targets[frame_index], | |
.StateBefore = D3D12_RESOURCE_STATE_PRESENT, | |
.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET, | |
.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, | |
}, | |
}; | |
ID3D12GraphicsCommandList_ResourceBarrier(d3d12_cmdlist, 1, &barrier); | |
D3D12_CPU_DESCRIPTOR_HANDLE rtvhandle = { 0 }; | |
ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(d3d12_rtvheap, &rtvhandle); | |
rtvhandle.ptr = (SIZE_T)((INT64)rtvhandle.ptr + rtv_descriptor_size * frame_index); | |
ID3D12GraphicsCommandList_OMSetRenderTargets(d3d12_cmdlist, 1, &rtvhandle, false, NULL); | |
float clear_color[] = { 0.2f, 0.0f, 0.3f, 1.0f }; | |
ID3D12GraphicsCommandList_ClearRenderTargetView(d3d12_cmdlist, rtvhandle, clear_color, 0, NULL); | |
ID3D12GraphicsCommandList_IASetPrimitiveTopology(d3d12_cmdlist, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); | |
ID3D12GraphicsCommandList_IASetVertexBuffers(d3d12_cmdlist, 0, 1, &d3d12_vbuffer_view); | |
ID3D12GraphicsCommandList_DrawInstanced(d3d12_cmdlist, 3, 1, 0, 0); | |
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET; | |
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT; | |
ID3D12GraphicsCommandList_ResourceBarrier(d3d12_cmdlist, 1, &barrier); | |
hr = ID3D12GraphicsCommandList_Close(d3d12_cmdlist); | |
SafeAssert(SUCCEEDED(hr)); | |
} | |
//~ Execute & Present | |
{ | |
ID3D12CommandList* cmdlists[] = { (ID3D12CommandList*)d3d12_cmdlist }; | |
ID3D12CommandQueue_ExecuteCommandLists(d3d12_cmdqueue, ArrayLength(cmdlists), cmdlists); | |
hr = IDXGISwapChain3_Present(dxgi_swapchain3, 1, 0); | |
SafeAssert(SUCCEEDED(hr)); | |
} | |
} | |
// TODO: cleanup. this is left as an exercise for the reader. | |
return 0; | |
} |
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
struct VS_INPUT | |
{ | |
float3 position : V0INPUT; | |
float4 color : V1INPUT; | |
}; | |
struct VS_OUTPUT | |
{ | |
float4 position : SV_POSITION; | |
float4 color : COLOR0; | |
}; | |
VS_OUTPUT Vertex(VS_INPUT input) | |
{ | |
VS_OUTPUT output; | |
output.position = float4(input.position, 1.0); | |
output.color = input.color; | |
return output; | |
} | |
float4 Pixel(VS_OUTPUT input) : SV_TARGET | |
{ | |
return input.color; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment