mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-05-15 03:41:34 +00:00
The problem is becasue a resource can not be set as input and output at same time on device context. So we have to track used slots and unset related slots before binding a group. This CL also unset all affect slots when a render pass or compute pass is end, so all related resources could be unref from the device context. Bug: dawn:1705 Change-Id: I597762ad8afa3b8df7139b0070f0b457d7319836 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/131380 Commit-Queue: Peng Huang <penghuang@chromium.org> Reviewed-by: Austin Eng <enga@chromium.org> Kokoro: Kokoro <noreply+kokoro@google.com>
716 lines
29 KiB
C++
716 lines
29 KiB
C++
// Copyright 2023 The Dawn Authors
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#include "dawn/native/d3d11/CommandBufferD3D11.h"
|
|
|
|
#include <algorithm>
|
|
#include <array>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "dawn/common/WindowsUtils.h"
|
|
#include "dawn/native/CommandEncoder.h"
|
|
#include "dawn/native/CommandValidation.h"
|
|
#include "dawn/native/Commands.h"
|
|
#include "dawn/native/ExternalTexture.h"
|
|
#include "dawn/native/RenderBundle.h"
|
|
#include "dawn/native/VertexFormat.h"
|
|
#include "dawn/native/d3d/D3DError.h"
|
|
#include "dawn/native/d3d11/BindGroupTrackerD3D11.h"
|
|
#include "dawn/native/d3d11/BufferD3D11.h"
|
|
#include "dawn/native/d3d11/ComputePipelineD3D11.h"
|
|
#include "dawn/native/d3d11/DeviceD3D11.h"
|
|
#include "dawn/native/d3d11/Forward.h"
|
|
#include "dawn/native/d3d11/RenderPipelineD3D11.h"
|
|
#include "dawn/native/d3d11/TextureD3D11.h"
|
|
#include "dawn/native/d3d11/UtilsD3D11.h"
|
|
|
|
namespace dawn::native::d3d11 {
|
|
namespace {
|
|
|
|
DXGI_FORMAT DXGIIndexFormat(wgpu::IndexFormat format) {
|
|
switch (format) {
|
|
case wgpu::IndexFormat::Uint16:
|
|
return DXGI_FORMAT_R16_UINT;
|
|
case wgpu::IndexFormat::Uint32:
|
|
return DXGI_FORMAT_R32_UINT;
|
|
default:
|
|
UNREACHABLE();
|
|
}
|
|
}
|
|
|
|
} // namespace
|
|
|
|
// Create CommandBuffer
|
|
Ref<CommandBuffer> CommandBuffer::Create(CommandEncoder* encoder,
|
|
const CommandBufferDescriptor* descriptor) {
|
|
return AcquireRef(new CommandBuffer(encoder, descriptor));
|
|
}
|
|
|
|
MaybeError CommandBuffer::Execute() {
|
|
CommandRecordingContext* commandContext = ToBackend(GetDevice())->GetPendingCommandContext();
|
|
|
|
auto LazyClearSyncScope = [commandContext](const SyncScopeResourceUsage& scope) -> MaybeError {
|
|
for (size_t i = 0; i < scope.textures.size(); i++) {
|
|
Texture* texture = ToBackend(scope.textures[i]);
|
|
|
|
// Clear subresources that are not render attachments. Render attachments will be
|
|
// cleared in RecordBeginRenderPass by setting the loadop to clear when the texture
|
|
// subresource has not been initialized before the render pass.
|
|
DAWN_TRY(scope.textureUsages[i].Iterate([&](const SubresourceRange& range,
|
|
wgpu::TextureUsage usage) -> MaybeError {
|
|
if (usage & ~wgpu::TextureUsage::RenderAttachment) {
|
|
DAWN_TRY(texture->EnsureSubresourceContentInitialized(commandContext, range));
|
|
}
|
|
return {};
|
|
}));
|
|
}
|
|
|
|
for (BufferBase* buffer : scope.buffers) {
|
|
DAWN_TRY(ToBackend(buffer)->EnsureDataInitialized(commandContext));
|
|
}
|
|
|
|
return {};
|
|
};
|
|
|
|
size_t nextComputePassNumber = 0;
|
|
size_t nextRenderPassNumber = 0;
|
|
|
|
Command type;
|
|
while (mCommands.NextCommandId(&type)) {
|
|
switch (type) {
|
|
case Command::BeginComputePass: {
|
|
mCommands.NextCommand<BeginComputePassCmd>();
|
|
for (const SyncScopeResourceUsage& scope :
|
|
GetResourceUsages().computePasses[nextComputePassNumber].dispatchUsages) {
|
|
DAWN_TRY(LazyClearSyncScope(scope));
|
|
}
|
|
DAWN_TRY(ExecuteComputePass(commandContext));
|
|
|
|
nextComputePassNumber++;
|
|
break;
|
|
}
|
|
|
|
case Command::BeginRenderPass: {
|
|
auto* cmd = mCommands.NextCommand<BeginRenderPassCmd>();
|
|
DAWN_TRY(
|
|
LazyClearSyncScope(GetResourceUsages().renderPasses[nextRenderPassNumber]));
|
|
LazyClearRenderPassAttachments(cmd);
|
|
DAWN_TRY(ExecuteRenderPass(cmd, commandContext));
|
|
|
|
nextRenderPassNumber++;
|
|
break;
|
|
}
|
|
|
|
case Command::CopyBufferToBuffer: {
|
|
CopyBufferToBufferCmd* copy = mCommands.NextCommand<CopyBufferToBufferCmd>();
|
|
if (copy->size == 0) {
|
|
// Skip no-op copies.
|
|
break;
|
|
}
|
|
|
|
Buffer* source = ToBackend(copy->source.Get());
|
|
Buffer* destination = ToBackend(copy->destination.Get());
|
|
|
|
// Buffer::Copy() will ensure the source and destination buffers are initialized.
|
|
DAWN_TRY(Buffer::Copy(commandContext, source, copy->sourceOffset, copy->size,
|
|
destination, copy->destinationOffset));
|
|
source->MarkUsedInPendingCommands();
|
|
destination->MarkUsedInPendingCommands();
|
|
break;
|
|
}
|
|
|
|
case Command::CopyBufferToTexture: {
|
|
CopyBufferToTextureCmd* copy = mCommands.NextCommand<CopyBufferToTextureCmd>();
|
|
if (copy->copySize.width == 0 || copy->copySize.height == 0 ||
|
|
copy->copySize.depthOrArrayLayers == 0) {
|
|
// Skip no-op copies.
|
|
continue;
|
|
}
|
|
|
|
auto& src = copy->source;
|
|
auto& dst = copy->destination;
|
|
|
|
Buffer* buffer = ToBackend(src.buffer.Get());
|
|
uint64_t bufferOffset = src.offset;
|
|
Ref<BufferBase> stagingBuffer;
|
|
// If the buffer is not mappable, we need to create a staging buffer and copy the
|
|
// data from the buffer to the staging buffer.
|
|
if (!(buffer->GetUsage() & kMappableBufferUsages)) {
|
|
const TexelBlockInfo& blockInfo =
|
|
ToBackend(dst.texture)->GetFormat().GetAspectInfo(dst.aspect).block;
|
|
// TODO(dawn:1768): use compute shader to copy data from buffer to texture.
|
|
BufferDescriptor desc;
|
|
DAWN_TRY_ASSIGN(desc.size,
|
|
ComputeRequiredBytesInCopy(blockInfo, copy->copySize,
|
|
src.bytesPerRow, src.rowsPerImage));
|
|
desc.usage = wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::MapRead;
|
|
DAWN_TRY_ASSIGN(stagingBuffer, GetDevice()->CreateBuffer(&desc));
|
|
|
|
DAWN_TRY(Buffer::Copy(commandContext, buffer, src.offset,
|
|
stagingBuffer->GetSize(), ToBackend(stagingBuffer.Get()),
|
|
0));
|
|
buffer = ToBackend(stagingBuffer.Get());
|
|
bufferOffset = 0;
|
|
}
|
|
|
|
Buffer::ScopedMap scopedMap;
|
|
DAWN_TRY_ASSIGN(scopedMap, Buffer::ScopedMap::Create(buffer));
|
|
DAWN_TRY(buffer->EnsureDataInitialized(commandContext));
|
|
|
|
Texture* texture = ToBackend(dst.texture.Get());
|
|
SubresourceRange subresources = GetSubresourcesAffectedByCopy(dst, copy->copySize);
|
|
|
|
DAWN_ASSERT(scopedMap.GetMappedData());
|
|
const uint8_t* data = scopedMap.GetMappedData() + bufferOffset;
|
|
DAWN_TRY(texture->Write(commandContext, subresources, dst.origin, copy->copySize,
|
|
data, src.bytesPerRow, src.rowsPerImage));
|
|
|
|
buffer->MarkUsedInPendingCommands();
|
|
break;
|
|
}
|
|
|
|
case Command::CopyTextureToBuffer: {
|
|
CopyTextureToBufferCmd* copy = mCommands.NextCommand<CopyTextureToBufferCmd>();
|
|
if (copy->copySize.width == 0 || copy->copySize.height == 0 ||
|
|
copy->copySize.depthOrArrayLayers == 0) {
|
|
// Skip no-op copies.
|
|
continue;
|
|
}
|
|
|
|
auto& src = copy->source;
|
|
auto& dst = copy->destination;
|
|
|
|
SubresourceRange subresources = GetSubresourcesAffectedByCopy(src, copy->copySize);
|
|
|
|
Buffer* buffer = ToBackend(dst.buffer.Get());
|
|
Buffer::ScopedMap scopedDstMap;
|
|
DAWN_TRY_ASSIGN(scopedDstMap, Buffer::ScopedMap::Create(buffer));
|
|
|
|
Texture::ReadCallback callback;
|
|
if (scopedDstMap.GetMappedData()) {
|
|
callback = [&](const uint8_t* data, uint64_t offset,
|
|
uint64_t size) -> MaybeError {
|
|
memcpy(scopedDstMap.GetMappedData() + dst.offset + offset, data, size);
|
|
return {};
|
|
};
|
|
} else {
|
|
callback = [&](const uint8_t* data, uint64_t offset,
|
|
uint64_t size) -> MaybeError {
|
|
DAWN_TRY(ToBackend(dst.buffer)
|
|
->Write(commandContext, dst.offset + offset, data, size));
|
|
return {};
|
|
};
|
|
}
|
|
|
|
DAWN_TRY(ToBackend(src.texture)
|
|
->Read(commandContext, subresources, src.origin, copy->copySize,
|
|
dst.bytesPerRow, dst.rowsPerImage, callback));
|
|
|
|
dst.buffer->MarkUsedInPendingCommands();
|
|
break;
|
|
}
|
|
|
|
case Command::CopyTextureToTexture: {
|
|
CopyTextureToTextureCmd* copy = mCommands.NextCommand<CopyTextureToTextureCmd>();
|
|
if (copy->copySize.width == 0 || copy->copySize.height == 0 ||
|
|
copy->copySize.depthOrArrayLayers == 0) {
|
|
// Skip no-op copies.
|
|
continue;
|
|
}
|
|
|
|
DAWN_TRY(Texture::Copy(commandContext, copy));
|
|
break;
|
|
}
|
|
|
|
case Command::ClearBuffer: {
|
|
ClearBufferCmd* cmd = mCommands.NextCommand<ClearBufferCmd>();
|
|
if (cmd->size == 0) {
|
|
// Skip no-op fills.
|
|
break;
|
|
}
|
|
Buffer* buffer = ToBackend(cmd->buffer.Get());
|
|
DAWN_TRY(buffer->Clear(commandContext, 0, cmd->offset, cmd->size));
|
|
buffer->MarkUsedInPendingCommands();
|
|
break;
|
|
}
|
|
|
|
case Command::ResolveQuerySet: {
|
|
return DAWN_UNIMPLEMENTED_ERROR("ResolveQuerySet unimplemented");
|
|
}
|
|
|
|
case Command::WriteTimestamp: {
|
|
return DAWN_UNIMPLEMENTED_ERROR("WriteTimestamp unimplemented");
|
|
}
|
|
|
|
case Command::WriteBuffer: {
|
|
WriteBufferCmd* cmd = mCommands.NextCommand<WriteBufferCmd>();
|
|
if (cmd->size == 0) {
|
|
// Skip no-op writes.
|
|
continue;
|
|
}
|
|
|
|
Buffer* dstBuffer = ToBackend(cmd->buffer.Get());
|
|
uint8_t* data = mCommands.NextData<uint8_t>(cmd->size);
|
|
DAWN_TRY(dstBuffer->Write(commandContext, cmd->offset, data, cmd->size));
|
|
dstBuffer->MarkUsedInPendingCommands();
|
|
|
|
break;
|
|
}
|
|
|
|
case Command::InsertDebugMarker:
|
|
case Command::PopDebugGroup:
|
|
case Command::PushDebugGroup: {
|
|
HandleDebugCommands(commandContext, type);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
return DAWN_FORMAT_INTERNAL_ERROR("Unknown command type: %d", type);
|
|
}
|
|
}
|
|
|
|
return {};
|
|
}
|
|
|
|
MaybeError CommandBuffer::ExecuteComputePass(CommandRecordingContext* commandContext) {
|
|
ComputePipeline* lastPipeline = nullptr;
|
|
BindGroupTracker bindGroupTracker(commandContext);
|
|
|
|
Command type;
|
|
while (mCommands.NextCommandId(&type)) {
|
|
switch (type) {
|
|
case Command::EndComputePass: {
|
|
mCommands.NextCommand<EndComputePassCmd>();
|
|
return {};
|
|
}
|
|
|
|
case Command::Dispatch: {
|
|
DispatchCmd* dispatch = mCommands.NextCommand<DispatchCmd>();
|
|
|
|
DAWN_TRY(bindGroupTracker.Apply());
|
|
|
|
DAWN_TRY(RecordNumWorkgroupsForDispatch(lastPipeline, commandContext, dispatch));
|
|
commandContext->GetD3D11DeviceContext()->Dispatch(dispatch->x, dispatch->y,
|
|
dispatch->z);
|
|
|
|
break;
|
|
}
|
|
|
|
case Command::DispatchIndirect: {
|
|
// TODO(1716): figure how to update num workgroups builtins
|
|
DispatchIndirectCmd* dispatch = mCommands.NextCommand<DispatchIndirectCmd>();
|
|
|
|
DAWN_TRY(bindGroupTracker.Apply());
|
|
|
|
uint64_t indirectBufferOffset = dispatch->indirectOffset;
|
|
Buffer* indirectBuffer = ToBackend(dispatch->indirectBuffer.Get());
|
|
|
|
commandContext->GetD3D11DeviceContext()->DispatchIndirect(
|
|
indirectBuffer->GetD3D11Buffer(), indirectBufferOffset);
|
|
|
|
break;
|
|
}
|
|
|
|
case Command::SetComputePipeline: {
|
|
SetComputePipelineCmd* cmd = mCommands.NextCommand<SetComputePipelineCmd>();
|
|
lastPipeline = ToBackend(cmd->pipeline).Get();
|
|
lastPipeline->ApplyNow(commandContext);
|
|
bindGroupTracker.OnSetPipeline(lastPipeline);
|
|
break;
|
|
}
|
|
|
|
case Command::SetBindGroup: {
|
|
SetBindGroupCmd* cmd = mCommands.NextCommand<SetBindGroupCmd>();
|
|
|
|
uint32_t* dynamicOffsets = nullptr;
|
|
if (cmd->dynamicOffsetCount > 0) {
|
|
dynamicOffsets = mCommands.NextData<uint32_t>(cmd->dynamicOffsetCount);
|
|
}
|
|
|
|
bindGroupTracker.OnSetBindGroup(cmd->index, cmd->group.Get(),
|
|
cmd->dynamicOffsetCount, dynamicOffsets);
|
|
|
|
break;
|
|
}
|
|
|
|
case Command::WriteTimestamp: {
|
|
return DAWN_UNIMPLEMENTED_ERROR("WriteTimestamp unimplemented");
|
|
}
|
|
|
|
case Command::InsertDebugMarker:
|
|
case Command::PopDebugGroup:
|
|
case Command::PushDebugGroup: {
|
|
HandleDebugCommands(commandContext, type);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
UNREACHABLE();
|
|
}
|
|
}
|
|
|
|
// EndComputePass should have been called
|
|
UNREACHABLE();
|
|
}
|
|
|
|
MaybeError CommandBuffer::ExecuteRenderPass(BeginRenderPassCmd* renderPass,
|
|
CommandRecordingContext* commandContext) {
|
|
ID3D11DeviceContext1* d3d11DeviceContext1 = commandContext->GetD3D11DeviceContext1();
|
|
|
|
// Hold ID3D11RenderTargetView ComPtr to make attachments alive.
|
|
ityp::array<ColorAttachmentIndex, ComPtr<ID3D11RenderTargetView>, kMaxColorAttachments>
|
|
d3d11RenderTargetViews = {};
|
|
ityp::array<ColorAttachmentIndex, ID3D11RenderTargetView*, kMaxColorAttachments>
|
|
d3d11RenderTargetViewPtrs = {};
|
|
ColorAttachmentIndex attachmentCount(uint8_t(0));
|
|
for (ColorAttachmentIndex i :
|
|
IterateBitSet(renderPass->attachmentState->GetColorAttachmentsMask())) {
|
|
TextureView* colorTextureView = ToBackend(renderPass->colorAttachments[i].view.Get());
|
|
DAWN_TRY_ASSIGN(d3d11RenderTargetViews[i], colorTextureView->CreateD3D11RenderTargetView());
|
|
d3d11RenderTargetViewPtrs[i] = d3d11RenderTargetViews[i].Get();
|
|
if (renderPass->colorAttachments[i].loadOp == wgpu::LoadOp::Clear) {
|
|
std::array<float, 4> clearColor =
|
|
ConvertToFloatColor(renderPass->colorAttachments[i].clearColor);
|
|
d3d11DeviceContext1->ClearRenderTargetView(d3d11RenderTargetViews[i].Get(),
|
|
clearColor.data());
|
|
}
|
|
attachmentCount = i;
|
|
attachmentCount++;
|
|
}
|
|
|
|
ComPtr<ID3D11DepthStencilView> d3d11DepthStencilView;
|
|
if (renderPass->attachmentState->HasDepthStencilAttachment()) {
|
|
auto* attachmentInfo = &renderPass->depthStencilAttachment;
|
|
const Format& attachmentFormat = attachmentInfo->view->GetTexture()->GetFormat();
|
|
|
|
TextureView* depthStencilTextureView =
|
|
ToBackend(renderPass->depthStencilAttachment.view.Get());
|
|
DAWN_TRY_ASSIGN(d3d11DepthStencilView,
|
|
depthStencilTextureView->CreateD3D11DepthStencilView(false, false));
|
|
UINT clearFlags = 0;
|
|
if (attachmentFormat.HasDepth() &&
|
|
renderPass->depthStencilAttachment.depthLoadOp == wgpu::LoadOp::Clear) {
|
|
clearFlags |= D3D11_CLEAR_DEPTH;
|
|
}
|
|
|
|
if (attachmentFormat.HasStencil() &&
|
|
renderPass->depthStencilAttachment.stencilLoadOp == wgpu::LoadOp::Clear) {
|
|
clearFlags |= D3D11_CLEAR_STENCIL;
|
|
}
|
|
|
|
d3d11DeviceContext1->ClearDepthStencilView(d3d11DepthStencilView.Get(), clearFlags,
|
|
attachmentInfo->clearDepth,
|
|
attachmentInfo->clearStencil);
|
|
}
|
|
|
|
d3d11DeviceContext1->OMSetRenderTargets(static_cast<uint8_t>(attachmentCount),
|
|
d3d11RenderTargetViewPtrs.data(),
|
|
d3d11DepthStencilView.Get());
|
|
|
|
// Set viewport
|
|
D3D11_VIEWPORT viewport;
|
|
viewport.TopLeftX = 0;
|
|
viewport.TopLeftY = 0;
|
|
viewport.Width = renderPass->width;
|
|
viewport.Height = renderPass->height;
|
|
viewport.MinDepth = 0.0f;
|
|
viewport.MaxDepth = 1.0f;
|
|
d3d11DeviceContext1->RSSetViewports(1, &viewport);
|
|
|
|
// Set scissor
|
|
D3D11_RECT scissor;
|
|
scissor.left = 0;
|
|
scissor.top = 0;
|
|
scissor.right = renderPass->width;
|
|
scissor.bottom = renderPass->height;
|
|
d3d11DeviceContext1->RSSetScissorRects(1, &scissor);
|
|
|
|
RenderPipeline* lastPipeline = nullptr;
|
|
BindGroupTracker bindGroupTracker(commandContext);
|
|
std::array<float, 4> blendColor = {0.0f, 0.0f, 0.0f, 0.0f};
|
|
uint32_t stencilReference = 0;
|
|
|
|
auto DoRenderBundleCommand = [&](CommandIterator* iter, Command type) -> MaybeError {
|
|
switch (type) {
|
|
case Command::Draw: {
|
|
DrawCmd* draw = iter->NextCommand<DrawCmd>();
|
|
|
|
DAWN_TRY(bindGroupTracker.Apply());
|
|
DAWN_TRY(RecordFirstIndexOffset(lastPipeline, commandContext, draw->firstVertex,
|
|
draw->firstInstance));
|
|
commandContext->GetD3D11DeviceContext()->DrawInstanced(
|
|
draw->vertexCount, draw->instanceCount, draw->firstVertex, draw->firstInstance);
|
|
|
|
break;
|
|
}
|
|
|
|
case Command::DrawIndexed: {
|
|
DrawIndexedCmd* draw = iter->NextCommand<DrawIndexedCmd>();
|
|
|
|
DAWN_TRY(bindGroupTracker.Apply());
|
|
DAWN_TRY(RecordFirstIndexOffset(lastPipeline, commandContext, draw->baseVertex,
|
|
draw->firstInstance));
|
|
commandContext->GetD3D11DeviceContext()->DrawIndexedInstanced(
|
|
draw->indexCount, draw->instanceCount, draw->firstIndex, draw->baseVertex,
|
|
draw->firstInstance);
|
|
|
|
break;
|
|
}
|
|
|
|
case Command::DrawIndirect: {
|
|
// TODO(dawn:1716): figure how to setup built-in variables for indirect draw.
|
|
DrawIndirectCmd* draw = iter->NextCommand<DrawIndirectCmd>();
|
|
|
|
DAWN_TRY(bindGroupTracker.Apply());
|
|
uint64_t indirectBufferOffset = draw->indirectOffset;
|
|
Buffer* indirectBuffer = ToBackend(draw->indirectBuffer.Get());
|
|
ASSERT(indirectBuffer != nullptr);
|
|
|
|
commandContext->GetD3D11DeviceContext()->DrawInstancedIndirect(
|
|
indirectBuffer->GetD3D11Buffer(), indirectBufferOffset);
|
|
|
|
break;
|
|
}
|
|
|
|
case Command::DrawIndexedIndirect: {
|
|
// TODO(dawn:1716): figure how to setup built-in variables for indirect draw.
|
|
DrawIndexedIndirectCmd* draw = iter->NextCommand<DrawIndexedIndirectCmd>();
|
|
|
|
DAWN_TRY(bindGroupTracker.Apply());
|
|
|
|
Buffer* indirectBuffer = ToBackend(draw->indirectBuffer.Get());
|
|
ASSERT(indirectBuffer != nullptr);
|
|
|
|
commandContext->GetD3D11DeviceContext()->DrawIndexedInstancedIndirect(
|
|
indirectBuffer->GetD3D11Buffer(), draw->indirectOffset);
|
|
|
|
break;
|
|
}
|
|
|
|
case Command::SetRenderPipeline: {
|
|
SetRenderPipelineCmd* cmd = iter->NextCommand<SetRenderPipelineCmd>();
|
|
|
|
lastPipeline = ToBackend(cmd->pipeline.Get());
|
|
lastPipeline->ApplyNow(commandContext, blendColor, stencilReference);
|
|
bindGroupTracker.OnSetPipeline(lastPipeline);
|
|
|
|
break;
|
|
}
|
|
|
|
case Command::SetBindGroup: {
|
|
SetBindGroupCmd* cmd = iter->NextCommand<SetBindGroupCmd>();
|
|
|
|
uint32_t* dynamicOffsets = nullptr;
|
|
if (cmd->dynamicOffsetCount > 0) {
|
|
dynamicOffsets = iter->NextData<uint32_t>(cmd->dynamicOffsetCount);
|
|
}
|
|
bindGroupTracker.OnSetBindGroup(cmd->index, cmd->group.Get(),
|
|
cmd->dynamicOffsetCount, dynamicOffsets);
|
|
|
|
break;
|
|
}
|
|
|
|
case Command::SetIndexBuffer: {
|
|
SetIndexBufferCmd* cmd = iter->NextCommand<SetIndexBufferCmd>();
|
|
|
|
UINT indexBufferBaseOffset = cmd->offset;
|
|
DXGI_FORMAT indexBufferFormat = DXGIIndexFormat(cmd->format);
|
|
|
|
commandContext->GetD3D11DeviceContext()->IASetIndexBuffer(
|
|
ToBackend(cmd->buffer)->GetD3D11Buffer(), indexBufferFormat,
|
|
indexBufferBaseOffset);
|
|
|
|
break;
|
|
}
|
|
|
|
case Command::SetVertexBuffer: {
|
|
SetVertexBufferCmd* cmd = iter->NextCommand<SetVertexBufferCmd>();
|
|
ASSERT(lastPipeline);
|
|
const VertexBufferInfo& info = lastPipeline->GetVertexBuffer(cmd->slot);
|
|
|
|
// TODO(dawn:1705): should we set vertex back to nullptr after the draw call?
|
|
UINT slot = static_cast<uint8_t>(cmd->slot);
|
|
ID3D11Buffer* buffer = ToBackend(cmd->buffer)->GetD3D11Buffer();
|
|
UINT arrayStride = info.arrayStride;
|
|
UINT offset = cmd->offset;
|
|
commandContext->GetD3D11DeviceContext()->IASetVertexBuffers(slot, 1, &buffer,
|
|
&arrayStride, &offset);
|
|
|
|
break;
|
|
}
|
|
|
|
case Command::InsertDebugMarker:
|
|
case Command::PopDebugGroup:
|
|
case Command::PushDebugGroup: {
|
|
HandleDebugCommands(commandContext, type);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
UNREACHABLE();
|
|
break;
|
|
}
|
|
|
|
return {};
|
|
};
|
|
|
|
Command type;
|
|
while (mCommands.NextCommandId(&type)) {
|
|
switch (type) {
|
|
case Command::EndRenderPass: {
|
|
mCommands.NextCommand<EndRenderPassCmd>();
|
|
// TODO(dawn:1705): resolve MSAA
|
|
return {};
|
|
}
|
|
|
|
case Command::SetStencilReference: {
|
|
SetStencilReferenceCmd* cmd = mCommands.NextCommand<SetStencilReferenceCmd>();
|
|
stencilReference = cmd->reference;
|
|
if (lastPipeline) {
|
|
lastPipeline->ApplyDepthStencilState(commandContext, stencilReference);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case Command::SetViewport: {
|
|
SetViewportCmd* cmd = mCommands.NextCommand<SetViewportCmd>();
|
|
|
|
D3D11_VIEWPORT viewport;
|
|
viewport.TopLeftX = cmd->x;
|
|
viewport.TopLeftY = cmd->y;
|
|
viewport.Width = cmd->width;
|
|
viewport.Height = cmd->height;
|
|
viewport.MinDepth = cmd->minDepth;
|
|
viewport.MaxDepth = cmd->maxDepth;
|
|
commandContext->GetD3D11DeviceContext()->RSSetViewports(1, &viewport);
|
|
break;
|
|
}
|
|
|
|
case Command::SetScissorRect: {
|
|
SetScissorRectCmd* cmd = mCommands.NextCommand<SetScissorRectCmd>();
|
|
|
|
D3D11_RECT scissorRect = {static_cast<LONG>(cmd->x), static_cast<LONG>(cmd->y),
|
|
static_cast<LONG>(cmd->x + cmd->width),
|
|
static_cast<LONG>(cmd->y + cmd->height)};
|
|
commandContext->GetD3D11DeviceContext()->RSSetScissorRects(1, &scissorRect);
|
|
break;
|
|
}
|
|
|
|
case Command::SetBlendConstant: {
|
|
SetBlendConstantCmd* cmd = mCommands.NextCommand<SetBlendConstantCmd>();
|
|
blendColor = ConvertToFloatColor(cmd->color);
|
|
if (lastPipeline) {
|
|
lastPipeline->ApplyBlendState(commandContext, blendColor);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case Command::ExecuteBundles: {
|
|
ExecuteBundlesCmd* cmd = mCommands.NextCommand<ExecuteBundlesCmd>();
|
|
auto bundles = mCommands.NextData<Ref<RenderBundleBase>>(cmd->count);
|
|
for (uint32_t i = 0; i < cmd->count; ++i) {
|
|
CommandIterator* iter = bundles[i]->GetCommands();
|
|
iter->Reset();
|
|
while (iter->NextCommandId(&type)) {
|
|
DAWN_TRY(DoRenderBundleCommand(iter, type));
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case Command::BeginOcclusionQuery: {
|
|
return DAWN_UNIMPLEMENTED_ERROR("BeginOcclusionQuery unimplemented.");
|
|
}
|
|
|
|
case Command::EndOcclusionQuery: {
|
|
return DAWN_UNIMPLEMENTED_ERROR("EndOcclusionQuery unimplemented.");
|
|
}
|
|
|
|
case Command::WriteTimestamp:
|
|
return DAWN_UNIMPLEMENTED_ERROR("WriteTimestamp unimplemented");
|
|
|
|
default: {
|
|
DAWN_TRY(DoRenderBundleCommand(&mCommands, type));
|
|
}
|
|
}
|
|
}
|
|
|
|
// EndRenderPass should have been called
|
|
UNREACHABLE();
|
|
}
|
|
|
|
void CommandBuffer::HandleDebugCommands(CommandRecordingContext* commandContext, Command command) {
|
|
switch (command) {
|
|
case Command::InsertDebugMarker: {
|
|
InsertDebugMarkerCmd* cmd = mCommands.NextCommand<InsertDebugMarkerCmd>();
|
|
std::wstring label = UTF8ToWStr(mCommands.NextData<char>(cmd->length + 1));
|
|
commandContext->GetD3DUserDefinedAnnotation()->SetMarker(label.c_str());
|
|
break;
|
|
}
|
|
|
|
case Command::PopDebugGroup: {
|
|
std::ignore = mCommands.NextCommand<PopDebugGroupCmd>();
|
|
commandContext->GetD3DUserDefinedAnnotation()->EndEvent();
|
|
break;
|
|
}
|
|
|
|
case Command::PushDebugGroup: {
|
|
PushDebugGroupCmd* cmd = mCommands.NextCommand<PushDebugGroupCmd>();
|
|
std::wstring label = UTF8ToWStr(mCommands.NextData<char>(cmd->length + 1));
|
|
commandContext->GetD3DUserDefinedAnnotation()->BeginEvent(label.c_str());
|
|
break;
|
|
}
|
|
default:
|
|
UNREACHABLE();
|
|
}
|
|
}
|
|
|
|
MaybeError CommandBuffer::RecordFirstIndexOffset(RenderPipeline* renderPipeline,
|
|
CommandRecordingContext* commandContext,
|
|
uint32_t firstVertex,
|
|
uint32_t firstInstance) {
|
|
if (!renderPipeline->GetUsesVertexOrInstanceIndex()) {
|
|
// Vertex and instance index are not used in shader, so we don't need to update the uniform
|
|
// buffer. The original value in the uniform buffer will not be used, so we don't need to
|
|
// clear it.
|
|
return {};
|
|
}
|
|
|
|
// TODO(dawn:1705): only update the uniform buffer when the value changes.
|
|
uint32_t data[4] = {
|
|
firstVertex,
|
|
firstInstance,
|
|
};
|
|
DAWN_TRY(commandContext->GetUniformBuffer()->Write(commandContext, 0, data, sizeof(data)));
|
|
|
|
return {};
|
|
}
|
|
|
|
MaybeError CommandBuffer::RecordNumWorkgroupsForDispatch(ComputePipeline* computePipeline,
|
|
CommandRecordingContext* commandContext,
|
|
DispatchCmd* dispatchCmd) {
|
|
// TODO(dawn:1705): only update the uniform buffer when the value changes.
|
|
uint32_t data[4] = {
|
|
dispatchCmd->x,
|
|
dispatchCmd->y,
|
|
dispatchCmd->z,
|
|
};
|
|
DAWN_TRY(commandContext->GetUniformBuffer()->Write(commandContext, 0, data, sizeof(data)));
|
|
|
|
return {};
|
|
}
|
|
|
|
} // namespace dawn::native::d3d11
|