d3d11: implement copy between non-mappable buffer and texture

Also enable TextureFormatTest

Bug: dawn:1768
Change-Id: I7bf54e05cd8510c28ea57304d084b93386d6c502
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/128340
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Peng Huang <penghuang@chromium.org>
This commit is contained in:
Peng Huang 2023-04-24 16:21:47 +00:00 committed by Dawn LUCI CQ
parent 378a1f51a2
commit 0c33c143dc
4 changed files with 78 additions and 38 deletions

View File

@ -59,9 +59,7 @@ MaybeError ValidationUsage(wgpu::BufferUsage usage) {
// ID3D11DeviceContext::CopyResource for these copy operations. // ID3D11DeviceContext::CopyResource for these copy operations.
bool IsMappable(wgpu::BufferUsage usage) { bool IsMappable(wgpu::BufferUsage usage) {
constexpr wgpu::BufferUsage kMapUsages = return usage & kMappableBufferUsages;
wgpu::BufferUsage::MapRead | wgpu::BufferUsage::MapWrite;
return usage & kMapUsages;
} }
D3D11_USAGE D3D11BufferUsage(wgpu::BufferUsage usage) { D3D11_USAGE D3D11BufferUsage(wgpu::BufferUsage usage) {

View File

@ -23,6 +23,7 @@
#include "dawn/native/BindGroup.h" #include "dawn/native/BindGroup.h"
#include "dawn/native/BindGroupTracker.h" #include "dawn/native/BindGroupTracker.h"
#include "dawn/native/CommandEncoder.h" #include "dawn/native/CommandEncoder.h"
#include "dawn/native/CommandValidation.h"
#include "dawn/native/Commands.h" #include "dawn/native/Commands.h"
#include "dawn/native/ExternalTexture.h" #include "dawn/native/ExternalTexture.h"
#include "dawn/native/RenderBundle.h" #include "dawn/native/RenderBundle.h"
@ -309,25 +310,44 @@ MaybeError CommandBuffer::Execute() {
continue; continue;
} }
Buffer* buffer = ToBackend(copy->source.buffer.Get()); 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; Buffer::ScopedMap scopedMap;
DAWN_TRY_ASSIGN(scopedMap, Buffer::ScopedMap::Create(buffer)); DAWN_TRY_ASSIGN(scopedMap, Buffer::ScopedMap::Create(buffer));
DAWN_TRY(buffer->EnsureDataInitialized(commandContext)); DAWN_TRY(buffer->EnsureDataInitialized(commandContext));
if (!scopedMap.GetMappedData()) { Texture* texture = ToBackend(dst.texture.Get());
// TODO(dawn:1768): implement CopyBufferToTexture with non-mappable buffers. SubresourceRange subresources = GetSubresourcesAffectedByCopy(dst, copy->copySize);
return DAWN_UNIMPLEMENTED_ERROR(
"CopyBufferToTexture isn't implemented with non-mappable buffers");
}
Texture* texture = ToBackend(copy->destination.texture.Get()); DAWN_ASSERT(scopedMap.GetMappedData());
SubresourceRange subresources = const uint8_t* data = scopedMap.GetMappedData() + bufferOffset;
GetSubresourcesAffectedByCopy(copy->destination, copy->copySize); DAWN_TRY(texture->Write(commandContext, subresources, dst.origin, copy->copySize,
const uint8_t* data = scopedMap.GetMappedData() + copy->source.offset; data, src.bytesPerRow, src.rowsPerImage));
DAWN_TRY(texture->Write(commandContext, subresources, copy->destination.origin,
copy->copySize, data, copy->source.bytesPerRow,
copy->source.rowsPerImage));
buffer->MarkUsedInPendingCommands(); buffer->MarkUsedInPendingCommands();
break; break;
} }
@ -348,6 +368,7 @@ MaybeError CommandBuffer::Execute() {
->EnsureSubresourceContentInitialized(commandContext, subresources)); ->EnsureSubresourceContentInitialized(commandContext, subresources));
// Create a staging texture. // Create a staging texture.
// TODO(dawn:1768): use compute shader to copy data from texture to buffer.
D3D11_TEXTURE2D_DESC stagingTextureDesc; D3D11_TEXTURE2D_DESC stagingTextureDesc;
stagingTextureDesc.Width = copy->copySize.width; stagingTextureDesc.Width = copy->copySize.width;
stagingTextureDesc.Height = copy->copySize.height; stagingTextureDesc.Height = copy->copySize.height;
@ -395,6 +416,12 @@ MaybeError CommandBuffer::Execute() {
} }
} }
Buffer* buffer = ToBackend(dst.buffer.Get());
Buffer::ScopedMap scopedDstMap;
DAWN_TRY_ASSIGN(scopedDstMap, Buffer::ScopedMap::Create(buffer));
DAWN_TRY(buffer->EnsureDataInitializedAsDestination(commandContext, copy));
for (uint32_t z = 0; z < copy->copySize.depthOrArrayLayers; ++z) { for (uint32_t z = 0; z < copy->copySize.depthOrArrayLayers; ++z) {
// Copy the staging texture to the buffer. // Copy the staging texture to the buffer.
// The Map() will block until the GPU is done with the texture. // The Map() will block until the GPU is done with the texture.
@ -405,24 +432,36 @@ MaybeError CommandBuffer::Execute() {
D3D11_MAP_READ, 0, &mappedResource), D3D11_MAP_READ, 0, &mappedResource),
"D3D11 map staging texture")); "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<uint8_t*>(mappedResource.pData); uint8_t* pSrcData = reinterpret_cast<uint8_t*>(mappedResource.pData);
const TexelBlockInfo& blockInfo = const TexelBlockInfo& blockInfo =
ToBackend(src.texture)->GetFormat().GetAspectInfo(src.aspect).block; ToBackend(src.texture)->GetFormat().GetAspectInfo(src.aspect).block;
uint32_t memcpySize = blockInfo.byteSize * copy->copySize.width; uint32_t bytesPerRow = blockInfo.byteSize * copy->copySize.width;
uint8_t* pDstData = scopedMap.GetMappedData() + dst.offset + if (scopedDstMap.GetMappedData()) {
uint8_t* pDstData = scopedDstMap.GetMappedData() + dst.offset +
dst.bytesPerRow * dst.rowsPerImage * z; dst.bytesPerRow * dst.rowsPerImage * z;
for (uint32_t y = 0; y < copy->copySize.height; ++y) { for (uint32_t y = 0; y < copy->copySize.height; ++y) {
memcpy(pDstData, pSrcData, memcpySize); memcpy(pDstData, pSrcData, bytesPerRow);
pDstData += dst.bytesPerRow; pDstData += dst.bytesPerRow;
pSrcData += mappedResource.RowPitch; pSrcData += mappedResource.RowPitch;
} }
} else {
uint64_t dstOffset = dst.offset + dst.bytesPerRow * dst.rowsPerImage * z;
if (dst.bytesPerRow == bytesPerRow &&
mappedResource.RowPitch == bytesPerRow) {
// If there is no padding in the rows, we can upload the whole image in
// one buffer->Write() call.
DAWN_TRY(buffer->Write(commandContext, dstOffset, pSrcData,
dst.bytesPerRow * copy->copySize.height));
} else {
// Otherwise, we need to upload each row separately.
for (uint32_t y = 0; y < copy->copySize.height; ++y) {
DAWN_TRY(buffer->Write(commandContext, dstOffset, pSrcData,
bytesPerRow));
dstOffset += dst.bytesPerRow;
pSrcData += mappedResource.RowPitch;
}
}
}
d3d11DeviceContext1->Unmap(stagingTexture.Get(), z); d3d11DeviceContext1->Unmap(stagingTexture.Get(), z);
} }
@ -893,12 +932,11 @@ MaybeError CommandBuffer::RecordFirstIndexOffset(RenderPipeline* renderPipeline,
} }
// TODO(dawn:1705): only update the uniform buffer when the value changes. // TODO(dawn:1705): only update the uniform buffer when the value changes.
uint32_t offsets[] = { uint32_t data[4] = {
firstVertex, firstVertex,
firstInstance, firstInstance,
}; };
DAWN_TRY( DAWN_TRY(commandContext->GetUniformBuffer()->Write(commandContext, 0, data, sizeof(data)));
commandContext->GetUniformBuffer()->Write(commandContext, 0, offsets, sizeof(offsets)));
return {}; return {};
} }
@ -907,9 +945,12 @@ MaybeError CommandBuffer::RecordNumWorkgroupsForDispatch(ComputePipeline* comput
CommandRecordingContext* commandContext, CommandRecordingContext* commandContext,
DispatchCmd* dispatchCmd) { DispatchCmd* dispatchCmd) {
// TODO(dawn:1705): only update the uniform buffer when the value changes. // TODO(dawn:1705): only update the uniform buffer when the value changes.
static_assert(sizeof(DispatchCmd) == sizeof(uint32_t[3])); uint32_t data[4] = {
DAWN_TRY(commandContext->GetUniformBuffer()->Write(commandContext, 0, dispatchCmd, dispatchCmd->x,
sizeof(*dispatchCmd))); dispatchCmd->y,
dispatchCmd->z,
};
DAWN_TRY(commandContext->GetUniformBuffer()->Write(commandContext, 0, data, sizeof(data)));
return {}; return {};
} }

