Skip to content

Commit

Permalink
ICB encoding for macOS draw calls
Browse files Browse the repository at this point in the history
  • Loading branch information
Jon Creighton committed Aug 16, 2022
1 parent 14ea128 commit 48979b5
Show file tree
Hide file tree
Showing 27 changed files with 1,458 additions and 63 deletions.
2 changes: 2 additions & 0 deletions pxr/imaging/hdSt/commandBuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ HdStCommandBuffer::PrepareDraw(
for (auto const& batch : _drawBatches) {
batch->PrepareDraw(gfxCmds, renderPassState, resourceRegistry);
}

resourceRegistry->SubmitComputeWork();
}

void
Expand Down
187 changes: 142 additions & 45 deletions pxr/imaging/hdSt/pipelineDrawBatch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
#include "pxr/imaging/hgi/blitCmds.h"
#include "pxr/imaging/hgi/blitCmdsOps.h"
#include "pxr/imaging/hgi/graphicsPipeline.h"
#include "pxr/imaging/hgi/indirectCommandEncoder.h"
#include "pxr/imaging/hgi/resourceBindings.h"

#include "pxr/base/tf/diagnostic.h"
Expand Down Expand Up @@ -931,7 +932,7 @@ HdSt_PipelineDrawBatch::_HasNothingToDraw() const

