Add the entry point of CreateReadyRenderPipeline

BUG=dawn:529
TEST=dawn_end2end_tests

Change-Id: I42ac0edc77e5b6119eb374da72698fca14596f7b
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/30540
Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
Reviewed-by: Austin Eng <enga@chromium.org>
This commit is contained in:
Jiawei Shao 2020-10-21 04:37:41 +00:00 committed by Commit Bot service account
parent cca03ca6bf
commit 03e1400fce
15 changed files with 532 additions and 44 deletions

View File

@ -519,6 +519,15 @@
{"value": 3, "name": "unknown"} {"value": 3, "name": "unknown"}
] ]
}, },
"create ready render pipeline callback": {
"category": "callback",
"args": [
{"name": "status", "type": "create ready pipeline status"},
{"name": "pipeline", "type": "render pipeline"},
{"name": "message", "type": "char", "annotation": "const*", "length": "strlen"},
{"name": "userdata", "type": "void", "annotation": "*"}
]
},
"cull mode": { "cull mode": {
"category": "enum", "category": "enum",
"values": [ "values": [
@ -593,6 +602,15 @@
{"name": "descriptor", "type": "query set descriptor", "annotation": "const*"} {"name": "descriptor", "type": "query set descriptor", "annotation": "const*"}
] ]
}, },
{
"name": "create ready render pipeline",
"returns": "void",
"args": [
{"name": "descriptor", "type": "render pipeline descriptor", "annotation": "const*"},
{"name": "callback", "type": "create ready render pipeline callback"},
{"name": "userdata", "type": "void", "annotation": "*"}
]
},
{ {
"name": "create render bundle encoder", "name": "create render bundle encoder",
"returns": "render bundle encoder", "returns": "render bundle encoder",

View File

@ -45,6 +45,12 @@
{ "name": "pipeline object handle", "type": "ObjectHandle", "handle_type": "compute pipeline"}, { "name": "pipeline object handle", "type": "ObjectHandle", "handle_type": "compute pipeline"},
{ "name": "descriptor", "type": "compute pipeline descriptor", "annotation": "const*"} { "name": "descriptor", "type": "compute pipeline descriptor", "annotation": "const*"}
], ],
"device create ready render pipeline": [
{ "name": "device", "type": "device" },
{ "name": "request serial", "type": "uint64_t" },
{ "name": "pipeline object handle", "type": "ObjectHandle", "handle_type": "render pipeline"},
{ "name": "descriptor", "type": "render pipeline descriptor", "annotation": "const*"}
],
"device pop error scope": [ "device pop error scope": [
{ "name": "device", "type": "device" }, { "name": "device", "type": "device" },
{ "name": "request serial", "type": "uint64_t" } { "name": "request serial", "type": "uint64_t" }
@ -85,7 +91,12 @@
"device create ready compute pipeline callback": [ "device create ready compute pipeline callback": [
{ "name": "request serial", "type": "uint64_t" }, { "name": "request serial", "type": "uint64_t" },
{ "name": "status", "type": "create ready pipeline status" }, { "name": "status", "type": "create ready pipeline status" },
{ "name": "message", "type": "char", "annotation": "const*", "length": "strlen"} { "name": "message", "type": "char", "annotation": "const*", "length": "strlen" }
],
"device create ready render pipeline callback": [
{ "name": "request serial", "type": "uint64_t" },
{ "name": "status", "type": "create ready pipeline status" },
{ "name": "message", "type": "char", "annotation": "const*", "length": "strlen" }
], ],
"device uncaptured error callback": [ "device uncaptured error callback": [
{ "name": "type", "type": "error type"}, { "name": "type", "type": "error type"},
@ -121,6 +132,7 @@
"BufferGetMappedRange", "BufferGetMappedRange",
"DeviceCreateBuffer", "DeviceCreateBuffer",
"DeviceCreateReadyComputePipeline", "DeviceCreateReadyComputePipeline",
"DeviceCreateReadyRenderPipeline",
"DevicePopErrorScope", "DevicePopErrorScope",
"DeviceSetDeviceLostCallback", "DeviceSetDeviceLostCallback",
"DeviceSetUncapturedErrorCallback", "DeviceSetUncapturedErrorCallback",

View File

@ -112,6 +112,18 @@ void ProcTableAsClass::DeviceCreateReadyComputePipeline(
OnDeviceCreateReadyComputePipelineCallback(self, descriptor, callback, userdata); OnDeviceCreateReadyComputePipelineCallback(self, descriptor, callback, userdata);
} }
void ProcTableAsClass::DeviceCreateReadyRenderPipeline(
WGPUDevice self,
WGPURenderPipelineDescriptor const * descriptor,
WGPUCreateReadyRenderPipelineCallback callback,
void* userdata) {
auto object = reinterpret_cast<ProcTableAsClass::Object*>(self);
object->createReadyRenderPipelineCallback = callback;
object->userdata = userdata;
OnDeviceCreateReadyRenderPipelineCallback(self, descriptor, callback, userdata);
}
void ProcTableAsClass::CallDeviceErrorCallback(WGPUDevice device, void ProcTableAsClass::CallDeviceErrorCallback(WGPUDevice device,
WGPUErrorType type, WGPUErrorType type,
const char* message) { const char* message) {
@ -143,6 +155,14 @@ void ProcTableAsClass::CallDeviceCreateReadyComputePipelineCallback(WGPUDevice d
object->createReadyComputePipelineCallback(status, pipeline, message, object->userdata); object->createReadyComputePipelineCallback(status, pipeline, message, object->userdata);
} }
void ProcTableAsClass::CallDeviceCreateReadyRenderPipelineCallback(WGPUDevice device,
WGPUCreateReadyPipelineStatus status,
WGPURenderPipeline pipeline,
const char* message) {
auto object = reinterpret_cast<ProcTableAsClass::Object*>(device);
object->createReadyRenderPipelineCallback(status, pipeline, message, object->userdata);
}
{% for type in by_category["object"] %} {% for type in by_category["object"] %}
{{as_cType(type.name)}} ProcTableAsClass::GetNew{{type.name.CamelCase()}}() { {{as_cType(type.name)}} ProcTableAsClass::GetNew{{type.name.CamelCase()}}() {
mObjects.emplace_back(new Object); mObjects.emplace_back(new Object);

View File

@ -56,6 +56,10 @@ class ProcTableAsClass {
WGPUComputePipelineDescriptor const * descriptor, WGPUComputePipelineDescriptor const * descriptor,
WGPUCreateReadyComputePipelineCallback callback, WGPUCreateReadyComputePipelineCallback callback,
void* userdata); void* userdata);
void DeviceCreateReadyRenderPipeline(WGPUDevice self,
WGPURenderPipelineDescriptor const * descriptor,
WGPUCreateReadyRenderPipelineCallback callback,
void* userdata);
void DeviceSetUncapturedErrorCallback(WGPUDevice self, void DeviceSetUncapturedErrorCallback(WGPUDevice self,
WGPUErrorCallback callback, WGPUErrorCallback callback,
void* userdata); void* userdata);
@ -80,6 +84,11 @@ class ProcTableAsClass {
WGPUComputePipelineDescriptor const * descriptor, WGPUComputePipelineDescriptor const * descriptor,
WGPUCreateReadyComputePipelineCallback callback, WGPUCreateReadyComputePipelineCallback callback,
void* userdata) = 0; void* userdata) = 0;
virtual void OnDeviceCreateReadyRenderPipelineCallback(
WGPUDevice device,
WGPURenderPipelineDescriptor const * descriptor,
WGPUCreateReadyRenderPipelineCallback callback,
void* userdata) = 0;
virtual void OnDeviceSetUncapturedErrorCallback(WGPUDevice device, virtual void OnDeviceSetUncapturedErrorCallback(WGPUDevice device,
WGPUErrorCallback callback, WGPUErrorCallback callback,
void* userdata) = 0; void* userdata) = 0;
@ -102,6 +111,10 @@ class ProcTableAsClass {
WGPUCreateReadyPipelineStatus status, WGPUCreateReadyPipelineStatus status,
WGPUComputePipeline pipeline, WGPUComputePipeline pipeline,
const char* message); const char* message);
void CallDeviceCreateReadyRenderPipelineCallback(WGPUDevice device,
WGPUCreateReadyPipelineStatus status,
WGPURenderPipeline pipeline,
const char* message);
void CallDeviceErrorCallback(WGPUDevice device, WGPUErrorType type, const char* message); void CallDeviceErrorCallback(WGPUDevice device, WGPUErrorType type, const char* message);
void CallDeviceLostCallback(WGPUDevice device, const char* message); void CallDeviceLostCallback(WGPUDevice device, const char* message);
void CallMapAsyncCallback(WGPUBuffer buffer, WGPUBufferMapAsyncStatus status); void CallMapAsyncCallback(WGPUBuffer buffer, WGPUBufferMapAsyncStatus status);
@ -111,6 +124,7 @@ class ProcTableAsClass {
ProcTableAsClass* procs = nullptr; ProcTableAsClass* procs = nullptr;
WGPUErrorCallback deviceErrorCallback = nullptr; WGPUErrorCallback deviceErrorCallback = nullptr;
WGPUCreateReadyComputePipelineCallback createReadyComputePipelineCallback = nullptr; WGPUCreateReadyComputePipelineCallback createReadyComputePipelineCallback = nullptr;
WGPUCreateReadyRenderPipelineCallback createReadyRenderPipelineCallback = nullptr;
WGPUDeviceLostCallback deviceLostCallback = nullptr; WGPUDeviceLostCallback deviceLostCallback = nullptr;
WGPUBufferMapCallback mapAsyncCallback = nullptr; WGPUBufferMapCallback mapAsyncCallback = nullptr;
WGPUFenceOnCompletionCallback fenceOnCompletionCallback = nullptr; WGPUFenceOnCompletionCallback fenceOnCompletionCallback = nullptr;
@ -150,6 +164,12 @@ class MockProcTable : public ProcTableAsClass {
WGPUCreateReadyComputePipelineCallback callback, WGPUCreateReadyComputePipelineCallback callback,
void* userdata), void* userdata),
(override)); (override));
MOCK_METHOD(void,
OnDeviceCreateReadyRenderPipelineCallback,
(WGPUDevice device, WGPURenderPipelineDescriptor const * descriptor,
WGPUCreateReadyRenderPipelineCallback callback,
void* userdata),
(override));
MOCK_METHOD(void, OnDeviceSetUncapturedErrorCallback, (WGPUDevice device, WGPUErrorCallback callback, void* userdata), (override)); MOCK_METHOD(void, OnDeviceSetUncapturedErrorCallback, (WGPUDevice device, WGPUErrorCallback callback, void* userdata), (override));
MOCK_METHOD(void, OnDeviceSetDeviceLostCallback, (WGPUDevice device, WGPUDeviceLostCallback callback, void* userdata), (override)); MOCK_METHOD(void, OnDeviceSetDeviceLostCallback, (WGPUDevice device, WGPUDeviceLostCallback callback, void* userdata), (override));
MOCK_METHOD(bool, OnDevicePopErrorScopeCallback, (WGPUDevice device, WGPUErrorCallback callback, void* userdata), (override)); MOCK_METHOD(bool, OnDevicePopErrorScopeCallback, (WGPUDevice device, WGPUErrorCallback callback, void* userdata), (override));

View File

@ -18,39 +18,72 @@
namespace dawn_native { namespace dawn_native {
CreateReadyPipelineTaskBase::CreateReadyPipelineTaskBase(void* userdata) : mUserData(userdata) {
}
CreateReadyPipelineTaskBase::~CreateReadyPipelineTaskBase() {
}
CreateReadyComputePipelineTask::CreateReadyComputePipelineTask( CreateReadyComputePipelineTask::CreateReadyComputePipelineTask(
ComputePipelineBase* pipeline, ComputePipelineBase* pipeline,
WGPUCreateReadyComputePipelineCallback callback, WGPUCreateReadyComputePipelineCallback callback,
void* userdata) void* userdata)
: mPipeline(pipeline), mCallback(callback), mUserData(userdata) { : CreateReadyPipelineTaskBase(userdata),
} mPipeline(pipeline),
mCreateReadyComputePipelineCallback(callback) {
CreateReadyComputePipelineTask::~CreateReadyComputePipelineTask() {
} }
void CreateReadyComputePipelineTask::Finish() { void CreateReadyComputePipelineTask::Finish() {
mCallback(WGPUCreateReadyPipelineStatus_Success, ASSERT(mPipeline != nullptr);
reinterpret_cast<WGPUComputePipeline>(mPipeline), "", mUserData); ASSERT(mCreateReadyComputePipelineCallback != nullptr);
mCreateReadyComputePipelineCallback(WGPUCreateReadyPipelineStatus_Success,
reinterpret_cast<WGPUComputePipeline>(mPipeline), "",
mUserData);
// Set mCreateReadyComputePipelineCallback to nullptr in case it is called more than once.
mCreateReadyComputePipelineCallback = nullptr;
}
CreateReadyRenderPipelineTask::CreateReadyRenderPipelineTask(
RenderPipelineBase* pipeline,
WGPUCreateReadyRenderPipelineCallback callback,
void* userdata)
: CreateReadyPipelineTaskBase(userdata),
mPipeline(pipeline),
mCreateReadyRenderPipelineCallback(callback) {
}
void CreateReadyRenderPipelineTask::Finish() {
ASSERT(mPipeline != nullptr);
ASSERT(mCreateReadyRenderPipelineCallback != nullptr);
mCreateReadyRenderPipelineCallback(WGPUCreateReadyPipelineStatus_Success,
reinterpret_cast<WGPURenderPipeline>(mPipeline), "",
mUserData);
// Set mCreateReadyPipelineCallback to nullptr in case it is called more than once.
mCreateReadyRenderPipelineCallback = nullptr;
} }
CreateReadyPipelineTracker::CreateReadyPipelineTracker(DeviceBase* device) : mDevice(device) { CreateReadyPipelineTracker::CreateReadyPipelineTracker(DeviceBase* device) : mDevice(device) {
} }
CreateReadyPipelineTracker::~CreateReadyPipelineTracker() { CreateReadyPipelineTracker::~CreateReadyPipelineTracker() {
ASSERT(mCreateReadyComputePipelineTasksInFlight.Empty()); ASSERT(mCreateReadyPipelineTasksInFlight.Empty());
} }
void CreateReadyPipelineTracker::TrackTask(std::unique_ptr<CreateReadyComputePipelineTask> task, void CreateReadyPipelineTracker::TrackTask(std::unique_ptr<CreateReadyPipelineTaskBase> task,
ExecutionSerial serial) { ExecutionSerial serial) {
mCreateReadyComputePipelineTasksInFlight.Enqueue(std::move(task), serial); mCreateReadyPipelineTasksInFlight.Enqueue(std::move(task), serial);
mDevice->AddFutureSerial(serial); mDevice->AddFutureSerial(serial);
} }
void CreateReadyPipelineTracker::Tick(ExecutionSerial finishedSerial) { void CreateReadyPipelineTracker::Tick(ExecutionSerial finishedSerial) {
for (auto& task : mCreateReadyComputePipelineTasksInFlight.IterateUpTo(finishedSerial)) { for (auto& task : mCreateReadyPipelineTasksInFlight.IterateUpTo(finishedSerial)) {
task->Finish(); task->Finish();
} }
mCreateReadyComputePipelineTasksInFlight.ClearUpTo(finishedSerial); mCreateReadyPipelineTasksInFlight.ClearUpTo(finishedSerial);
} }
} // namespace dawn_native } // namespace dawn_native

View File

@ -25,19 +25,41 @@ namespace dawn_native {
class ComputePipelineBase; class ComputePipelineBase;
class DeviceBase; class DeviceBase;
class PipelineBase;
class RenderPipelineBase;
struct CreateReadyComputePipelineTask { struct CreateReadyPipelineTaskBase {
CreateReadyPipelineTaskBase(void* userData);
virtual ~CreateReadyPipelineTaskBase();
virtual void Finish() = 0;
protected:
void* mUserData;
};
struct CreateReadyComputePipelineTask final : public CreateReadyPipelineTaskBase {
CreateReadyComputePipelineTask(ComputePipelineBase* pipeline, CreateReadyComputePipelineTask(ComputePipelineBase* pipeline,
WGPUCreateReadyComputePipelineCallback callback, WGPUCreateReadyComputePipelineCallback callback,
void* userdata); void* userdata);
~CreateReadyComputePipelineTask();
void Finish(); void Finish() final;
private: private:
ComputePipelineBase* mPipeline; ComputePipelineBase* mPipeline;
WGPUCreateReadyComputePipelineCallback mCallback; WGPUCreateReadyComputePipelineCallback mCreateReadyComputePipelineCallback;
void* mUserData; };
struct CreateReadyRenderPipelineTask final : public CreateReadyPipelineTaskBase {
CreateReadyRenderPipelineTask(RenderPipelineBase* pipeline,
WGPUCreateReadyRenderPipelineCallback callback,
void* userdata);
void Finish() final;
private:
RenderPipelineBase* mPipeline;
WGPUCreateReadyRenderPipelineCallback mCreateReadyRenderPipelineCallback;
}; };
class CreateReadyPipelineTracker { class CreateReadyPipelineTracker {
@ -45,14 +67,13 @@ namespace dawn_native {
CreateReadyPipelineTracker(DeviceBase* device); CreateReadyPipelineTracker(DeviceBase* device);
~CreateReadyPipelineTracker(); ~CreateReadyPipelineTracker();
void TrackTask(std::unique_ptr<CreateReadyComputePipelineTask> task, void TrackTask(std::unique_ptr<CreateReadyPipelineTaskBase> task, ExecutionSerial serial);
ExecutionSerial serial);
void Tick(ExecutionSerial finishedSerial); void Tick(ExecutionSerial finishedSerial);
private: private:
DeviceBase* mDevice; DeviceBase* mDevice;
SerialQueue<ExecutionSerial, std::unique_ptr<CreateReadyComputePipelineTask>> SerialQueue<ExecutionSerial, std::unique_ptr<CreateReadyPipelineTaskBase>>
mCreateReadyComputePipelineTasksInFlight; mCreateReadyPipelineTasksInFlight;
}; };
} // namespace dawn_native } // namespace dawn_native

View File

@ -674,6 +674,22 @@ namespace dawn_native {
return result; return result;
} }
void DeviceBase::CreateReadyRenderPipeline(const RenderPipelineDescriptor* descriptor,
WGPUCreateReadyRenderPipelineCallback callback,
void* userdata) {
RenderPipelineBase* result = nullptr;
MaybeError maybeError = CreateRenderPipelineInternal(&result, descriptor);
if (maybeError.IsError()) {
std::unique_ptr<ErrorData> error = maybeError.AcquireError();
callback(WGPUCreateReadyPipelineStatus_Error, nullptr, error->GetMessage().c_str(),
userdata);
return;
}
std::unique_ptr<CreateReadyRenderPipelineTask> request =
std::make_unique<CreateReadyRenderPipelineTask>(result, callback, userdata);
mCreateReadyPipelineTracker->TrackTask(std::move(request), GetPendingCommandSerial());
}
RenderBundleEncoder* DeviceBase::CreateRenderBundleEncoder( RenderBundleEncoder* DeviceBase::CreateRenderBundleEncoder(
const RenderBundleEncoderDescriptor* descriptor) { const RenderBundleEncoderDescriptor* descriptor) {
RenderBundleEncoder* result = nullptr; RenderBundleEncoder* result = nullptr;

View File

@ -149,6 +149,9 @@ namespace dawn_native {
void CreateReadyComputePipeline(const ComputePipelineDescriptor* descriptor, void CreateReadyComputePipeline(const ComputePipelineDescriptor* descriptor,
WGPUCreateReadyComputePipelineCallback callback, WGPUCreateReadyComputePipelineCallback callback,
void* userdata); void* userdata);
void CreateReadyRenderPipeline(const RenderPipelineDescriptor* descriptor,
WGPUCreateReadyRenderPipelineCallback callback,
void* userdata);
RenderBundleEncoder* CreateRenderBundleEncoder( RenderBundleEncoder* CreateRenderBundleEncoder(
const RenderBundleEncoderDescriptor* descriptor); const RenderBundleEncoderDescriptor* descriptor);
RenderPipelineBase* CreateRenderPipeline(const RenderPipelineDescriptor* descriptor); RenderPipelineBase* CreateRenderPipeline(const RenderPipelineDescriptor* descriptor);

View File

@ -85,8 +85,13 @@ namespace dawn_wire { namespace client {
bool Client::DoDeviceCreateReadyComputePipelineCallback(uint64_t requestSerial, bool Client::DoDeviceCreateReadyComputePipelineCallback(uint64_t requestSerial,
WGPUCreateReadyPipelineStatus status, WGPUCreateReadyPipelineStatus status,
const char* message) { const char* message) {
mDevice->OnCreateReadyComputePipelineCallback(requestSerial, status, message); return mDevice->OnCreateReadyComputePipelineCallback(requestSerial, status, message);
return true; }
bool Client::DoDeviceCreateReadyRenderPipelineCallback(uint64_t requestSerial,
WGPUCreateReadyPipelineStatus status,
const char* message) {
return mDevice->OnCreateReadyRenderPipelineCallback(requestSerial, status, message);
} }
}} // namespace dawn_wire::client }} // namespace dawn_wire::client

View File

@ -43,10 +43,18 @@ namespace dawn_wire { namespace client {
it.second.callback(WGPUErrorType_Unknown, "Device destroyed", it.second.userdata); it.second.callback(WGPUErrorType_Unknown, "Device destroyed", it.second.userdata);
} }
auto createReadyComputePipelineRequests = std::move(mCreateReadyComputePipelineRequests); auto createReadyPipelineRequests = std::move(mCreateReadyPipelineRequests);
for (const auto& it : createReadyComputePipelineRequests) { for (const auto& it : createReadyPipelineRequests) {
it.second.callback(WGPUCreateReadyPipelineStatus_Unknown, nullptr, "Device destroyed", if (it.second.createReadyComputePipelineCallback != nullptr) {
it.second.createReadyComputePipelineCallback(WGPUCreateReadyPipelineStatus_Unknown,
nullptr, "Device destroyed",
it.second.userdata); it.second.userdata);
} else {
ASSERT(it.second.createReadyRenderPipelineCallback != nullptr);
it.second.createReadyRenderPipelineCallback(WGPUCreateReadyPipelineStatus_Unknown,
nullptr, "Device destroyed",
it.second.userdata);
}
} }
// Destroy the default queue // Destroy the default queue
@ -170,33 +178,32 @@ namespace dawn_wire { namespace client {
cmd.device = ToAPI(this); cmd.device = ToAPI(this);
cmd.descriptor = descriptor; cmd.descriptor = descriptor;
uint64_t serial = mCreateReadyComputePipelineRequestSerial++; uint64_t serial = mCreateReadyPipelineRequestSerial++;
ASSERT(mCreateReadyComputePipelineRequests.find(serial) == ASSERT(mCreateReadyPipelineRequests.find(serial) == mCreateReadyPipelineRequests.end());
mCreateReadyComputePipelineRequests.end());
cmd.requestSerial = serial; cmd.requestSerial = serial;
auto* allocation = GetClient()->ComputePipelineAllocator().New(this); auto* allocation = GetClient()->ComputePipelineAllocator().New(this);
CreateReadyComputePipelineRequest request = {}; CreateReadyPipelineRequest request = {};
request.callback = callback; request.createReadyComputePipelineCallback = callback;
request.userdata = userdata; request.userdata = userdata;
request.pipelineObjectID = allocation->object->id; request.pipelineObjectID = allocation->object->id;
cmd.pipelineObjectHandle = ObjectHandle{allocation->object->id, allocation->generation}; cmd.pipelineObjectHandle = ObjectHandle{allocation->object->id, allocation->generation};
GetClient()->SerializeCommand(cmd); GetClient()->SerializeCommand(cmd);
mCreateReadyComputePipelineRequests[serial] = std::move(request); mCreateReadyPipelineRequests[serial] = std::move(request);
} }
bool Device::OnCreateReadyComputePipelineCallback(uint64_t requestSerial, bool Device::OnCreateReadyComputePipelineCallback(uint64_t requestSerial,
WGPUCreateReadyPipelineStatus status, WGPUCreateReadyPipelineStatus status,
const char* message) { const char* message) {
const auto& requestIt = mCreateReadyComputePipelineRequests.find(requestSerial); const auto& requestIt = mCreateReadyPipelineRequests.find(requestSerial);
if (requestIt == mCreateReadyComputePipelineRequests.end()) { if (requestIt == mCreateReadyPipelineRequests.end()) {
return false; return false;
} }
CreateReadyComputePipelineRequest request = std::move(requestIt->second); CreateReadyPipelineRequest request = std::move(requestIt->second);
mCreateReadyComputePipelineRequests.erase(requestIt); mCreateReadyPipelineRequests.erase(requestIt);
auto pipelineAllocation = auto pipelineAllocation =
GetClient()->ComputePipelineAllocator().GetObject(request.pipelineObjectID); GetClient()->ComputePipelineAllocator().GetObject(request.pipelineObjectID);
@ -205,14 +212,64 @@ namespace dawn_wire { namespace client {
// free the allocation both on the client side and the server side. // free the allocation both on the client side and the server side.
if (status != WGPUCreateReadyPipelineStatus_Success) { if (status != WGPUCreateReadyPipelineStatus_Success) {
GetClient()->ComputePipelineAllocator().Free(pipelineAllocation); GetClient()->ComputePipelineAllocator().Free(pipelineAllocation);
request.callback(status, nullptr, message, request.userdata); request.createReadyComputePipelineCallback(status, nullptr, message, request.userdata);
return true; return true;
} }
WGPUComputePipeline pipeline = reinterpret_cast<WGPUComputePipeline>(pipelineAllocation); WGPUComputePipeline pipeline = reinterpret_cast<WGPUComputePipeline>(pipelineAllocation);
request.callback(status, pipeline, message, request.userdata); request.createReadyComputePipelineCallback(status, pipeline, message, request.userdata);
return true; return true;
} }
void Device::CreateReadyRenderPipeline(WGPURenderPipelineDescriptor const* descriptor,
WGPUCreateReadyRenderPipelineCallback callback,
void* userdata) {
DeviceCreateReadyRenderPipelineCmd cmd;
cmd.device = ToAPI(this);
cmd.descriptor = descriptor;
uint64_t serial = mCreateReadyPipelineRequestSerial++;
ASSERT(mCreateReadyPipelineRequests.find(serial) == mCreateReadyPipelineRequests.end());
cmd.requestSerial = serial;
auto* allocation = GetClient()->RenderPipelineAllocator().New(this);
CreateReadyPipelineRequest request = {};
request.createReadyRenderPipelineCallback = callback;
request.userdata = userdata;
request.pipelineObjectID = allocation->object->id;
cmd.pipelineObjectHandle = ObjectHandle(allocation->object->id, allocation->generation);
GetClient()->SerializeCommand(cmd);
mCreateReadyPipelineRequests[serial] = std::move(request);
}
bool Device::OnCreateReadyRenderPipelineCallback(uint64_t requestSerial,
WGPUCreateReadyPipelineStatus status,
const char* message) {
const auto& requestIt = mCreateReadyPipelineRequests.find(requestSerial);
if (requestIt == mCreateReadyPipelineRequests.end()) {
return false;
}
CreateReadyPipelineRequest request = std::move(requestIt->second);
mCreateReadyPipelineRequests.erase(requestIt);
auto pipelineAllocation =
GetClient()->RenderPipelineAllocator().GetObject(request.pipelineObjectID);
// If the return status is a failure we should give a null pipeline to the callback and
// free the allocation both on the client side and the server side.
if (status != WGPUCreateReadyPipelineStatus_Success) {
GetClient()->RenderPipelineAllocator().Free(pipelineAllocation);
request.createReadyRenderPipelineCallback(status, nullptr, message, request.userdata);
return true;
}
WGPURenderPipeline pipeline = reinterpret_cast<WGPURenderPipeline>(pipelineAllocation);
request.createReadyRenderPipelineCallback(status, pipeline, message, request.userdata);
return true;
}
}} // namespace dawn_wire::client }} // namespace dawn_wire::client

View File

@ -43,6 +43,9 @@ namespace dawn_wire { namespace client {
void CreateReadyComputePipeline(WGPUComputePipelineDescriptor const* descriptor, void CreateReadyComputePipeline(WGPUComputePipelineDescriptor const* descriptor,
WGPUCreateReadyComputePipelineCallback callback, WGPUCreateReadyComputePipelineCallback callback,
void* userdata); void* userdata);
void CreateReadyRenderPipeline(WGPURenderPipelineDescriptor const* descriptor,
WGPUCreateReadyRenderPipelineCallback callback,
void* userdata);
void HandleError(WGPUErrorType errorType, const char* message); void HandleError(WGPUErrorType errorType, const char* message);
void HandleDeviceLost(const char* message); void HandleDeviceLost(const char* message);
@ -52,6 +55,9 @@ namespace dawn_wire { namespace client {
bool OnCreateReadyComputePipelineCallback(uint64_t requestSerial, bool OnCreateReadyComputePipelineCallback(uint64_t requestSerial,
WGPUCreateReadyPipelineStatus status, WGPUCreateReadyPipelineStatus status,
const char* message); const char* message);
bool OnCreateReadyRenderPipelineCallback(uint64_t requestSerial,
WGPUCreateReadyPipelineStatus status,
const char* message);
WGPUQueue GetDefaultQueue(); WGPUQueue GetDefaultQueue();
@ -64,13 +70,14 @@ namespace dawn_wire { namespace client {
uint64_t mErrorScopeRequestSerial = 0; uint64_t mErrorScopeRequestSerial = 0;
uint64_t mErrorScopeStackSize = 0; uint64_t mErrorScopeStackSize = 0;
struct CreateReadyComputePipelineRequest { struct CreateReadyPipelineRequest {
WGPUCreateReadyComputePipelineCallback callback = nullptr; WGPUCreateReadyComputePipelineCallback createReadyComputePipelineCallback = nullptr;
WGPUCreateReadyRenderPipelineCallback createReadyRenderPipelineCallback = nullptr;
void* userdata = nullptr; void* userdata = nullptr;
ObjectId pipelineObjectID; ObjectId pipelineObjectID;
}; };
std::map<uint64_t, CreateReadyComputePipelineRequest> mCreateReadyComputePipelineRequests; std::map<uint64_t, CreateReadyPipelineRequest> mCreateReadyPipelineRequests;
uint64_t mCreateReadyComputePipelineRequestSerial = 0; uint64_t mCreateReadyPipelineRequestSerial = 0;
Client* mClient = nullptr; Client* mClient = nullptr;
WGPUErrorCallback mErrorCallback = nullptr; WGPUErrorCallback mErrorCallback = nullptr;

View File

@ -99,6 +99,10 @@ namespace dawn_wire { namespace server {
WGPUComputePipeline pipeline, WGPUComputePipeline pipeline,
const char* message, const char* message,
void* userdata); void* userdata);
static void ForwardCreateReadyRenderPipeline(WGPUCreateReadyPipelineStatus status,
WGPURenderPipeline pipeline,
const char* message,
void* userdata);
// Error callbacks // Error callbacks
void OnUncapturedError(WGPUErrorType type, const char* message); void OnUncapturedError(WGPUErrorType type, const char* message);
@ -115,6 +119,10 @@ namespace dawn_wire { namespace server {
WGPUComputePipeline pipeline, WGPUComputePipeline pipeline,
const char* message, const char* message,
CreateReadyPipelineUserData* userdata); CreateReadyPipelineUserData* userdata);
void OnCreateReadyRenderPipelineCallback(WGPUCreateReadyPipelineStatus status,
WGPURenderPipeline pipeline,
const char* message,
CreateReadyPipelineUserData* userdata);
#include "dawn_wire/server/ServerPrototypes_autogen.inc" #include "dawn_wire/server/ServerPrototypes_autogen.inc"

View File

@ -36,6 +36,16 @@ namespace dawn_wire { namespace server {
status, pipeline, message, createReadyPipelineUserData); status, pipeline, message, createReadyPipelineUserData);
} }
void Server::ForwardCreateReadyRenderPipeline(WGPUCreateReadyPipelineStatus status,
WGPURenderPipeline pipeline,
const char* message,
void* userdata) {
CreateReadyPipelineUserData* createReadyPipelineUserData =
static_cast<CreateReadyPipelineUserData*>(userdata);
createReadyPipelineUserData->server->OnCreateReadyRenderPipelineCallback(
status, pipeline, message, createReadyPipelineUserData);
}
void Server::OnUncapturedError(WGPUErrorType type, const char* message) { void Server::OnUncapturedError(WGPUErrorType type, const char* message) {
ReturnDeviceUncapturedErrorCallbackCmd cmd; ReturnDeviceUncapturedErrorCallbackCmd cmd;
cmd.type = type; cmd.type = type;
@ -105,6 +115,47 @@ namespace dawn_wire { namespace server {
SerializeCommand(cmd); SerializeCommand(cmd);
} }
bool Server::DoDeviceCreateReadyRenderPipeline(WGPUDevice cDevice,
uint64_t requestSerial,
ObjectHandle pipelineObjectHandle,
const WGPURenderPipelineDescriptor* descriptor) {
auto* resultData = RenderPipelineObjects().Allocate(pipelineObjectHandle.id);
if (resultData == nullptr) {
return false;
}
resultData->generation = pipelineObjectHandle.generation;
std::unique_ptr<CreateReadyPipelineUserData> userdata =
std::make_unique<CreateReadyPipelineUserData>();
userdata->server = this;
userdata->requestSerial = requestSerial;
userdata->pipelineObjectID = pipelineObjectHandle.id;
mProcs.deviceCreateReadyRenderPipeline(
cDevice, descriptor, ForwardCreateReadyRenderPipeline, userdata.release());
return true;
}
void Server::OnCreateReadyRenderPipelineCallback(WGPUCreateReadyPipelineStatus status,
WGPURenderPipeline pipeline,
const char* message,
CreateReadyPipelineUserData* userdata) {
std::unique_ptr<CreateReadyPipelineUserData> data(userdata);
if (status != WGPUCreateReadyPipelineStatus_Success) {
RenderPipelineObjects().Free(data->pipelineObjectID);
} else {
RenderPipelineObjects().Get(data->pipelineObjectID)->handle = pipeline;
}
ReturnDeviceCreateReadyRenderPipelineCallbackCmd cmd;
cmd.status = status;
cmd.requestSerial = data->requestSerial;
cmd.message = message;
SerializeCommand(cmd);
}
// static // static
void Server::ForwardPopErrorScope(WGPUErrorType type, const char* message, void* userdata) { void Server::ForwardPopErrorScope(WGPUErrorType type, const char* message, void* userdata) {
auto* data = reinterpret_cast<ErrorScopeUserdata*>(userdata); auto* data = reinterpret_cast<ErrorScopeUserdata*>(userdata);

View File

@ -14,11 +14,13 @@
#include "tests/DawnTest.h" #include "tests/DawnTest.h"
#include "utils/ComboRenderPipelineDescriptor.h"
#include "utils/WGPUHelpers.h" #include "utils/WGPUHelpers.h"
namespace { namespace {
struct CreateReadyPipelineTask { struct CreateReadyPipelineTask {
wgpu::ComputePipeline computePipeline; wgpu::ComputePipeline computePipeline = nullptr;
wgpu::RenderPipeline renderPipeline = nullptr;
bool isCompleted = false; bool isCompleted = false;
std::string message; std::string message;
}; };
@ -130,6 +132,133 @@ TEST_P(CreateReadyPipelineTest, CreateComputePipelineFailed) {
ASSERT_EQ(nullptr, task.computePipeline.Get()); ASSERT_EQ(nullptr, task.computePipeline.Get());
} }
// Verify the basic use of CreateReadyRenderPipeline() works on all backends.
TEST_P(CreateReadyPipelineTest, BasicUseOfCreateReadyRenderPipeline) {
constexpr wgpu::TextureFormat kOutputAttachmentFormat = wgpu::TextureFormat::RGBA8Unorm;
const char* vertexShader = R"(
#version 450
void main() {
gl_Position = vec4(0.f, 0.f, 0.f, 1.f);
gl_PointSize = 1.0f;
})";
const char* fragmentShader = R"(
#version 450
layout(location = 0) out vec4 o_color;
void main() {
o_color = vec4(0.f, 1.f, 0.f, 1.f);
})";
utils::ComboRenderPipelineDescriptor renderPipelineDescriptor(device);
wgpu::ShaderModule vsModule =
utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, vertexShader);
wgpu::ShaderModule fsModule =
utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment, fragmentShader);
renderPipelineDescriptor.vertexStage.module = vsModule;
renderPipelineDescriptor.cFragmentStage.module = fsModule;
renderPipelineDescriptor.cColorStates[0].format = kOutputAttachmentFormat;
renderPipelineDescriptor.primitiveTopology = wgpu::PrimitiveTopology::PointList;
CreateReadyPipelineTask task;
device.CreateReadyRenderPipeline(
&renderPipelineDescriptor,
[](WGPUCreateReadyPipelineStatus status, WGPURenderPipeline returnPipeline,
const char* message, void* userdata) {
ASSERT_EQ(WGPUCreateReadyPipelineStatus::WGPUCreateReadyPipelineStatus_Success, status);
CreateReadyPipelineTask* task = static_cast<CreateReadyPipelineTask*>(userdata);
task->renderPipeline = wgpu::RenderPipeline::Acquire(returnPipeline);
task->isCompleted = true;
task->message = message;
},
&task);
wgpu::TextureDescriptor textureDescriptor;
textureDescriptor.size = {1, 1, 1};
textureDescriptor.format = kOutputAttachmentFormat;
textureDescriptor.usage = wgpu::TextureUsage::OutputAttachment | wgpu::TextureUsage::CopySrc;
wgpu::Texture outputTexture = device.CreateTexture(&textureDescriptor);
utils::ComboRenderPassDescriptor renderPassDescriptor({outputTexture.CreateView()});
renderPassDescriptor.cColorAttachments[0].loadOp = wgpu::LoadOp::Clear;
renderPassDescriptor.cColorAttachments[0].clearColor = {1.f, 0.f, 0.f, 1.f};
wgpu::CommandBuffer commands;
{
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::RenderPassEncoder renderPassEncoder = encoder.BeginRenderPass(&renderPassDescriptor);
while (!task.isCompleted) {
WaitABit();
}
ASSERT_TRUE(task.message.empty());
ASSERT_NE(nullptr, task.renderPipeline.Get());
renderPassEncoder.SetPipeline(task.renderPipeline);
renderPassEncoder.Draw(1);
renderPassEncoder.EndPass();
commands = encoder.Finish();
}
queue.Submit(1, &commands);
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), outputTexture, 0, 0);
}
// Verify CreateReadyRenderPipeline() works as expected when there is any error that happens during
// the creation of the render pipeline. The SPEC requires that during the call of
// CreateReadyRenderPipeline() any error won't be forwarded to the error scope / unhandled error
// callback.
TEST_P(CreateReadyPipelineTest, CreateRenderPipelineFailed) {
DAWN_SKIP_TEST_IF(IsDawnValidationSkipped());
constexpr wgpu::TextureFormat kOutputAttachmentFormat = wgpu::TextureFormat::Depth32Float;
const char* vertexShader = R"(
#version 450
void main() {
gl_Position = vec4(0.f, 0.f, 0.f, 1.f);
gl_PointSize = 1.0f;
})";
const char* fragmentShader = R"(
#version 450
layout(location = 0) out vec4 o_color;
void main() {
o_color = vec4(0.f, 1.f, 0.f, 1.f);
})";
utils::ComboRenderPipelineDescriptor renderPipelineDescriptor(device);
wgpu::ShaderModule vsModule =
utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, vertexShader);
wgpu::ShaderModule fsModule =
utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment, fragmentShader);
renderPipelineDescriptor.vertexStage.module = vsModule;
renderPipelineDescriptor.cFragmentStage.module = fsModule;
renderPipelineDescriptor.cColorStates[0].format = kOutputAttachmentFormat;
renderPipelineDescriptor.primitiveTopology = wgpu::PrimitiveTopology::PointList;
CreateReadyPipelineTask task;
device.CreateReadyRenderPipeline(
&renderPipelineDescriptor,
[](WGPUCreateReadyPipelineStatus status, WGPURenderPipeline returnPipeline,
const char* message, void* userdata) {
ASSERT_EQ(WGPUCreateReadyPipelineStatus::WGPUCreateReadyPipelineStatus_Error, status);
CreateReadyPipelineTask* task = static_cast<CreateReadyPipelineTask*>(userdata);
task->renderPipeline = wgpu::RenderPipeline::Acquire(returnPipeline);
task->isCompleted = true;
task->message = message;
},
&task);
while (!task.isCompleted) {
WaitABit();
}
ASSERT_FALSE(task.message.empty());
ASSERT_EQ(nullptr, task.computePipeline.Get());
}
DAWN_INSTANTIATE_TEST(CreateReadyPipelineTest, DAWN_INSTANTIATE_TEST(CreateReadyPipelineTest,
D3D12Backend(), D3D12Backend(),
MetalBackend(), MetalBackend(),

View File

@ -39,6 +39,25 @@ namespace {
mockCreateReadyComputePipelineCallback->Call(status, pipeline, message, userdata); mockCreateReadyComputePipelineCallback->Call(status, pipeline, message, userdata);
} }
class MockCreateReadyRenderPipelineCallback {
public:
MOCK_METHOD(void,
Call,
(WGPUCreateReadyPipelineStatus status,
WGPURenderPipeline pipeline,
const char* message,
void* userdata));
};
std::unique_ptr<StrictMock<MockCreateReadyRenderPipelineCallback>>
mockCreateReadyRenderPipelineCallback;
void ToMockCreateReadyRenderPipelineCallback(WGPUCreateReadyPipelineStatus status,
WGPURenderPipeline pipeline,
const char* message,
void* userdata) {
mockCreateReadyRenderPipelineCallback->Call(status, pipeline, message, userdata);
}
} // anonymous namespace } // anonymous namespace
class WireCreateReadyPipelineTest : public WireTest { class WireCreateReadyPipelineTest : public WireTest {
@ -48,6 +67,8 @@ class WireCreateReadyPipelineTest : public WireTest {
mockCreateReadyComputePipelineCallback = mockCreateReadyComputePipelineCallback =
std::make_unique<StrictMock<MockCreateReadyComputePipelineCallback>>(); std::make_unique<StrictMock<MockCreateReadyComputePipelineCallback>>();
mockCreateReadyRenderPipelineCallback =
std::make_unique<StrictMock<MockCreateReadyRenderPipelineCallback>>();
} }
void TearDown() override { void TearDown() override {
@ -55,6 +76,7 @@ class WireCreateReadyPipelineTest : public WireTest {
// Delete mock so that expectations are checked // Delete mock so that expectations are checked
mockCreateReadyComputePipelineCallback = nullptr; mockCreateReadyComputePipelineCallback = nullptr;
mockCreateReadyRenderPipelineCallback = nullptr;
} }
void FlushClient() { void FlushClient() {
@ -125,3 +147,69 @@ TEST_F(WireCreateReadyPipelineTest, CreateReadyComputePipelineError) {
FlushServer(); FlushServer();
} }
// Test when creating a render pipeline with CreateReadyRenderPipeline() successfully.
TEST_F(WireCreateReadyPipelineTest, CreateReadyRenderPipelineSuccess) {
WGPUShaderModuleDescriptor vertexDescriptor = {};
WGPUShaderModule vsModule = wgpuDeviceCreateShaderModule(device, &vertexDescriptor);
WGPUShaderModule apiVsModule = api.GetNewShaderModule();
EXPECT_CALL(api, DeviceCreateShaderModule(apiDevice, _)).WillOnce(Return(apiVsModule));
WGPURenderPipelineDescriptor pipelineDescriptor{};
pipelineDescriptor.vertexStage.module = vsModule;
pipelineDescriptor.vertexStage.entryPoint = "main";
WGPUProgrammableStageDescriptor fragmentStage = {};
fragmentStage.module = vsModule;
fragmentStage.entryPoint = "main";
pipelineDescriptor.fragmentStage = &fragmentStage;
wgpuDeviceCreateReadyRenderPipeline(device, &pipelineDescriptor,
ToMockCreateReadyRenderPipelineCallback, this);
EXPECT_CALL(api, OnDeviceCreateReadyRenderPipelineCallback(apiDevice, _, _, _))
.WillOnce(InvokeWithoutArgs([&]() {
api.CallDeviceCreateReadyRenderPipelineCallback(
apiDevice, WGPUCreateReadyPipelineStatus_Success, nullptr, "");
}));
FlushClient();
EXPECT_CALL(*mockCreateReadyRenderPipelineCallback,
Call(WGPUCreateReadyPipelineStatus_Success, _, StrEq(""), this))
.Times(1);
FlushServer();
}
// Test when creating a render pipeline with CreateReadyRenderPipeline() results in an error.
TEST_F(WireCreateReadyPipelineTest, CreateReadyRenderPipelineError) {
WGPUShaderModuleDescriptor vertexDescriptor = {};
WGPUShaderModule vsModule = wgpuDeviceCreateShaderModule(device, &vertexDescriptor);
WGPUShaderModule apiVsModule = api.GetNewShaderModule();
EXPECT_CALL(api, DeviceCreateShaderModule(apiDevice, _)).WillOnce(Return(apiVsModule));
WGPURenderPipelineDescriptor pipelineDescriptor{};
pipelineDescriptor.vertexStage.module = vsModule;
pipelineDescriptor.vertexStage.entryPoint = "main";
WGPUProgrammableStageDescriptor fragmentStage = {};
fragmentStage.module = vsModule;
fragmentStage.entryPoint = "main";
pipelineDescriptor.fragmentStage = &fragmentStage;
wgpuDeviceCreateReadyRenderPipeline(device, &pipelineDescriptor,
ToMockCreateReadyRenderPipelineCallback, this);
EXPECT_CALL(api, OnDeviceCreateReadyRenderPipelineCallback(apiDevice, _, _, _))
.WillOnce(InvokeWithoutArgs([&]() {
api.CallDeviceCreateReadyRenderPipelineCallback(
apiDevice, WGPUCreateReadyPipelineStatus_Error, nullptr, "Some error message");
}));
FlushClient();
EXPECT_CALL(*mockCreateReadyRenderPipelineCallback,
Call(WGPUCreateReadyPipelineStatus_Error, _, StrEq("Some error message"), this))
.Times(1);
FlushServer();
}