Add offset and size to Get[Const]MappedRange.

Bug: dawn:445
Change-Id: I73758d95e61d1fbe69f328907a6170a1b27d785b
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/24983
Commit-Queue: Kai Ninomiya <kainino@chromium.org>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
This commit is contained in:
Corentin Wallez 2020-07-17 18:50:37 +00:00 committed by Commit Bot service account
parent 4b7ca6bf96
commit f6e7044697
13 changed files with 225 additions and 61 deletions

View File

@ -209,11 +209,19 @@
}, },
{ {
"name": "get mapped range", "name": "get mapped range",
"returns": "void *" "returns": "void *",
"args": [
{"name": "offset", "type": "size_t", "default": 0},
{"name": "size", "type": "size_t", "default": 0}
]
}, },
{ {
"name": "get const mapped range", "name": "get const mapped range",
"returns": "void const *" "returns": "void const *",
"args": [
{"name": "offset", "type": "size_t", "default": 0},
{"name": "size", "type": "size_t", "default": 0}
]
}, },
{ {
"name": "unmap" "name": "unmap"

View File

@ -140,6 +140,8 @@ namespace dawn_native {
: ObjectBase(device, tag), mSize(descriptor->size), mState(BufferState::Unmapped) { : ObjectBase(device, tag), mSize(descriptor->size), mState(BufferState::Unmapped) {
if (descriptor->mappedAtCreation) { if (descriptor->mappedAtCreation) {
mState = BufferState::MappedAtCreation; mState = BufferState::MappedAtCreation;
mMapOffset = 0;
mMapSize = mSize;
} }
} }
@ -169,6 +171,8 @@ namespace dawn_native {
MaybeError BufferBase::MapAtCreation() { MaybeError BufferBase::MapAtCreation() {
ASSERT(!IsError()); ASSERT(!IsError());
mState = BufferState::MappedAtCreation; mState = BufferState::MappedAtCreation;
mMapOffset = 0;
mMapSize = mSize;
// 0-sized buffers are not supposed to be written to, Return back any non-null pointer. // 0-sized buffers are not supposed to be written to, Return back any non-null pointer.
// Handle 0-sized buffers first so we don't try to map them in the backend. // Handle 0-sized buffers first so we don't try to map them in the backend.
@ -294,6 +298,7 @@ namespace dawn_native {
mMapReadCallback = callback; mMapReadCallback = callback;
mMapUserdata = userdata; mMapUserdata = userdata;
mMapOffset = 0; mMapOffset = 0;
mMapSize = mSize;
mState = BufferState::Mapped; mState = BufferState::Mapped;
if (GetDevice()->ConsumedError(MapReadAsyncImpl())) { if (GetDevice()->ConsumedError(MapReadAsyncImpl())) {
@ -323,6 +328,7 @@ namespace dawn_native {
mMapWriteCallback = callback; mMapWriteCallback = callback;
mMapUserdata = userdata; mMapUserdata = userdata;
mMapOffset = 0; mMapOffset = 0;
mMapSize = mSize;
mState = BufferState::Mapped; mState = BufferState::Mapped;
if (GetDevice()->ConsumedError(MapWriteAsyncImpl())) { if (GetDevice()->ConsumedError(MapWriteAsyncImpl())) {
@ -359,6 +365,7 @@ namespace dawn_native {
mMapSerial++; mMapSerial++;
mMapMode = mode; mMapMode = mode;
mMapOffset = offset; mMapOffset = offset;
mMapSize = size;
mMapCallback = callback; mMapCallback = callback;
mMapUserdata = userdata; mMapUserdata = userdata;
mState = BufferState::Mapped; mState = BufferState::Mapped;
@ -372,28 +379,28 @@ namespace dawn_native {
tracker->Track(this, mMapSerial, MapType::Async); tracker->Track(this, mMapSerial, MapType::Async);
} }
void* BufferBase::GetMappedRange() { void* BufferBase::GetMappedRange(size_t offset, size_t size) {
return GetMappedRangeInternal(true); return GetMappedRangeInternal(true, offset, size);
} }
const void* BufferBase::GetConstMappedRange() { const void* BufferBase::GetConstMappedRange(size_t offset, size_t size) {
return GetMappedRangeInternal(false); return GetMappedRangeInternal(false, offset, size);
} }
// TODO(dawn:445): When CreateBufferMapped is removed, make GetMappedRangeInternal also take // TODO(dawn:445): When CreateBufferMapped is removed, make GetMappedRangeInternal also take
// care of the validation of GetMappedRange. // care of the validation of GetMappedRange.
void* BufferBase::GetMappedRangeInternal(bool writable) { void* BufferBase::GetMappedRangeInternal(bool writable, size_t offset, size_t size) {
if (!CanGetMappedRange(writable)) { if (!CanGetMappedRange(writable, offset, size)) {
return nullptr; return nullptr;
} }
if (mStagingBuffer != nullptr) { if (mStagingBuffer != nullptr) {
return static_cast<uint8_t*>(mStagingBuffer->GetMappedPointer()) + mMapOffset; return static_cast<uint8_t*>(mStagingBuffer->GetMappedPointer()) + offset;
} }
if (mSize == 0) { if (mSize == 0) {
return reinterpret_cast<uint8_t*>(intptr_t(0xCAFED00D)); return reinterpret_cast<uint8_t*>(intptr_t(0xCAFED00D));
} }
return static_cast<uint8_t*>(GetMappedPointerImpl()) + mMapOffset; return static_cast<uint8_t*>(GetMappedPointerImpl()) + offset;
} }
void BufferBase::Destroy() { void BufferBase::Destroy() {
@ -554,7 +561,16 @@ namespace dawn_native {
return {}; return {};
} }
bool BufferBase::CanGetMappedRange(bool writable) const { bool BufferBase::CanGetMappedRange(bool writable, size_t offset, size_t size) const {
if (size > mMapSize || offset < mMapOffset) {
return false;
}
size_t offsetInMappedRange = offset - mMapOffset;
if (offsetInMappedRange > mMapSize - size) {
return false;
}
// Note that: // Note that:
// //
// - We don't check that the device is alive because the application can ask for the // - We don't check that the device is alive because the application can ask for the
@ -622,11 +638,11 @@ namespace dawn_native {
switch (type) { switch (type) {
case MapType::Read: case MapType::Read:
CallMapReadCallback(mapSerial, WGPUBufferMapAsyncStatus_Success, CallMapReadCallback(mapSerial, WGPUBufferMapAsyncStatus_Success,
GetMappedRangeInternal(false), GetSize()); GetMappedRangeInternal(false, 0, mSize), GetSize());
break; break;
case MapType::Write: case MapType::Write:
CallMapWriteCallback(mapSerial, WGPUBufferMapAsyncStatus_Success, CallMapWriteCallback(mapSerial, WGPUBufferMapAsyncStatus_Success,
GetMappedRangeInternal(true), GetSize()); GetMappedRangeInternal(true, 0, mSize), GetSize());
break; break;
case MapType::Async: case MapType::Async:
CallMapCallback(mapSerial, WGPUBufferMapAsyncStatus_Success); CallMapCallback(mapSerial, WGPUBufferMapAsyncStatus_Success);

View File

@ -67,8 +67,8 @@ namespace dawn_native {
size_t size, size_t size,
WGPUBufferMapCallback callback, WGPUBufferMapCallback callback,
void* userdata); void* userdata);
void* GetMappedRange(); void* GetMappedRange(size_t offset, size_t size);
const void* GetConstMappedRange(); const void* GetConstMappedRange(size_t offset, size_t size);
void Unmap(); void Unmap();
void Destroy(); void Destroy();
@ -93,7 +93,7 @@ namespace dawn_native {
virtual bool IsMappableAtCreation() const = 0; virtual bool IsMappableAtCreation() const = 0;
MaybeError CopyFromStagingBuffer(); MaybeError CopyFromStagingBuffer();
void* GetMappedRangeInternal(bool writable); void* GetMappedRangeInternal(bool writable, size_t offset, size_t size);
void CallMapReadCallback(uint32_t serial, void CallMapReadCallback(uint32_t serial,
WGPUBufferMapAsyncStatus status, WGPUBufferMapAsyncStatus status,
const void* pointer, const void* pointer,
@ -112,7 +112,7 @@ namespace dawn_native {
WGPUBufferMapAsyncStatus* status) const; WGPUBufferMapAsyncStatus* status) const;
MaybeError ValidateUnmap() const; MaybeError ValidateUnmap() const;
MaybeError ValidateDestroy() const; MaybeError ValidateDestroy() const;
bool CanGetMappedRange(bool writable) const; bool CanGetMappedRange(bool writable, size_t offset, size_t size) const;
uint64_t mSize = 0; uint64_t mSize = 0;
wgpu::BufferUsage mUsage = wgpu::BufferUsage::None; wgpu::BufferUsage mUsage = wgpu::BufferUsage::None;
@ -128,6 +128,7 @@ namespace dawn_native {
uint32_t mMapSerial = 0; uint32_t mMapSerial = 0;
wgpu::MapMode mMapMode = wgpu::MapMode::None; wgpu::MapMode mMapMode = wgpu::MapMode::None;
size_t mMapOffset = 0; size_t mMapOffset = 0;
size_t mMapSize = 0;
}; };
} // namespace dawn_native } // namespace dawn_native

View File

@ -624,7 +624,7 @@ namespace dawn_native {
WGPUCreateBufferMappedResult result = {}; WGPUCreateBufferMappedResult result = {};
result.buffer = reinterpret_cast<WGPUBuffer>(buffer); result.buffer = reinterpret_cast<WGPUBuffer>(buffer);
result.data = buffer->GetMappedRange(); result.data = buffer->GetMappedRange(0, descriptor->size);
result.dataLength = descriptor->size; result.dataLength = descriptor->size;
if (result.data != nullptr) { if (result.data != nullptr) {

View File

@ -315,7 +315,7 @@ namespace dawn_native { namespace opengl {
Ref<Buffer> srcBuffer = AcquireRef(ToBackend(device->CreateBuffer(&descriptor))); Ref<Buffer> srcBuffer = AcquireRef(ToBackend(device->CreateBuffer(&descriptor)));
// Fill the buffer with clear color // Fill the buffer with clear color
memset(srcBuffer->GetMappedRange(), clearColor, descriptor.size); memset(srcBuffer->GetMappedRange(0, descriptor.size), clearColor, descriptor.size);
srcBuffer->Unmap(); srcBuffer->Unmap();
// Bind buffer and texture, and make the buffer to texture copy // Bind buffer and texture, and make the buffer to texture copy

View File

@ -273,6 +273,7 @@ namespace dawn_wire { namespace client {
WGPUBufferMapCallback callback; WGPUBufferMapCallback callback;
void* userdata; void* userdata;
size_t mapOffset; size_t mapOffset;
size_t mapSize;
Buffer* self; Buffer* self;
}; };
ProxyData* proxy = new ProxyData; ProxyData* proxy = new ProxyData;
@ -292,6 +293,7 @@ namespace dawn_wire { namespace client {
proxy->callback(status, proxy->userdata); proxy->callback(status, proxy->userdata);
} }
proxy->self->mMapOffset = proxy->mapOffset; proxy->self->mMapOffset = proxy->mapOffset;
proxy->self->mMapSize = proxy->mapSize;
delete proxy; delete proxy;
}, },
proxy); proxy);
@ -304,6 +306,7 @@ namespace dawn_wire { namespace client {
proxy->callback(status, proxy->userdata); proxy->callback(status, proxy->userdata);
} }
proxy->self->mMapOffset = proxy->mapOffset; proxy->self->mMapOffset = proxy->mapOffset;
proxy->self->mMapSize = proxy->mapSize;
delete proxy; delete proxy;
}, },
proxy); proxy);
@ -396,18 +399,19 @@ namespace dawn_wire { namespace client {
return true; return true;
} }
void* Buffer::GetMappedRange() { void* Buffer::GetMappedRange(size_t offset, size_t size) {
if (!IsMappedForWriting()) { if (!IsMappedForWriting() || !CheckGetMappedRangeOffsetSize(offset, size)) {
return nullptr; return nullptr;
} }
return static_cast<uint8_t*>(mMappedData) + mMapOffset; return static_cast<uint8_t*>(mMappedData) + offset;
} }
const void* Buffer::GetConstMappedRange() { const void* Buffer::GetConstMappedRange(size_t offset, size_t size) {
if (!IsMappedForWriting() && !IsMappedForReading()) { if (!(IsMappedForWriting() || IsMappedForReading()) ||
!CheckGetMappedRangeOffsetSize(offset, size)) {
return nullptr; return nullptr;
} }
return static_cast<uint8_t*>(mMappedData) + mMapOffset; return static_cast<uint8_t*>(mMappedData) + offset;
} }
void Buffer::Unmap() { void Buffer::Unmap() {
@ -446,6 +450,7 @@ namespace dawn_wire { namespace client {
mMappedData = nullptr; mMappedData = nullptr;
mMapOffset = 0; mMapOffset = 0;
mMapSize = mSize;
ClearMapRequests(WGPUBufferMapAsyncStatus_Unknown); ClearMapRequests(WGPUBufferMapAsyncStatus_Unknown);
BufferUnmapCmd cmd; BufferUnmapCmd cmd;
@ -483,4 +488,12 @@ namespace dawn_wire { namespace client {
return mWriteHandle != nullptr; return mWriteHandle != nullptr;
} }
bool Buffer::CheckGetMappedRangeOffsetSize(size_t offset, size_t size) const {
if (size > mMapSize || offset < mMapOffset) {
return false;
}
size_t offsetInMappedRange = offset - mMapOffset;
return offsetInMappedRange <= mMapSize - size;
}
}} // namespace dawn_wire::client }} // namespace dawn_wire::client

View File

@ -47,18 +47,19 @@ namespace dawn_wire { namespace client {
size_t size, size_t size,
WGPUBufferMapCallback callback, WGPUBufferMapCallback callback,
void* userdata); void* userdata);
void* GetMappedRange(); void* GetMappedRange(size_t offset, size_t size);
const void* GetConstMappedRange(); const void* GetConstMappedRange(size_t offset, size_t size);
void Unmap(); void Unmap();
void Destroy(); void Destroy();
void SetSubData(uint64_t start, uint64_t count, const void* data); void SetSubData(uint64_t start, uint64_t count, const void* data);
private:
bool IsMappedForReading() const; bool IsMappedForReading() const;
bool IsMappedForWriting() const; bool IsMappedForWriting() const;
bool CheckGetMappedRangeOffsetSize(size_t offset, size_t size) const;
private:
// We want to defer all the validation to the server, which means we could have multiple // We want to defer all the validation to the server, which means we could have multiple
// map request in flight at a single time and need to track them separately. // map request in flight at a single time and need to track them separately.
// On well-behaved applications, only one request should exist at a single time. // On well-behaved applications, only one request should exist at a single time.
@ -82,6 +83,7 @@ namespace dawn_wire { namespace client {
std::unique_ptr<MemoryTransferService::WriteHandle> mWriteHandle = nullptr; std::unique_ptr<MemoryTransferService::WriteHandle> mWriteHandle = nullptr;
void* mMappedData = nullptr; void* mMappedData = nullptr;
size_t mMapOffset = 0; size_t mMapOffset = 0;
size_t mMapSize = 0;
}; };
}} // namespace dawn_wire::client }} // namespace dawn_wire::client

View File

@ -27,6 +27,7 @@ namespace dawn_wire { namespace server {
ObjectHandle buffer; ObjectHandle buffer;
WGPUBuffer bufferObj; WGPUBuffer bufferObj;
uint32_t requestSerial; uint32_t requestSerial;
uint64_t offset;
uint64_t size; uint64_t size;
WGPUMapModeFlags mode; WGPUMapModeFlags mode;
// TODO(enga): Use a tagged pointer to save space. // TODO(enga): Use a tagged pointer to save space.

View File

@ -82,6 +82,7 @@ namespace dawn_wire { namespace server {
userdata->buffer = ObjectHandle{bufferId, buffer->generation}; userdata->buffer = ObjectHandle{bufferId, buffer->generation};
userdata->bufferObj = buffer->handle; userdata->bufferObj = buffer->handle;
userdata->requestSerial = requestSerial; userdata->requestSerial = requestSerial;
userdata->offset = offset;
userdata->size = size; userdata->size = size;
userdata->mode = mode; userdata->mode = mode;
@ -248,7 +249,7 @@ namespace dawn_wire { namespace server {
const void* readData = nullptr; const void* readData = nullptr;
if (isSuccess && isRead) { if (isSuccess && isRead) {
// Get the serialization size of the message to initialize ReadHandle data. // Get the serialization size of the message to initialize ReadHandle data.
readData = mProcs.bufferGetConstMappedRange(data->bufferObj); readData = mProcs.bufferGetConstMappedRange(data->bufferObj, data->offset, data->size);
cmd.readInitialDataInfoLength = cmd.readInitialDataInfoLength =
data->readHandle->SerializeInitialDataSize(readData, data->size); data->readHandle->SerializeInitialDataSize(readData, data->size);
} }
@ -268,8 +269,9 @@ namespace dawn_wire { namespace server {
bufferData->writeHandle = std::move(data->writeHandle); bufferData->writeHandle = std::move(data->writeHandle);
bufferData->mapWriteState = BufferMapWriteState::Mapped; bufferData->mapWriteState = BufferMapWriteState::Mapped;
// Set the target of the WriteHandle to the mapped buffer data. // Set the target of the WriteHandle to the mapped buffer data.
bufferData->writeHandle->SetTarget(mProcs.bufferGetMappedRange(data->bufferObj), bufferData->writeHandle->SetTarget(
data->size); mProcs.bufferGetMappedRange(data->bufferObj, data->offset, data->size),
data->size);
} }
} }
} }

View File

@ -382,7 +382,7 @@ TEST_P(BufferMappingTests, MapRead_NonZeroOffset) {
queue.WriteBuffer(buffer, 0, &myData, sizeof(myData)); queue.WriteBuffer(buffer, 0, &myData, sizeof(myData));
MapAsyncAndWait(buffer, wgpu::MapMode::Read, 4, 4); MapAsyncAndWait(buffer, wgpu::MapMode::Read, 4, 4);
ASSERT_EQ(myData[1], *static_cast<const uint32_t*>(buffer.GetConstMappedRange())); ASSERT_EQ(myData[1], *static_cast<const uint32_t*>(buffer.GetConstMappedRange(4)));
buffer.Unmap(); buffer.Unmap();
} }
@ -451,7 +451,7 @@ TEST_P(BufferMappingTests, MapWrite_NonZeroOffset) {
uint32_t myData = 2934875; uint32_t myData = 2934875;
MapAsyncAndWait(buffer, wgpu::MapMode::Write, 4, 4); MapAsyncAndWait(buffer, wgpu::MapMode::Write, 4, 4);
memcpy(buffer.GetMappedRange(), &myData, sizeof(myData)); memcpy(buffer.GetMappedRange(4), &myData, sizeof(myData));
buffer.Unmap(); buffer.Unmap();
EXPECT_BUFFER_U32_EQ(myData, buffer, 4); EXPECT_BUFFER_U32_EQ(myData, buffer, 4);
@ -518,7 +518,7 @@ TEST_P(BufferMappingTests, OffsetNotUpdatedOnError) {
} }
// mMapOffset has not been updated so it should still be 4, which is data[1] // mMapOffset has not been updated so it should still be 4, which is data[1]
ASSERT_EQ(0, memcmp(buffer.GetConstMappedRange(), &data[1], sizeof(uint32_t))); ASSERT_EQ(0, memcmp(buffer.GetConstMappedRange(4), &data[1], sizeof(uint32_t)));
} }
DAWN_INSTANTIATE_TEST(BufferMappingTests, DAWN_INSTANTIATE_TEST(BufferMappingTests,

View File

@ -252,6 +252,46 @@ TEST_F(BufferValidationTest, MapAsync_OffsetSizeAlignment) {
} }
} }
// Test map async with an invalid offset and size OOB checks
TEST_F(BufferValidationTest, MapAsync_OffsetSizeOOB) {
// Valid case: full buffer is ok.
{
wgpu::Buffer buffer = CreateMapReadBuffer(8);
buffer.MapAsync(wgpu::MapMode::Read, 0, 8, nullptr, nullptr);
}
// Valid case: range in the middle of the buffer is ok.
{
wgpu::Buffer buffer = CreateMapReadBuffer(12);
buffer.MapAsync(wgpu::MapMode::Read, 4, 4, nullptr, nullptr);
}
// Valid case: empty range at the end of the buffer is ok.
{
wgpu::Buffer buffer = CreateMapReadBuffer(8);
buffer.MapAsync(wgpu::MapMode::Read, 8, 0, nullptr, nullptr);
}
// Error case, offset is larger than the buffer size (even if size is 0).
{
wgpu::Buffer buffer = CreateMapReadBuffer(8);
AssertMapAsyncError(buffer, wgpu::MapMode::Read, 12, 0);
}
// Error case, offset + size is larger than the buffer
{
wgpu::Buffer buffer = CreateMapReadBuffer(12);
AssertMapAsyncError(buffer, wgpu::MapMode::Read, 8, 8);
}
// Error case, offset + size is larger than the buffer, overflow case.
{
wgpu::Buffer buffer = CreateMapReadBuffer(12);
AssertMapAsyncError(buffer, wgpu::MapMode::Read, 4,
std::numeric_limits<size_t>::max() & ~size_t(3));
}
}
// Test map async with a buffer that has the wrong usage // Test map async with a buffer that has the wrong usage
TEST_F(BufferValidationTest, MapAsync_WrongUsage) { TEST_F(BufferValidationTest, MapAsync_WrongUsage) {
{ {
@ -1051,7 +1091,7 @@ TEST_F(BufferValidationTest, UnmapUnmappedBuffer) {
} }
// Test that it is invalid to call GetMappedRange on an unmapped buffer. // Test that it is invalid to call GetMappedRange on an unmapped buffer.
TEST_F(BufferValidationTest, GetMappedRangeOnUnmappedBuffer) { TEST_F(BufferValidationTest, GetMappedRange_OnUnmappedBuffer) {
// Unmapped at creation case. // Unmapped at creation case.
{ {
wgpu::BufferDescriptor desc; wgpu::BufferDescriptor desc;
@ -1138,7 +1178,7 @@ TEST_F(BufferValidationTest, GetMappedRangeOnUnmappedBuffer) {
} }
// Test that it is invalid to call GetMappedRange on a destroyed buffer. // Test that it is invalid to call GetMappedRange on a destroyed buffer.
TEST_F(BufferValidationTest, GetMappedRangeOnDestroyedBuffer) { TEST_F(BufferValidationTest, GetMappedRange_OnDestroyedBuffer) {
// Destroyed after creation case. // Destroyed after creation case.
{ {
wgpu::BufferDescriptor desc; wgpu::BufferDescriptor desc;
@ -1225,8 +1265,8 @@ TEST_F(BufferValidationTest, GetMappedRangeOnDestroyedBuffer) {
} }
} }
// Test that it is invalid to call GetMappedRange on a buffer afterMapReadAsync // Test that it is invalid to call GetMappedRange on a buffer after MapReadAsync
TEST_F(BufferValidationTest, GetMappedRangeOnMappedForReading) { TEST_F(BufferValidationTest, GetMappedRange_OnMappedForReading) {
{ {
wgpu::Buffer buf = CreateMapReadBuffer(4); wgpu::Buffer buf = CreateMapReadBuffer(4);
@ -1251,7 +1291,7 @@ TEST_F(BufferValidationTest, GetMappedRangeOnMappedForReading) {
} }
// Test valid cases to call GetMappedRange on a buffer. // Test valid cases to call GetMappedRange on a buffer.
TEST_F(BufferValidationTest, GetMappedRangeValidCases) { TEST_F(BufferValidationTest, GetMappedRange_ValidBufferStateCases) {
// GetMappedRange after CreateBufferMapped case. // GetMappedRange after CreateBufferMapped case.
{ {
wgpu::CreateBufferMappedResult result = CreateBufferMapped(4, wgpu::BufferUsage::CopySrc); wgpu::CreateBufferMappedResult result = CreateBufferMapped(4, wgpu::BufferUsage::CopySrc);
@ -1303,7 +1343,7 @@ TEST_F(BufferValidationTest, GetMappedRangeValidCases) {
} }
// Test valid cases to call GetMappedRange on an error buffer. // Test valid cases to call GetMappedRange on an error buffer.
TEST_F(BufferValidationTest, GetMappedRangeOnErrorBuffer) { TEST_F(BufferValidationTest, GetMappedRange_OnErrorBuffer) {
wgpu::BufferDescriptor desc; wgpu::BufferDescriptor desc;
desc.size = 4; desc.size = 4;
desc.usage = wgpu::BufferUsage::Storage | wgpu::BufferUsage::MapRead; desc.usage = wgpu::BufferUsage::Storage | wgpu::BufferUsage::MapRead;
@ -1377,3 +1417,62 @@ TEST_F(BufferValidationTest, GetMappedRangeOnErrorBuffer) {
ASSERT_EQ(buffer.GetConstMappedRange(), buffer.GetMappedRange()); ASSERT_EQ(buffer.GetConstMappedRange(), buffer.GetMappedRange());
} }
} }
// Test validation of the GetMappedRange parameters
TEST_F(BufferValidationTest, GetMappedRange_OffsetSizeOOB) {
// Valid case: full range is ok
{
wgpu::Buffer buffer = CreateMapWriteBuffer(8);
buffer.MapAsync(wgpu::MapMode::Write, 0, 8, nullptr, nullptr);
EXPECT_NE(buffer.GetMappedRange(0, 8), nullptr);
}
// Valid case: full range is ok with defaulted MapAsync size
{
wgpu::Buffer buffer = CreateMapWriteBuffer(8);
buffer.MapAsync(wgpu::MapMode::Write, 0, 0, nullptr, nullptr);
EXPECT_NE(buffer.GetMappedRange(0, 8), nullptr);
}
// Valid case: empty range at the end is ok
{
wgpu::Buffer buffer = CreateMapWriteBuffer(8);
buffer.MapAsync(wgpu::MapMode::Write, 0, 8, nullptr, nullptr);
EXPECT_NE(buffer.GetMappedRange(8, 0), nullptr);
}
// Valid case: range in the middle is ok.
{
wgpu::Buffer buffer = CreateMapWriteBuffer(12);
buffer.MapAsync(wgpu::MapMode::Write, 0, 12, nullptr, nullptr);
EXPECT_NE(buffer.GetMappedRange(4, 4), nullptr);
}
// Error case: offset is larger than the mapped range (even with size = 0)
{
wgpu::Buffer buffer = CreateMapWriteBuffer(8);
buffer.MapAsync(wgpu::MapMode::Write, 0, 8, nullptr, nullptr);
EXPECT_EQ(buffer.GetMappedRange(9, 0), nullptr);
}
// Error case: offset + size is larger than the mapped range
{
wgpu::Buffer buffer = CreateMapWriteBuffer(12);
buffer.MapAsync(wgpu::MapMode::Write, 0, 12, nullptr, nullptr);
EXPECT_EQ(buffer.GetMappedRange(8, 5), nullptr);
}
// Error case: offset + size is larger than the mapped range, overflow case
{
wgpu::Buffer buffer = CreateMapWriteBuffer(12);
buffer.MapAsync(wgpu::MapMode::Write, 0, 12, nullptr, nullptr);
EXPECT_EQ(buffer.GetMappedRange(8, std::numeric_limits<size_t>::max()), nullptr);
}
// Error case: offset is before the start of the range
{
wgpu::Buffer buffer = CreateMapWriteBuffer(12);
buffer.MapAsync(wgpu::MapMode::Write, 4, 4, nullptr, nullptr);
EXPECT_EQ(buffer.GetMappedRange(3, 4), nullptr);
}
}

View File

@ -128,7 +128,8 @@ TEST_F(WireBufferMappingTests, MappingForReadSuccessBuffer) {
EXPECT_CALL(api, OnBufferMapAsyncCallback(apiBuffer, _, _)).WillOnce(InvokeWithoutArgs([&]() { EXPECT_CALL(api, OnBufferMapAsyncCallback(apiBuffer, _, _)).WillOnce(InvokeWithoutArgs([&]() {
api.CallMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success); api.CallMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success);
})); }));
EXPECT_CALL(api, BufferGetConstMappedRange(apiBuffer)).WillOnce(Return(&bufferContent)); EXPECT_CALL(api, BufferGetConstMappedRange(apiBuffer, 0, kBufferSize))
.WillOnce(Return(&bufferContent));
FlushClient(); FlushClient();
@ -171,7 +172,8 @@ TEST_F(WireBufferMappingTests, DestroyBeforeReadRequestEnd) {
EXPECT_CALL(api, OnBufferMapAsyncCallback(apiBuffer, _, _)).WillOnce(InvokeWithoutArgs([&]() { EXPECT_CALL(api, OnBufferMapAsyncCallback(apiBuffer, _, _)).WillOnce(InvokeWithoutArgs([&]() {
api.CallMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success); api.CallMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success);
})); }));
EXPECT_CALL(api, BufferGetConstMappedRange(apiBuffer)).WillOnce(Return(&bufferContent)); EXPECT_CALL(api, BufferGetConstMappedRange(apiBuffer, 0, kBufferSize))
.WillOnce(Return(&bufferContent));
// Destroy before the client gets the success, so the callback is called with unknown. // Destroy before the client gets the success, so the callback is called with unknown.
EXPECT_CALL(*mockBufferMapReadCallback, Call(WGPUBufferMapAsyncStatus_Unknown, nullptr, 0, _)) EXPECT_CALL(*mockBufferMapReadCallback, Call(WGPUBufferMapAsyncStatus_Unknown, nullptr, 0, _))
@ -192,7 +194,8 @@ TEST_F(WireBufferMappingTests, UnmapCalledTooEarlyForRead) {
EXPECT_CALL(api, OnBufferMapAsyncCallback(apiBuffer, _, _)).WillOnce(InvokeWithoutArgs([&]() { EXPECT_CALL(api, OnBufferMapAsyncCallback(apiBuffer, _, _)).WillOnce(InvokeWithoutArgs([&]() {
api.CallMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success); api.CallMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success);
})); }));
EXPECT_CALL(api, BufferGetConstMappedRange(apiBuffer)).WillOnce(Return(&bufferContent)); EXPECT_CALL(api, BufferGetConstMappedRange(apiBuffer, 0, kBufferSize))
.WillOnce(Return(&bufferContent));
FlushClient(); FlushClient();
@ -214,7 +217,8 @@ TEST_F(WireBufferMappingTests, MappingForReadingErrorWhileAlreadyMappedGetsNullp
EXPECT_CALL(api, OnBufferMapAsyncCallback(apiBuffer, _, _)).WillOnce(InvokeWithoutArgs([&]() { EXPECT_CALL(api, OnBufferMapAsyncCallback(apiBuffer, _, _)).WillOnce(InvokeWithoutArgs([&]() {
api.CallMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success); api.CallMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success);
})); }));
EXPECT_CALL(api, BufferGetConstMappedRange(apiBuffer)).WillOnce(Return(&bufferContent)); EXPECT_CALL(api, BufferGetConstMappedRange(apiBuffer, 0, kBufferSize))
.WillOnce(Return(&bufferContent));
FlushClient(); FlushClient();
@ -246,7 +250,8 @@ TEST_F(WireBufferMappingTests, UnmapInsideMapReadCallback) {
EXPECT_CALL(api, OnBufferMapAsyncCallback(apiBuffer, _, _)).WillOnce(InvokeWithoutArgs([&]() { EXPECT_CALL(api, OnBufferMapAsyncCallback(apiBuffer, _, _)).WillOnce(InvokeWithoutArgs([&]() {
api.CallMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success); api.CallMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success);
})); }));
EXPECT_CALL(api, BufferGetConstMappedRange(apiBuffer)).WillOnce(Return(&bufferContent)); EXPECT_CALL(api, BufferGetConstMappedRange(apiBuffer, 0, kBufferSize))
.WillOnce(Return(&bufferContent));
FlushClient(); FlushClient();
@ -270,7 +275,8 @@ TEST_F(WireBufferMappingTests, DestroyInsideMapReadCallback) {
EXPECT_CALL(api, OnBufferMapAsyncCallback(apiBuffer, _, _)).WillOnce(InvokeWithoutArgs([&]() { EXPECT_CALL(api, OnBufferMapAsyncCallback(apiBuffer, _, _)).WillOnce(InvokeWithoutArgs([&]() {
api.CallMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success); api.CallMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success);
})); }));
EXPECT_CALL(api, BufferGetConstMappedRange(apiBuffer)).WillOnce(Return(&bufferContent)); EXPECT_CALL(api, BufferGetConstMappedRange(apiBuffer, 0, kBufferSize))
.WillOnce(Return(&bufferContent));
FlushClient(); FlushClient();
@ -298,7 +304,8 @@ TEST_F(WireBufferMappingTests, MappingForWriteSuccessBuffer) {
EXPECT_CALL(api, OnBufferMapAsyncCallback(apiBuffer, _, _)).WillOnce(InvokeWithoutArgs([&]() { EXPECT_CALL(api, OnBufferMapAsyncCallback(apiBuffer, _, _)).WillOnce(InvokeWithoutArgs([&]() {
api.CallMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success); api.CallMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success);
})); }));
EXPECT_CALL(api, BufferGetMappedRange(apiBuffer)).WillOnce(Return(&serverBufferContent)); EXPECT_CALL(api, BufferGetMappedRange(apiBuffer, 0, kBufferSize))
.WillOnce(Return(&serverBufferContent));
FlushClient(); FlushClient();
@ -348,7 +355,8 @@ TEST_F(WireBufferMappingTests, DestroyBeforeWriteRequestEnd) {
EXPECT_CALL(api, OnBufferMapAsyncCallback(apiBuffer, _, _)).WillOnce(InvokeWithoutArgs([&]() { EXPECT_CALL(api, OnBufferMapAsyncCallback(apiBuffer, _, _)).WillOnce(InvokeWithoutArgs([&]() {
api.CallMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success); api.CallMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success);
})); }));
EXPECT_CALL(api, BufferGetMappedRange(apiBuffer)).WillOnce(Return(&bufferContent)); EXPECT_CALL(api, BufferGetMappedRange(apiBuffer, 0, kBufferSize))
.WillOnce(Return(&bufferContent));
// Destroy before the client gets the success, so the callback is called with unknown. // Destroy before the client gets the success, so the callback is called with unknown.
EXPECT_CALL(*mockBufferMapWriteCallback, Call(WGPUBufferMapAsyncStatus_Unknown, nullptr, 0, _)) EXPECT_CALL(*mockBufferMapWriteCallback, Call(WGPUBufferMapAsyncStatus_Unknown, nullptr, 0, _))
@ -369,7 +377,8 @@ TEST_F(WireBufferMappingTests, UnmapCalledTooEarlyForWrite) {
EXPECT_CALL(api, OnBufferMapAsyncCallback(apiBuffer, _, _)).WillOnce(InvokeWithoutArgs([&]() { EXPECT_CALL(api, OnBufferMapAsyncCallback(apiBuffer, _, _)).WillOnce(InvokeWithoutArgs([&]() {
api.CallMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success); api.CallMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success);
})); }));
EXPECT_CALL(api, BufferGetMappedRange(apiBuffer)).WillOnce(Return(&bufferContent)); EXPECT_CALL(api, BufferGetMappedRange(apiBuffer, 0, kBufferSize))
.WillOnce(Return(&bufferContent));
FlushClient(); FlushClient();
@ -392,7 +401,8 @@ TEST_F(WireBufferMappingTests, MappingForWritingErrorWhileAlreadyMappedGetsNullp
EXPECT_CALL(api, OnBufferMapAsyncCallback(apiBuffer, _, _)).WillOnce(InvokeWithoutArgs([&]() { EXPECT_CALL(api, OnBufferMapAsyncCallback(apiBuffer, _, _)).WillOnce(InvokeWithoutArgs([&]() {
api.CallMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success); api.CallMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success);
})); }));
EXPECT_CALL(api, BufferGetMappedRange(apiBuffer)).WillOnce(Return(&bufferContent)); EXPECT_CALL(api, BufferGetMappedRange(apiBuffer, 0, kBufferSize))
.WillOnce(Return(&bufferContent));
FlushClient(); FlushClient();
@ -425,7 +435,8 @@ TEST_F(WireBufferMappingTests, UnmapInsideMapWriteCallback) {
EXPECT_CALL(api, OnBufferMapAsyncCallback(apiBuffer, _, _)).WillOnce(InvokeWithoutArgs([&]() { EXPECT_CALL(api, OnBufferMapAsyncCallback(apiBuffer, _, _)).WillOnce(InvokeWithoutArgs([&]() {
api.CallMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success); api.CallMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success);
})); }));
EXPECT_CALL(api, BufferGetMappedRange(apiBuffer)).WillOnce(Return(&bufferContent)); EXPECT_CALL(api, BufferGetMappedRange(apiBuffer, 0, kBufferSize))
.WillOnce(Return(&bufferContent));
FlushClient(); FlushClient();
@ -450,7 +461,8 @@ TEST_F(WireBufferMappingTests, DestroyInsideMapWriteCallback) {
EXPECT_CALL(api, OnBufferMapAsyncCallback(apiBuffer, _, _)).WillOnce(InvokeWithoutArgs([&]() { EXPECT_CALL(api, OnBufferMapAsyncCallback(apiBuffer, _, _)).WillOnce(InvokeWithoutArgs([&]() {
api.CallMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success); api.CallMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success);
})); }));
EXPECT_CALL(api, BufferGetMappedRange(apiBuffer)).WillOnce(Return(&bufferContent)); EXPECT_CALL(api, BufferGetMappedRange(apiBuffer, 0, kBufferSize))
.WillOnce(Return(&bufferContent));
FlushClient(); FlushClient();
@ -548,7 +560,8 @@ TEST_F(WireBufferMappingTests, CreateBufferMappedThenMapSuccess) {
EXPECT_CALL(api, OnBufferMapAsyncCallback(apiBuffer, _, _)).WillOnce(InvokeWithoutArgs([&]() { EXPECT_CALL(api, OnBufferMapAsyncCallback(apiBuffer, _, _)).WillOnce(InvokeWithoutArgs([&]() {
api.CallMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success); api.CallMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success);
})); }));
EXPECT_CALL(api, BufferGetMappedRange(apiBuffer)).WillOnce(Return(&apiBufferData)); EXPECT_CALL(api, BufferGetMappedRange(apiBuffer, 0, kBufferSize))
.WillOnce(Return(&apiBufferData));
FlushClient(); FlushClient();

View File

@ -143,7 +143,7 @@ class WireMemoryTransferServiceTests : public WireTest {
std::pair<WGPUBuffer, WGPUBuffer> CreateBuffer() { std::pair<WGPUBuffer, WGPUBuffer> CreateBuffer() {
WGPUBufferDescriptor descriptor = {}; WGPUBufferDescriptor descriptor = {};
descriptor.size = sizeof(mBufferContent); descriptor.size = kBufferSize;
WGPUBuffer apiBuffer = api.GetNewBuffer(); WGPUBuffer apiBuffer = api.GetNewBuffer();
WGPUBuffer buffer = wgpuDeviceCreateBuffer(device, &descriptor); WGPUBuffer buffer = wgpuDeviceCreateBuffer(device, &descriptor);
@ -349,6 +349,8 @@ class WireMemoryTransferServiceTests : public WireTest {
// Represents the buffer contents for the test. // Represents the buffer contents for the test.
static uint32_t mBufferContent; static uint32_t mBufferContent;
static constexpr size_t kBufferSize = sizeof(mBufferContent);
// The client's zero-initialized buffer for writing. // The client's zero-initialized buffer for writing.
uint32_t mMappedBufferContent = 0; uint32_t mMappedBufferContent = 0;
@ -389,7 +391,8 @@ TEST_F(WireMemoryTransferServiceTests, BufferMapReadSuccess) {
EXPECT_CALL(api, OnBufferMapAsyncCallback(apiBuffer, _, _)).WillOnce(InvokeWithoutArgs([&]() { EXPECT_CALL(api, OnBufferMapAsyncCallback(apiBuffer, _, _)).WillOnce(InvokeWithoutArgs([&]() {
api.CallMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success); api.CallMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success);
})); }));
EXPECT_CALL(api, BufferGetConstMappedRange(apiBuffer)).WillOnce(Return(&mBufferContent)); EXPECT_CALL(api, BufferGetConstMappedRange(apiBuffer, 0, kBufferSize))
.WillOnce(Return(&mBufferContent));
FlushClient(); FlushClient();
@ -521,7 +524,8 @@ TEST_F(WireMemoryTransferServiceTests, BufferMapReadDeserializeInitialDataFailur
EXPECT_CALL(api, OnBufferMapAsyncCallback(apiBuffer, _, _)).WillOnce(InvokeWithoutArgs([&]() { EXPECT_CALL(api, OnBufferMapAsyncCallback(apiBuffer, _, _)).WillOnce(InvokeWithoutArgs([&]() {
api.CallMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success); api.CallMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success);
})); }));
EXPECT_CALL(api, BufferGetConstMappedRange(apiBuffer)).WillOnce(Return(&mBufferContent)); EXPECT_CALL(api, BufferGetConstMappedRange(apiBuffer, 0, kBufferSize))
.WillOnce(Return(&mBufferContent));
FlushClient(); FlushClient();
@ -565,7 +569,8 @@ TEST_F(WireMemoryTransferServiceTests, BufferMapReadDestroyBeforeUnmap) {
EXPECT_CALL(api, OnBufferMapAsyncCallback(apiBuffer, _, _)).WillOnce(InvokeWithoutArgs([&]() { EXPECT_CALL(api, OnBufferMapAsyncCallback(apiBuffer, _, _)).WillOnce(InvokeWithoutArgs([&]() {
api.CallMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success); api.CallMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success);
})); }));
EXPECT_CALL(api, BufferGetConstMappedRange(apiBuffer)).WillOnce(Return(&mBufferContent)); EXPECT_CALL(api, BufferGetConstMappedRange(apiBuffer, 0, kBufferSize))
.WillOnce(Return(&mBufferContent));
FlushClient(); FlushClient();
@ -616,7 +621,8 @@ TEST_F(WireMemoryTransferServiceTests, BufferMapWriteSuccess) {
EXPECT_CALL(api, OnBufferMapAsyncCallback(apiBuffer, _, _)).WillOnce(InvokeWithoutArgs([&]() { EXPECT_CALL(api, OnBufferMapAsyncCallback(apiBuffer, _, _)).WillOnce(InvokeWithoutArgs([&]() {
api.CallMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success); api.CallMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success);
})); }));
EXPECT_CALL(api, BufferGetMappedRange(apiBuffer)).WillOnce(Return(&mMappedBufferContent)); EXPECT_CALL(api, BufferGetMappedRange(apiBuffer, 0, kBufferSize))
.WillOnce(Return(&mMappedBufferContent));
FlushClient(); FlushClient();
@ -755,7 +761,8 @@ TEST_F(WireMemoryTransferServiceTests, BufferMapWriteHandleOpenFailure) {
EXPECT_CALL(api, OnBufferMapAsyncCallback(apiBuffer, _, _)).WillOnce(InvokeWithoutArgs([&]() { EXPECT_CALL(api, OnBufferMapAsyncCallback(apiBuffer, _, _)).WillOnce(InvokeWithoutArgs([&]() {
api.CallMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success); api.CallMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success);
})); }));
EXPECT_CALL(api, BufferGetMappedRange(apiBuffer)).WillOnce(Return(&mMappedBufferContent)); EXPECT_CALL(api, BufferGetMappedRange(apiBuffer, 0, kBufferSize))
.WillOnce(Return(&mMappedBufferContent));
FlushClient(); FlushClient();
@ -795,7 +802,8 @@ TEST_F(WireMemoryTransferServiceTests, BufferMapWriteDeserializeFlushFailure) {
EXPECT_CALL(api, OnBufferMapAsyncCallback(apiBuffer, _, _)).WillOnce(InvokeWithoutArgs([&]() { EXPECT_CALL(api, OnBufferMapAsyncCallback(apiBuffer, _, _)).WillOnce(InvokeWithoutArgs([&]() {
api.CallMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success); api.CallMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success);
})); }));
EXPECT_CALL(api, BufferGetMappedRange(apiBuffer)).WillOnce(Return(&mMappedBufferContent)); EXPECT_CALL(api, BufferGetMappedRange(apiBuffer, 0, kBufferSize))
.WillOnce(Return(&mMappedBufferContent));
FlushClient(); FlushClient();
@ -846,7 +854,8 @@ TEST_F(WireMemoryTransferServiceTests, BufferMapWriteDestroyBeforeUnmap) {
EXPECT_CALL(api, OnBufferMapAsyncCallback(apiBuffer, _, _)).WillOnce(InvokeWithoutArgs([&]() { EXPECT_CALL(api, OnBufferMapAsyncCallback(apiBuffer, _, _)).WillOnce(InvokeWithoutArgs([&]() {
api.CallMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success); api.CallMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success);
})); }));
EXPECT_CALL(api, BufferGetMappedRange(apiBuffer)).WillOnce(Return(&mMappedBufferContent)); EXPECT_CALL(api, BufferGetMappedRange(apiBuffer, 0, kBufferSize))
.WillOnce(Return(&mMappedBufferContent));
FlushClient(); FlushClient();