void Initialize_Upload() { for(uint64 i = 0; i < MaxUploadSubmissions; ++i) DXCall(Device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_COPY, IID_PPV_ARGS(&UploadSubmissions[i].CmdAllocator))); DXCall(Device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_COPY, UploadSubmissions[0].CmdAllocator, nullptr, IID_PPV_ARGS(&UploadCmdList))); DXCall(UploadCmdList->Close()); D3D12_COMMAND_QUEUE_DESC queueDesc = { }; queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; queueDesc.Type = D3D12_COMMAND_LIST_TYPE_COPY; DXCall(Device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&UploadCmdQueue))); UploadFence.Init(0); D3D12_RESOURCE_DESC resourceDesc = { }; resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; resourceDesc.Width = uint32(UploadBufferSize); resourceDesc.Height = 1; resourceDesc.DepthOrArraySize = 1; resourceDesc.MipLevels = 1; resourceDesc.Format = DXGI_FORMAT_UNKNOWN; resourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE; resourceDesc.SampleDesc.Count = 1; resourceDesc.SampleDesc.Quality = 0; resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; resourceDesc.Alignment = 0; DXCall(Device->CreateCommittedResource(DX12::GetUploadHeapProps(), D3D12_HEAP_FLAG_NONE, &resourceDesc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&UploadBuffer))); D3D12_RANGE readRange = { }; DXCall(UploadBuffer->Map(0, &readRange, reinterpret_cast<void**>(&UploadBufferCPUAddr))); // Temporary buffer memory that swaps every frame resourceDesc.Width = uint32(TempBufferSize); for(uint64 i = 0; i < RenderLatency; ++i) { DXCall(Device->CreateCommittedResource(DX12::GetUploadHeapProps(), D3D12_HEAP_FLAG_NONE, &resourceDesc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&TempFrameBuffers[i]))); DXCall(TempFrameBuffers[i]->Map(0, &readRange, reinterpret_cast<void**>(&TempFrameCPUMem[i]))); TempFrameGPUMem[i] = TempFrameBuffers[i]->GetGPUVirtualAddress(); } // Texture conversion resources DXCall(Device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_COMPUTE, IID_PPV_ARGS(&convertCmdAllocator))); DXCall(Device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_COMPUTE, convertCmdAllocator, nullptr, IID_PPV_ARGS(&convertCmdList))); DXCall(convertCmdList->Close()); DXCall(convertCmdList->Reset(convertCmdAllocator, nullptr)); D3D12_COMMAND_QUEUE_DESC convertQueueDesc = {}; convertQueueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; convertQueueDesc.Type = D3D12_COMMAND_LIST_TYPE_COMPUTE; DXCall(Device->CreateCommandQueue(&convertQueueDesc, IID_PPV_ARGS(&convertCmdQueue))); CompileOptions opts; opts.Add("TGSize_", convertTGSize); const std::wstring shaderPath = SampleFrameworkDir() + L"Shaders\\DecodeTextureCS.hlsl"; convertCS = CompileFromFile(shaderPath.c_str(), "DecodeTextureCS", ShaderType::Compute, ShaderProfile::SM51, opts); convertArrayCS = CompileFromFile(shaderPath.c_str(), "DecodeTextureArrayCS", ShaderType::Compute, ShaderProfile::SM51, opts); { D3D12_DESCRIPTOR_RANGE ranges[2] = {}; ranges[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; ranges[0].NumDescriptors = 1; ranges[0].BaseShaderRegister = 0; ranges[0].RegisterSpace = 0; ranges[0].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; ranges[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; ranges[1].NumDescriptors = 1; ranges[1].BaseShaderRegister = 0; ranges[1].RegisterSpace = 0; ranges[1].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; D3D12_ROOT_PARAMETER rootParameters[1] = {}; rootParameters[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; rootParameters[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; rootParameters[0].DescriptorTable.pDescriptorRanges = ranges; rootParameters[0].DescriptorTable.NumDescriptorRanges = ArraySize_(ranges); D3D12_ROOT_SIGNATURE_DESC rootSignatureDesc = {}; rootSignatureDesc.NumParameters = ArraySize_(rootParameters); rootSignatureDesc.pParameters = rootParameters; rootSignatureDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_NONE; DX12::CreateRootSignature(&convertRootSignature, rootSignatureDesc); } { D3D12_COMPUTE_PIPELINE_STATE_DESC psoDesc = { }; psoDesc.CS = convertCS.ByteCode(); psoDesc.pRootSignature = convertRootSignature; psoDesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE; Device->CreateComputePipelineState(&psoDesc, IID_PPV_ARGS(&convertPSO)); psoDesc.CS = convertArrayCS.ByteCode(); Device->CreateComputePipelineState(&psoDesc, IID_PPV_ARGS(&convertArrayPSO)); } convertFence.Init(0); // Readback resources DXCall(Device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_COPY, IID_PPV_ARGS(&readbackCmdAllocator))); DXCall(Device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_COPY, readbackCmdAllocator, nullptr, IID_PPV_ARGS(&readbackCmdList))); DXCall(readbackCmdList->Close()); DXCall(readbackCmdList->Reset(readbackCmdAllocator, nullptr)); readbackFence.Init(0); }
namespace DX12 { static ID3D12GraphicsCommandList* convertCmdList = nullptr; static ID3D12CommandQueue* convertCmdQueue = nullptr; static ID3D12CommandAllocator* convertCmdAllocator = nullptr; static ID3D12RootSignature* convertRootSignature = nullptr; static ID3D12PipelineState* convertPSO = nullptr; static ID3D12PipelineState* convertArrayPSO = nullptr; static CompiledShaderPtr convertCS; static CompiledShaderPtr convertArrayCS; static uint32 convertTGSize = 16; static Fence convertFence; static ID3D12GraphicsCommandList* readbackCmdList = nullptr; static ID3D12CommandAllocator* readbackCmdAllocator = nullptr; static Fence readbackFence; static const uint64 UploadBufferSize = 16 * 1024 * 1024; static const uint64 MaxUploadSubmissions = 16; static ID3D12GraphicsCommandList* UploadCmdList = nullptr; static ID3D12CommandQueue* UploadCmdQueue = nullptr; static ID3D12Resource* UploadBuffer = nullptr; static uint8* UploadBufferCPUAddr = nullptr; static uint64 UploadBufferStart = 0; static uint64 UploadBufferUsed = 0; static Fence UploadFence; static uint64 UploadFenceValue = 0; struct UploadSubmission { ID3D12CommandAllocator* CmdAllocator = nullptr; uint64 Offset = 0; uint64 Size = 0; uint64 FenceValue = uint64(-1); uint64 Padding = 0; void Reset() { Offset = 0; Size = 0; FenceValue = uint64(-1); Padding = 0; } }; static UploadSubmission UploadSubmissions[MaxUploadSubmissions]; static uint64 UploadSubmissionStart = 0; static uint64 UploadSubmissionUsed = 0; static const uint64 TempBufferSize = 2 * 1024 * 1024; static ID3D12Resource* TempFrameBuffers[RenderLatency] = { }; static uint8* TempFrameCPUMem[RenderLatency] = { }; static uint64 TempFrameGPUMem[RenderLatency] = { }; static uint64 TempFrameUsed = 0; static void ClearFinishedUploads(uint64 flushCount) { const uint64 start = UploadSubmissionStart; const uint64 used = UploadSubmissionUsed; for(uint64 i = 0; i < used; ++i) { const uint64 idx = (start + i) % MaxUploadSubmissions; UploadSubmission& submission = UploadSubmissions[idx]; Assert_(submission.Size > 0); Assert_(submission.FenceValue != uint64(-1)); Assert_(UploadBufferUsed >= submission.Size); if(i < flushCount) UploadFence.Wait(submission.FenceValue); if(UploadFence.Signaled(submission.FenceValue)) { UploadSubmissionStart = (UploadSubmissionStart + 1) % MaxUploadSubmissions; UploadSubmissionUsed -= 1; UploadBufferStart = (UploadBufferStart + submission.Padding) % UploadBufferSize; Assert_(submission.Offset == UploadBufferStart); Assert_(UploadBufferStart + submission.Size <= UploadBufferSize); UploadBufferStart = (UploadBufferStart + submission.Size) % UploadBufferSize; UploadBufferUsed -= (submission.Size + submission.Padding); submission.Reset(); if(UploadBufferUsed == 0) UploadBufferStart = 0; } } } static bool AllocUploadSubmission(uint64 size) { Assert_(UploadSubmissionUsed <= MaxUploadSubmissions); if(UploadSubmissionUsed == MaxUploadSubmissions) return false; const uint64 submissionIdx = (UploadSubmissionStart + UploadSubmissionUsed) % MaxUploadSubmissions; Assert_(UploadSubmissions[submissionIdx].Size == 0); Assert_(UploadBufferUsed <= UploadBufferSize); if(size > (UploadBufferSize - UploadBufferUsed)) return false; const uint64 start = UploadBufferStart; const uint64 end = UploadBufferStart + UploadBufferUsed; uint64 allocOffset = uint64(-1); uint64 padding = 0; if(end < UploadBufferSize) { const uint64 endAmt = UploadBufferSize - end; if(endAmt >= size) { allocOffset = end; } else if(start >= size) { // Wrap around to the beginning allocOffset = 0; UploadBufferUsed += endAmt; padding = endAmt; } } else { const uint64 wrappedEnd = end % UploadBufferSize; if((start - wrappedEnd) >= size) allocOffset = wrappedEnd; } if(allocOffset == uint64(-1)) return false; UploadSubmissionUsed += 1; UploadBufferUsed += size; ++UploadFenceValue; UploadSubmissions[submissionIdx].Offset = allocOffset; UploadSubmissions[submissionIdx].Size = size; UploadSubmissions[submissionIdx].FenceValue = UploadFenceValue; UploadSubmissions[submissionIdx].Padding = padding; return true; } void Initialize_Upload() { for(uint64 i = 0; i < MaxUploadSubmissions; ++i) DXCall(Device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_COPY, IID_PPV_ARGS(&UploadSubmissions[i].CmdAllocator))); DXCall(Device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_COPY, UploadSubmissions[0].CmdAllocator, nullptr, IID_PPV_ARGS(&UploadCmdList))); DXCall(UploadCmdList->Close()); D3D12_COMMAND_QUEUE_DESC queueDesc = { }; queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; queueDesc.Type = D3D12_COMMAND_LIST_TYPE_COPY; DXCall(Device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&UploadCmdQueue))); UploadFence.Init(0); D3D12_RESOURCE_DESC resourceDesc = { }; resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; resourceDesc.Width = uint32(UploadBufferSize); resourceDesc.Height = 1; resourceDesc.DepthOrArraySize = 1; resourceDesc.MipLevels = 1; resourceDesc.Format = DXGI_FORMAT_UNKNOWN; resourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE; resourceDesc.SampleDesc.Count = 1; resourceDesc.SampleDesc.Quality = 0; resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; resourceDesc.Alignment = 0; DXCall(Device->CreateCommittedResource(DX12::GetUploadHeapProps(), D3D12_HEAP_FLAG_NONE, &resourceDesc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&UploadBuffer))); D3D12_RANGE readRange = { }; DXCall(UploadBuffer->Map(0, &readRange, reinterpret_cast<void**>(&UploadBufferCPUAddr))); // Temporary buffer memory that swaps every frame resourceDesc.Width = uint32(TempBufferSize); for(uint64 i = 0; i < RenderLatency; ++i) { DXCall(Device->CreateCommittedResource(DX12::GetUploadHeapProps(), D3D12_HEAP_FLAG_NONE, &resourceDesc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&TempFrameBuffers[i]))); DXCall(TempFrameBuffers[i]->Map(0, &readRange, reinterpret_cast<void**>(&TempFrameCPUMem[i]))); TempFrameGPUMem[i] = TempFrameBuffers[i]->GetGPUVirtualAddress(); } // Texture conversion resources DXCall(Device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_COMPUTE, IID_PPV_ARGS(&convertCmdAllocator))); DXCall(Device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_COMPUTE, convertCmdAllocator, nullptr, IID_PPV_ARGS(&convertCmdList))); DXCall(convertCmdList->Close()); DXCall(convertCmdList->Reset(convertCmdAllocator, nullptr)); D3D12_COMMAND_QUEUE_DESC convertQueueDesc = {}; convertQueueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; convertQueueDesc.Type = D3D12_COMMAND_LIST_TYPE_COMPUTE; DXCall(Device->CreateCommandQueue(&convertQueueDesc, IID_PPV_ARGS(&convertCmdQueue))); CompileOptions opts; opts.Add("TGSize_", convertTGSize); const std::wstring shaderPath = SampleFrameworkDir() + L"Shaders\\DecodeTextureCS.hlsl"; convertCS = CompileFromFile(shaderPath.c_str(), "DecodeTextureCS", ShaderType::Compute, ShaderProfile::SM51, opts); convertArrayCS = CompileFromFile(shaderPath.c_str(), "DecodeTextureArrayCS", ShaderType::Compute, ShaderProfile::SM51, opts); { D3D12_DESCRIPTOR_RANGE ranges[2] = {}; ranges[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; ranges[0].NumDescriptors = 1; ranges[0].BaseShaderRegister = 0; ranges[0].RegisterSpace = 0; ranges[0].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; ranges[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; ranges[1].NumDescriptors = 1; ranges[1].BaseShaderRegister = 0; ranges[1].RegisterSpace = 0; ranges[1].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; D3D12_ROOT_PARAMETER rootParameters[1] = {}; rootParameters[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; rootParameters[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; rootParameters[0].DescriptorTable.pDescriptorRanges = ranges; rootParameters[0].DescriptorTable.NumDescriptorRanges = ArraySize_(ranges); D3D12_ROOT_SIGNATURE_DESC rootSignatureDesc = {}; rootSignatureDesc.NumParameters = ArraySize_(rootParameters); rootSignatureDesc.pParameters = rootParameters; rootSignatureDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_NONE; DX12::CreateRootSignature(&convertRootSignature, rootSignatureDesc); } { D3D12_COMPUTE_PIPELINE_STATE_DESC psoDesc = { }; psoDesc.CS = convertCS.ByteCode(); psoDesc.pRootSignature = convertRootSignature; psoDesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE; Device->CreateComputePipelineState(&psoDesc, IID_PPV_ARGS(&convertPSO)); psoDesc.CS = convertArrayCS.ByteCode(); Device->CreateComputePipelineState(&psoDesc, IID_PPV_ARGS(&convertArrayPSO)); } convertFence.Init(0); // Readback resources DXCall(Device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_COPY, IID_PPV_ARGS(&readbackCmdAllocator))); DXCall(Device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_COPY, readbackCmdAllocator, nullptr, IID_PPV_ARGS(&readbackCmdList))); DXCall(readbackCmdList->Close()); DXCall(readbackCmdList->Reset(readbackCmdAllocator, nullptr)); readbackFence.Init(0); } void Shutdown_Upload() { for(uint64 i = 0; i < ArraySize_(TempFrameBuffers); ++i) Release(TempFrameBuffers[i]); Release(UploadCmdList); Release(UploadBuffer); Release(UploadCmdQueue); UploadFence.Shutdown(); for(uint64 i = 0; i < MaxUploadSubmissions; ++i) Release(UploadSubmissions[i].CmdAllocator); Release(convertCmdAllocator); Release(convertCmdList); Release(convertCmdQueue); Release(convertPSO); Release(convertArrayPSO); Release(convertRootSignature); convertFence.Shutdown(); Release(readbackCmdAllocator); Release(readbackCmdList); readbackFence.Shutdown(); } void EndFrame_Upload() { // Make sure to sync on any pending uploads ClearFinishedUploads(0); GfxQueue->Wait(UploadFence.D3DFence, UploadFenceValue); TempFrameUsed = 0; } UploadContext ResourceUploadBegin(uint64 size) { Assert_(Device != nullptr); size = AlignTo(size, 512); Assert_(size <= UploadBufferSize); Assert_(size > 0); ClearFinishedUploads(0); while(AllocUploadSubmission(size) == false) ClearFinishedUploads(1); Assert_(UploadSubmissionUsed > 0); const uint64 submissionIdx = (UploadSubmissionStart + (UploadSubmissionUsed - 1)) % MaxUploadSubmissions; UploadSubmission& submission = UploadSubmissions[submissionIdx]; Assert_(submission.Size == size); DXCall(submission.CmdAllocator->Reset()); DXCall(UploadCmdList->Reset(submission.CmdAllocator, nullptr)); UploadContext context; context.CmdList = UploadCmdList; context.Resource = UploadBuffer; context.CPUAddress = UploadBufferCPUAddr + submission.Offset; context.ResourceOffset = submission.Offset; return context; } void ResourceUploadEnd(UploadContext& context) { Assert_(context.CmdList != nullptr); // Finish off and execute the command list DXCall(UploadCmdList->Close()); ID3D12CommandList* cmdLists[1] = { UploadCmdList }; UploadCmdQueue->ExecuteCommandLists(1, cmdLists); Assert_(UploadSubmissionUsed > 0); const uint64 submissionIdx = (UploadSubmissionStart + (UploadSubmissionUsed - 1)) % MaxUploadSubmissions; UploadSubmission& submission = UploadSubmissions[submissionIdx]; Assert_(submission.Size != 0); UploadFence.Signal(UploadCmdQueue, submission.FenceValue); context = UploadContext(); } MapResult AcquireTempBufferMem(uint64 size, uint64 alignment) { TempFrameUsed = AlignTo(TempFrameUsed, alignment); Assert_(TempFrameUsed + size <= TempBufferSize); MapResult result; result.CPUAddress = TempFrameCPUMem[CurrFrameIdx] + TempFrameUsed; result.GPUAddress = TempFrameGPUMem[CurrFrameIdx] + TempFrameUsed; result.ResourceOffset = TempFrameUsed; result.Resource = TempFrameBuffers[CurrFrameIdx]; TempFrameUsed += size; return result; } void ConvertAndReadbackTexture(const Texture& texture, DXGI_FORMAT outputFormat, ReadbackBuffer& readbackBuffer) { Assert_(convertCmdList != nullptr); Assert_(texture.Valid()); Assert_(texture.Depth == 1); // Create a buffer for the CS to write flattened, converted texture data into FormattedBufferInit init; init.Format = outputFormat; init.NumElements = texture.Width * texture.Height * texture.ArraySize; init.CreateUAV = true; FormattedBuffer convertBuffer; convertBuffer.Initialize(init); convertBuffer.Transition(convertCmdList, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS); // Run the conversion compute shader DX12::SetDescriptorHeaps(convertCmdList); convertCmdList->SetComputeRootSignature(convertRootSignature); convertCmdList->SetPipelineState(texture.ArraySize > 1 ? convertArrayPSO : convertPSO); D3D12_CPU_DESCRIPTOR_HANDLE descriptors[2] = { texture.SRV.CPUHandle, convertBuffer.UAV() }; BindShaderResources(convertCmdList, 0, ArraySize_(descriptors), descriptors, CmdListMode::Compute, ShaderResourceType::SRV_UAV_CBV); uint32 dispatchX = DispatchSize(convertTGSize, texture.Width); uint32 dispatchY = DispatchSize(convertTGSize, texture.Height); uint32 dispatchZ = texture.ArraySize; convertCmdList->Dispatch(dispatchX, dispatchY, dispatchZ); convertBuffer.Transition(convertCmdList, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE); // Execute the conversion command list and signal a fence DXCall(convertCmdList->Close()); ID3D12CommandList* cmdLists[1] = { convertCmdList }; convertCmdQueue->ExecuteCommandLists(1, cmdLists); convertFence.Signal(convertCmdQueue, 1); // Have the readback wait for conversion finish, and then have it copy the data to a readback buffer ID3D12CommandQueue* readbackQueue = UploadCmdQueue; readbackQueue->Wait(convertFence.D3DFence, 1); readbackBuffer.Shutdown(); readbackBuffer.Initialize(convertBuffer.InternalBuffer.Size); readbackCmdList->CopyResource(readbackBuffer.Resource, convertBuffer.InternalBuffer.Resource); // Execute the readback command list and signal a fence DXCall(readbackCmdList->Close()); cmdLists[0] = readbackCmdList; readbackQueue->ExecuteCommandLists(1, cmdLists); readbackFence.Signal(readbackQueue, 1); readbackFence.Wait(1); // Clean up convertFence.Clear(0); readbackFence.Clear(0); DXCall(convertCmdAllocator->Reset()); DXCall(convertCmdList->Reset(convertCmdAllocator, nullptr)); DXCall(readbackCmdAllocator->Reset()); DXCall(readbackCmdList->Reset(readbackCmdAllocator, nullptr)); convertBuffer.Shutdown(); } } // namespace DX12
void PostProcessHelper::PostProcess(CompiledShaderPtr pixelShader, const char* name, const uint32* inputs, uint64 numInputs, const RenderTexture*const* outputs, uint64 numOutputs) { Assert_(cmdList != nullptr); Assert_(numOutputs > 0); Assert_(outputs != nullptr); Assert_(numInputs == 0 || inputs != nullptr); Assert_(numInputs <= MaxInputs); PIXMarker marker(cmdList, name); HashSource hashSource; for(uint64 i = 0; i < numOutputs; ++i) { hashSource.OutputFormats[i] = outputs[i]->Texture.Format; hashSource.MSAASamples = outputs[i]->MSAASamples; } Hash psoHash = GenerateHash(&hashSource, sizeof(HashSource)); psoHash = CombineHashes(psoHash, pixelShader->ByteCodeHash); ID3D12PipelineState* pso = nullptr; // The most linear of searches! const uint64 numPSOs = pipelineStates.Count(); for(uint64 i = 0; i < numPSOs; ++i) { if(pipelineStates[i].Hash == psoHash) { pso = pipelineStates[i].PSO; break; } } if(pso == nullptr) { D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; psoDesc.pRootSignature = rootSignature; psoDesc.VS = fullScreenTriVS.ByteCode(); psoDesc.PS = pixelShader.ByteCode(); psoDesc.RasterizerState = DX12::GetRasterizerState(RasterizerState::NoCull); psoDesc.BlendState = DX12::GetBlendState(BlendState::Disabled); psoDesc.DepthStencilState = DX12::GetDepthState(DepthState::Disabled); psoDesc.SampleMask = UINT_MAX; psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; psoDesc.NumRenderTargets = uint32(numOutputs); for(uint64 i = 0; i < numOutputs; ++i) psoDesc.RTVFormats[i] = hashSource.OutputFormats[i]; psoDesc.DSVFormat = DXGI_FORMAT_UNKNOWN; psoDesc.SampleDesc.Count = uint32(hashSource.MSAASamples); DXCall(DX12::Device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&pso))); CachedPSO cachedPSO; cachedPSO.Hash = psoHash; cachedPSO.PSO = pso; pipelineStates.Add(cachedPSO); } D3D12_CPU_DESCRIPTOR_HANDLE rtvHandles[8] = { }; for(uint64 i = 0; i < numOutputs; ++i) rtvHandles[i] = outputs[i]->RTV; cmdList->OMSetRenderTargets(uint32(numOutputs), rtvHandles, false, nullptr); cmdList->SetGraphicsRootSignature(rootSignature); cmdList->SetPipelineState(pso); DX12::BindStandardDescriptorTable(cmdList, RootParam_StandardDescriptors, CmdListMode::Graphics); AppSettings::BindCBufferGfx(cmdList, RootParam_AppSettings); uint32 srvIndices[MaxInputs] = { }; for(uint64 i = 0; i < numInputs; ++i) srvIndices[i] = inputs[i]; for(uint64 i = numInputs; i < MaxInputs; ++i) srvIndices[i] = DX12::NullTexture2DSRV; DX12::BindTempConstantBuffer(cmdList, srvIndices, RootParam_SRVIndices, CmdListMode::Graphics); DX12::SetViewport(cmdList, outputs[0]->Texture.Width, outputs[0]->Texture.Height); cmdList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); cmdList->DrawInstanced(3, 1, 0, 0); }