View File

@ -46,10 +46,10 @@ MaybeError CommandRecordingContext::Open(Device* device) {
d3d11DeviceContext4.As(&mD3D11UserDefinedAnnotation), d3d11DeviceContext4.As(&mD3D11UserDefinedAnnotation),
"D3D11 querying immediate context for ID3DUserDefinedAnnotation interface")); "D3D11 querying immediate context for ID3DUserDefinedAnnotation interface"));
constexpr size_t kMaxNumBuiltinElements = 3;
// Create a uniform buffer for built in variables. // Create a uniform buffer for built in variables.
BufferDescriptor descriptor; BufferDescriptor descriptor;
// The maximum number of builtin elements is 4 (vec4). It must be multiple of 4.
constexpr size_t kMaxNumBuiltinElements = 4;
descriptor.size = sizeof(uint32_t) * kMaxNumBuiltinElements; descriptor.size = sizeof(uint32_t) * kMaxNumBuiltinElements;
descriptor.usage = wgpu::BufferUsage::Uniform | wgpu::BufferUsage::CopyDst; descriptor.usage = wgpu::BufferUsage::Uniform | wgpu::BufferUsage::CopyDst;
descriptor.mappedAtCreation = false; descriptor.mappedAtCreation = false;

View File

@ -897,6 +897,7 @@ TEST_P(TextureFormatTest, RGB9E5Ufloat) {
} }
DAWN_INSTANTIATE_TEST(TextureFormatTest, DAWN_INSTANTIATE_TEST(TextureFormatTest,
D3D11Backend(),
D3D12Backend(), D3D12Backend(),
MetalBackend(), MetalBackend(),
OpenGLBackend(), OpenGLBackend(),