#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); }