mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-12-14 23:56:16 +00:00
Implement Buffer::MapAsync
MapAsync in dawn_native is fully implemented and only missing a couple cleanups that can be done once MapRead/WriteAsync are removed. MapAsync in dawn_wire is left as a pure shim on top of MapRead/WriteAsync and will be transitioned to its own commands in follow-ups. All MapRead/WriteAsync end2end and validation tests are duplicated for MapAsync. Bug: dawn:445 Change-Id: Ib1430b9257149917be19a84f13e0ddd2a8eccc32 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/24260 Commit-Queue: Corentin Wallez <cwallez@chromium.org> Reviewed-by: Austin Eng <enga@chromium.org> Reviewed-by: Stephen White <senorblanco@chromium.org>
This commit is contained in:
committed by
Commit Bot service account
parent
92f501dbfd
commit
0d52f800a1
@@ -317,6 +317,216 @@ DAWN_INSTANTIATE_TEST(BufferMapWriteTests,
|
||||
OpenGLBackend(),
|
||||
VulkanBackend());
|
||||
|
||||
class BufferMappingTests : public DawnTest {
|
||||
protected:
|
||||
void MapAsyncAndWait(const wgpu::Buffer& buffer,
|
||||
wgpu::MapMode mode,
|
||||
size_t offset,
|
||||
size_t size) {
|
||||
bool done = false;
|
||||
buffer.MapAsync(
|
||||
mode, offset, size,
|
||||
[](WGPUBufferMapAsyncStatus status, void* userdata) {
|
||||
ASSERT_EQ(WGPUBufferMapAsyncStatus_Success, status);
|
||||
*static_cast<bool*>(userdata) = true;
|
||||
},
|
||||
&done);
|
||||
|
||||
while (!done) {
|
||||
WaitABit();
|
||||
}
|
||||
}
|
||||
|
||||
wgpu::Buffer CreateMapReadBuffer(uint64_t size) {
|
||||
wgpu::BufferDescriptor descriptor;
|
||||
descriptor.size = size;
|
||||
descriptor.usage = wgpu::BufferUsage::MapRead | wgpu::BufferUsage::CopyDst;
|
||||
return device.CreateBuffer(&descriptor);
|
||||
}
|
||||
|
||||
wgpu::Buffer CreateMapWriteBuffer(uint64_t size) {
|
||||
wgpu::BufferDescriptor descriptor;
|
||||
descriptor.size = size;
|
||||
descriptor.usage = wgpu::BufferUsage::MapWrite | wgpu::BufferUsage::CopySrc;
|
||||
return device.CreateBuffer(&descriptor);
|
||||
}
|
||||
};
|
||||
|
||||
// Test that the simplest map read works
|
||||
TEST_P(BufferMappingTests, MapRead_Basic) {
|
||||
wgpu::Buffer buffer = CreateMapReadBuffer(4);
|
||||
|
||||
uint32_t myData = 0x01020304;
|
||||
queue.WriteBuffer(buffer, 0, &myData, sizeof(myData));
|
||||
|
||||
MapAsyncAndWait(buffer, wgpu::MapMode::Read, 0, 4);
|
||||
ASSERT_NE(nullptr, buffer.GetConstMappedRange());
|
||||
ASSERT_EQ(myData, *static_cast<const uint32_t*>(buffer.GetConstMappedRange()));
|
||||
buffer.Unmap();
|
||||
}
|
||||
|
||||
// Test map-reading a zero-sized buffer.
|
||||
TEST_P(BufferMappingTests, MapRead_ZeroSized) {
|
||||
wgpu::Buffer buffer = CreateMapReadBuffer(0);
|
||||
|
||||
MapAsyncAndWait(buffer, wgpu::MapMode::Read, 0, 0);
|
||||
ASSERT_NE(buffer.GetConstMappedRange(), nullptr);
|
||||
buffer.Unmap();
|
||||
}
|
||||
|
||||
// Test map-reading with a non-zero offset
|
||||
TEST_P(BufferMappingTests, MapRead_NonZeroOffset) {
|
||||
wgpu::Buffer buffer = CreateMapReadBuffer(8);
|
||||
|
||||
uint32_t myData[2] = {0x01020304, 0x05060708};
|
||||
queue.WriteBuffer(buffer, 0, &myData, sizeof(myData));
|
||||
|
||||
MapAsyncAndWait(buffer, wgpu::MapMode::Read, 4, 4);
|
||||
ASSERT_EQ(myData[1], *static_cast<const uint32_t*>(buffer.GetConstMappedRange()));
|
||||
buffer.Unmap();
|
||||
}
|
||||
|
||||
// Map read and unmap twice. Test that both of these two iterations work.
|
||||
TEST_P(BufferMappingTests, MapRead_Twice) {
|
||||
wgpu::Buffer buffer = CreateMapReadBuffer(4);
|
||||
|
||||
uint32_t myData = 0x01020304;
|
||||
queue.WriteBuffer(buffer, 0, &myData, sizeof(myData));
|
||||
|
||||
MapAsyncAndWait(buffer, wgpu::MapMode::Read, 0, 4);
|
||||
ASSERT_EQ(myData, *static_cast<const uint32_t*>(buffer.GetConstMappedRange()));
|
||||
buffer.Unmap();
|
||||
|
||||
myData = 0x05060708;
|
||||
queue.WriteBuffer(buffer, 0, &myData, sizeof(myData));
|
||||
|
||||
MapAsyncAndWait(buffer, wgpu::MapMode::Read, 0, 4);
|
||||
ASSERT_EQ(myData, *static_cast<const uint32_t*>(buffer.GetConstMappedRange()));
|
||||
buffer.Unmap();
|
||||
}
|
||||
|
||||
// Test map-reading a large buffer.
|
||||
TEST_P(BufferMappingTests, MapRead_Large) {
|
||||
constexpr uint32_t kDataSize = 1000 * 1000;
|
||||
wgpu::Buffer buffer = CreateMapReadBuffer(kDataSize * sizeof(uint32_t));
|
||||
|
||||
std::vector<uint32_t> myData;
|
||||
for (uint32_t i = 0; i < kDataSize; ++i) {
|
||||
myData.push_back(i);
|
||||
}
|
||||
queue.WriteBuffer(buffer, 0, myData.data(), kDataSize * sizeof(uint32_t));
|
||||
|
||||
MapAsyncAndWait(buffer, wgpu::MapMode::Read, 0, 4);
|
||||
ASSERT_EQ(0, memcmp(buffer.GetConstMappedRange(), myData.data(), kDataSize * sizeof(uint32_t)));
|
||||
buffer.Unmap();
|
||||
}
|
||||
|
||||
// Test that the simplest map write works.
|
||||
TEST_P(BufferMappingTests, MapWrite_Basic) {
|
||||
wgpu::Buffer buffer = CreateMapWriteBuffer(4);
|
||||
|
||||
uint32_t myData = 2934875;
|
||||
MapAsyncAndWait(buffer, wgpu::MapMode::Write, 0, 4);
|
||||
ASSERT_NE(nullptr, buffer.GetMappedRange());
|
||||
ASSERT_NE(nullptr, buffer.GetConstMappedRange());
|
||||
memcpy(buffer.GetMappedRange(), &myData, sizeof(myData));
|
||||
buffer.Unmap();
|
||||
|
||||
EXPECT_BUFFER_U32_EQ(myData, buffer, 0);
|
||||
}
|
||||
|
||||
// Test map-writing a zero-sized buffer.
|
||||
TEST_P(BufferMappingTests, MapWrite_ZeroSized) {
|
||||
wgpu::Buffer buffer = CreateMapWriteBuffer(0);
|
||||
|
||||
MapAsyncAndWait(buffer, wgpu::MapMode::Write, 0, 0);
|
||||
ASSERT_NE(buffer.GetConstMappedRange(), nullptr);
|
||||
ASSERT_NE(buffer.GetMappedRange(), nullptr);
|
||||
buffer.Unmap();
|
||||
}
|
||||
|
||||
// Test map-writing with a non-zero offset.
|
||||
TEST_P(BufferMappingTests, MapWrite_NonZeroOffset) {
|
||||
wgpu::Buffer buffer = CreateMapWriteBuffer(8);
|
||||
|
||||
uint32_t myData = 2934875;
|
||||
MapAsyncAndWait(buffer, wgpu::MapMode::Write, 4, 4);
|
||||
memcpy(buffer.GetMappedRange(), &myData, sizeof(myData));
|
||||
buffer.Unmap();
|
||||
|
||||
EXPECT_BUFFER_U32_EQ(myData, buffer, 4);
|
||||
}
|
||||
|
||||
// Map, write and unmap twice. Test that both of these two iterations work.
|
||||
TEST_P(BufferMappingTests, MapWrite_Twice) {
|
||||
wgpu::Buffer buffer = CreateMapWriteBuffer(4);
|
||||
|
||||
uint32_t myData = 2934875;
|
||||
MapAsyncAndWait(buffer, wgpu::MapMode::Write, 0, 4);
|
||||
memcpy(buffer.GetMappedRange(), &myData, sizeof(myData));
|
||||
buffer.Unmap();
|
||||
|
||||
EXPECT_BUFFER_U32_EQ(myData, buffer, 0);
|
||||
|
||||
myData = 9999999;
|
||||
MapAsyncAndWait(buffer, wgpu::MapMode::Write, 0, 4);
|
||||
memcpy(buffer.GetMappedRange(), &myData, sizeof(myData));
|
||||
buffer.Unmap();
|
||||
|
||||
EXPECT_BUFFER_U32_EQ(myData, buffer, 0);
|
||||
}
|
||||
|
||||
// Test mapping a large buffer.
|
||||
TEST_P(BufferMappingTests, MapWrite_Large) {
|
||||
constexpr uint32_t kDataSize = 1000 * 1000;
|
||||
wgpu::Buffer buffer = CreateMapWriteBuffer(kDataSize * sizeof(uint32_t));
|
||||
|
||||
std::vector<uint32_t> myData;
|
||||
for (uint32_t i = 0; i < kDataSize; ++i) {
|
||||
myData.push_back(i);
|
||||
}
|
||||
|
||||
MapAsyncAndWait(buffer, wgpu::MapMode::Write, 0, 4);
|
||||
memcpy(buffer.GetMappedRange(), myData.data(), kDataSize * sizeof(uint32_t));
|
||||
buffer.Unmap();
|
||||
|
||||
EXPECT_BUFFER_U32_RANGE_EQ(myData.data(), buffer, 0, kDataSize);
|
||||
}
|
||||
|
||||
// Test that the map offset isn't updated when the call is an error.
|
||||
TEST_P(BufferMappingTests, OffsetNotUpdatedOnError) {
|
||||
uint32_t data[3] = {0xCA7, 0xB0A7, 0xBA7};
|
||||
wgpu::Buffer buffer = CreateMapReadBuffer(sizeof(data));
|
||||
queue.WriteBuffer(buffer, 0, data, sizeof(data));
|
||||
|
||||
// Map the buffer but do not wait on the result yet.
|
||||
bool done = false;
|
||||
buffer.MapAsync(
|
||||
wgpu::MapMode::Read, 4, 4,
|
||||
[](WGPUBufferMapAsyncStatus status, void* userdata) {
|
||||
ASSERT_EQ(WGPUBufferMapAsyncStatus_Success, status);
|
||||
*static_cast<bool*>(userdata) = true;
|
||||
},
|
||||
&done);
|
||||
|
||||
// Call MapAsync another time, it is an error because the buffer is already being mapped so
|
||||
// mMapOffset is not updated.
|
||||
ASSERT_DEVICE_ERROR(buffer.MapAsync(wgpu::MapMode::Read, 8, 4, nullptr, nullptr));
|
||||
|
||||
while (!done) {
|
||||
WaitABit();
|
||||
}
|
||||
|
||||
// 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)));
|
||||
}
|
||||
|
||||
DAWN_INSTANTIATE_TEST(BufferMappingTests,
|
||||
D3D12Backend(),
|
||||
MetalBackend(),
|
||||
OpenGLBackend(),
|
||||
VulkanBackend());
|
||||
|
||||
class CreateBufferMappedTests : public DawnTest {
|
||||
protected:
|
||||
static void MapReadCallback(WGPUBufferMapAsyncStatus status,
|
||||
@@ -1058,6 +1268,42 @@ TEST_P(BufferTests, CreateBufferOOMMapWriteAsync) {
|
||||
RunTest(descriptor);
|
||||
}
|
||||
|
||||
// Test that mapping an OOM buffer fails gracefully
|
||||
TEST_P(BufferTests, CreateBufferOOMMapAsync) {
|
||||
// TODO(http://crbug.com/dawn/27): Missing support.
|
||||
DAWN_SKIP_TEST_IF(IsOpenGL());
|
||||
DAWN_SKIP_TEST_IF(IsAsan());
|
||||
|
||||
auto RunTest = [this](const wgpu::BufferDescriptor& descriptor) {
|
||||
wgpu::Buffer buffer;
|
||||
ASSERT_DEVICE_ERROR(buffer = device.CreateBuffer(&descriptor));
|
||||
|
||||
bool done = false;
|
||||
ASSERT_DEVICE_ERROR(buffer.MapAsync(
|
||||
wgpu::MapMode::Write, 0, 4,
|
||||
[](WGPUBufferMapAsyncStatus status, void* userdata) {
|
||||
EXPECT_EQ(status, WGPUBufferMapAsyncStatus_Error);
|
||||
*static_cast<bool*>(userdata) = true;
|
||||
},
|
||||
&done));
|
||||
|
||||
while (!done) {
|
||||
WaitABit();
|
||||
}
|
||||
};
|
||||
|
||||
wgpu::BufferDescriptor descriptor;
|
||||
descriptor.usage = wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::MapWrite;
|
||||
|
||||
// Test an enormous buffer
|
||||
descriptor.size = std::numeric_limits<uint64_t>::max();
|
||||
RunTest(descriptor);
|
||||
|
||||
// UINT64_MAX may be special cased. Test a smaller, but really large buffer also fails
|
||||
descriptor.size = 1ull << 50;
|
||||
RunTest(descriptor);
|
||||
}
|
||||
|
||||
DAWN_INSTANTIATE_TEST(BufferTests,
|
||||
D3D12Backend(),
|
||||
MetalBackend(),
|
||||
|
||||
@@ -58,6 +58,16 @@ static void ToMockBufferMapWriteCallback(WGPUBufferMapAsyncStatus status,
|
||||
userdata);
|
||||
}
|
||||
|
||||
class MockBufferMapAsyncCallback {
|
||||
public:
|
||||
MOCK_METHOD(void, Call, (WGPUBufferMapAsyncStatus status, void* userdata));
|
||||
};
|
||||
|
||||
static std::unique_ptr<MockBufferMapAsyncCallback> mockBufferMapAsyncCallback;
|
||||
static void ToMockBufferMapAsyncCallback(WGPUBufferMapAsyncStatus status, void* userdata) {
|
||||
mockBufferMapAsyncCallback->Call(status, userdata);
|
||||
}
|
||||
|
||||
class BufferValidationTest : public ValidationTest {
|
||||
protected:
|
||||
wgpu::Buffer CreateMapReadBuffer(uint64_t size) {
|
||||
@@ -67,6 +77,7 @@ class BufferValidationTest : public ValidationTest {
|
||||
|
||||
return device.CreateBuffer(&descriptor);
|
||||
}
|
||||
|
||||
wgpu::Buffer CreateMapWriteBuffer(uint64_t size) {
|
||||
wgpu::BufferDescriptor descriptor;
|
||||
descriptor.size = size;
|
||||
@@ -92,6 +103,13 @@ class BufferValidationTest : public ValidationTest {
|
||||
return device.CreateBuffer(&descriptor);
|
||||
}
|
||||
|
||||
void AssertMapAsyncError(wgpu::Buffer buffer, wgpu::MapMode mode, size_t offset, size_t size) {
|
||||
EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Error, _)).Times(1);
|
||||
|
||||
ASSERT_DEVICE_ERROR(
|
||||
buffer.MapAsync(mode, offset, size, ToMockBufferMapAsyncCallback, nullptr));
|
||||
}
|
||||
|
||||
wgpu::Queue queue;
|
||||
|
||||
private:
|
||||
@@ -100,6 +118,7 @@ class BufferValidationTest : public ValidationTest {
|
||||
|
||||
mockBufferMapReadCallback = std::make_unique<MockBufferMapReadCallback>();
|
||||
mockBufferMapWriteCallback = std::make_unique<MockBufferMapWriteCallback>();
|
||||
mockBufferMapAsyncCallback = std::make_unique<MockBufferMapAsyncCallback>();
|
||||
queue = device.GetDefaultQueue();
|
||||
}
|
||||
|
||||
@@ -107,6 +126,7 @@ class BufferValidationTest : public ValidationTest {
|
||||
// Delete mocks so that expectations are checked
|
||||
mockBufferMapReadCallback = nullptr;
|
||||
mockBufferMapWriteCallback = nullptr;
|
||||
mockBufferMapAsyncCallback = nullptr;
|
||||
|
||||
ValidationTest::TearDown();
|
||||
}
|
||||
@@ -164,7 +184,272 @@ TEST_F(BufferValidationTest, CreationMapUsageRestrictions) {
|
||||
}
|
||||
|
||||
// Test the success case for mapping buffer for reading
|
||||
TEST_F(BufferValidationTest, MapReadSuccess) {
|
||||
TEST_F(BufferValidationTest, MapAsync_ReadSuccess) {
|
||||
wgpu::Buffer buf = CreateMapReadBuffer(4);
|
||||
|
||||
buf.MapAsync(wgpu::MapMode::Read, 0, 4, ToMockBufferMapAsyncCallback, nullptr);
|
||||
|
||||
EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Success, _)).Times(1);
|
||||
WaitForAllOperations(device);
|
||||
|
||||
buf.Unmap();
|
||||
}
|
||||
|
||||
// Test the success case for mapping buffer for writing
|
||||
TEST_F(BufferValidationTest, MapAsync_WriteSuccess) {
|
||||
wgpu::Buffer buf = CreateMapWriteBuffer(4);
|
||||
|
||||
buf.MapAsync(wgpu::MapMode::Write, 0, 4, ToMockBufferMapAsyncCallback, nullptr);
|
||||
|
||||
EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Success, _)).Times(1);
|
||||
WaitForAllOperations(device);
|
||||
|
||||
buf.Unmap();
|
||||
}
|
||||
|
||||
// Test map async with a buffer that's an error
|
||||
TEST_F(BufferValidationTest, MapAsync_ErrorBuffer) {
|
||||
wgpu::BufferDescriptor desc;
|
||||
desc.size = 4;
|
||||
desc.usage = wgpu::BufferUsage::MapRead | wgpu::BufferUsage::MapWrite;
|
||||
wgpu::Buffer buffer;
|
||||
ASSERT_DEVICE_ERROR(buffer = device.CreateBuffer(&desc));
|
||||
|
||||
AssertMapAsyncError(buffer, wgpu::MapMode::Read, 0, 4);
|
||||
AssertMapAsyncError(buffer, wgpu::MapMode::Write, 0, 4);
|
||||
}
|
||||
|
||||
// Test map async with an invalid offset and size alignment.
|
||||
TEST_F(BufferValidationTest, MapAsync_OffsetSizeAlignment) {
|
||||
// Control case, both aligned to 4 is ok.
|
||||
{
|
||||
wgpu::Buffer buffer = CreateMapReadBuffer(8);
|
||||
buffer.MapAsync(wgpu::MapMode::Read, 4, 4, nullptr, nullptr);
|
||||
}
|
||||
{
|
||||
wgpu::Buffer buffer = CreateMapWriteBuffer(8);
|
||||
buffer.MapAsync(wgpu::MapMode::Write, 4, 4, nullptr, nullptr);
|
||||
}
|
||||
|
||||
// Error case, offset aligned to 2 is an error.
|
||||
{
|
||||
wgpu::Buffer buffer = CreateMapReadBuffer(8);
|
||||
AssertMapAsyncError(buffer, wgpu::MapMode::Read, 2, 4);
|
||||
}
|
||||
{
|
||||
wgpu::Buffer buffer = CreateMapWriteBuffer(8);
|
||||
AssertMapAsyncError(buffer, wgpu::MapMode::Write, 2, 4);
|
||||
}
|
||||
|
||||
// Error case, size aligned to 2 is an error.
|
||||
{
|
||||
wgpu::Buffer buffer = CreateMapReadBuffer(8);
|
||||
AssertMapAsyncError(buffer, wgpu::MapMode::Read, 0, 6);
|
||||
}
|
||||
{
|
||||
wgpu::Buffer buffer = CreateMapWriteBuffer(8);
|
||||
AssertMapAsyncError(buffer, wgpu::MapMode::Write, 0, 6);
|
||||
}
|
||||
}
|
||||
|
||||
// Test map async with a buffer that has the wrong usage
|
||||
TEST_F(BufferValidationTest, MapAsync_WrongUsage) {
|
||||
{
|
||||
wgpu::BufferDescriptor desc;
|
||||
desc.usage = wgpu::BufferUsage::Vertex;
|
||||
desc.size = 4;
|
||||
wgpu::Buffer buffer = device.CreateBuffer(&desc);
|
||||
|
||||
AssertMapAsyncError(buffer, wgpu::MapMode::Read, 0, 4);
|
||||
AssertMapAsyncError(buffer, wgpu::MapMode::Write, 0, 4);
|
||||
}
|
||||
{
|
||||
wgpu::Buffer buffer = CreateMapReadBuffer(4);
|
||||
AssertMapAsyncError(buffer, wgpu::MapMode::Write, 0, 4);
|
||||
}
|
||||
{
|
||||
wgpu::Buffer buffer = CreateMapWriteBuffer(4);
|
||||
AssertMapAsyncError(buffer, wgpu::MapMode::Read, 0, 4);
|
||||
}
|
||||
}
|
||||
|
||||
// Test map async with a wrong mode
|
||||
TEST_F(BufferValidationTest, MapAsync_WrongMode) {
|
||||
{
|
||||
wgpu::Buffer buffer = CreateMapReadBuffer(4);
|
||||
AssertMapAsyncError(buffer, wgpu::MapMode::None, 0, 4);
|
||||
}
|
||||
{
|
||||
wgpu::Buffer buffer = CreateMapReadBuffer(4);
|
||||
AssertMapAsyncError(buffer, wgpu::MapMode::Read | wgpu::MapMode::Write, 0, 4);
|
||||
}
|
||||
}
|
||||
|
||||
// Test map async with a buffer that's already mapped
|
||||
TEST_F(BufferValidationTest, MapAsync_AlreadyMapped) {
|
||||
{
|
||||
wgpu::Buffer buffer = CreateMapReadBuffer(4);
|
||||
buffer.MapAsync(wgpu::MapMode::Read, 0, 4, nullptr, nullptr);
|
||||
AssertMapAsyncError(buffer, wgpu::MapMode::Read, 0, 4);
|
||||
}
|
||||
{
|
||||
wgpu::Buffer buffer = BufferMappedAtCreation(4, wgpu::BufferUsage::MapRead);
|
||||
AssertMapAsyncError(buffer, wgpu::MapMode::Read, 0, 4);
|
||||
}
|
||||
{
|
||||
wgpu::Buffer buffer = CreateMapWriteBuffer(4);
|
||||
buffer.MapAsync(wgpu::MapMode::Write, 0, 4, nullptr, nullptr);
|
||||
AssertMapAsyncError(buffer, wgpu::MapMode::Write, 0, 4);
|
||||
}
|
||||
{
|
||||
wgpu::Buffer buffer = BufferMappedAtCreation(4, wgpu::BufferUsage::MapWrite);
|
||||
AssertMapAsyncError(buffer, wgpu::MapMode::Write, 0, 4);
|
||||
}
|
||||
}
|
||||
|
||||
// Test map async with a buffer that's destroyed
|
||||
TEST_F(BufferValidationTest, MapAsync_Destroy) {
|
||||
{
|
||||
wgpu::Buffer buffer = CreateMapReadBuffer(4);
|
||||
buffer.Destroy();
|
||||
AssertMapAsyncError(buffer, wgpu::MapMode::Read, 0, 4);
|
||||
}
|
||||
{
|
||||
wgpu::Buffer buffer = CreateMapWriteBuffer(4);
|
||||
buffer.Destroy();
|
||||
AssertMapAsyncError(buffer, wgpu::MapMode::Write, 0, 4);
|
||||
}
|
||||
}
|
||||
|
||||
// Test map async but unmapping before the result is ready.
|
||||
TEST_F(BufferValidationTest, MapAsync_UnmapBeforeResult) {
|
||||
{
|
||||
wgpu::Buffer buf = CreateMapReadBuffer(4);
|
||||
buf.MapAsync(wgpu::MapMode::Read, 0, 4, ToMockBufferMapAsyncCallback, nullptr);
|
||||
|
||||
EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Unknown, _))
|
||||
.Times(1);
|
||||
buf.Unmap();
|
||||
|
||||
// The callback shouldn't be called again.
|
||||
WaitForAllOperations(device);
|
||||
}
|
||||
{
|
||||
wgpu::Buffer buf = CreateMapWriteBuffer(4);
|
||||
buf.MapAsync(wgpu::MapMode::Write, 0, 4, ToMockBufferMapAsyncCallback, nullptr);
|
||||
|
||||
EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Unknown, _))
|
||||
.Times(1);
|
||||
buf.Unmap();
|
||||
|
||||
// The callback shouldn't be called again.
|
||||
WaitForAllOperations(device);
|
||||
}
|
||||
}
|
||||
|
||||
// When a MapAsync is cancelled with Unmap it might still be in flight, test doing a new request
|
||||
// works as expected and we don't get the cancelled request's data.
|
||||
TEST_F(BufferValidationTest, MapAsync_UnmapBeforeResultAndMapAgain) {
|
||||
{
|
||||
wgpu::Buffer buf = CreateMapReadBuffer(4);
|
||||
buf.MapAsync(wgpu::MapMode::Read, 0, 4, ToMockBufferMapAsyncCallback, this + 0);
|
||||
|
||||
EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Unknown, this + 0))
|
||||
.Times(1);
|
||||
buf.Unmap();
|
||||
|
||||
buf.MapAsync(wgpu::MapMode::Read, 0, 4, ToMockBufferMapAsyncCallback, this + 1);
|
||||
EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Success, this + 1))
|
||||
.Times(1);
|
||||
WaitForAllOperations(device);
|
||||
}
|
||||
{
|
||||
wgpu::Buffer buf = CreateMapWriteBuffer(4);
|
||||
buf.MapAsync(wgpu::MapMode::Write, 0, 4, ToMockBufferMapAsyncCallback, this + 0);
|
||||
|
||||
EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Unknown, this + 0))
|
||||
.Times(1);
|
||||
buf.Unmap();
|
||||
|
||||
buf.MapAsync(wgpu::MapMode::Write, 0, 4, ToMockBufferMapAsyncCallback, this + 1);
|
||||
EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Success, this + 1))
|
||||
.Times(1);
|
||||
WaitForAllOperations(device);
|
||||
}
|
||||
}
|
||||
|
||||
// Test map async but destroying before the result is ready.
|
||||
TEST_F(BufferValidationTest, MapAsync_DestroyBeforeResult) {
|
||||
{
|
||||
wgpu::Buffer buf = CreateMapReadBuffer(4);
|
||||
buf.MapAsync(wgpu::MapMode::Read, 0, 4, ToMockBufferMapAsyncCallback, nullptr);
|
||||
|
||||
EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Unknown, _))
|
||||
.Times(1);
|
||||
buf.Destroy();
|
||||
|
||||
// The callback shouldn't be called again.
|
||||
WaitForAllOperations(device);
|
||||
}
|
||||
{
|
||||
wgpu::Buffer buf = CreateMapWriteBuffer(4);
|
||||
buf.MapAsync(wgpu::MapMode::Write, 0, 4, ToMockBufferMapAsyncCallback, nullptr);
|
||||
|
||||
EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Unknown, _))
|
||||
.Times(1);
|
||||
buf.Destroy();
|
||||
|
||||
// The callback shouldn't be called again.
|
||||
WaitForAllOperations(device);
|
||||
}
|
||||
}
|
||||
|
||||
// Test that the MapCallback isn't fired twice when unmap() is called inside the callback
|
||||
TEST_F(BufferValidationTest, MapAsync_UnmapCalledInCallback) {
|
||||
{
|
||||
wgpu::Buffer buf = CreateMapReadBuffer(4);
|
||||
buf.MapAsync(wgpu::MapMode::Read, 0, 4, ToMockBufferMapAsyncCallback, nullptr);
|
||||
|
||||
EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Success, _))
|
||||
.WillOnce(InvokeWithoutArgs([&]() { buf.Unmap(); }));
|
||||
|
||||
WaitForAllOperations(device);
|
||||
}
|
||||
{
|
||||
wgpu::Buffer buf = CreateMapWriteBuffer(4);
|
||||
buf.MapAsync(wgpu::MapMode::Write, 0, 4, ToMockBufferMapAsyncCallback, nullptr);
|
||||
|
||||
EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Success, _))
|
||||
.WillOnce(InvokeWithoutArgs([&]() { buf.Unmap(); }));
|
||||
|
||||
WaitForAllOperations(device);
|
||||
}
|
||||
}
|
||||
|
||||
// Test that the MapCallback isn't fired twice when destroy() is called inside the callback
|
||||
TEST_F(BufferValidationTest, MapAsync_DestroyCalledInCallback) {
|
||||
{
|
||||
wgpu::Buffer buf = CreateMapReadBuffer(4);
|
||||
buf.MapAsync(wgpu::MapMode::Read, 0, 4, ToMockBufferMapAsyncCallback, nullptr);
|
||||
|
||||
EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Success, _))
|
||||
.WillOnce(InvokeWithoutArgs([&]() { buf.Destroy(); }));
|
||||
|
||||
WaitForAllOperations(device);
|
||||
}
|
||||
{
|
||||
wgpu::Buffer buf = CreateMapWriteBuffer(4);
|
||||
buf.MapAsync(wgpu::MapMode::Write, 0, 4, ToMockBufferMapAsyncCallback, nullptr);
|
||||
|
||||
EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Success, _))
|
||||
.WillOnce(InvokeWithoutArgs([&]() { buf.Destroy(); }));
|
||||
|
||||
WaitForAllOperations(device);
|
||||
}
|
||||
}
|
||||
|
||||
// Test the success case for mapping buffer for reading
|
||||
TEST_F(BufferValidationTest, MapReadAsyncSuccess) {
|
||||
wgpu::Buffer buf = CreateMapReadBuffer(4);
|
||||
|
||||
buf.MapReadAsync(ToMockBufferMapReadCallback, nullptr);
|
||||
@@ -178,7 +463,7 @@ TEST_F(BufferValidationTest, MapReadSuccess) {
|
||||
}
|
||||
|
||||
// Test the success case for mapping buffer for writing
|
||||
TEST_F(BufferValidationTest, MapWriteSuccess) {
|
||||
TEST_F(BufferValidationTest, MapWriteAsyncSuccess) {
|
||||
wgpu::Buffer buf = CreateMapWriteBuffer(4);
|
||||
|
||||
buf.MapWriteAsync(ToMockBufferMapWriteCallback, nullptr);
|
||||
@@ -605,6 +890,30 @@ TEST_F(BufferValidationTest, SubmitMappedBuffer) {
|
||||
wgpu::Buffer bufA = device.CreateBuffer(&descriptorA);
|
||||
wgpu::Buffer bufB = device.CreateBuffer(&descriptorB);
|
||||
|
||||
bufA.MapAsync(wgpu::MapMode::Write, 0, 4, nullptr, nullptr);
|
||||
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
encoder.CopyBufferToBuffer(bufA, 0, bufB, 0, 4);
|
||||
wgpu::CommandBuffer commands = encoder.Finish();
|
||||
ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
|
||||
WaitForAllOperations(device);
|
||||
}
|
||||
{
|
||||
wgpu::Buffer bufA = device.CreateBuffer(&descriptorA);
|
||||
wgpu::Buffer bufB = device.CreateBuffer(&descriptorB);
|
||||
|
||||
bufB.MapAsync(wgpu::MapMode::Read, 0, 4, nullptr, nullptr);
|
||||
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
encoder.CopyBufferToBuffer(bufA, 0, bufB, 0, 4);
|
||||
wgpu::CommandBuffer commands = encoder.Finish();
|
||||
ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
|
||||
WaitForAllOperations(device);
|
||||
}
|
||||
{
|
||||
wgpu::Buffer bufA = device.CreateBuffer(&descriptorA);
|
||||
wgpu::Buffer bufB = device.CreateBuffer(&descriptorB);
|
||||
|
||||
bufA.MapWriteAsync(ToMockBufferMapWriteCallback, nullptr);
|
||||
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
@@ -721,6 +1030,24 @@ TEST_F(BufferValidationTest, UnmapUnmappedBuffer) {
|
||||
buf.Unmap();
|
||||
buf.Unmap();
|
||||
}
|
||||
{
|
||||
wgpu::Buffer buf = CreateMapReadBuffer(4);
|
||||
// Buffer starts unmapped. Unmap should succeed.
|
||||
buf.Unmap();
|
||||
buf.MapAsync(wgpu::MapMode::Read, 0, 4, nullptr, nullptr);
|
||||
buf.Unmap();
|
||||
// Unmapping twice should succeed
|
||||
buf.Unmap();
|
||||
}
|
||||
{
|
||||
wgpu::Buffer buf = CreateMapWriteBuffer(4);
|
||||
// Buffer starts unmapped. Unmap should succeed.
|
||||
buf.Unmap();
|
||||
buf.MapAsync(wgpu::MapMode::Write, 0, 4, nullptr, nullptr);
|
||||
// Unmapping twice should succeed
|
||||
buf.Unmap();
|
||||
buf.Unmap();
|
||||
}
|
||||
}
|
||||
|
||||
// Test that it is invalid to call GetMappedRange on an unmapped buffer.
|
||||
@@ -779,6 +1106,32 @@ TEST_F(BufferValidationTest, GetMappedRangeOnUnmappedBuffer) {
|
||||
WaitForAllOperations(device);
|
||||
buf.Unmap();
|
||||
|
||||
ASSERT_EQ(nullptr, buf.GetMappedRange());
|
||||
ASSERT_EQ(nullptr, buf.GetConstMappedRange());
|
||||
}
|
||||
// Unmapped after MapAsync read case.
|
||||
{
|
||||
wgpu::Buffer buf = CreateMapReadBuffer(4);
|
||||
|
||||
buf.MapAsync(wgpu::MapMode::Read, 0, 4, ToMockBufferMapAsyncCallback, nullptr);
|
||||
EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Success, _))
|
||||
.Times(1);
|
||||
WaitForAllOperations(device);
|
||||
buf.Unmap();
|
||||
|
||||
ASSERT_EQ(nullptr, buf.GetMappedRange());
|
||||
ASSERT_EQ(nullptr, buf.GetConstMappedRange());
|
||||
}
|
||||
|
||||
// Unmapped after MapAsync write case.
|
||||
{
|
||||
wgpu::Buffer buf = CreateMapWriteBuffer(4);
|
||||
buf.MapAsync(wgpu::MapMode::Write, 0, 4, ToMockBufferMapAsyncCallback, nullptr);
|
||||
EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Success, _))
|
||||
.Times(1);
|
||||
WaitForAllOperations(device);
|
||||
buf.Unmap();
|
||||
|
||||
ASSERT_EQ(nullptr, buf.GetMappedRange());
|
||||
ASSERT_EQ(nullptr, buf.GetConstMappedRange());
|
||||
}
|
||||
@@ -841,6 +1194,32 @@ TEST_F(BufferValidationTest, GetMappedRangeOnDestroyedBuffer) {
|
||||
WaitForAllOperations(device);
|
||||
buf.Destroy();
|
||||
|
||||
ASSERT_EQ(nullptr, buf.GetMappedRange());
|
||||
ASSERT_EQ(nullptr, buf.GetConstMappedRange());
|
||||
}
|
||||
// Destroyed after MapAsync read case.
|
||||
{
|
||||
wgpu::Buffer buf = CreateMapReadBuffer(4);
|
||||
|
||||
buf.MapAsync(wgpu::MapMode::Read, 0, 4, ToMockBufferMapAsyncCallback, nullptr);
|
||||
EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Success, _))
|
||||
.Times(1);
|
||||
WaitForAllOperations(device);
|
||||
buf.Destroy();
|
||||
|
||||
ASSERT_EQ(nullptr, buf.GetMappedRange());
|
||||
ASSERT_EQ(nullptr, buf.GetConstMappedRange());
|
||||
}
|
||||
|
||||
// Destroyed after MapAsync write case.
|
||||
{
|
||||
wgpu::Buffer buf = CreateMapWriteBuffer(4);
|
||||
buf.MapAsync(wgpu::MapMode::Write, 0, 4, ToMockBufferMapAsyncCallback, nullptr);
|
||||
EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Success, _))
|
||||
.Times(1);
|
||||
WaitForAllOperations(device);
|
||||
buf.Destroy();
|
||||
|
||||
ASSERT_EQ(nullptr, buf.GetMappedRange());
|
||||
ASSERT_EQ(nullptr, buf.GetConstMappedRange());
|
||||
}
|
||||
@@ -848,15 +1227,27 @@ TEST_F(BufferValidationTest, GetMappedRangeOnDestroyedBuffer) {
|
||||
|
||||
// Test that it is invalid to call GetMappedRange on a buffer afterMapReadAsync
|
||||
TEST_F(BufferValidationTest, GetMappedRangeOnMappedForReading) {
|
||||
wgpu::Buffer buf = CreateMapReadBuffer(4);
|
||||
{
|
||||
wgpu::Buffer buf = CreateMapReadBuffer(4);
|
||||
|
||||
buf.MapReadAsync(ToMockBufferMapReadCallback, nullptr);
|
||||
EXPECT_CALL(*mockBufferMapReadCallback,
|
||||
Call(WGPUBufferMapAsyncStatus_Success, Ne(nullptr), 4u, _))
|
||||
.Times(1);
|
||||
WaitForAllOperations(device);
|
||||
buf.MapReadAsync(ToMockBufferMapReadCallback, nullptr);
|
||||
EXPECT_CALL(*mockBufferMapReadCallback,
|
||||
Call(WGPUBufferMapAsyncStatus_Success, Ne(nullptr), 4u, _))
|
||||
.Times(1);
|
||||
WaitForAllOperations(device);
|
||||
|
||||
ASSERT_EQ(nullptr, buf.GetMappedRange());
|
||||
ASSERT_EQ(nullptr, buf.GetMappedRange());
|
||||
}
|
||||
{
|
||||
wgpu::Buffer buf = CreateMapReadBuffer(4);
|
||||
|
||||
buf.MapAsync(wgpu::MapMode::Read, 0, 4, ToMockBufferMapAsyncCallback, nullptr);
|
||||
EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Success, _))
|
||||
.Times(1);
|
||||
WaitForAllOperations(device);
|
||||
|
||||
ASSERT_EQ(nullptr, buf.GetMappedRange());
|
||||
}
|
||||
}
|
||||
|
||||
// Test valid cases to call GetMappedRange on a buffer.
|
||||
|
||||
Reference in New Issue
Block a user