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:
parent
378a1f51a2
commit
0c33c143dc
|
@ -59,9 +59,7 @@ MaybeError ValidationUsage(wgpu::BufferUsage usage) {
|
|||
// ID3D11DeviceContext::CopyResource for these copy operations.
|
||||
|
||||
bool IsMappable(wgpu::BufferUsage usage) {
|
||||
constexpr wgpu::BufferUsage kMapUsages =
|
||||
wgpu::BufferUsage::MapRead | wgpu::BufferUsage::MapWrite;
|
||||
return usage & kMapUsages;
|
||||
return usage & kMappableBufferUsages;
|
||||
}
|
||||
|
||||
D3D11_USAGE D3D11BufferUsage(wgpu::BufferUsage usage) {
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "dawn/native/BindGroup.h"
|
||||
#include "dawn/native/BindGroupTracker.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"
|
||||
|
@ -309,25 +310,44 @@ MaybeError CommandBuffer::Execute() {
|
|||
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;
|
||||
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(dst.texture.Get());
|
||||
SubresourceRange subresources = GetSubresourcesAffectedByCopy(dst, copy->copySize);
|
||||
|
||||
Texture* texture = ToBackend(copy->destination.texture.Get());
|
||||
SubresourceRange subresources =
|
||||
GetSubresourcesAffectedByCopy(copy->destination, copy->copySize);
|
||||
const uint8_t* data = scopedMap.GetMappedData() + copy->source.offset;
|
||||
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));
|
||||
|
||||
DAWN_TRY(texture->Write(commandContext, subresources, copy->destination.origin,
|
||||
copy->copySize, data, copy->source.bytesPerRow,
|
||||
copy->source.rowsPerImage));
|
||||
buffer->MarkUsedInPendingCommands();
|
||||
break;
|
||||
}
|
||||
|
@ -348,6 +368,7 @@ MaybeError CommandBuffer::Execute() {
|
|||
->EnsureSubresourceContentInitialized(commandContext, subresources));
|
||||
|
||||
// Create a staging texture.
|
||||
// TODO(dawn:1768): use compute shader to copy data from texture to buffer.
|
||||
D3D11_TEXTURE2D_DESC stagingTextureDesc;
|
||||
stagingTextureDesc.Width = copy->copySize.width;
|
||||
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) {
|
||||
// Copy the staging texture to the buffer.
|
||||
// The Map() will block until the GPU is done with the texture.
|
||||
|
@ -405,23 +432,35 @@ MaybeError CommandBuffer::Execute() {
|
|||
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<uint8_t*>(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;
|
||||
uint32_t bytesPerRow = blockInfo.byteSize * copy->copySize.width;
|
||||
if (scopedDstMap.GetMappedData()) {
|
||||
uint8_t* pDstData = scopedDstMap.GetMappedData() + dst.offset +
|
||||
dst.bytesPerRow * dst.rowsPerImage * z;
|
||||
for (uint32_t y = 0; y < copy->copySize.height; ++y) {
|
||||
memcpy(pDstData, pSrcData, bytesPerRow);
|
||||
pDstData += dst.bytesPerRow;
|
||||
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);
|
||||
}
|
||||
|
@ -893,12 +932,11 @@ MaybeError CommandBuffer::RecordFirstIndexOffset(RenderPipeline* renderPipeline,
|
|||
}
|
||||
|
||||
// TODO(dawn:1705): only update the uniform buffer when the value changes.
|
||||
uint32_t offsets[] = {
|
||||
uint32_t data[4] = {
|
||||
firstVertex,
|
||||
firstInstance,
|
||||
};
|
||||
DAWN_TRY(
|
||||
commandContext->GetUniformBuffer()->Write(commandContext, 0, offsets, sizeof(offsets)));
|
||||
DAWN_TRY(commandContext->GetUniformBuffer()->Write(commandContext, 0, data, sizeof(data)));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
@ -907,9 +945,12 @@ MaybeError CommandBuffer::RecordNumWorkgroupsForDispatch(ComputePipeline* comput
|
|||
CommandRecordingContext* commandContext,
|
||||
DispatchCmd* dispatchCmd) {
|
||||
// TODO(dawn:1705): only update the uniform buffer when the value changes.
|
||||
static_assert(sizeof(DispatchCmd) == sizeof(uint32_t[3]));
|
||||
DAWN_TRY(commandContext->GetUniformBuffer()->Write(commandContext, 0, dispatchCmd,
|
||||
sizeof(*dispatchCmd)));
|
||||
uint32_t data[4] = {
|
||||
dispatchCmd->x,
|
||||
dispatchCmd->y,
|
||||
dispatchCmd->z,
|
||||
};
|
||||
DAWN_TRY(commandContext->GetUniformBuffer()->Write(commandContext, 0, data, sizeof(data)));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
|
|
@ -46,10 +46,10 @@ MaybeError CommandRecordingContext::Open(Device* device) {
|
|||
d3d11DeviceContext4.As(&mD3D11UserDefinedAnnotation),
|
||||
"D3D11 querying immediate context for ID3DUserDefinedAnnotation interface"));
|
||||
|
||||
constexpr size_t kMaxNumBuiltinElements = 3;
|
||||
|
||||
// Create a uniform buffer for built in variables.
|
||||
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.usage = wgpu::BufferUsage::Uniform | wgpu::BufferUsage::CopyDst;
|
||||
descriptor.mappedAtCreation = false;
|
||||
|
|
|
@ -897,6 +897,7 @@ TEST_P(TextureFormatTest, RGB9E5Ufloat) {
|
|||
}
|
||||
|
||||
DAWN_INSTANTIATE_TEST(TextureFormatTest,
|
||||
D3D11Backend(),
|
||||
D3D12Backend(),
|
||||
MetalBackend(),
|
||||
OpenGLBackend(),
|
||||
|
|
Loading…
Reference in New Issue