diff --git a/src/dawn/native/BUILD.gn b/src/dawn/native/BUILD.gn index de52c673b3..17448d9752 100644 --- a/src/dawn/native/BUILD.gn +++ b/src/dawn/native/BUILD.gn @@ -435,6 +435,8 @@ source_set("sources") { "d3d11/BindGroupLayoutD3D11.h", "d3d11/BufferD3D11.cpp", "d3d11/BufferD3D11.h", + "d3d11/CommandBufferD3D11.cpp", + "d3d11/CommandBufferD3D11.h", "d3d11/CommandRecordingContextD3D11.cpp", "d3d11/CommandRecordingContextD3D11.h", "d3d11/ComputePipelineD3D11.cpp", diff --git a/src/dawn/native/CMakeLists.txt b/src/dawn/native/CMakeLists.txt index 3c60795b65..2f80cbec2a 100644 --- a/src/dawn/native/CMakeLists.txt +++ b/src/dawn/native/CMakeLists.txt @@ -292,6 +292,8 @@ if (DAWN_ENABLE_D3D11) "d3d11/BindGroupLayoutD3D11.h" "d3d11/BufferD3D11.cpp" "d3d11/BufferD3D11.h" + "d3d11/CommandBufferD3D11.cpp" + "d3d11/CommandBufferD3D11.h" "d3d11/CommandRecordingContextD3D11.cpp" "d3d11/CommandRecordingContextD3D11.h" "d3d11/ComputePipelineD3D11.cpp" diff --git a/src/dawn/native/d3d11/BufferD3D11.cpp b/src/dawn/native/d3d11/BufferD3D11.cpp index 260f89c271..bbeb2cbefd 100644 --- a/src/dawn/native/d3d11/BufferD3D11.cpp +++ b/src/dawn/native/d3d11/BufferD3D11.cpp @@ -471,18 +471,18 @@ MaybeError Buffer::WriteInternal(CommandRecordingContext* commandContext, return {}; } -MaybeError Buffer::CopyFromBuffer(CommandRecordingContext* commandContext, - uint64_t offset, - size_t size, - Buffer* source, - uint64_t sourceOffset) { - if (size == 0) { - // Skip no-op copies. - return {}; - } +// static +MaybeError Buffer::Copy(CommandRecordingContext* commandContext, + Buffer* source, + uint64_t sourceOffset, + size_t size, + Buffer* destination, + uint64_t destinationOffset) { + DAWN_ASSERT(size != 0); DAWN_TRY(source->EnsureDataInitialized(commandContext)); - DAWN_TRY(EnsureDataInitializedAsDestination(commandContext, offset, size)); + DAWN_TRY( + destination->EnsureDataInitializedAsDestination(commandContext, destinationOffset, size)); D3D11_BOX srcBox; srcBox.left = sourceOffset; @@ -492,8 +492,9 @@ MaybeError Buffer::CopyFromBuffer(CommandRecordingContext* commandContext, srcBox.front = 0; srcBox.back = 1; commandContext->GetD3D11DeviceContext()->CopySubresourceRegion( - GetD3D11Buffer(), /*DstSubresource=*/0, /*DstX=*/offset, /*DstY=*/0, /*DstZ=*/0, - source->GetD3D11Buffer(), /*SrcSubresource=*/0, &srcBox); + destination->mD3d11Buffer.Get(), /*DstSubresource=*/0, /*DstX=*/destinationOffset, + /*DstY=*/0, + /*DstZ=*/0, source->mD3d11Buffer.Get(), /*SrcSubresource=*/0, &srcBox); return {}; } diff --git a/src/dawn/native/d3d11/BufferD3D11.h b/src/dawn/native/d3d11/BufferD3D11.h index e85fc87f51..d8633179cb 100644 --- a/src/dawn/native/d3d11/BufferD3D11.h +++ b/src/dawn/native/d3d11/BufferD3D11.h @@ -56,11 +56,13 @@ class Buffer final : public BufferBase { uint64_t offset, const void* data, size_t size); - MaybeError CopyFromBuffer(CommandRecordingContext* commandContext, - uint64_t offset, - size_t size, - Buffer* source, - uint64_t sourceOffset); + + static MaybeError Copy(CommandRecordingContext* commandContext, + Buffer* source, + uint64_t sourceOffset, + size_t size, + Buffer* destination, + uint64_t destinationOffset); class ScopedMap : public NonCopyable { public: diff --git a/src/dawn/native/d3d11/CommandBufferD3D11.cpp b/src/dawn/native/d3d11/CommandBufferD3D11.cpp new file mode 100644 index 0000000000..e0e28ddf9b --- /dev/null +++ b/src/dawn/native/d3d11/CommandBufferD3D11.cpp @@ -0,0 +1,269 @@ +// 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 +#include +#include +#include + +#include "dawn/common/WindowsUtils.h" +#include "dawn/native/BindGroup.h" +#include "dawn/native/BindGroupTracker.h" +#include "dawn/native/CommandEncoder.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/BufferD3D11.h" +#include "dawn/native/d3d11/ComputePipelineD3D11.h" +#include "dawn/native/d3d11/DeviceD3D11.h" +#include "dawn/native/d3d11/Forward.h" +#include "dawn/native/d3d11/PipelineLayoutD3D11.h" +#include "dawn/native/d3d11/RenderPipelineD3D11.h" +#include "dawn/native/d3d11/SamplerD3D11.h" +#include "dawn/native/d3d11/TextureD3D11.h" +#include "dawn/native/d3d11/UtilsD3D11.h" + +namespace dawn::native::d3d11 { + +// Create CommandBuffer +Ref CommandBuffer::Create(CommandEncoder* encoder, + const CommandBufferDescriptor* descriptor) { + return AcquireRef(new CommandBuffer(encoder, descriptor)); +} + +MaybeError CommandBuffer::Execute() { + CommandRecordingContext* commandContext = ToBackend(GetDevice())->GetPendingCommandContext(); + + ID3D11DeviceContext1* d3d11DeviceContext1 = commandContext->GetD3D11DeviceContext1(); + + Command type; + while (mCommands.NextCommandId(&type)) { + switch (type) { + case Command::BeginComputePass: { + mCommands.NextCommand(); + return DAWN_UNIMPLEMENTED_ERROR("Compute pass not implemented"); + } + + case Command::BeginRenderPass: { + [[maybe_unused]] auto* cmd = mCommands.NextCommand(); + return DAWN_UNIMPLEMENTED_ERROR("Render pass not implemented"); + } + + case Command::CopyBufferToBuffer: { + CopyBufferToBufferCmd* copy = mCommands.NextCommand(); + 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)); + break; + } + + case Command::CopyBufferToTexture: { + CopyBufferToTextureCmd* copy = mCommands.NextCommand(); + if (copy->copySize.width == 0 || copy->copySize.height == 0 || + copy->copySize.depthOrArrayLayers == 0) { + // Skip no-op copies. + continue; + } + + Buffer* buffer = ToBackend(copy->source.buffer.Get()); + Buffer::ScopedMap scopedMap; + DAWN_TRY_ASSIGN(scopedMap, Buffer::ScopedMap::Create(buffer)); + DAWN_TRY(buffer->EnsureDataInitialized(commandContext)); + + if (!scopedMap.GetMappedData()) { + // TODO(dawn:1768): implement CopyBufferToTexture with non-mappable buffers. + return DAWN_UNIMPLEMENTED_ERROR( + "CopyBufferToTexture isn't implemented with non-mappable buffers"); + } + + Texture* texture = ToBackend(copy->destination.texture.Get()); + SubresourceRange subresources = + GetSubresourcesAffectedByCopy(copy->destination, copy->copySize); + const uint8_t* data = scopedMap.GetMappedData() + copy->source.offset; + + DAWN_TRY(texture->Write(commandContext, subresources, copy->destination.origin, + copy->copySize, data, copy->source.bytesPerRow, + copy->source.rowsPerImage)); + break; + } + + case Command::CopyTextureToBuffer: { + CopyTextureToBufferCmd* copy = mCommands.NextCommand(); + 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); + DAWN_TRY(ToBackend(src.texture) + ->EnsureSubresourceContentInitialized(commandContext, subresources)); + + // Create a staging texture. + D3D11_TEXTURE2D_DESC stagingTextureDesc; + stagingTextureDesc.Width = copy->copySize.width; + stagingTextureDesc.Height = copy->copySize.height; + stagingTextureDesc.MipLevels = 1; + stagingTextureDesc.ArraySize = copy->copySize.depthOrArrayLayers; + stagingTextureDesc.Format = ToBackend(src.texture)->GetD3D11Format(); + stagingTextureDesc.SampleDesc.Count = 1; + stagingTextureDesc.SampleDesc.Quality = 0; + stagingTextureDesc.Usage = D3D11_USAGE_STAGING; + stagingTextureDesc.BindFlags = 0; + stagingTextureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + stagingTextureDesc.MiscFlags = 0; + + ComPtr stagingTexture; + DAWN_TRY(CheckHRESULT(commandContext->GetD3D11Device()->CreateTexture2D( + &stagingTextureDesc, nullptr, &stagingTexture), + "D3D11 create staging texture")); + + uint32_t subresource = + src.texture->GetSubresourceIndex(src.mipLevel, src.origin.z, src.aspect); + + if (src.texture->GetDimension() != wgpu::TextureDimension::e2D) { + return DAWN_UNIMPLEMENTED_ERROR( + "CopyTextureToBuffer is not implemented for non-2D textures"); + } else { + for (uint32_t z = 0; z < copy->copySize.depthOrArrayLayers; ++z) { + // Copy the texture to the staging texture. + if (src.texture->GetFormat().HasDepthOrStencil()) { + d3d11DeviceContext1->CopySubresourceRegion( + stagingTexture.Get(), z, 0, 0, 0, + ToBackend(src.texture)->GetD3D11Resource(), subresource, nullptr); + } else { + D3D11_BOX srcBox; + srcBox.left = src.origin.x; + srcBox.right = src.origin.x + copy->copySize.width; + srcBox.top = src.origin.y; + srcBox.bottom = src.origin.y + copy->copySize.height; + srcBox.front = 0; + srcBox.back = 1; + + d3d11DeviceContext1->CopySubresourceRegion( + stagingTexture.Get(), z, 0, 0, 0, + ToBackend(src.texture)->GetD3D11Resource(), subresource, &srcBox); + } + } + } + + for (uint32_t z = 0; z < copy->copySize.depthOrArrayLayers; ++z) { + // Copy the staging texture to the buffer. + // The Map() will block until the GPU is done with the texture. + // TODO(dawn:1705): avoid blocking the CPU. + D3D11_MAPPED_SUBRESOURCE mappedResource; + DAWN_TRY( + CheckHRESULT(d3d11DeviceContext1->Map(stagingTexture.Get(), z, + D3D11_MAP_READ, 0, &mappedResource), + "D3D11 map staging texture")); + + Buffer* buffer = ToBackend(dst.buffer.Get()); + + Buffer::ScopedMap scopedMap; + DAWN_TRY_ASSIGN(scopedMap, Buffer::ScopedMap::Create(buffer)); + DAWN_TRY(buffer->EnsureDataInitializedAsDestination( + commandContext, dst.offset, dst.bytesPerRow * copy->copySize.height)); + uint8_t* pSrcData = reinterpret_cast(mappedResource.pData); + + const TexelBlockInfo& blockInfo = + ToBackend(src.texture)->GetFormat().GetAspectInfo(src.aspect).block; + uint32_t memcpySize = blockInfo.byteSize * copy->copySize.width; + uint8_t* pDstData = scopedMap.GetMappedData() + dst.offset + + dst.bytesPerRow * dst.rowsPerImage * z; + for (uint32_t y = 0; y < copy->copySize.height; ++y) { + memcpy(pDstData, pSrcData, memcpySize); + pDstData += dst.bytesPerRow; + pSrcData += mappedResource.RowPitch; + } + d3d11DeviceContext1->Unmap(stagingTexture.Get(), z); + } + + break; + } + + case Command::CopyTextureToTexture: { + CopyTextureToTextureCmd* copy = mCommands.NextCommand(); + 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(); + 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)); + 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(); + if (cmd->size == 0) { + // Skip no-op writes. + continue; + } + + Buffer* dstBuffer = ToBackend(cmd->buffer.Get()); + uint8_t* data = mCommands.NextData(cmd->size); + DAWN_TRY(dstBuffer->Write(commandContext, cmd->offset, data, cmd->size)); + + break; + } + + case Command::InsertDebugMarker: + case Command::PopDebugGroup: + case Command::PushDebugGroup: { + return DAWN_UNIMPLEMENTED_ERROR("Debug markers unimplemented"); + } + + default: + return DAWN_FORMAT_INTERNAL_ERROR("Unknown command type: %d", type); + } + } + + return {}; +} + +} // namespace dawn::native::d3d11 diff --git a/src/dawn/native/d3d11/CommandBufferD3D11.h b/src/dawn/native/d3d11/CommandBufferD3D11.h new file mode 100644 index 0000000000..0f5e991f25 --- /dev/null +++ b/src/dawn/native/d3d11/CommandBufferD3D11.h @@ -0,0 +1,41 @@ +// 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. + +#ifndef SRC_DAWN_NATIVE_D3D11_COMMANDBUFFERD3D11_H_ +#define SRC_DAWN_NATIVE_D3D11_COMMANDBUFFERD3D11_H_ + +#include "dawn/native/CommandBuffer.h" + +namespace dawn::native { +enum class Command; +struct BeginRenderPassCmd; +} // namespace dawn::native + +namespace dawn::native::d3d11 { + +class CommandRecordingContext; + +class CommandBuffer final : public CommandBufferBase { + public: + static Ref Create(CommandEncoder* encoder, + const CommandBufferDescriptor* descriptor); + MaybeError Execute(); + + private: + using CommandBufferBase::CommandBufferBase; +}; + +} // namespace dawn::native::d3d11 + +#endif // SRC_DAWN_NATIVE_D3D11_COMMANDBUFFERD3D11_H_ diff --git a/src/dawn/native/d3d11/DeviceD3D11.cpp b/src/dawn/native/d3d11/DeviceD3D11.cpp index 1d09e97384..72be4a488a 100644 --- a/src/dawn/native/d3d11/DeviceD3D11.cpp +++ b/src/dawn/native/d3d11/DeviceD3D11.cpp @@ -20,19 +20,16 @@ #include #include "dawn/common/GPUInfo.h" -#include "dawn/native/Buffer.h" -#include "dawn/native/ComputePipeline.h" #include "dawn/native/D3D11Backend.h" #include "dawn/native/DynamicUploader.h" #include "dawn/native/Instance.h" -#include "dawn/native/RenderPipeline.h" -#include "dawn/native/Texture.h" #include "dawn/native/d3d/D3DError.h" #include "dawn/native/d3d11/AdapterD3D11.h" #include "dawn/native/d3d11/BackendD3D11.h" #include "dawn/native/d3d11/BindGroupD3D11.h" #include "dawn/native/d3d11/BindGroupLayoutD3D11.h" #include "dawn/native/d3d11/BufferD3D11.h" +#include "dawn/native/d3d11/CommandBufferD3D11.h" #include "dawn/native/d3d11/ComputePipelineD3D11.h" #include "dawn/native/d3d11/PipelineLayoutD3D11.h" #include "dawn/native/d3d11/PlatformFunctionsD3D11.h" @@ -259,7 +256,7 @@ ResultOrError> Device::CreateBufferImpl(const BufferDescriptor* ResultOrError> Device::CreateCommandBuffer( CommandEncoder* encoder, const CommandBufferDescriptor* descriptor) { - return DAWN_UNIMPLEMENTED_ERROR("CreateCommandBuffer"); + return CommandBuffer::Create(encoder, descriptor); } Ref Device::CreateUninitializedComputePipelineImpl( @@ -327,8 +324,8 @@ MaybeError Device::CopyFromStagingToBufferImpl(BufferBase* source, uint64_t destinationOffset, uint64_t size) { CommandRecordingContext* commandContext = GetPendingCommandContext(); - return ToBackend(destination) - ->CopyFromBuffer(commandContext, destinationOffset, size, ToBackend(source), sourceOffset); + return Buffer::Copy(commandContext, ToBackend(source), sourceOffset, size, + ToBackend(destination), destinationOffset); } MaybeError Device::CopyFromStagingToTextureImpl(const BufferBase* source, diff --git a/src/dawn/native/d3d11/QueueD3D11.cpp b/src/dawn/native/d3d11/QueueD3D11.cpp index 3f6676d001..e2b08bf898 100644 --- a/src/dawn/native/d3d11/QueueD3D11.cpp +++ b/src/dawn/native/d3d11/QueueD3D11.cpp @@ -15,8 +15,11 @@ #include "dawn/native/d3d11/QueueD3D11.h" #include "dawn/native/d3d11/BufferD3D11.h" +#include "dawn/native/d3d11/CommandBufferD3D11.h" #include "dawn/native/d3d11/DeviceD3D11.h" +#include "dawn/native/d3d11/TextureD3D11.h" #include "dawn/platform/DawnPlatform.h" +#include "dawn/platform/tracing/TraceEvent.h" namespace dawn::native::d3d11 { @@ -25,7 +28,17 @@ Ref Queue::Create(Device* device, const QueueDescriptor* descriptor) { } MaybeError Queue::SubmitImpl(uint32_t commandCount, CommandBufferBase* const* commands) { - return DAWN_UNIMPLEMENTED_ERROR("Submit is not implemented for D3D11"); + Device* device = ToBackend(GetDevice()); + + TRACE_EVENT_BEGIN0(GetDevice()->GetPlatform(), Recording, "CommandBufferD3D11::Execute"); + for (uint32_t i = 0; i < commandCount; ++i) { + DAWN_TRY(ToBackend(commands[i])->Execute()); + } + TRACE_EVENT_END0(GetDevice()->GetPlatform(), Recording, "CommandBufferD3D11::Execute"); + + DAWN_TRY(device->NextSerial()); + + return {}; } MaybeError Queue::WriteBufferImpl(BufferBase* buffer, @@ -40,7 +53,26 @@ MaybeError Queue::WriteTextureImpl(const ImageCopyTexture& destination, const void* data, const TextureDataLayout& dataLayout, const Extent3D& writeSizePixel) { - return DAWN_UNIMPLEMENTED_ERROR("WriteTexture is not implemented for D3D11"); + if (writeSizePixel.width == 0 || writeSizePixel.height == 0 || + writeSizePixel.depthOrArrayLayers == 0) { + return {}; + } + + CommandRecordingContext* commandContext = ToBackend(GetDevice())->GetPendingCommandContext(); + + TextureCopy textureCopy; + textureCopy.texture = destination.texture; + textureCopy.mipLevel = destination.mipLevel; + textureCopy.origin = destination.origin; + textureCopy.aspect = SelectFormatAspects(destination.texture->GetFormat(), destination.aspect); + + SubresourceRange subresources = GetSubresourcesAffectedByCopy(textureCopy, writeSizePixel); + + Texture* texture = ToBackend(destination.texture); + + return texture->Write(commandContext, subresources, destination.origin, writeSizePixel, + static_cast(data), dataLayout.bytesPerRow, + dataLayout.rowsPerImage); } } // namespace dawn::native::d3d11 diff --git a/src/dawn/native/d3d11/TextureD3D11.cpp b/src/dawn/native/d3d11/TextureD3D11.cpp index cd36cd5322..6f7a85a916 100644 --- a/src/dawn/native/d3d11/TextureD3D11.cpp +++ b/src/dawn/native/d3d11/TextureD3D11.cpp @@ -20,6 +20,7 @@ #include "dawn/common/Constants.h" #include "dawn/common/Math.h" +#include "dawn/native/CommandBuffer.h" #include "dawn/native/DynamicUploader.h" #include "dawn/native/EnumMaskIterator.h" #include "dawn/native/IntegerTypes.h" @@ -136,8 +137,7 @@ MaybeError Texture::InitializeAsInternalTexture() { if (device->IsToggleEnabled(Toggle::NonzeroClearResourcesOnCreationForTesting)) { CommandRecordingContext* commandContext = device->GetPendingCommandContext(); - DAWN_TRY( - ClearTexture(commandContext, GetAllSubresources(), TextureBase::ClearValue::NonZero)); + DAWN_TRY(Clear(commandContext, GetAllSubresources(), TextureBase::ClearValue::NonZero)); } SetLabelImpl(); @@ -261,11 +261,49 @@ D3D11_DEPTH_STENCIL_VIEW_DESC Texture::GetDSVDescriptor(const SubresourceRange& return dsvDesc; } -MaybeError Texture::ClearTexture(CommandRecordingContext* commandContext, - const SubresourceRange& range, - TextureBase::ClearValue clearValue) { - // TODO(dawn:1740): Implement this. - return DAWN_UNIMPLEMENTED_ERROR("ClearTexture"); +MaybeError Texture::Clear(CommandRecordingContext* commandContext, + const SubresourceRange& range, + TextureBase::ClearValue clearValue) { + // TODO(dawn:1740): Clear non-renderable texture. + if ((GetUsage() & wgpu::TextureUsage::RenderAttachment) == 0) { + return DAWN_UNIMPLEMENTED_ERROR("Clearing non-renderable textures is not implemented"); + } + + TextureViewDescriptor desc; + desc.format = GetFormat().format; + switch (GetDimension()) { + case wgpu::TextureDimension::e1D: + desc.dimension = wgpu::TextureViewDimension::e1D; + break; + case wgpu::TextureDimension::e2D: + desc.dimension = wgpu::TextureViewDimension::e2D; + break; + case wgpu::TextureDimension::e3D: + desc.dimension = wgpu::TextureViewDimension::e3D; + break; + } + // TODO(dawn:1740): support clearing multiple layers. + if (range.levelCount != 1 || range.layerCount != 1) { + return DAWN_UNIMPLEMENTED_ERROR("Clearing multiple layers is not implemented"); + } + + desc.baseMipLevel = range.baseMipLevel; + desc.mipLevelCount = range.levelCount; + desc.baseArrayLayer = range.baseArrayLayer; + desc.arrayLayerCount = range.layerCount; + desc.aspect = wgpu::TextureAspect::All; + + Ref view = TextureView::Create(this, &desc); + ComPtr d3d11RTV; + DAWN_TRY_ASSIGN(d3d11RTV, view->CreateD3D11RenderTargetView()); + + static constexpr std::array zero = {0.0f, 0.0f, 0.0f, 0.0f}; + static constexpr std::array nonZero = {1.0f, 1.0f, 1.0f, 1.0f}; + + commandContext->GetD3D11DeviceContext()->ClearRenderTargetView( + d3d11RTV.Get(), clearValue == TextureBase::ClearValue::Zero ? zero.data() : nonZero.data()); + + return {}; } void Texture::SetLabelHelper(const char* prefix) { @@ -284,11 +322,91 @@ MaybeError Texture::EnsureSubresourceContentInitialized(CommandRecordingContext* if (!IsSubresourceContentInitialized(range)) { // If subresource has not been initialized, clear it to black as it could contain // dirty bits from recycled memory - DAWN_TRY(ClearTexture(commandContext, range, TextureBase::ClearValue::Zero)); + DAWN_TRY(Clear(commandContext, range, TextureBase::ClearValue::Zero)); } return {}; } +MaybeError Texture::Write(CommandRecordingContext* commandContext, + const SubresourceRange& subresources, + const Origin3D& origin, + const Extent3D& size, + const uint8_t* data, + uint32_t bytesPerRow, + uint32_t rowsPerImage) { + DAWN_ASSERT(size.width != 0 && size.height != 0 && size.depthOrArrayLayers != 0); + + if (IsCompleteSubresourceCopiedTo(this, size, subresources.baseMipLevel)) { + SetIsSubresourceContentInitialized(true, subresources); + } else { + DAWN_TRY(EnsureSubresourceContentInitialized(commandContext, subresources)); + } + + D3D11_BOX dstBox; + dstBox.left = origin.x; + dstBox.right = origin.x + size.width; + dstBox.top = origin.y; + dstBox.bottom = origin.y + size.height; + + if (GetDimension() == wgpu::TextureDimension::e3D) { + dstBox.front = origin.z; + dstBox.back = origin.z + size.depthOrArrayLayers; + uint32_t subresource = + GetSubresourceIndex(subresources.baseMipLevel, origin.z, subresources.aspects); + commandContext->GetD3D11DeviceContext1()->UpdateSubresource(GetD3D11Resource(), subresource, + &dstBox, data, bytesPerRow, 0); + } else { + dstBox.front = 0; + dstBox.back = 1; + for (uint32_t z = origin.z; z < size.depthOrArrayLayers; ++z) { + uint32_t subresource = + GetSubresourceIndex(subresources.baseMipLevel, z, subresources.aspects); + commandContext->GetD3D11DeviceContext1()->UpdateSubresource( + GetD3D11Resource(), subresource, &dstBox, data, bytesPerRow, 0); + data += rowsPerImage * bytesPerRow; + } + } + + return {}; +} + +// static +MaybeError Texture::Copy(CommandRecordingContext* commandContext, CopyTextureToTextureCmd* copy) { + ASSERT(copy->copySize.width != 0 && copy->copySize.height != 0 && + copy->copySize.depthOrArrayLayers != 0); + + auto& src = copy->source; + auto& dst = copy->destination; + + SubresourceRange subresources = GetSubresourcesAffectedByCopy(src, copy->copySize); + DAWN_TRY( + ToBackend(src.texture)->EnsureSubresourceContentInitialized(commandContext, subresources)); + + subresources = GetSubresourcesAffectedByCopy(dst, copy->copySize); + if (IsCompleteSubresourceCopiedTo(dst.texture.Get(), copy->copySize, dst.mipLevel)) { + dst.texture->SetIsSubresourceContentInitialized(true, subresources); + } else { + DAWN_TRY(ToBackend(dst.texture) + ->EnsureSubresourceContentInitialized(commandContext, subresources)); + } + + D3D11_BOX srcBox; + srcBox.left = src.origin.x; + srcBox.right = src.origin.x + copy->copySize.width; + srcBox.top = src.origin.y; + srcBox.bottom = src.origin.y + copy->copySize.height; + srcBox.front = 0; + srcBox.back = 1; + + uint32_t subresource = src.texture->GetSubresourceIndex(src.mipLevel, src.origin.z, src.aspect); + + commandContext->GetD3D11DeviceContext1()->CopySubresourceRegion( + ToBackend(dst.texture)->GetD3D11Resource(), dst.mipLevel, dst.origin.x, dst.origin.y, + dst.origin.z, ToBackend(src.texture)->GetD3D11Resource(), subresource, &srcBox); + + return {}; +} + // static Ref TextureView::Create(TextureBase* texture, const TextureViewDescriptor* descriptor) { @@ -301,7 +419,7 @@ DXGI_FORMAT TextureView::GetD3D11Format() const { return d3d::DXGITextureFormat(GetFormat().format); } -ResultOrError> TextureView::GetD3D11ShaderResourceView() const { +ResultOrError> TextureView::CreateD3D11ShaderResourceView() const { Device* device = ToBackend(GetDevice()); D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; srvDesc.Format = d3d::DXGITextureFormat(GetFormat().format); @@ -436,7 +554,7 @@ ResultOrError> TextureView::GetD3D11ShaderResou return srv; } -ResultOrError> TextureView::GetD3D11RenderTargetView() const { +ResultOrError> TextureView::CreateD3D11RenderTargetView() const { D3D11_RENDER_TARGET_VIEW_DESC rtvDesc = ToBackend(GetTexture())->GetRTVDescriptor(GetFormat(), GetSubresourceRange()); ComPtr rtv; @@ -448,7 +566,7 @@ ResultOrError> TextureView::GetD3D11RenderTargetV return rtv; } -ResultOrError> TextureView::GetD3D11DepthStencilView( +ResultOrError> TextureView::CreateD3D11DepthStencilView( bool depthReadOnly, bool stencilReadOnly) const { ComPtr dsv; @@ -463,7 +581,8 @@ ResultOrError> TextureView::GetD3D11DepthStencilV return dsv; } -ResultOrError> TextureView::GetD3D11UnorderedAccessView() const { +ResultOrError> TextureView::CreateD3D11UnorderedAccessView() + const { D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc; uavDesc.Format = GetD3D11Format(); diff --git a/src/dawn/native/d3d11/TextureD3D11.h b/src/dawn/native/d3d11/TextureD3D11.h index 725e9b5c66..3eba67c158 100644 --- a/src/dawn/native/d3d11/TextureD3D11.h +++ b/src/dawn/native/d3d11/TextureD3D11.h @@ -22,6 +22,10 @@ #include "dawn/native/Texture.h" #include "dawn/native/d3d/d3d_platform.h" +namespace dawn::native { +struct CopyTextureToTextureCmd; +} // namespace dawn::native + namespace dawn::native::d3d11 { class CommandRecordingContext; @@ -48,6 +52,15 @@ class Texture final : public TextureBase { MaybeError EnsureSubresourceContentInitialized(CommandRecordingContext* commandContext, const SubresourceRange& range); + MaybeError Write(CommandRecordingContext* commandContext, + const SubresourceRange& subresources, + const Origin3D& origin, + const Extent3D& size, + const uint8_t* data, + uint32_t bytesPerRow, + uint32_t rowsPerImage); + static MaybeError Copy(CommandRecordingContext* commandContext, CopyTextureToTextureCmd* copy); + private: Texture(Device* device, const TextureDescriptor* descriptor, TextureState state); ~Texture() override; @@ -62,11 +75,9 @@ class Texture final : public TextureBase { void SetLabelImpl() override; void DestroyImpl() override; - MaybeError ClearTexture(CommandRecordingContext* commandContext, - const SubresourceRange& range, - TextureBase::ClearValue clearValue); - - MaybeError WriteTexture(); + MaybeError Clear(CommandRecordingContext* commandContext, + const SubresourceRange& range, + TextureBase::ClearValue clearValue); ComPtr mD3d11Resource; }; @@ -76,12 +87,12 @@ class TextureView final : public TextureViewBase { static Ref Create(TextureBase* texture, const TextureViewDescriptor* descriptor); DXGI_FORMAT GetD3D11Format() const; - ResultOrError> GetD3D11ShaderResourceView() const; - ResultOrError> GetD3D11RenderTargetView() const; - ResultOrError> GetD3D11DepthStencilView( + ResultOrError> CreateD3D11ShaderResourceView() const; + ResultOrError> CreateD3D11RenderTargetView() const; + ResultOrError> CreateD3D11DepthStencilView( bool depthReadOnly, bool stencilReadOnly) const; - ResultOrError> GetD3D11UnorderedAccessView() const; + ResultOrError> CreateD3D11UnorderedAccessView() const; private: using TextureViewBase::TextureViewBase; diff --git a/src/dawn/tests/end2end/BufferTests.cpp b/src/dawn/tests/end2end/BufferTests.cpp index a9b33d7ee4..1467e4f5a0 100644 --- a/src/dawn/tests/end2end/BufferTests.cpp +++ b/src/dawn/tests/end2end/BufferTests.cpp @@ -553,6 +553,7 @@ TEST_P(BufferMappingTests, RegressChromium1421170) { } DAWN_INSTANTIATE_TEST(BufferMappingTests, + D3D11Backend(), D3D12Backend(), MetalBackend(), OpenGLBackend(), @@ -633,6 +634,11 @@ TEST_P(BufferMappingCallbackTests, EmptySubmissionAndThenMap) { } TEST_P(BufferMappingCallbackTests, UseTheBufferAndThenMap) { + // TODO(dawn:1705): enable this test for D3D11. D3D11 MapAsync() calls + // ID3D11DeviceContext::Map() which will synchronize with GPU. so the callback will always be + // called earlier comparing to other backends. + DAWN_SUPPRESS_TEST_IF(IsD3D11()); + wgpu::Buffer buffer = CreateMapWriteBuffer(4); MapAsyncAndWait(buffer, wgpu::MapMode::Write, 0, wgpu::kWholeMapSize); buffer.Unmap(); @@ -672,6 +678,11 @@ TEST_P(BufferMappingCallbackTests, UseTheBufferAndThenMap) { } TEST_P(BufferMappingCallbackTests, EmptySubmissionWriteAndThenMap) { + // TODO(dawn:1705): enable this test for D3D11. D3D11 MapAsync() calls + // ID3D11DeviceContext::Map() which will synchronize with GPU. so the callback will always be + // called earlier comparing to other backends. + DAWN_SUPPRESS_TEST_IF(IsD3D11()); + wgpu::Buffer buffer = CreateMapReadBuffer(4); MapAsyncAndWait(buffer, wgpu::MapMode::Read, 0, wgpu::kWholeMapSize); buffer.Unmap(); @@ -713,7 +724,11 @@ TEST_P(BufferMappingCallbackTests, EmptySubmissionWriteAndThenMap) { buffer.Unmap(); } -DAWN_INSTANTIATE_TEST(BufferMappingCallbackTests, D3D12Backend(), MetalBackend(), VulkanBackend()); +DAWN_INSTANTIATE_TEST(BufferMappingCallbackTests, + D3D11Backend(), + D3D12Backend(), + MetalBackend(), + VulkanBackend()); class BufferMappedAtCreationTests : public DawnTest { protected: @@ -961,6 +976,7 @@ TEST_P(BufferMappedAtCreationTests, GetMappedRangeZeroSized) { } DAWN_INSTANTIATE_TEST(BufferMappedAtCreationTests, + D3D11Backend(), D3D12Backend(), D3D12Backend({}, {"use_d3d12_resource_heap_tier2"}), MetalBackend(), @@ -1111,6 +1127,7 @@ TEST_P(BufferTests, CreateBufferOOMMapAsync) { } DAWN_INSTANTIATE_TEST(BufferTests, + D3D11Backend(), D3D12Backend(), MetalBackend(), OpenGLBackend(), @@ -1143,6 +1160,7 @@ TEST_P(BufferNoSuballocationTests, WriteBufferThenDestroy) { } DAWN_INSTANTIATE_TEST(BufferNoSuballocationTests, + D3D11Backend({"disable_resource_suballocation"}), D3D12Backend({"disable_resource_suballocation"}), MetalBackend({"disable_resource_suballocation"}), OpenGLBackend({"disable_resource_suballocation"}),