From 6c8ae19be66cee247980a48e736a4e05d14de179 Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Tue, 2 Dec 2025 16:39:36 -0800 Subject: Immediate-mode renderer, triangle demo, shader compilation in cmake, Agility SDK --- dxg/src/dxcommon.c | 173 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 dxg/src/dxcommon.c (limited to 'dxg/src/dxcommon.c') diff --git a/dxg/src/dxcommon.c b/dxg/src/dxcommon.c new file mode 100644 index 0000000..ecc9a88 --- /dev/null +++ b/dxg/src/dxcommon.c @@ -0,0 +1,173 @@ +#include + +// Required so that D3D12.dll can find and load D3D12Core.dll and other DLLs +// from the Agility SDK. The macro comes from CMakeLists.txt. +__declspec(dllexport) extern const UINT D3D12SDKVersion = AGILITY_SDK_VERSION; +__declspec(dllexport) extern const char* D3D12SDKPath = AGILITY_SDK_INSTALL; +D3D12_RESOURCE_BARRIER CD3DX12_RESOURCE_BARRIER_Transition( + ID3D12Resource* pResource, + D3D12_RESOURCE_STATES stateBefore, + D3D12_RESOURCE_STATES stateAfter) { + return (D3D12_RESOURCE_BARRIER){ + .Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, + .Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE, + .Transition.pResource = pResource, + .Transition.StateBefore = stateBefore, + .Transition.StateAfter = stateAfter, + .Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES}; +} + +D3D12_RASTERIZER_DESC CD3DX12_RASTERIZER_DESC_DEFAULT() { + return (D3D12_RASTERIZER_DESC){ + .FillMode = D3D12_FILL_MODE_SOLID, + .CullMode = D3D12_CULL_MODE_BACK, + .FrontCounterClockwise = FALSE, + .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}; +} + +D3D12_BLEND_DESC CD3DX12_BLEND_DESC_DEFAULT() { + const D3D12_RENDER_TARGET_BLEND_DESC defaultRenderTargetBlendDesc = { + FALSE, FALSE, + D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD, + D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD, + D3D12_LOGIC_OP_NOOP, + D3D12_COLOR_WRITE_ENABLE_ALL, + }; + D3D12_BLEND_DESC desc = { + .AlphaToCoverageEnable = FALSE, + .IndependentBlendEnable = FALSE, + }; + for (UINT i = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; ++i) { + desc.RenderTarget[i] = defaultRenderTargetBlendDesc; + } + return desc; +} + +void dxg_wait(ID3D12Fence* pFence, HANDLE fenceEvent, UINT64 fenceValue) { + assert(pFence); + // Wait for commands to finish execution. + // It is possible that execution has already finished by the time we + // get here, so first check the fence's completed value. + if (pFence->lpVtbl->GetCompletedValue(pFence) < fenceValue) { + // GPU Signal still pending. Configure a Windows event and wait for it. + // The event fires when the GPU signals. + // + // Indicate that the fence event is to be fired when the fence reaches + // the given fence value. + TrapIfFailed(pFence->lpVtbl->SetEventOnCompletion(pFence, fenceValue, fenceEvent)); + // Will wake up when the fence takes on the given fence value. + WaitForSingleObject(fenceEvent, INFINITE); + } +} + +// ----------------------------------------------------------------------------- +// Command Recorder +// ----------------------------------------------------------------------------- + +HRESULT dxg_cmdrec_init(CommandRecorder* pRec, ID3D12Device* pDevice) { + assert(pRec); + assert(pDevice); + + HRESULT result = S_OK; + + const D3D12_COMMAND_LIST_TYPE type = D3D12_COMMAND_LIST_TYPE_DIRECT; + + if ((result = pDevice->lpVtbl->CreateCommandAllocator( + pDevice, type, &IID_ID3D12CommandAllocator, &pRec->pCmdAllocator)) != S_OK) { + return result; + } + + if ((result = pDevice->lpVtbl->CreateCommandList( + pDevice, 0, type, pRec->pCmdAllocator, NULL, &IID_ID3D12CommandList, &pRec->pCmdList)) != S_OK) { + return result; + } + + // Command lists start open. Close it for API convenience. + if ((result = pRec->pCmdList->lpVtbl->Close(pRec->pCmdList)) != S_OK) { + return result; + } + + return result; +} + +void dxg_cmdrec_destroy(CommandRecorder* pRec) { + assert(pRec); + SafeRelease(pRec->pCmdList); + SafeRelease(pRec->pCmdAllocator); +} + +HRESULT dxg_cmdrec_reset(CommandRecorder* pRec) { + assert(pRec); + assert(pRec->pCmdAllocator); + assert(pRec->pCmdList); + HRESULT result = S_OK; + if ((result = pRec->pCmdAllocator->lpVtbl->Reset(pRec->pCmdAllocator)) != S_OK) { + return result; + } + if ((result = pRec->pCmdList->lpVtbl->Reset(pRec->pCmdList, pRec->pCmdAllocator, NULL)) != S_OK) { + return result; + } + return result; +} + +// ----------------------------------------------------------------------------- +// Upload Buffer +// ----------------------------------------------------------------------------- + +void dxg_upload_buffer_init(UploadBuffer* pBuf, ID3D12Device* pDevice, size_t size) { + assert(pBuf); + assert(pDevice); + + pBuf->size = size; + + const D3D12_HEAP_PROPERTIES props = { + .Type = D3D12_HEAP_TYPE_UPLOAD, + .CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE, + .MemoryPoolPreference = D3D12_MEMORY_POOL_L0, + .CreationNodeMask = 0, + .VisibleNodeMask = 0 + }; + // Constant buffers need to be aligned to 256 bytes. Other types of buffers + // do not have this requirement. To make the upload buffer general, use the + // worst-case alignment. + const D3D12_RESOURCE_DESC desc = { + .Dimension = D3D12_RESOURCE_DIMENSION_BUFFER, + .Alignment = 256, + .Width = size, + .Height = 0, + .DepthOrArraySize = 0, + .MipLevels = 0, + .Format = DXGI_FORMAT_UNKNOWN, + .SampleDesc = (DXGI_SAMPLE_DESC){0}, + .Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN, + .Flags = D3D12_RESOURCE_FLAG_NONE + }; + TrapIfFailed(pDevice->lpVtbl->CreateCommittedResource( + pDevice, + &props, + D3D12_HEAP_FLAG_NONE, + &desc, + D3D12_RESOURCE_STATE_COPY_SOURCE, + NULL, + &IID_ID3D12Resource, + &pBuf->pUploadBuffer)); +} + +void dxg_upload_buffer_destroy(UploadBuffer* pBuf, ID3D12Device* pDevice) { + assert(pDevice); + assert(pBuf); + SafeRelease(pBuf->pUploadBuffer); +} + +void dxg_upload_buffer_load(UploadBuffer* pBuf, const void* pData, size_t bytes, ID3D12Resource* pDstBuffer) { + assert(pBuf); + assert(pData); + assert(pDstBuffer); +} -- cgit v1.2.3