Add reflection APIs for wgpu::Buffer.

Changes dawn::native procs to correctly convert C++ enum and bitmask
returns values.

Bug: dawn:1451
Change-Id: I39a8d218f76e25b178a83eeb99d653222d39d040
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/92440
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Loko Kung <lokokung@google.com>
Commit-Queue: Austin Eng <enga@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
This commit is contained in:
Corentin Wallez 2022-06-08 14:46:41 +00:00 committed by Dawn LUCI CQ
parent faa64a60ef
commit d428187d35
10 changed files with 132 additions and 13 deletions

View File

@ -433,6 +433,14 @@
{"name": "label", "type": "char", "annotation": "const*", "length": "strlen"} {"name": "label", "type": "char", "annotation": "const*", "length": "strlen"}
] ]
}, },
{
"name": "get usage",
"returns": "buffer usage"
},
{
"name": "get size",
"returns": "uint64_t"
},
{ {
"name": "unmap" "name": "unmap"
}, },

View File

@ -189,6 +189,8 @@
"BufferMapAsync", "BufferMapAsync",
"BufferGetConstMappedRange", "BufferGetConstMappedRange",
"BufferGetMappedRange", "BufferGetMappedRange",
"BufferGetSize",
"BufferGetUsage",
"DeviceCreateBuffer", "DeviceCreateBuffer",
"DeviceCreateComputePipelineAsync", "DeviceCreateComputePipelineAsync",
"DeviceCreateRenderPipelineAsync", "DeviceCreateRenderPipelineAsync",

View File

@ -66,7 +66,7 @@ namespace {{native_namespace}} {
{%- endfor -%} {%- endfor -%}
); );
{% if method.return_type.name.canonical_case() != "void" %} {% if method.return_type.name.canonical_case() != "void" %}
{% if method.return_type.category == "object" %} {% if method.return_type.category in ["object", "enum", "bitmask"] %}
return ToAPI(result); return ToAPI(result);
{% else %} {% else %}
return result; return result;
@ -104,7 +104,7 @@ namespace {{native_namespace}} {
{%- endfor -%} {%- endfor -%}
); );
{% if function.return_type.name.canonical_case() != "void" %} {% if function.return_type.name.canonical_case() != "void" %}
{% if function.return_type.category == "object" %} {% if function.return_type.category in ["object", "enum", "bitmask"] %}
return ToAPI(result); return ToAPI(result);
{% else %} {% else %}
return result; return result;

View File

@ -77,6 +77,16 @@ namespace {{native_namespace}} {
static constexpr uint32_t value = {{len(e.values)}}; static constexpr uint32_t value = {{len(e.values)}};
}; };
{% endfor %} {% endfor %}
{% for type in by_category["enum"] + by_category["bitmask"] %}
inline {{as_cType(type.name)}} ToAPI({{namespace}}::{{as_cppType(type.name)}} rhs) {
return static_cast<{{as_cType(type.name)}}>(rhs);
}
inline {{namespace}}::{{as_cppType(type.name)}} FromAPI({{as_cType(type.name)}} rhs) {
return static_cast<{{namespace}}::{{as_cppType(type.name)}}>(rhs);
}
{% endfor %}
} }
#endif // {{NATIVE_DIR}}_{{PREFIX}}_PLATFORM_AUTOGEN_H_ #endif // {{NATIVE_DIR}}_{{PREFIX}}_PLATFORM_AUTOGEN_H_

View File

