Correctly support setSubData of 0 bytes.
DynamicUploader/RingBuffer were incorrectly assuming that they could not get empty allocation requests. Fix this and add a test. The test also surfaced a bug in the Metal backend where the command recording context could be left with a blit encoder open that was not properly handled on device shutdown. Bug: chromium:1069076 Change-Id: I9793b37142bd509254ce2894fa9f6208e9a68048 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/19291 Commit-Queue: Corentin Wallez <cwallez@chromium.org> Reviewed-by: Kai Ninomiya <kainino@chromium.org>
This commit is contained in:
parent
0721c1cf2a
commit
d3bbcc3334
|
@ -67,7 +67,7 @@ namespace dawn_native {
|
||||||
// If the buffer is not split where waste occurs (e.g. cannot fit new sub-alloc in front), a
|
// If the buffer is not split where waste occurs (e.g. cannot fit new sub-alloc in front), a
|
||||||
// subsequent sub-alloc could fail where the used size was previously adjusted to include
|
// subsequent sub-alloc could fail where the used size was previously adjusted to include
|
||||||
// the wasted.
|
// the wasted.
|
||||||
if (allocationSize == 0 || mUsedSize >= mMaxBlockSize) {
|
if (mUsedSize >= mMaxBlockSize) {
|
||||||
return kInvalidOffset;
|
return kInvalidOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,8 +43,14 @@ namespace dawn_native { namespace metal {
|
||||||
}
|
}
|
||||||
|
|
||||||
id<MTLCommandBuffer> CommandRecordingContext::AcquireCommands() {
|
id<MTLCommandBuffer> CommandRecordingContext::AcquireCommands() {
|
||||||
ASSERT(!mInEncoder);
|
if (mCommands == nil) {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A blit encoder can be left open from SetSubData, make sure we close it.
|
||||||
|
EndBlit();
|
||||||
|
|
||||||
|
ASSERT(!mInEncoder);
|
||||||
id<MTLCommandBuffer> commands = mCommands;
|
id<MTLCommandBuffer> commands = mCommands;
|
||||||
mCommands = nil;
|
mCommands = nil;
|
||||||
return commands;
|
return commands;
|
||||||
|
|
|
@ -213,10 +213,6 @@ namespace dawn_native { namespace metal {
|
||||||
|
|
||||||
mLastSubmittedSerial++;
|
mLastSubmittedSerial++;
|
||||||
|
|
||||||
// Ensure the blit encoder is ended. It may have been opened to perform a lazy clear or
|
|
||||||
// buffer upload.
|
|
||||||
mCommandContext.EndBlit();
|
|
||||||
|
|
||||||
// Acquire the pending command buffer, which is retained. It must be released later.
|
// Acquire the pending command buffer, which is retained. It must be released later.
|
||||||
id<MTLCommandBuffer> pendingCommands = mCommandContext.AcquireCommands();
|
id<MTLCommandBuffer> pendingCommands = mCommandContext.AcquireCommands();
|
||||||
|
|
||||||
|
@ -268,6 +264,11 @@ namespace dawn_native { namespace metal {
|
||||||
BufferBase* destination,
|
BufferBase* destination,
|
||||||
uint64_t destinationOffset,
|
uint64_t destinationOffset,
|
||||||
uint64_t size) {
|
uint64_t size) {
|
||||||
|
// Metal validation layers forbid 0-sized copies, skip it since it is a noop.
|
||||||
|
if (size == 0) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
id<MTLBuffer> uploadBuffer = ToBackend(source)->GetBufferHandle();
|
id<MTLBuffer> uploadBuffer = ToBackend(source)->GetBufferHandle();
|
||||||
id<MTLBuffer> buffer = ToBackend(destination)->GetMTLBuffer();
|
id<MTLBuffer> buffer = ToBackend(destination)->GetMTLBuffer();
|
||||||
[GetPendingCommandContext()->EnsureBlit() copyFromBuffer:uploadBuffer
|
[GetPendingCommandContext()->EnsureBlit() copyFromBuffer:uploadBuffer
|
||||||
|
|
|
@ -560,6 +560,11 @@ namespace dawn_native { namespace vulkan {
|
||||||
BufferBase* destination,
|
BufferBase* destination,
|
||||||
uint64_t destinationOffset,
|
uint64_t destinationOffset,
|
||||||
uint64_t size) {
|
uint64_t size) {
|
||||||
|
// It is a validation error to do a 0-sized copy in Vulkan skip it since it is a noop.
|
||||||
|
if (size == 0) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
CommandRecordingContext* recordingContext = GetPendingRecordingContext();
|
CommandRecordingContext* recordingContext = GetPendingRecordingContext();
|
||||||
|
|
||||||
// Insert memory barrier to ensure host write operations are made visible before
|
// Insert memory barrier to ensure host write operations are made visible before
|
||||||
|
|
|
@ -249,6 +249,22 @@ TEST_P(BufferSetSubDataTests, SmallDataAtZero) {
|
||||||
EXPECT_BUFFER_U32_EQ(value, buffer, 0);
|
EXPECT_BUFFER_U32_EQ(value, buffer, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test the simplest set sub data: setting nothing
|
||||||
|
TEST_P(BufferSetSubDataTests, ZeroSized) {
|
||||||
|
wgpu::BufferDescriptor descriptor;
|
||||||
|
descriptor.size = 4;
|
||||||
|
descriptor.usage = wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst;
|
||||||
|
wgpu::Buffer buffer = device.CreateBuffer(&descriptor);
|
||||||
|
|
||||||
|
uint32_t initialValue = 0x42;
|
||||||
|
buffer.SetSubData(0, sizeof(initialValue), &initialValue);
|
||||||
|
|
||||||
|
buffer.SetSubData(0, 0, nullptr);
|
||||||
|
|
||||||
|
// The content of the buffer isn't changed
|
||||||
|
EXPECT_BUFFER_U32_EQ(initialValue, buffer, 0);
|
||||||
|
}
|
||||||
|
|
||||||
// Call SetSubData at offset 0 via a u32 twice. Test that data is updated accoordingly.
|
// Call SetSubData at offset 0 via a u32 twice. Test that data is updated accoordingly.
|
||||||
TEST_P(BufferSetSubDataTests, SetTwice) {
|
TEST_P(BufferSetSubDataTests, SetTwice) {
|
||||||
wgpu::BufferDescriptor descriptor;
|
wgpu::BufferDescriptor descriptor;
|
||||||
|
|
Loading…
Reference in New Issue