computeCmds->InsertMemoryBarrier(HgiMemoryBarrierAll);
for (auto const& batch : _drawBatches) {
- batch->EncodeDraw(renderPassState, resourceRegistry);
+ batch->EncodeDraw(renderPassState, resourceRegistry,
+ /*firstDrawBatch*/batch == *_drawBatches.begin());
}
computeCmds->InsertMemoryBarrier(HgiMemoryBarrierAll);
// draw batches
//
for (auto const& batch : _drawBatches) {
- batch->ExecuteDraw(gfxCmds, renderPassState, resourceRegistry);
+ batch->ExecuteDraw(gfxCmds, renderPassState, resourceRegistry,
+ /*firstDrawBatch*/batch == *_drawBatches.begin());
}
HD_PERF_COUNTER_SET(HdPerfTokens->drawBatches, _drawBatches.size());
/// Encode drawing commands for this batch.
virtual void EncodeDraw(
HdStRenderPassStateSharedPtr const & renderPassState,
- HdStResourceRegistrySharedPtr const & resourceRegistry) = 0;
+ HdStResourceRegistrySharedPtr const & resourceRegistry,
+ bool firstDrawBatch) = 0;
/// Executes the drawing commands for this batch.
virtual void ExecuteDraw(
HgiGraphicsCmds *gfxCmds,
HdStRenderPassStateSharedPtr const &renderPassState,
- HdStResourceRegistrySharedPtr const & resourceRegistry) = 0;
+ HdStResourceRegistrySharedPtr const & resourceRegistry,
+ bool firstDrawBatch) = 0;
/// Let the batch know that one of it's draw item instances has changed
/// NOTE: This callback is called from multiple threads, so needs to be
// Camera state needs to be updated once per pass (not per batch).
stRenderPassState->ApplyStateFromCamera();
- _drawBatch->ExecuteDraw(gfxCmds.get(), stRenderPassState, resourceRegistry);
+ _drawBatch->ExecuteDraw(gfxCmds.get(), stRenderPassState, resourceRegistry,
+ /*firstDrawBatch*/true);
gfxCmds->PopDebugGroup();
_hgi->SubmitCmds(gfxCmds.get());
void
HdSt_IndirectDrawBatch::EncodeDraw(
HdStRenderPassStateSharedPtr const & renderPassState,
- HdStResourceRegistrySharedPtr const & resourceRegistry)
+ HdStResourceRegistrySharedPtr const & resourceRegistry,
+ bool /*firstDrawBatch*/)
{
// No implementation.
}
HdSt_IndirectDrawBatch::ExecuteDraw(
HgiGraphicsCmds * gfxCmds,
HdStRenderPassStateSharedPtr const & renderPassState,
- HdStResourceRegistrySharedPtr const & resourceRegistry)
+ HdStResourceRegistrySharedPtr const & resourceRegistry,
+ bool /*firstDrawBatch*/)
{
HgiGLGraphicsCmds* glGfxCmds = dynamic_cast<HgiGLGraphicsCmds*>(gfxCmds);
HDST_API
void EncodeDraw(
HdStRenderPassStateSharedPtr const & renderPassState,
- HdStResourceRegistrySharedPtr const & resourceRegistry) override;
+ HdStResourceRegistrySharedPtr const & resourceRegistry,
+ bool firstDrawBatch) override;
/// Executes the drawing commands for this batch.
HDST_API
void ExecuteDraw(
HgiGraphicsCmds *gfxCmds,
HdStRenderPassStateSharedPtr const &renderPassState,
- HdStResourceRegistrySharedPtr const &resourceRegistry) override;
+ HdStResourceRegistrySharedPtr const &resourceRegistry,
+ bool firstDrawBatch) override;
HDST_API
void DrawItemInstanceChanged(
void
HdSt_PipelineDrawBatch::EncodeDraw(
HdStRenderPassStateSharedPtr const & renderPassState,
- HdStResourceRegistrySharedPtr const & resourceRegistry)
+ HdStResourceRegistrySharedPtr const & resourceRegistry,
+ bool firstDrawBatch)
{
if (_HasNothingToDraw()) return;
_indirectCommands.reset();
if (drawICB) {
- _PrepareIndirectCommandBuffer(renderPassState, resourceRegistry);
+ _PrepareIndirectCommandBuffer(renderPassState, resourceRegistry,
+ firstDrawBatch);
}
}
_GetDrawPipeline(
HdStRenderPassStateSharedPtr const & renderPassState,
HdStResourceRegistrySharedPtr const & resourceRegistry,
- _BindingState const & state)
+ _BindingState const & state,
+ bool firstDrawBatch)
{
// Drawing pipeline is compatible as long as the shader and
// pipeline state are the same.
uint64_t hash = salt;
hash = TfHash::Combine(hash, programHandle.Get());
hash = TfHash::Combine(hash, renderPassState->GetGraphicsPipelineHash(
- state.geometricShader));
+ state.geometricShader, firstDrawBatch));
HdInstance<HgiGraphicsPipelineSharedPtr> pipelineInstance =
resourceRegistry->RegisterGraphicsPipeline(hash);
HgiGraphicsPipelineDesc pipeDesc;
renderPassState->InitGraphicsPipelineDesc(&pipeDesc,
- state.geometricShader);
+ state.geometricShader,
+ firstDrawBatch);
pipeDesc.shaderProgram = state.glslProgram->GetProgram();
pipeDesc.vertexBuffers = _GetVertexBuffersForDrawing(state);
_GetPTCSPipeline(
HdStRenderPassStateSharedPtr const & renderPassState,
HdStResourceRegistrySharedPtr const & resourceRegistry,
- _BindingState const & state)
+ _BindingState const & state,
+ bool firstDrawBatch)
{
// PTCS pipeline is compatible as long as the shader and
// pipeline state are the same.
uint64_t hash = salt;
hash = TfHash::Combine(hash, programHandle.Get());
hash = TfHash::Combine(hash, renderPassState->GetGraphicsPipelineHash(
- state.geometricShader));
+ state.geometricShader, firstDrawBatch));
HdInstance<HgiGraphicsPipelineSharedPtr> pipelineInstance =
resourceRegistry->RegisterGraphicsPipeline(hash);
HgiGraphicsPipelineDesc pipeDesc;
renderPassState->InitGraphicsPipelineDesc(&pipeDesc,
- state.geometricShader);
+ state.geometricShader,
+ firstDrawBatch);
pipeDesc.rasterizationState.rasterizerEnabled = false;
pipeDesc.multiSampleState.sampleCount = HgiSampleCount1;
HdSt_PipelineDrawBatch::ExecuteDraw(
HgiGraphicsCmds * gfxCmds,
HdStRenderPassStateSharedPtr const & renderPassState,
- HdStResourceRegistrySharedPtr const & resourceRegistry)
+ HdStResourceRegistrySharedPtr const & resourceRegistry,
+ bool firstDrawBatch)
{
TRACE_FUNCTION();
if (_tessFactorsBuffer) {
// Metal tessellation tessFactors are computed by PTCS.
- _ExecutePTCS(gfxCmds, renderPassState, resourceRegistry);
-
+ _ExecutePTCS(gfxCmds, renderPassState, resourceRegistry,
+ firstDrawBatch);
// Finish computing tessFactors before drawing.
gfxCmds->InsertMemoryBarrier(HgiMemoryBarrierAll);
}
_GetDrawPipeline(
renderPassState,
resourceRegistry,
- state);
-
+ state,
+ firstDrawBatch);
+
HgiGraphicsPipelineHandle psoHandle = *pso.get();
gfxCmds->BindPipeline(psoHandle);
void
HdSt_PipelineDrawBatch::_PrepareIndirectCommandBuffer(
HdStRenderPassStateSharedPtr const & renderPassState,
- HdStResourceRegistrySharedPtr const & resourceRegistry)
+ HdStResourceRegistrySharedPtr const & resourceRegistry,
+ bool firstDrawBatch)
{
Hgi *hgi = resourceRegistry->GetHgi();
_DrawingProgram & program = _GetDrawingProgram(renderPassState,
_GetDrawPipeline(
renderPassState,
resourceRegistry,
- state);
+ state,
+ firstDrawBatch);
HgiGraphicsPipelineHandle psoHandle = *pso.get();
void
HdSt_PipelineDrawBatch::_ExecutePTCS(
- HgiGraphicsCmds *ptcsGfxCmds,
- HdStRenderPassStateSharedPtr const & renderPassState,
- HdStResourceRegistrySharedPtr const & resourceRegistry)
+ HgiGraphicsCmds *ptcsGfxCmds,
+ HdStRenderPassStateSharedPtr const & renderPassState,
+ HdStResourceRegistrySharedPtr const & resourceRegistry,
+ bool firstDrawBatch)
{
TRACE_FUNCTION();
HgiGraphicsPipelineSharedPtr const & psoTess =
_GetPTCSPipeline(renderPassState,
resourceRegistry,
- state);
+ state,
+ firstDrawBatch);
HgiGraphicsPipelineHandle psoTessHandle = *psoTess.get();
ptcsGfxCmds->BindPipeline(psoTessHandle);
HDST_API
void EncodeDraw(
HdStRenderPassStateSharedPtr const & renderPassState,
- HdStResourceRegistrySharedPtr const & resourceRegistry) override;
+ HdStResourceRegistrySharedPtr const & resourceRegistry,
+ bool firstDrawBatch) override;
/// Executes the drawing commands for this batch.
HDST_API
void ExecuteDraw(
HgiGraphicsCmds *gfxCmds,
HdStRenderPassStateSharedPtr const & renderPassState,
- HdStResourceRegistrySharedPtr const & resourceRegistry) override;
+ HdStResourceRegistrySharedPtr const & resourceRegistry,
+ bool firstDrawBatch) override;
HDST_API
void DrawItemInstanceChanged(
void _PrepareIndirectCommandBuffer(
HdStRenderPassStateSharedPtr const & renderPassState,
- HdStResourceRegistrySharedPtr const & resourceRegistry);
+ HdStResourceRegistrySharedPtr const & resourceRegistry,
+ bool firstDrawBatch);
bool _HasNothingToDraw() const;
void _ExecutePTCS(
HgiGraphicsCmds *ptcsGfxCmds,
HdStRenderPassStateSharedPtr const & renderPassState,
- HdStResourceRegistrySharedPtr const & resourceRegistry);
+ HdStResourceRegistrySharedPtr const & resourceRegistry,
+ bool firstDrawBatch);
void _BeginGPUCountVisibleInstances(
HdStResourceRegistrySharedPtr const & resourceRegistry);
void
HdStRenderPassState::_InitAttachmentState(
- HgiGraphicsPipelineDesc * pipeDesc) const
+ HgiGraphicsPipelineDesc * pipeDesc,
+ bool firstDrawBatch) const
{
// For Metal and Vulkan, we have to pass the color and depth descriptors
// down so that they are available when creating the Render Pipeline State
_InitAttachmentDesc(
attachment, binding, binding.renderBuffer, aovIndex);
+ // For HgiVulkan, don't want to run a clear operation unless this is
+ // the first draw batch in a graphics cmds submission.
+ if (!firstDrawBatch) {
+ attachment.loadOp = HgiAttachmentLoadOpLoad;
+ attachment.clearValue = GfVec4f(0);
+ }
+
if (HdAovHasDepthSemantic(binding.aovName) ||
HdAovHasDepthStencilSemantic(binding.aovName)) {
pipeDesc->depthAttachmentDesc = attachment;
void
HdStRenderPassState::InitGraphicsPipelineDesc(
HgiGraphicsPipelineDesc * pipeDesc,
- HdSt_GeometricShaderSharedPtr const & geometricShader) const
+ HdSt_GeometricShaderSharedPtr const & geometricShader,
+ bool firstDrawBatch) const
{
_InitPrimitiveState(pipeDesc, geometricShader);
_InitDepthStencilState(&pipeDesc->depthState);
_InitMultiSampleState(&pipeDesc->multiSampleState);
_InitRasterizationState(&pipeDesc->rasterizationState, geometricShader);
- _InitAttachmentState(pipeDesc);
+ _InitAttachmentState(pipeDesc, firstDrawBatch);
}
uint64_t
HdStRenderPassState::GetGraphicsPipelineHash(
- HdSt_GeometricShaderSharedPtr const & geometricShader) const
+ HdSt_GeometricShaderSharedPtr const & geometricShader,
+ bool firstDrawBatch) const
{
// Hash all of the state that is captured in the pipeline state object.
uint64_t hash = TfHash::Combine(
geometricShader->ResolveCullMode(_cullStyle),
geometricShader->GetHgiPrimitiveType(),
geometricShader->GetPrimitiveIndexSize());
-
+
// Hash the aov bindings by name and format.
for (HdRenderPassAovBinding const& binding : GetAovBindings()) {
HdStRenderBuffer *renderBuffer =
const uint32_t msaaCount = renderBuffer->IsMultiSampled() ?
renderBuffer->GetMSAASampleCount() : 1;
-
+ const bool clear =
+ firstDrawBatch ? !binding.clearValue.IsEmpty() : false;
+
hash = TfHash::Combine(hash,
binding.aovName,
renderBuffer->GetFormat(),
- msaaCount);
+ msaaCount,
+ clear);
}
-
+
return hash;
}
HDST_API
void InitGraphicsPipelineDesc(
HgiGraphicsPipelineDesc * pipeDesc,
- HdSt_GeometricShaderSharedPtr const & geometricShader) const;
+ HdSt_GeometricShaderSharedPtr const & geometricShader,
+ bool firstDrawBatch) const;
/// Generates the hash for the settings used to init the graphics pipeline.
HDST_API
uint64_t GetGraphicsPipelineHash(
- HdSt_GeometricShaderSharedPtr const & geometricShader) const;
+ HdSt_GeometricShaderSharedPtr const & geometricShader,
+ bool firstDrawBatch) const;
// A 4d-vector v encodes a 2d-transform as follows:
// (x, y) |-> (v[0] * x + v[2], v[1] * y + v[3]).
void _InitPrimitiveState(
HgiGraphicsPipelineDesc * pipeDesc,
HdSt_GeometricShaderSharedPtr const & geometricShader) const;
- void _InitAttachmentState(HgiGraphicsPipelineDesc * pipeDesc) const;
+ void _InitAttachmentState(HgiGraphicsPipelineDesc * pipeDesc,
+ bool firstDrawBatch) const;
void _InitDepthStencilState(HgiDepthStencilState * depthState) const;
void _InitMultiSampleState(HgiMultiSampleState * multisampleState) const;
void _InitRasterizationState(
(*batchIt)->PrepareDraw(nullptr, renderPassState, registry);
}
TF_FOR_ALL(batchIt, drawBatches) {
- (*batchIt)->ExecuteDraw(nullptr, renderPassState, registry);
+ (*batchIt)->ExecuteDraw(nullptr, renderPassState, registry,
+ /*firstDrawBatch*/*batchIt == *drawBatches.begin());
}
dict = registry->GetResourceAllocation();
Dump("----- executed -----\n", dict, perfLog);
HdStRenderPassStateSharedPtr const renderPassState =
std::make_shared<HdStRenderPassState>();
batch->PrepareDraw(nullptr, renderPassState, registry);
- batch->ExecuteDraw(nullptr, renderPassState, registry);
+ batch->ExecuteDraw(nullptr, renderPassState, registry,
+ /*firstDrawBatch*/true);
// ---------------------------------------------------
{
TfErrorMark mark;
- batch->ExecuteDraw(nullptr, passState, registry);
+ batch->ExecuteDraw(nullptr, passState, registry,
+ /*firstDrawBatch*/true);
if (mark.IsClean()) {
std::cout << "Did not get expected shader compilation error\n";
VkRenderPassBeginInfo beginInfo =
{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
beginInfo.renderPass = pso->GetVulkanRenderPass();
- beginInfo.framebuffer= pso->AcquireVulkanFramebuffer(_descriptor,&size);
+ beginInfo.framebuffer= pso->AcquireVulkanFramebuffer(
+ _descriptor, &size);
beginInfo.renderArea.extent.width = size[0];
beginInfo.renderArea.extent.height = size[1];
- beginInfo.clearValueCount =
- static_cast<uint32_t>(_vkClearValues.size());
- beginInfo.pClearValues = _vkClearValues.data();
+
+ // Only pass clear values to VkRenderPassBeginInfo if the pipeline has
+ // attachments that specify a clear op.
+ if (pso->GetClearNeeded()) {
+ beginInfo.clearValueCount =
+ static_cast<uint32_t>(_vkClearValues.size());
+ beginInfo.pClearValues = _vkClearValues.data();
+ }
VkSubpassContents contents = VK_SUBPASS_CONTENTS_INLINE;
, _vkPipeline(nullptr)
, _vkRenderPass(nullptr)
, _vkPipelineLayout(nullptr)
+ , _clearNeeded(false)
{
VkGraphicsPipelineCreateInfo pipeCreateInfo =
{VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO};
return _inflightBits;
}
-static void
-_ProcessAttachment(
+void
+HgiVulkanGraphicsPipeline::_ProcessAttachment(
HgiAttachmentDesc const& attachment,
uint32_t attachmentIndex,
HgiSampleCount sampleCount,
attachment.format, isDepthAttachment);
vkAttachDesc->initialLayout = layout;
vkAttachDesc->loadOp = HgiVulkanConversions::GetLoadOp(attachment.loadOp);
+
+ // If any attachments specify a clear op, clearing the renderpass will be
+ // needed.
+ if (attachment.loadOp == HgiAttachmentLoadOpClear) {
+ _clearNeeded = true;
+ }
+
vkAttachDesc->samples = HgiVulkanConversions::GetSampleCount(sampleCount);
vkAttachDesc->storeOp= HgiVulkanConversions::GetStoreOp(attachment.storeOp);
// XXX Hgi doesn't provide stencil ops, assume it matches depth attachment.
HGIVULKAN_API
uint64_t & GetInflightBits();
+ /// Returns true if any of the attachments in HgiGraphicsPipelineDesc
+ /// specify a clear operation.
+ HGIVULKAN_API
+ bool GetClearNeeded() const
+ {
+ return _clearNeeded;
+ }
+
protected:
friend class HgiVulkan;
HgiVulkanGraphicsPipeline & operator=(const HgiVulkanGraphicsPipeline&) = delete;
HgiVulkanGraphicsPipeline(const HgiVulkanGraphicsPipeline&) = delete;
+ void _ProcessAttachment(
+ HgiAttachmentDesc const& attachment,
+ uint32_t attachmentIndex,
+ HgiSampleCount sampleCount,
+ VkAttachmentDescription2* vkAttachDesc,
+ VkAttachmentReference2* vkRef);
void _CreateRenderPass();
struct HgiVulkan_Framebuffer {
VkRenderPass _vkRenderPass;
VkPipelineLayout _vkPipelineLayout;
VkDescriptorSetLayoutVector _vkDescriptorSetLayouts;
+ bool _clearNeeded;
std::vector<HgiVulkan_Framebuffer> _framebuffers;
};