@ -158,7 +158,10 @@ BufferBase::BufferBase(DeviceBase* device, const BufferDescriptor* descriptor)
BufferBase::BufferBase(DeviceBase* device, BufferBase::BufferBase(DeviceBase* device,
const BufferDescriptor* descriptor, const BufferDescriptor* descriptor,
ObjectBase::ErrorTag tag) ObjectBase::ErrorTag tag)
: ApiObjectBase(device, tag), mSize(descriptor->size), mState(BufferState::Unmapped) { : ApiObjectBase(device, tag),
mSize(descriptor->size),
mUsage(descriptor->usage),
mState(BufferState::Unmapped) {
if (descriptor->mappedAtCreation) { if (descriptor->mappedAtCreation) {
mState = BufferState::MappedAtCreation; mState = BufferState::MappedAtCreation;
mMapOffset = 0; mMapOffset = 0;
@ -215,9 +218,14 @@ wgpu::BufferUsage BufferBase::GetUsage() const {
} }
wgpu::BufferUsage BufferBase::GetUsageExternalOnly() const { wgpu::BufferUsage BufferBase::GetUsageExternalOnly() const {
ASSERT(!IsError());
return GetUsage() & ~kAllInternalBufferUsages; return GetUsage() & ~kAllInternalBufferUsages;
} }
wgpu::BufferUsage BufferBase::APIGetUsage() const {
return mUsage & ~kAllInternalBufferUsages;
}
MaybeError BufferBase::MapAtCreation() { MaybeError BufferBase::MapAtCreation() {
DAWN_TRY(MapAtCreationInternal()); DAWN_TRY(MapAtCreationInternal());
@ -378,6 +386,10 @@ void BufferBase::APIDestroy() {
Destroy(); Destroy();
} }
uint64_t BufferBase::APIGetSize() const {
return mSize;
}
MaybeError BufferBase::CopyFromStagingBuffer() { MaybeError BufferBase::CopyFromStagingBuffer() {
ASSERT(mStagingBuffer); ASSERT(mStagingBuffer);
if (mSize == 0) { if (mSize == 0) {

View File

@ -48,8 +48,6 @@ class BufferBase : public ApiObjectBase {
MappedAtCreation, MappedAtCreation,
Destroyed, Destroyed,
}; };
BufferBase(DeviceBase* device, const BufferDescriptor* descriptor);
static BufferBase* MakeError(DeviceBase* device, const BufferDescriptor* descriptor); static BufferBase* MakeError(DeviceBase* device, const BufferDescriptor* descriptor);
ObjectType GetType() const override; ObjectType GetType() const override;
@ -86,12 +84,15 @@ class BufferBase : public ApiObjectBase {
const void* APIGetConstMappedRange(size_t offset, size_t size); const void* APIGetConstMappedRange(size_t offset, size_t size);
void APIUnmap(); void APIUnmap();
void APIDestroy(); void APIDestroy();
wgpu::BufferUsage APIGetUsage() const;
uint64_t APIGetSize() const;
protected: protected:
BufferBase(DeviceBase* device, const BufferDescriptor* descriptor);
BufferBase(DeviceBase* device, const BufferDescriptor* descriptor, ObjectBase::ErrorTag tag); BufferBase(DeviceBase* device, const BufferDescriptor* descriptor, ObjectBase::ErrorTag tag);
// Constructor used only for mocking and testing. // Constructor used only for mocking and testing.
BufferBase(DeviceBase* device, BufferState state); BufferBase(DeviceBase* device, BufferState state);
void DestroyImpl() override; void DestroyImpl() override;
~BufferBase() override; ~BufferBase() override;

View File

@ -940,3 +940,74 @@ TEST_F(BufferValidationTest, GetMappedRange_OffsetSizeOOB) {
EXPECT_EQ(buffer.GetMappedRange(0, 0), nullptr); EXPECT_EQ(buffer.GetMappedRange(0, 0), nullptr);
} }
} }
// Test that the buffer creation parameters are correctly reflected for succesfully created buffers.
TEST_F(BufferValidationTest, CreationParameterReflectionForValidBuffer) {
// Test reflection on two succesfully created but different buffers. The reflected data should
// be different!
{
wgpu::BufferDescriptor desc;
desc.size = 16;
desc.usage = wgpu::BufferUsage::Uniform;
wgpu::Buffer buf = device.CreateBuffer(&desc);
EXPECT_EQ(wgpu::BufferUsage::Uniform, buf.GetUsage());
EXPECT_EQ(16u, buf.GetSize());
}
{
wgpu::BufferDescriptor desc;
desc.size = 32;
desc.usage = wgpu::BufferUsage::Storage;
wgpu::Buffer buf = device.CreateBuffer(&desc);
EXPECT_EQ(wgpu::BufferUsage::Storage, buf.GetUsage());
EXPECT_EQ(32u, buf.GetSize());
}
}
// Test that the buffer creation parameters are correctly reflected for buffers invalid because of
// validation errors.
TEST_F(BufferValidationTest, CreationParameterReflectionForErrorBuffer) {
wgpu::BufferDescriptor desc;
desc.usage = wgpu::BufferUsage::Uniform;
desc.size = 19;
desc.mappedAtCreation = true;
// Error! MappedAtCreation requires size % 4 == 0.
wgpu::Buffer buf;
ASSERT_DEVICE_ERROR(buf = device.CreateBuffer(&desc));
// Reflection data is still exactly what was in the descriptor.
EXPECT_EQ(wgpu::BufferUsage::Uniform, buf.GetUsage());
EXPECT_EQ(19u, buf.GetSize());
}
// Test that the buffer creation parameters are correctly reflected for buffers invalid because of
// OOM.
TEST_F(BufferValidationTest, CreationParameterReflectionForOOMBuffer) {
constexpr uint64_t kAmazinglyLargeSize = 0x1234'5678'90AB'CDEF;
wgpu::BufferDescriptor desc;
desc.usage = wgpu::BufferUsage::Storage;
desc.size = kAmazinglyLargeSize;
// OOM!
wgpu::Buffer buf;
ASSERT_DEVICE_ERROR(buf = device.CreateBuffer(&desc));
// Reflection data is still exactly what was in the descriptor.
EXPECT_EQ(wgpu::BufferUsage::Storage, buf.GetUsage());
EXPECT_EQ(kAmazinglyLargeSize, buf.GetSize());
}
// Test that buffer reflection doesn't show internal usages
TEST_F(BufferValidationTest, CreationParameterReflectionNoInternalUsage) {
wgpu::BufferDescriptor desc;
desc.size = 16;
// QueryResolve also adds kInternalStorageBuffer for processing of queries.
desc.usage = wgpu::BufferUsage::QueryResolve;
wgpu::Buffer buf = device.CreateBuffer(&desc);
// The reflection shouldn't show kInternalStorageBuffer
EXPECT_EQ(wgpu::BufferUsage::QueryResolve, buf.GetUsage());
EXPECT_EQ(16u, buf.GetSize());
}

View File

@ -54,7 +54,7 @@ WGPUBuffer Buffer::Create(Device* device, const WGPUBufferDescriptor* descriptor
wireClient->GetMemoryTransferService()->CreateReadHandle(descriptor->size)); wireClient->GetMemoryTransferService()->CreateReadHandle(descriptor->size));
if (readHandle == nullptr) { if (readHandle == nullptr) {
device->InjectError(WGPUErrorType_OutOfMemory, "Failed to create buffer mapping"); device->InjectError(WGPUErrorType_OutOfMemory, "Failed to create buffer mapping");
return device->CreateErrorBuffer(); return CreateError(device, descriptor);
} }
cmd.readHandleCreateInfoLength = readHandle->SerializeCreateSize(); cmd.readHandleCreateInfoLength = readHandle->SerializeCreateSize();
} }
@ -65,7 +65,7 @@ WGPUBuffer Buffer::Create(Device* device, const WGPUBufferDescriptor* descriptor
wireClient->GetMemoryTransferService()->CreateWriteHandle(descriptor->size)); wireClient->GetMemoryTransferService()->CreateWriteHandle(descriptor->size));
if (writeHandle == nullptr) { if (writeHandle == nullptr) {
device->InjectError(WGPUErrorType_OutOfMemory, "Failed to create buffer mapping"); device->InjectError(WGPUErrorType_OutOfMemory, "Failed to create buffer mapping");
return device->CreateErrorBuffer(); return CreateError(device, descriptor);
} }
cmd.writeHandleCreateInfoLength = writeHandle->SerializeCreateSize(); cmd.writeHandleCreateInfoLength = writeHandle->SerializeCreateSize();
} }
@ -79,6 +79,7 @@ WGPUBuffer Buffer::Create(Device* device, const WGPUBufferDescriptor* descriptor
buffer->mDevice = device; buffer->mDevice = device;
buffer->mDeviceIsAlive = device->GetAliveWeakPtr(); buffer->mDeviceIsAlive = device->GetAliveWeakPtr();
buffer->mSize = descriptor->size; buffer->mSize = descriptor->size;
buffer->mUsage = static_cast<WGPUBufferUsage>(descriptor->usage);
buffer->mDestructWriteHandleOnUnmap = false; buffer->mDestructWriteHandleOnUnmap = false;
if (descriptor->mappedAtCreation) { if (descriptor->mappedAtCreation) {
@ -124,10 +125,12 @@ WGPUBuffer Buffer::Create(Device* device, const WGPUBufferDescriptor* descriptor
} }
// static // static
WGPUBuffer Buffer::CreateError(Device* device) { WGPUBuffer Buffer::CreateError(Device* device, const WGPUBufferDescriptor* descriptor) {
auto* allocation = device->client->BufferAllocator().New(device->client); auto* allocation = device->client->BufferAllocator().New(device->client);
allocation->object->mDevice = device; allocation->object->mDevice = device;
allocation->object->mDeviceIsAlive = device->GetAliveWeakPtr(); allocation->object->mDeviceIsAlive = device->GetAliveWeakPtr();
allocation->object->mSize = descriptor->size;
allocation->object->mUsage = static_cast<WGPUBufferUsage>(descriptor->usage);
DeviceCreateErrorBufferCmd cmd; DeviceCreateErrorBufferCmd cmd;
cmd.self = ToAPI(device); cmd.self = ToAPI(device);
@ -365,6 +368,14 @@ void Buffer::Destroy() {
client->SerializeCommand(cmd); client->SerializeCommand(cmd);
} }
WGPUBufferUsage Buffer::GetUsage() const {
return mUsage;
}
uint64_t Buffer::GetSize() const {
return mSize;
}
bool Buffer::IsMappedForReading() const { bool Buffer::IsMappedForReading() const {
return mMapState == MapState::MappedForRead; return mMapState == MapState::MappedForRead;
} }

View File

@ -28,10 +28,8 @@ class Device;
class Buffer final : public ObjectBase { class Buffer final : public ObjectBase {
public: public:
using ObjectBase::ObjectBase;
static WGPUBuffer Create(Device* device, const WGPUBufferDescriptor* descriptor); static WGPUBuffer Create(Device* device, const WGPUBufferDescriptor* descriptor);
static WGPUBuffer CreateError(Device* device); static WGPUBuffer CreateError(Device* device, const WGPUBufferDescriptor* descriptor);
Buffer(Client* client, uint32_t refcount, uint32_t id); Buffer(Client* client, uint32_t refcount, uint32_t id);
~Buffer(); ~Buffer();
@ -51,6 +49,10 @@ class Buffer final : public ObjectBase {
void Destroy(); void Destroy();
// Note that these values can be arbitrary since they aren't validated in the wire client.
WGPUBufferUsage GetUsage() const;
uint64_t GetSize() const;
private: private:
void CancelCallbacksForDisconnect() override; void CancelCallbacksForDisconnect() override;
void ClearAllCallbacks(WGPUBufferMapAsyncStatus status); void ClearAllCallbacks(WGPUBufferMapAsyncStatus status);
@ -90,6 +92,7 @@ class Buffer final : public ObjectBase {
}; };
RequestTracker<MapRequestData> mRequests; RequestTracker<MapRequestData> mRequests;
uint64_t mSize = 0; uint64_t mSize = 0;
WGPUBufferUsage mUsage;
// Only one mapped pointer can be active at a time because Unmap clears all the in-flight // Only one mapped pointer can be active at a time because Unmap clears all the in-flight
// requests. // requests.

View File

@ -200,7 +200,8 @@ WGPUBuffer Device::CreateBuffer(const WGPUBufferDescriptor* descriptor) {
} }
WGPUBuffer Device::CreateErrorBuffer() { WGPUBuffer Device::CreateErrorBuffer() {
return Buffer::CreateError(this); WGPUBufferDescriptor fakeDescriptor = {};
return Buffer::CreateError(this, &fakeDescriptor);
} }
WGPUQueue Device::GetQueue() { WGPUQueue Device::GetQueue() {