void
HdSt_PipelineDrawBatch::PrepareDraw(
HgiGraphicsCmds *,
HgiGraphicsCmds *gfxCmds,
HdStRenderPassStateSharedPtr const & renderPassState,
HdStResourceRegistrySharedPtr const & resourceRegistry)
{
Expand All @@ -953,6 +954,21 @@ HdSt_PipelineDrawBatch::PrepareDraw(
_dispatchBuffer->CopyData(_drawCommandBuffer);
_drawCommandBufferDirty = false;
}

Hgi *hgi = resourceRegistry->GetHgi();
HgiCapabilities const *capabilities = hgi->GetCapabilities();

// For ICBs on Apple Silicon, we do not support rendering to non-MSAA
// surfaces, such as OIT as Volumetrics. Disable in these cases.
bool const drawICB =
capabilities->IsSet(HgiDeviceCapabilitiesBitsIndirectCommandBuffers) &&
gfxCmds &&
renderPassState->GetMultiSampleEnabled();

_indirectCommands.reset();
if (drawICB) {
_PrepareIndirectCommandBuffer(renderPassState, resourceRegistry);
}

if (_useGpuCulling) {
// Ignore passed in gfxCmds for now since GPU frustum culling
Expand Down Expand Up @@ -1235,56 +1251,68 @@ HdSt_PipelineDrawBatch::ExecuteDraw(
if (!TF_VERIFY(_dispatchBuffer)) return;

if (_HasNothingToDraw()) return;

HgiCapabilities const *capabilities =
resourceRegistry->GetHgi()->GetCapabilities();

// Drawing can be either direct or indirect. For either case,
// the drawing batch and drawing program are prepared to resolve
// drawing coordinate state indirectly, i.e. from buffer data.
bool const drawIndirect =
capabilities->IsSet(HgiDeviceCapabilitiesBitsMultiDrawIndirect);
_DrawingProgram & program = _GetDrawingProgram(renderPassState,
resourceRegistry);
if (!TF_VERIFY(program.IsValid())) return;

_BindingState state(
_drawItemInstances.front()->GetDrawItem(),
_dispatchBuffer,
program.GetBinder(),
program.GetGLSLProgram(),
program.GetComposedShaders(),
program.GetGeometricShader());

Hgi * hgi = resourceRegistry->GetHgi();

HgiGraphicsPipelineSharedPtr pso =
_GetDrawPipeline(
renderPassState,
resourceRegistry,
state);

HgiGraphicsPipelineHandle psoHandle = *pso.get();
gfxCmds->BindPipeline(psoHandle);

HgiResourceBindingsDesc bindingsDesc;
state.GetBindingsForDrawing(&bindingsDesc);

HgiResourceBindingsHandle resourceBindings =
hgi->CreateResourceBindings(bindingsDesc);
gfxCmds->BindResources(resourceBindings);
Hgi *hgi = resourceRegistry->GetHgi();
HgiCapabilities const *capabilities = hgi->GetCapabilities();

bool const drawICB =
capabilities->IsSet(HgiDeviceCapabilitiesBitsIndirectCommandBuffers);

HgiVertexBufferBindingVector bindings;
_GetVertexBufferBindingsForDrawing(&bindings, state);
gfxCmds->BindVertexBuffers(bindings);
if (drawICB && _indirectCommands) {
HgiIndirectCommandEncoder *encoder = hgi->GetIndirectCommandEncoder();
encoder->ExecuteDraw(gfxCmds, _indirectCommands.get());

if (drawIndirect) {
_ExecuteDrawIndirect(gfxCmds, state.indexBar);
} else {
_ExecuteDrawImmediate(gfxCmds, state.indexBar);
hgi->DestroyResourceBindings(&(_indirectCommands->resourceBindings));
_indirectCommands.reset();
}
else {
_DrawingProgram & program = _GetDrawingProgram(renderPassState,
resourceRegistry);
if (!TF_VERIFY(program.IsValid())) return;

_BindingState state(
_drawItemInstances.front()->GetDrawItem(),
_dispatchBuffer,
program.GetBinder(),
program.GetGLSLProgram(),
program.GetComposedShaders(),
program.GetGeometricShader());

HgiGraphicsPipelineSharedPtr pso =
_GetDrawPipeline(
renderPassState,
resourceRegistry,
state);

HgiGraphicsPipelineHandle psoHandle = *pso.get();
gfxCmds->BindPipeline(psoHandle);

HgiResourceBindingsDesc bindingsDesc;
state.GetBindingsForDrawing(&bindingsDesc);

HgiResourceBindingsHandle resourceBindings =
hgi->CreateResourceBindings(bindingsDesc);
gfxCmds->BindResources(resourceBindings);

HgiVertexBufferBindingVector bindings;
_GetVertexBufferBindingsForDrawing(&bindings, state);
gfxCmds->BindVertexBuffers(bindings);

// Drawing can be either direct or indirect. For either case,
// the drawing batch and drawing program are prepared to resolve
// drawing coordinate state indirectly, i.e. from buffer data.
bool const drawIndirect =
capabilities->IsSet(HgiDeviceCapabilitiesBitsMultiDrawIndirect);

if (drawIndirect) {
_ExecuteDrawIndirect(gfxCmds, state.indexBar);
} else {
_ExecuteDrawImmediate(gfxCmds, state.indexBar);
}

hgi->DestroyResourceBindings(&resourceBindings);
hgi->DestroyResourceBindings(&resourceBindings);
}

HD_PERF_COUNTER_INCR(HdPerfTokens->drawCalls);
HD_PERF_COUNTER_ADD(HdTokens->itemsDrawn, _numVisibleItems);
Expand Down Expand Up @@ -1430,6 +1458,75 @@ _GetCullPipeline(
return pipelineInstance.GetValue();
}

void
HdSt_PipelineDrawBatch::_PrepareIndirectCommandBuffer(
HdStRenderPassStateSharedPtr const & renderPassState,
HdStResourceRegistrySharedPtr const & resourceRegistry)
{
Hgi *hgi = resourceRegistry->GetHgi();
_DrawingProgram & program = _GetDrawingProgram(renderPassState,
resourceRegistry);
if (!TF_VERIFY(program.IsValid())) return;

_BindingState state(
_drawItemInstances.front()->GetDrawItem(),
_dispatchBuffer,
program.GetBinder(),
program.GetGLSLProgram(),
program.GetComposedShaders(),
program.GetGeometricShader());

HgiGraphicsPipelineSharedPtr pso =
_GetDrawPipeline(
renderPassState,
resourceRegistry,
state);

HgiGraphicsPipelineHandle psoHandle = *pso.get();

HgiResourceBindingsDesc bindingsDesc;
state.GetBindingsForDrawing(&bindingsDesc);

HgiResourceBindingsHandle resourceBindings =
hgi->CreateResourceBindings(bindingsDesc);

HgiVertexBufferBindingVector vertexBindings;
_GetVertexBufferBindingsForDrawing(&vertexBindings, state);

HdStBufferResourceSharedPtr paramBuffer = _dispatchBuffer->
GetBufferArrayRange()->GetResource(HdTokens->drawDispatch);

HgiIndirectCommandEncoder *encoder = hgi->GetIndirectCommandEncoder();
HgiComputeCmds *computeCmds = resourceRegistry->GetGlobalComputeCmds();

if (!_useDrawIndexed) {
_indirectCommands = encoder->EncodeDraw(
computeCmds,
psoHandle,
resourceBindings,
vertexBindings,
paramBuffer->GetHandle(),
paramBuffer->GetOffset(),
_dispatchBuffer->GetCount(),
paramBuffer->GetStride());
} else {
HdStBufferResourceSharedPtr indexBuffer =
state.indexBar->GetResource(HdTokens->indices);

_indirectCommands = encoder->EncodeDrawIndexed(
computeCmds,
psoHandle,
resourceBindings,
vertexBindings,
indexBuffer->GetHandle(),
paramBuffer->GetHandle(),
paramBuffer->GetOffset(),
_dispatchBuffer->GetCount(),
paramBuffer->GetStride(),
_patchBaseVertexByteOffset);
}
}

void
HdSt_PipelineDrawBatch::_ExecuteFrustumCull(
bool const updateBufferData,
Expand Down
7 changes: 7 additions & 0 deletions pxr/imaging/hdSt/pipelineDrawBatch.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
PXR_NAMESPACE_OPEN_SCOPE

class HgiCapabilities;
struct HgiIndirectCommands;
using HdBindingRequestVector = std::vector<HdBindingRequest>;

/// \class HdSt_PipelineDrawBatch
Expand Down Expand Up @@ -128,6 +129,10 @@ class HdSt_PipelineDrawBatch : public HdSt_DrawBatch
HdStResourceRegistrySharedPtr const & resourceRegistry);

void _CompileBatch(HdStResourceRegistrySharedPtr const & resourceRegistry);

void _PrepareIndirectCommandBuffer(
HdStRenderPassStateSharedPtr const & renderPassState,
HdStResourceRegistrySharedPtr const & resourceRegistry);

bool _HasNothingToDraw() const;

Expand Down Expand Up @@ -179,6 +184,8 @@ class HdSt_PipelineDrawBatch : public HdSt_DrawBatch
size_t _instanceCountOffset;
size_t _cullInstanceCountOffset;
size_t _patchBaseVertexByteOffset;

std::unique_ptr<struct HgiIndirectCommands> _indirectCommands;
};


Expand Down
1 change: 1 addition & 0 deletions pxr/imaging/hgi/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ pxr_library(hgi
graphicsCmdsDesc
graphicsPipeline
hgi
indirectCommandEncoder
resourceBindings
sampler
shaderFunction
Expand Down
4 changes: 4 additions & 0 deletions pxr/imaging/hgi/enums.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ using HgiBits = uint32_t;
/// <li>HgiDeviceCapabilitiesBitsBasePrimitiveOffset:
/// The device requires workaround for base primitive offset</li>
/// </ul>
/// <li>HgiDeviceCapabilitiesBitsIndirectCommandBuffers:
/// Indirect command buffers are supported</li>
/// </ul>
///
enum HgiDeviceCapabilitiesBits : HgiBits
{
Expand All @@ -91,6 +94,7 @@ enum HgiDeviceCapabilitiesBits : HgiBits
HgiDeviceCapabilitiesBitsCustomDepthRange = 1 << 13,
HgiDeviceCapabilitiesBitsMetalTessellation = 1 << 14,
HgiDeviceCapabilitiesBitsBasePrimitiveOffset = 1 << 15,
HgiDeviceCapabilitiesBitsIndirectCommandBuffers = 1 << 16,
};

using HgiDeviceCapabilities = HgiBits;
Expand Down
1 change: 1 addition & 0 deletions pxr/imaging/hgi/graphicsCmds.h
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ class HgiGraphicsCmds : public HgiCmds
HGI_API
virtual void MemoryBarrier(HgiMemoryBarrier barrier) = 0;


protected:
HGI_API
HgiGraphicsCmds();
Expand Down
4 changes: 4 additions & 0 deletions pxr/imaging/hgi/hgi.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
PXR_NAMESPACE_OPEN_SCOPE

class HgiCapabilities;
class HgiIndirectCommandEncoder;

using HgiUniquePtr = std::unique_ptr<class Hgi>;

Expand Down Expand Up @@ -295,6 +296,9 @@ class Hgi
HGI_API
virtual HgiCapabilities const* GetCapabilities() const = 0;

HGI_API
virtual HgiIndirectCommandEncoder* GetIndirectCommandEncoder() = 0;

/// Optionally called by client app at the start of a new rendering frame.
/// We can't rely on StartFrame for anything important, because it is up to
/// the external client to (optionally) call this and they may never do.
Expand Down
31 changes: 31 additions & 0 deletions pxr/imaging/hgi/indirectCommandEncoder.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//
// Copyright 2022 Pixar
//
// Licensed under the Apache License, Version 2.0 (the "Apache License")
// with the following modification; you may not use this file except in
// compliance with the Apache License and the following modification to it:
// Section 6. Trademarks. is deleted and replaced with:
//
// 6. Trademarks. This License does not grant permission to use the trade
// names, trademarks, service marks, or product names of the Licensor
// and its affiliates, except as required to comply with Section 4(c) of
// the License and to reproduce the content of the NOTICE file.
//
// You may obtain a copy of the Apache License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the Apache License with the above modification is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the Apache License for the specific
// language governing permissions and limitations under the Apache License.
//

#include "pxr/imaging/hgi/indirectCommandEncoder.h"

PXR_NAMESPACE_OPEN_SCOPE

HgiIndirectCommandEncoder::~HgiIndirectCommandEncoder() = default;

PXR_NAMESPACE_CLOSE_SCOPE
Loading

0 comments on commit 48979b5

Please sign in to comment.