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:
parent
cca03ca6bf
commit
03e1400fce
18
dawn.json
18
dawn.json
|
@ -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",
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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"
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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(),
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue