diff --git a/src/dawn_native/d3d12/CommandBufferD3D12.cpp b/src/dawn_native/d3d12/CommandBufferD3D12.cpp index aeb87d70e3..a56b89ac71 100644 --- a/src/dawn_native/d3d12/CommandBufferD3D12.cpp +++ b/src/dawn_native/d3d12/CommandBufferD3D12.cpp @@ -448,6 +448,36 @@ namespace dawn_native { namespace d3d12 { std::array mD3D12BufferViews = {}; }; + class IndexBufferTracker { + public: + void OnSetIndexBuffer(Buffer* buffer, uint64_t offset) { + mD3D12BufferView.BufferLocation = buffer->GetVA() + offset; + mD3D12BufferView.SizeInBytes = buffer->GetSize() - offset; + + // We don't need to dirty the state unless BufferLocation or SizeInBytes + // change, but most of the time this will always be the case. + mLastAppliedIndexFormat = DXGI_FORMAT_UNKNOWN; + } + + void OnSetPipeline(const RenderPipelineBase* pipeline) { + mD3D12BufferView.Format = + DXGIIndexFormat(pipeline->GetVertexInputDescriptor()->indexFormat); + } + + void Apply(ID3D12GraphicsCommandList* commandList) { + if (mD3D12BufferView.Format == mLastAppliedIndexFormat) { + return; + } + + commandList->IASetIndexBuffer(&mD3D12BufferView); + mLastAppliedIndexFormat = mD3D12BufferView.Format; + } + + private: + DXGI_FORMAT mLastAppliedIndexFormat = DXGI_FORMAT_UNKNOWN; + D3D12_INDEX_BUFFER_VIEW mD3D12BufferView = {}; + }; + void AllocateAndSetDescriptorHeaps(Device* device, BindGroupStateTracker* bindingTracker, RenderPassDescriptorHeapTracker* renderPassTracker, @@ -997,6 +1027,7 @@ namespace dawn_native { namespace d3d12 { RenderPipeline* lastPipeline = nullptr; PipelineLayout* lastLayout = nullptr; VertexBufferTracker vertexBufferTracker = {}; + IndexBufferTracker indexBufferTracker = {}; auto EncodeRenderBundleCommand = [&](CommandIterator* iter, Command type) { switch (type) { @@ -1011,6 +1042,7 @@ namespace dawn_native { namespace d3d12 { case Command::DrawIndexed: { DrawIndexedCmd* draw = iter->NextCommand(); + indexBufferTracker.Apply(commandList.Get()); vertexBufferTracker.Apply(commandList.Get(), lastPipeline); commandList->DrawIndexedInstanced(draw->indexCount, draw->instanceCount, draw->firstIndex, draw->baseVertex, @@ -1032,6 +1064,7 @@ namespace dawn_native { namespace d3d12 { case Command::DrawIndexedIndirect: { DrawIndexedIndirectCmd* draw = iter->NextCommand(); + indexBufferTracker.Apply(commandList.Get()); vertexBufferTracker.Apply(commandList.Get(), lastPipeline); Buffer* buffer = ToBackend(draw->indirectBuffer.Get()); ComPtr signature = @@ -1086,6 +1119,7 @@ namespace dawn_native { namespace d3d12 { commandList->SetPipelineState(pipeline->GetPipelineState().Get()); commandList->IASetPrimitiveTopology(pipeline->GetD3D12PrimitiveTopology()); + indexBufferTracker.OnSetPipeline(pipeline); bindingTracker->SetInheritedBindGroups(commandList, lastLayout, layout); lastPipeline = pipeline; @@ -1108,17 +1142,7 @@ namespace dawn_native { namespace d3d12 { case Command::SetIndexBuffer: { SetIndexBufferCmd* cmd = iter->NextCommand(); - Buffer* buffer = ToBackend(cmd->buffer.Get()); - D3D12_INDEX_BUFFER_VIEW bufferView; - bufferView.BufferLocation = buffer->GetVA() + cmd->offset; - bufferView.SizeInBytes = buffer->GetSize() - cmd->offset; - // TODO(cwallez@chromium.org): Make index buffers lazily applied, right now - // this will break if the pipeline is changed for one with a different index - // format after SetIndexBuffer - bufferView.Format = - DXGIIndexFormat(lastPipeline->GetVertexInputDescriptor()->indexFormat); - - commandList->IASetIndexBuffer(&bufferView); + indexBufferTracker.OnSetIndexBuffer(ToBackend(cmd->buffer.Get()), cmd->offset); } break; case Command::SetVertexBuffers: {