Add the entry point of CreateReadyComputePipeline
This patch adds the entry point of CreateReadyComputePipeline in both dawn_native and dawn_wire. TODOs: 1. Add more tests in dawn_unittests and dawn_end2end_tests. 2. Put the main logic of creating a pipeline into a separate thread. BUG=dawn:529 TEST=dawn_end2end_tests Change-Id: I7edd269a5422a8b85320a7f9173df925decba633 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/30060 Commit-Queue: Jiawei Shao <jiawei.shao@intel.com> Reviewed-by: Austin Eng <enga@chromium.org>
This commit is contained in:
parent
47a6a94e15
commit
ae5f950444
27
dawn.json
27
dawn.json
|
@ -501,6 +501,24 @@
|
||||||
{"name": "compute stage", "type": "programmable stage descriptor"}
|
{"name": "compute stage", "type": "programmable stage descriptor"}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"create ready compute pipeline callback": {
|
||||||
|
"category": "callback",
|
||||||
|
"args": [
|
||||||
|
{"name": "status", "type": "create ready pipeline status"},
|
||||||
|
{"name": "pipeline", "type": "compute pipeline"},
|
||||||
|
{"name": "message", "type": "char", "annotation": "const*", "length": "strlen"},
|
||||||
|
{"name": "userdata", "type": "void", "annotation": "*"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"create ready pipeline status": {
|
||||||
|
"category": "enum",
|
||||||
|
"values": [
|
||||||
|
{"value": 0, "name": "success"},
|
||||||
|
{"value": 1, "name": "error"},
|
||||||
|
{"value": 2, "name": "device lost"},
|
||||||
|
{"value": 3, "name": "unknown"}
|
||||||
|
]
|
||||||
|
},
|
||||||
"cull mode": {
|
"cull mode": {
|
||||||
"category": "enum",
|
"category": "enum",
|
||||||
"values": [
|
"values": [
|
||||||
|
@ -552,6 +570,15 @@
|
||||||
{"name": "descriptor", "type": "compute pipeline descriptor", "annotation": "const*"}
|
{"name": "descriptor", "type": "compute pipeline descriptor", "annotation": "const*"}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "create ready compute pipeline",
|
||||||
|
"returns": "void",
|
||||||
|
"args": [
|
||||||
|
{"name": "descriptor", "type": "compute pipeline descriptor", "annotation": "const*"},
|
||||||
|
{"name": "callback", "type": "create ready compute pipeline callback"},
|
||||||
|
{"name": "userdata", "type": "void", "annotation": "*"}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "create pipeline layout",
|
"name": "create pipeline layout",
|
||||||
"returns": "pipeline layout",
|
"returns": "pipeline layout",
|
||||||
|
|
|
@ -39,6 +39,12 @@
|
||||||
{ "name": "handle create info length", "type": "uint64_t" },
|
{ "name": "handle create info length", "type": "uint64_t" },
|
||||||
{ "name": "handle create info", "type": "uint8_t", "annotation": "const*", "length": "handle create info length", "skip_serialize": true}
|
{ "name": "handle create info", "type": "uint8_t", "annotation": "const*", "length": "handle create info length", "skip_serialize": true}
|
||||||
],
|
],
|
||||||
|
"device create ready compute pipeline": [
|
||||||
|
{ "name": "device", "type": "device" },
|
||||||
|
{ "name": "request serial", "type": "uint64_t" },
|
||||||
|
{ "name": "pipeline object handle", "type": "ObjectHandle", "handle_type": "compute pipeline"},
|
||||||
|
{ "name": "descriptor", "type": "compute 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" }
|
||||||
|
@ -76,6 +82,11 @@
|
||||||
{ "name": "read initial data info length", "type": "uint64_t" },
|
{ "name": "read initial data info length", "type": "uint64_t" },
|
||||||
{ "name": "read initial data info", "type": "uint8_t", "annotation": "const*", "length": "read initial data info length", "skip_serialize": true }
|
{ "name": "read initial data info", "type": "uint8_t", "annotation": "const*", "length": "read initial data info length", "skip_serialize": true }
|
||||||
],
|
],
|
||||||
|
"device create ready compute 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"},
|
||||||
{ "name": "message", "type": "char", "annotation": "const*", "length": "strlen" }
|
{ "name": "message", "type": "char", "annotation": "const*", "length": "strlen" }
|
||||||
|
@ -109,6 +120,7 @@
|
||||||
"BufferGetConstMappedRange",
|
"BufferGetConstMappedRange",
|
||||||
"BufferGetMappedRange",
|
"BufferGetMappedRange",
|
||||||
"DeviceCreateBuffer",
|
"DeviceCreateBuffer",
|
||||||
|
"DeviceCreateReadyComputePipeline",
|
||||||
"DevicePopErrorScope",
|
"DevicePopErrorScope",
|
||||||
"DeviceSetDeviceLostCallback",
|
"DeviceSetDeviceLostCallback",
|
||||||
"DeviceSetUncapturedErrorCallback",
|
"DeviceSetUncapturedErrorCallback",
|
||||||
|
|
|
@ -100,6 +100,18 @@ void ProcTableAsClass::FenceOnCompletion(WGPUFence self,
|
||||||
OnFenceOnCompletionCallback(self, value, callback, userdata);
|
OnFenceOnCompletionCallback(self, value, callback, userdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ProcTableAsClass::DeviceCreateReadyComputePipeline(
|
||||||
|
WGPUDevice self,
|
||||||
|
WGPUComputePipelineDescriptor const * descriptor,
|
||||||
|
WGPUCreateReadyComputePipelineCallback callback,
|
||||||
|
void* userdata) {
|
||||||
|
auto object = reinterpret_cast<ProcTableAsClass::Object*>(self);
|
||||||
|
object->createReadyComputePipelineCallback = callback;
|
||||||
|
object->userdata = userdata;
|
||||||
|
|
||||||
|
OnDeviceCreateReadyComputePipelineCallback(self, descriptor, callback, userdata);
|
||||||
|
}
|
||||||
|
|
||||||
void ProcTableAsClass::CallDeviceErrorCallback(WGPUDevice device,
|
void ProcTableAsClass::CallDeviceErrorCallback(WGPUDevice device,
|
||||||
WGPUErrorType type,
|
WGPUErrorType type,
|
||||||
const char* message) {
|
const char* message) {
|
||||||
|
@ -123,6 +135,14 @@ void ProcTableAsClass::CallFenceOnCompletionCallback(WGPUFence fence,
|
||||||
object->fenceOnCompletionCallback(status, object->userdata);
|
object->fenceOnCompletionCallback(status, object->userdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ProcTableAsClass::CallDeviceCreateReadyComputePipelineCallback(WGPUDevice device,
|
||||||
|
WGPUCreateReadyPipelineStatus status,
|
||||||
|
WGPUComputePipeline pipeline,
|
||||||
|
const char* message) {
|
||||||
|
auto object = reinterpret_cast<ProcTableAsClass::Object*>(device);
|
||||||
|
object->createReadyComputePipelineCallback(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);
|
||||||
|
|
|
@ -52,6 +52,10 @@ class ProcTableAsClass {
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
// Stores callback and userdata and calls the On* methods
|
// Stores callback and userdata and calls the On* methods
|
||||||
|
void DeviceCreateReadyComputePipeline(WGPUDevice self,
|
||||||
|
WGPUComputePipelineDescriptor const * descriptor,
|
||||||
|
WGPUCreateReadyComputePipelineCallback callback,
|
||||||
|
void* userdata);
|
||||||
void DeviceSetUncapturedErrorCallback(WGPUDevice self,
|
void DeviceSetUncapturedErrorCallback(WGPUDevice self,
|
||||||
WGPUErrorCallback callback,
|
WGPUErrorCallback callback,
|
||||||
void* userdata);
|
void* userdata);
|
||||||
|
@ -71,6 +75,11 @@ class ProcTableAsClass {
|
||||||
void* userdata);
|
void* userdata);
|
||||||
|
|
||||||
// Special cased mockable methods
|
// Special cased mockable methods
|
||||||
|
virtual void OnDeviceCreateReadyComputePipelineCallback(
|
||||||
|
WGPUDevice device,
|
||||||
|
WGPUComputePipelineDescriptor const * descriptor,
|
||||||
|
WGPUCreateReadyComputePipelineCallback callback,
|
||||||
|
void* userdata) = 0;
|
||||||
virtual void OnDeviceSetUncapturedErrorCallback(WGPUDevice device,
|
virtual void OnDeviceSetUncapturedErrorCallback(WGPUDevice device,
|
||||||
WGPUErrorCallback callback,
|
WGPUErrorCallback callback,
|
||||||
void* userdata) = 0;
|
void* userdata) = 0;
|
||||||
|
@ -89,6 +98,10 @@ class ProcTableAsClass {
|
||||||
void* userdata) = 0;
|
void* userdata) = 0;
|
||||||
|
|
||||||
// Calls the stored callbacks
|
// Calls the stored callbacks
|
||||||
|
void CallDeviceCreateReadyComputePipelineCallback(WGPUDevice device,
|
||||||
|
WGPUCreateReadyPipelineStatus status,
|
||||||
|
WGPUComputePipeline 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);
|
||||||
|
@ -97,6 +110,7 @@ class ProcTableAsClass {
|
||||||
struct Object {
|
struct Object {
|
||||||
ProcTableAsClass* procs = nullptr;
|
ProcTableAsClass* procs = nullptr;
|
||||||
WGPUErrorCallback deviceErrorCallback = nullptr;
|
WGPUErrorCallback deviceErrorCallback = nullptr;
|
||||||
|
WGPUCreateReadyComputePipelineCallback createReadyComputePipelineCallback = nullptr;
|
||||||
WGPUDeviceLostCallback deviceLostCallback = nullptr;
|
WGPUDeviceLostCallback deviceLostCallback = nullptr;
|
||||||
WGPUBufferMapCallback mapAsyncCallback = nullptr;
|
WGPUBufferMapCallback mapAsyncCallback = nullptr;
|
||||||
WGPUFenceOnCompletionCallback fenceOnCompletionCallback = nullptr;
|
WGPUFenceOnCompletionCallback fenceOnCompletionCallback = nullptr;
|
||||||
|
@ -130,6 +144,12 @@ class MockProcTable : public ProcTableAsClass {
|
||||||
MOCK_METHOD(void, {{as_MethodSuffix(type.name, Name("release"))}}, ({{as_cType(type.name)}} self), (override));
|
MOCK_METHOD(void, {{as_MethodSuffix(type.name, Name("release"))}}, ({{as_cType(type.name)}} self), (override));
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
|
MOCK_METHOD(void,
|
||||||
|
OnDeviceCreateReadyComputePipelineCallback,
|
||||||
|
(WGPUDevice device, WGPUComputePipelineDescriptor const * descriptor,
|
||||||
|
WGPUCreateReadyComputePipelineCallback 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));
|
||||||
|
|
|
@ -183,6 +183,8 @@ source_set("dawn_native_sources") {
|
||||||
"ComputePassEncoder.h",
|
"ComputePassEncoder.h",
|
||||||
"ComputePipeline.cpp",
|
"ComputePipeline.cpp",
|
||||||
"ComputePipeline.h",
|
"ComputePipeline.h",
|
||||||
|
"CreateReadyPipelineTracker.cpp",
|
||||||
|
"CreateReadyPipelineTracker.h",
|
||||||
"Device.cpp",
|
"Device.cpp",
|
||||||
"Device.h",
|
"Device.h",
|
||||||
"DynamicUploader.cpp",
|
"DynamicUploader.cpp",
|
||||||
|
|
|
@ -66,6 +66,8 @@ target_sources(dawn_native PRIVATE
|
||||||
"ComputePassEncoder.h"
|
"ComputePassEncoder.h"
|
||||||
"ComputePipeline.cpp"
|
"ComputePipeline.cpp"
|
||||||
"ComputePipeline.h"
|
"ComputePipeline.h"
|
||||||
|
"CreateReadyPipelineTracker.cpp",
|
||||||
|
"CreateReadyPipelineTracker.h",
|
||||||
"Device.cpp"
|
"Device.cpp"
|
||||||
"Device.h"
|
"Device.h"
|
||||||
"DynamicUploader.cpp"
|
"DynamicUploader.cpp"
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
// Copyright 2020 The Dawn Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "dawn_native/CreateReadyPipelineTracker.h"
|
||||||
|
|
||||||
|
#include "dawn_native/Device.h"
|
||||||
|
|
||||||
|
namespace dawn_native {
|
||||||
|
|
||||||
|
CreateReadyComputePipelineTask::CreateReadyComputePipelineTask(
|
||||||
|
ComputePipelineBase* pipeline,
|
||||||
|
WGPUCreateReadyComputePipelineCallback callback,
|
||||||
|
void* userdata)
|
||||||
|
: mPipeline(pipeline), mCallback(callback), mUserData(userdata) {
|
||||||
|
}
|
||||||
|
|
||||||
|
CreateReadyComputePipelineTask::~CreateReadyComputePipelineTask() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void CreateReadyComputePipelineTask::Finish() {
|
||||||
|
mCallback(WGPUCreateReadyPipelineStatus_Success,
|
||||||
|
reinterpret_cast<WGPUComputePipeline>(mPipeline), "", mUserData);
|
||||||
|
}
|
||||||
|
|
||||||
|
CreateReadyPipelineTracker::CreateReadyPipelineTracker(DeviceBase* device) : mDevice(device) {
|
||||||
|
}
|
||||||
|
|
||||||
|
CreateReadyPipelineTracker::~CreateReadyPipelineTracker() {
|
||||||
|
ASSERT(mCreateReadyComputePipelineTasksInFlight.Empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
void CreateReadyPipelineTracker::TrackTask(std::unique_ptr<CreateReadyComputePipelineTask> task,
|
||||||
|
ExecutionSerial serial) {
|
||||||
|
mCreateReadyComputePipelineTasksInFlight.Enqueue(std::move(task), serial);
|
||||||
|
mDevice->AddFutureSerial(serial);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CreateReadyPipelineTracker::Tick(ExecutionSerial finishedSerial) {
|
||||||
|
for (auto& task : mCreateReadyComputePipelineTasksInFlight.IterateUpTo(finishedSerial)) {
|
||||||
|
task->Finish();
|
||||||
|
}
|
||||||
|
mCreateReadyComputePipelineTasksInFlight.ClearUpTo(finishedSerial);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace dawn_native
|
|
@ -0,0 +1,60 @@
|
||||||
|
// Copyright 2020 The Dawn Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef DAWNNATIVE_CREATEREADYPIPELINETRACKER_H_
|
||||||
|
#define DAWNNATIVE_CREATEREADYPIPELINETRACKER_H_
|
||||||
|
|
||||||
|
#include "common/SerialQueue.h"
|
||||||
|
#include "dawn/webgpu.h"
|
||||||
|
#include "dawn_native/IntegerTypes.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace dawn_native {
|
||||||
|
|
||||||
|
class ComputePipelineBase;
|
||||||
|
class DeviceBase;
|
||||||
|
|
||||||
|
struct CreateReadyComputePipelineTask {
|
||||||
|
CreateReadyComputePipelineTask(ComputePipelineBase* pipeline,
|
||||||
|
WGPUCreateReadyComputePipelineCallback callback,
|
||||||
|
void* userdata);
|
||||||
|
~CreateReadyComputePipelineTask();
|
||||||
|
|
||||||
|
void Finish();
|
||||||
|
|
||||||
|
private:
|
||||||
|
ComputePipelineBase* mPipeline;
|
||||||
|
WGPUCreateReadyComputePipelineCallback mCallback;
|
||||||
|
void* mUserData;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CreateReadyPipelineTracker {
|
||||||
|
public:
|
||||||
|
CreateReadyPipelineTracker(DeviceBase* device);
|
||||||
|
~CreateReadyPipelineTracker();
|
||||||
|
|
||||||
|
void TrackTask(std::unique_ptr<CreateReadyComputePipelineTask> task,
|
||||||
|
ExecutionSerial serial);
|
||||||
|
void Tick(ExecutionSerial finishedSerial);
|
||||||
|
|
||||||
|
private:
|
||||||
|
DeviceBase* mDevice;
|
||||||
|
SerialQueue<ExecutionSerial, std::unique_ptr<CreateReadyComputePipelineTask>>
|
||||||
|
mCreateReadyComputePipelineTasksInFlight;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace dawn_native
|
||||||
|
|
||||||
|
#endif
|
|
@ -23,6 +23,7 @@
|
||||||
#include "dawn_native/CommandBuffer.h"
|
#include "dawn_native/CommandBuffer.h"
|
||||||
#include "dawn_native/CommandEncoder.h"
|
#include "dawn_native/CommandEncoder.h"
|
||||||
#include "dawn_native/ComputePipeline.h"
|
#include "dawn_native/ComputePipeline.h"
|
||||||
|
#include "dawn_native/CreateReadyPipelineTracker.h"
|
||||||
#include "dawn_native/DynamicUploader.h"
|
#include "dawn_native/DynamicUploader.h"
|
||||||
#include "dawn_native/ErrorData.h"
|
#include "dawn_native/ErrorData.h"
|
||||||
#include "dawn_native/ErrorScope.h"
|
#include "dawn_native/ErrorScope.h"
|
||||||
|
@ -102,6 +103,7 @@ namespace dawn_native {
|
||||||
mCaches = std::make_unique<DeviceBase::Caches>();
|
mCaches = std::make_unique<DeviceBase::Caches>();
|
||||||
mErrorScopeTracker = std::make_unique<ErrorScopeTracker>(this);
|
mErrorScopeTracker = std::make_unique<ErrorScopeTracker>(this);
|
||||||
mDynamicUploader = std::make_unique<DynamicUploader>(this);
|
mDynamicUploader = std::make_unique<DynamicUploader>(this);
|
||||||
|
mCreateReadyPipelineTracker = std::make_unique<CreateReadyPipelineTracker>(this);
|
||||||
mDeprecationWarnings = std::make_unique<DeprecationWarnings>();
|
mDeprecationWarnings = std::make_unique<DeprecationWarnings>();
|
||||||
|
|
||||||
// Starting from now the backend can start doing reentrant calls so the device is marked as
|
// Starting from now the backend can start doing reentrant calls so the device is marked as
|
||||||
|
@ -149,6 +151,8 @@ namespace dawn_native {
|
||||||
// pending callbacks.
|
// pending callbacks.
|
||||||
mErrorScopeTracker->Tick(GetCompletedCommandSerial());
|
mErrorScopeTracker->Tick(GetCompletedCommandSerial());
|
||||||
GetDefaultQueue()->Tick(GetCompletedCommandSerial());
|
GetDefaultQueue()->Tick(GetCompletedCommandSerial());
|
||||||
|
mCreateReadyPipelineTracker->Tick(GetCompletedCommandSerial());
|
||||||
|
|
||||||
// call TickImpl once last time to clean up resources
|
// call TickImpl once last time to clean up resources
|
||||||
// Ignore errors so that we can continue with destruction
|
// Ignore errors so that we can continue with destruction
|
||||||
IgnoreErrors(TickImpl());
|
IgnoreErrors(TickImpl());
|
||||||
|
@ -163,6 +167,7 @@ namespace dawn_native {
|
||||||
}
|
}
|
||||||
mErrorScopeTracker = nullptr;
|
mErrorScopeTracker = nullptr;
|
||||||
mDynamicUploader = nullptr;
|
mDynamicUploader = nullptr;
|
||||||
|
mCreateReadyPipelineTracker = nullptr;
|
||||||
|
|
||||||
mEmptyBindGroupLayout = nullptr;
|
mEmptyBindGroupLayout = nullptr;
|
||||||
|
|
||||||
|
@ -619,6 +624,22 @@ namespace dawn_native {
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
void DeviceBase::CreateReadyComputePipeline(const ComputePipelineDescriptor* descriptor,
|
||||||
|
WGPUCreateReadyComputePipelineCallback callback,
|
||||||
|
void* userdata) {
|
||||||
|
ComputePipelineBase* result = nullptr;
|
||||||
|
MaybeError maybeError = CreateComputePipelineInternal(&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<CreateReadyComputePipelineTask> request =
|
||||||
|
std::make_unique<CreateReadyComputePipelineTask>(result, callback, userdata);
|
||||||
|
mCreateReadyPipelineTracker->TrackTask(std::move(request), GetPendingCommandSerial());
|
||||||
|
}
|
||||||
PipelineLayoutBase* DeviceBase::CreatePipelineLayout(
|
PipelineLayoutBase* DeviceBase::CreatePipelineLayout(
|
||||||
const PipelineLayoutDescriptor* descriptor) {
|
const PipelineLayoutDescriptor* descriptor) {
|
||||||
PipelineLayoutBase* result = nullptr;
|
PipelineLayoutBase* result = nullptr;
|
||||||
|
@ -750,6 +771,7 @@ namespace dawn_native {
|
||||||
mDynamicUploader->Deallocate(mCompletedSerial);
|
mDynamicUploader->Deallocate(mCompletedSerial);
|
||||||
mErrorScopeTracker->Tick(mCompletedSerial);
|
mErrorScopeTracker->Tick(mCompletedSerial);
|
||||||
GetDefaultQueue()->Tick(mCompletedSerial);
|
GetDefaultQueue()->Tick(mCompletedSerial);
|
||||||
|
mCreateReadyPipelineTracker->Tick(mCompletedSerial);
|
||||||
}
|
}
|
||||||
|
|
||||||
return !IsDeviceIdle();
|
return !IsDeviceIdle();
|
||||||
|
|
|
@ -33,6 +33,7 @@ namespace dawn_native {
|
||||||
class AttachmentState;
|
class AttachmentState;
|
||||||
class AttachmentStateBlueprint;
|
class AttachmentStateBlueprint;
|
||||||
class BindGroupLayoutBase;
|
class BindGroupLayoutBase;
|
||||||
|
class CreateReadyPipelineTracker;
|
||||||
class DynamicUploader;
|
class DynamicUploader;
|
||||||
class ErrorScope;
|
class ErrorScope;
|
||||||
class ErrorScopeTracker;
|
class ErrorScopeTracker;
|
||||||
|
@ -145,6 +146,9 @@ namespace dawn_native {
|
||||||
PipelineLayoutBase* CreatePipelineLayout(const PipelineLayoutDescriptor* descriptor);
|
PipelineLayoutBase* CreatePipelineLayout(const PipelineLayoutDescriptor* descriptor);
|
||||||
QuerySetBase* CreateQuerySet(const QuerySetDescriptor* descriptor);
|
QuerySetBase* CreateQuerySet(const QuerySetDescriptor* descriptor);
|
||||||
QueueBase* CreateQueue();
|
QueueBase* CreateQueue();
|
||||||
|
void CreateReadyComputePipeline(const ComputePipelineDescriptor* descriptor,
|
||||||
|
WGPUCreateReadyComputePipelineCallback callback,
|
||||||
|
void* userdata);
|
||||||
RenderBundleEncoder* CreateRenderBundleEncoder(
|
RenderBundleEncoder* CreateRenderBundleEncoder(
|
||||||
const RenderBundleEncoderDescriptor* descriptor);
|
const RenderBundleEncoderDescriptor* descriptor);
|
||||||
RenderPipelineBase* CreateRenderPipeline(const RenderPipelineDescriptor* descriptor);
|
RenderPipelineBase* CreateRenderPipeline(const RenderPipelineDescriptor* descriptor);
|
||||||
|
@ -362,6 +366,7 @@ namespace dawn_native {
|
||||||
|
|
||||||
std::unique_ptr<DynamicUploader> mDynamicUploader;
|
std::unique_ptr<DynamicUploader> mDynamicUploader;
|
||||||
std::unique_ptr<ErrorScopeTracker> mErrorScopeTracker;
|
std::unique_ptr<ErrorScopeTracker> mErrorScopeTracker;
|
||||||
|
std::unique_ptr<CreateReadyPipelineTracker> mCreateReadyPipelineTracker;
|
||||||
Ref<QueueBase> mDefaultQueue;
|
Ref<QueueBase> mDefaultQueue;
|
||||||
|
|
||||||
struct DeprecationWarnings;
|
struct DeprecationWarnings;
|
||||||
|
|
|
@ -82,4 +82,11 @@ namespace dawn_wire { namespace client {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Client::DoDeviceCreateReadyComputePipelineCallback(uint64_t requestSerial,
|
||||||
|
WGPUCreateReadyPipelineStatus status,
|
||||||
|
const char* message) {
|
||||||
|
mDevice->OnCreateReadyComputePipelineCallback(requestSerial, status, message);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
}} // namespace dawn_wire::client
|
}} // namespace dawn_wire::client
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
#include "dawn_wire/client/Device.h"
|
#include "dawn_wire/client/Device.h"
|
||||||
|
|
||||||
#include "common/Assert.h"
|
#include "common/Assert.h"
|
||||||
#include "dawn_wire/WireCmd_autogen.h"
|
|
||||||
#include "dawn_wire/client/ApiObjects_autogen.h"
|
#include "dawn_wire/client/ApiObjects_autogen.h"
|
||||||
#include "dawn_wire/client/Client.h"
|
#include "dawn_wire/client/Client.h"
|
||||||
#include "dawn_wire/client/ObjectAllocator.h"
|
#include "dawn_wire/client/ObjectAllocator.h"
|
||||||
|
@ -44,6 +43,12 @@ 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);
|
||||||
|
for (const auto& it : createReadyComputePipelineRequests) {
|
||||||
|
it.second.callback(WGPUCreateReadyPipelineStatus_Unknown, nullptr, "Device destroyed",
|
||||||
|
it.second.userdata);
|
||||||
|
}
|
||||||
|
|
||||||
// Destroy the default queue
|
// Destroy the default queue
|
||||||
DestroyObjectCmd cmd;
|
DestroyObjectCmd cmd;
|
||||||
cmd.objectType = ObjectType::Queue;
|
cmd.objectType = ObjectType::Queue;
|
||||||
|
@ -158,4 +163,56 @@ namespace dawn_wire { namespace client {
|
||||||
return ToAPI(mDefaultQueue);
|
return ToAPI(mDefaultQueue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Device::CreateReadyComputePipeline(WGPUComputePipelineDescriptor const* descriptor,
|
||||||
|
WGPUCreateReadyComputePipelineCallback callback,
|
||||||
|
void* userdata) {
|
||||||
|
DeviceCreateReadyComputePipelineCmd cmd;
|
||||||
|
cmd.device = ToAPI(this);
|
||||||
|
cmd.descriptor = descriptor;
|
||||||
|
|
||||||
|
uint64_t serial = mCreateReadyComputePipelineRequestSerial++;
|
||||||
|
ASSERT(mCreateReadyComputePipelineRequests.find(serial) ==
|
||||||
|
mCreateReadyComputePipelineRequests.end());
|
||||||
|
cmd.requestSerial = serial;
|
||||||
|
|
||||||
|
auto* allocation = GetClient()->ComputePipelineAllocator().New(this);
|
||||||
|
CreateReadyComputePipelineRequest request = {};
|
||||||
|
request.callback = callback;
|
||||||
|
request.userdata = userdata;
|
||||||
|
request.pipelineObjectID = allocation->object->id;
|
||||||
|
|
||||||
|
cmd.pipelineObjectHandle = ObjectHandle{allocation->object->id, allocation->generation};
|
||||||
|
GetClient()->SerializeCommand(cmd);
|
||||||
|
|
||||||
|
mCreateReadyComputePipelineRequests[serial] = std::move(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Device::OnCreateReadyComputePipelineCallback(uint64_t requestSerial,
|
||||||
|
WGPUCreateReadyPipelineStatus status,
|
||||||
|
const char* message) {
|
||||||
|
const auto& requestIt = mCreateReadyComputePipelineRequests.find(requestSerial);
|
||||||
|
if (requestIt == mCreateReadyComputePipelineRequests.end()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CreateReadyComputePipelineRequest request = std::move(requestIt->second);
|
||||||
|
mCreateReadyComputePipelineRequests.erase(requestIt);
|
||||||
|
|
||||||
|
auto pipelineAllocation =
|
||||||
|
GetClient()->ComputePipelineAllocator().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()->ComputePipelineAllocator().Free(pipelineAllocation);
|
||||||
|
request.callback(status, nullptr, message, request.userdata);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
WGPUComputePipeline pipeline = reinterpret_cast<WGPUComputePipeline>(pipelineAllocation);
|
||||||
|
request.callback(status, pipeline, message, request.userdata);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
}} // namespace dawn_wire::client
|
}} // namespace dawn_wire::client
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
#include <dawn/webgpu.h>
|
#include <dawn/webgpu.h>
|
||||||
|
|
||||||
|
#include "dawn_wire/WireCmd_autogen.h"
|
||||||
#include "dawn_wire/client/ObjectBase.h"
|
#include "dawn_wire/client/ObjectBase.h"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
@ -39,12 +40,18 @@ namespace dawn_wire { namespace client {
|
||||||
bool PopErrorScope(WGPUErrorCallback callback, void* userdata);
|
bool PopErrorScope(WGPUErrorCallback callback, void* userdata);
|
||||||
WGPUBuffer CreateBuffer(const WGPUBufferDescriptor* descriptor);
|
WGPUBuffer CreateBuffer(const WGPUBufferDescriptor* descriptor);
|
||||||
WGPUBuffer CreateErrorBuffer();
|
WGPUBuffer CreateErrorBuffer();
|
||||||
|
void CreateReadyComputePipeline(WGPUComputePipelineDescriptor const* descriptor,
|
||||||
|
WGPUCreateReadyComputePipelineCallback 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);
|
||||||
bool OnPopErrorScopeCallback(uint64_t requestSerial,
|
bool OnPopErrorScopeCallback(uint64_t requestSerial,
|
||||||
WGPUErrorType type,
|
WGPUErrorType type,
|
||||||
const char* message);
|
const char* message);
|
||||||
|
bool OnCreateReadyComputePipelineCallback(uint64_t requestSerial,
|
||||||
|
WGPUCreateReadyPipelineStatus status,
|
||||||
|
const char* message);
|
||||||
|
|
||||||
WGPUQueue GetDefaultQueue();
|
WGPUQueue GetDefaultQueue();
|
||||||
|
|
||||||
|
@ -57,6 +64,14 @@ namespace dawn_wire { namespace client {
|
||||||
uint64_t mErrorScopeRequestSerial = 0;
|
uint64_t mErrorScopeRequestSerial = 0;
|
||||||
uint64_t mErrorScopeStackSize = 0;
|
uint64_t mErrorScopeStackSize = 0;
|
||||||
|
|
||||||
|
struct CreateReadyComputePipelineRequest {
|
||||||
|
WGPUCreateReadyComputePipelineCallback callback = nullptr;
|
||||||
|
void* userdata = nullptr;
|
||||||
|
ObjectId pipelineObjectID;
|
||||||
|
};
|
||||||
|
std::map<uint64_t, CreateReadyComputePipelineRequest> mCreateReadyComputePipelineRequests;
|
||||||
|
uint64_t mCreateReadyComputePipelineRequestSerial = 0;
|
||||||
|
|
||||||
Client* mClient = nullptr;
|
Client* mClient = nullptr;
|
||||||
WGPUErrorCallback mErrorCallback = nullptr;
|
WGPUErrorCallback mErrorCallback = nullptr;
|
||||||
WGPUDeviceLostCallback mDeviceLostCallback = nullptr;
|
WGPUDeviceLostCallback mDeviceLostCallback = nullptr;
|
||||||
|
|
|
@ -55,6 +55,12 @@ namespace dawn_wire { namespace server {
|
||||||
uint64_t requestSerial;
|
uint64_t requestSerial;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct CreateReadyPipelineUserData {
|
||||||
|
Server* server;
|
||||||
|
uint64_t requestSerial;
|
||||||
|
ObjectId pipelineObjectID;
|
||||||
|
};
|
||||||
|
|
||||||
class Server : public ServerBase {
|
class Server : public ServerBase {
|
||||||
public:
|
public:
|
||||||
Server(WGPUDevice device,
|
Server(WGPUDevice device,
|
||||||
|
@ -89,6 +95,10 @@ namespace dawn_wire { namespace server {
|
||||||
static void ForwardBufferMapAsync(WGPUBufferMapAsyncStatus status, void* userdata);
|
static void ForwardBufferMapAsync(WGPUBufferMapAsyncStatus status, void* userdata);
|
||||||
static void ForwardFenceCompletedValue(WGPUFenceCompletionStatus status, void* userdata);
|
static void ForwardFenceCompletedValue(WGPUFenceCompletionStatus status, void* userdata);
|
||||||
static void ForwardFenceOnCompletion(WGPUFenceCompletionStatus status, void* userdata);
|
static void ForwardFenceOnCompletion(WGPUFenceCompletionStatus status, void* userdata);
|
||||||
|
static void ForwardCreateReadyComputePipeline(WGPUCreateReadyPipelineStatus status,
|
||||||
|
WGPUComputePipeline pipeline,
|
||||||
|
const char* message,
|
||||||
|
void* userdata);
|
||||||
|
|
||||||
// Error callbacks
|
// Error callbacks
|
||||||
void OnUncapturedError(WGPUErrorType type, const char* message);
|
void OnUncapturedError(WGPUErrorType type, const char* message);
|
||||||
|
@ -101,6 +111,10 @@ namespace dawn_wire { namespace server {
|
||||||
FenceCompletionUserdata* userdata);
|
FenceCompletionUserdata* userdata);
|
||||||
void OnFenceOnCompletion(WGPUFenceCompletionStatus status,
|
void OnFenceOnCompletion(WGPUFenceCompletionStatus status,
|
||||||
FenceOnCompletionUserdata* userdata);
|
FenceOnCompletionUserdata* userdata);
|
||||||
|
void OnCreateReadyComputePipelineCallback(WGPUCreateReadyPipelineStatus status,
|
||||||
|
WGPUComputePipeline pipeline,
|
||||||
|
const char* message,
|
||||||
|
CreateReadyPipelineUserData* userdata);
|
||||||
|
|
||||||
#include "dawn_wire/server/ServerPrototypes_autogen.inc"
|
#include "dawn_wire/server/ServerPrototypes_autogen.inc"
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,16 @@ namespace dawn_wire { namespace server {
|
||||||
server->OnDeviceLost(message);
|
server->OnDeviceLost(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Server::ForwardCreateReadyComputePipeline(WGPUCreateReadyPipelineStatus status,
|
||||||
|
WGPUComputePipeline pipeline,
|
||||||
|
const char* message,
|
||||||
|
void* userdata) {
|
||||||
|
CreateReadyPipelineUserData* createReadyPipelineUserData =
|
||||||
|
static_cast<CreateReadyPipelineUserData*>(userdata);
|
||||||
|
createReadyPipelineUserData->server->OnCreateReadyComputePipelineCallback(
|
||||||
|
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;
|
||||||
|
@ -53,6 +63,48 @@ namespace dawn_wire { namespace server {
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Server::DoDeviceCreateReadyComputePipeline(
|
||||||
|
WGPUDevice cDevice,
|
||||||
|
uint64_t requestSerial,
|
||||||
|
ObjectHandle pipelineObjectHandle,
|
||||||
|
const WGPUComputePipelineDescriptor* descriptor) {
|
||||||
|
auto* resultData = ComputePipelineObjects().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.deviceCreateReadyComputePipeline(
|
||||||
|
cDevice, descriptor, ForwardCreateReadyComputePipeline, userdata.release());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Server::OnCreateReadyComputePipelineCallback(WGPUCreateReadyPipelineStatus status,
|
||||||
|
WGPUComputePipeline pipeline,
|
||||||
|
const char* message,
|
||||||
|
CreateReadyPipelineUserData* userdata) {
|
||||||
|
std::unique_ptr<CreateReadyPipelineUserData> data(userdata);
|
||||||
|
if (status != WGPUCreateReadyPipelineStatus_Success) {
|
||||||
|
ComputePipelineObjects().Free(data->pipelineObjectID);
|
||||||
|
} else {
|
||||||
|
ComputePipelineObjects().Get(data->pipelineObjectID)->handle = pipeline;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnDeviceCreateReadyComputePipelineCallbackCmd 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);
|
||||||
|
|
|
@ -215,6 +215,7 @@ test("dawn_unittests") {
|
||||||
"unittests/wire/WireArgumentTests.cpp",
|
"unittests/wire/WireArgumentTests.cpp",
|
||||||
"unittests/wire/WireBasicTests.cpp",
|
"unittests/wire/WireBasicTests.cpp",
|
||||||
"unittests/wire/WireBufferMappingTests.cpp",
|
"unittests/wire/WireBufferMappingTests.cpp",
|
||||||
|
"unittests/wire/WireCreateReadyPipelineTests.cpp",
|
||||||
"unittests/wire/WireDisconnectTests.cpp",
|
"unittests/wire/WireDisconnectTests.cpp",
|
||||||
"unittests/wire/WireErrorCallbackTests.cpp",
|
"unittests/wire/WireErrorCallbackTests.cpp",
|
||||||
"unittests/wire/WireExtensionTests.cpp",
|
"unittests/wire/WireExtensionTests.cpp",
|
||||||
|
@ -273,6 +274,7 @@ source_set("dawn_end2end_tests_sources") {
|
||||||
"end2end/ComputeSharedMemoryTests.cpp",
|
"end2end/ComputeSharedMemoryTests.cpp",
|
||||||
"end2end/ComputeStorageBufferBarrierTests.cpp",
|
"end2end/ComputeStorageBufferBarrierTests.cpp",
|
||||||
"end2end/CopyTests.cpp",
|
"end2end/CopyTests.cpp",
|
||||||
|
"end2end/CreateReadyPipelineTests.cpp",
|
||||||
"end2end/CullingTests.cpp",
|
"end2end/CullingTests.cpp",
|
||||||
"end2end/DebugMarkerTests.cpp",
|
"end2end/DebugMarkerTests.cpp",
|
||||||
"end2end/DeprecatedAPITests.cpp",
|
"end2end/DeprecatedAPITests.cpp",
|
||||||
|
|
|
@ -0,0 +1,137 @@
|
||||||
|
// Copyright 2020 The Dawn Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "tests/DawnTest.h"
|
||||||
|
|
||||||
|
#include "utils/WGPUHelpers.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
struct CreateReadyPipelineTask {
|
||||||
|
wgpu::ComputePipeline computePipeline;
|
||||||
|
bool isCompleted = false;
|
||||||
|
std::string message;
|
||||||
|
};
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
|
class CreateReadyPipelineTest : public DawnTest {};
|
||||||
|
|
||||||
|
// Verify the basic use of CreateReadyComputePipeline works on all backends.
|
||||||
|
TEST_P(CreateReadyPipelineTest, BasicUseOfCreateReadyComputePipeline) {
|
||||||
|
const char* computeShader = R"(
|
||||||
|
#version 450
|
||||||
|
layout(std140, set = 0, binding = 0) buffer SSBO { uint value; } ssbo;
|
||||||
|
void main() {
|
||||||
|
ssbo.value = 1u;
|
||||||
|
})";
|
||||||
|
|
||||||
|
wgpu::ComputePipelineDescriptor csDesc;
|
||||||
|
csDesc.computeStage.module =
|
||||||
|
utils::CreateShaderModule(device, utils::SingleShaderStage::Compute, computeShader);
|
||||||
|
csDesc.computeStage.entryPoint = "main";
|
||||||
|
|
||||||
|
CreateReadyPipelineTask task;
|
||||||
|
device.CreateReadyComputePipeline(
|
||||||
|
&csDesc,
|
||||||
|
[](WGPUCreateReadyPipelineStatus status, WGPUComputePipeline returnPipeline,
|
||||||
|
const char* message, void* userdata) {
|
||||||
|
ASSERT_EQ(WGPUCreateReadyPipelineStatus::WGPUCreateReadyPipelineStatus_Success, status);
|
||||||
|
|
||||||
|
CreateReadyPipelineTask* task = static_cast<CreateReadyPipelineTask*>(userdata);
|
||||||
|
task->computePipeline = wgpu::ComputePipeline::Acquire(returnPipeline);
|
||||||
|
task->isCompleted = true;
|
||||||
|
task->message = message;
|
||||||
|
},
|
||||||
|
&task);
|
||||||
|
|
||||||
|
wgpu::BufferDescriptor bufferDesc;
|
||||||
|
bufferDesc.size = sizeof(uint32_t);
|
||||||
|
bufferDesc.usage = wgpu::BufferUsage::Storage | wgpu::BufferUsage::CopySrc;
|
||||||
|
wgpu::Buffer ssbo = device.CreateBuffer(&bufferDesc);
|
||||||
|
|
||||||
|
wgpu::CommandBuffer commands;
|
||||||
|
{
|
||||||
|
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||||
|
wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
|
||||||
|
|
||||||
|
while (!task.isCompleted) {
|
||||||
|
WaitABit();
|
||||||
|
}
|
||||||
|
ASSERT_TRUE(task.message.empty());
|
||||||
|
ASSERT_NE(nullptr, task.computePipeline.Get());
|
||||||
|
wgpu::BindGroup bindGroup =
|
||||||
|
utils::MakeBindGroup(device, task.computePipeline.GetBindGroupLayout(0),
|
||||||
|
{
|
||||||
|
{0, ssbo, 0, sizeof(uint32_t)},
|
||||||
|
});
|
||||||
|
pass.SetBindGroup(0, bindGroup);
|
||||||
|
pass.SetPipeline(task.computePipeline);
|
||||||
|
|
||||||
|
pass.Dispatch(1);
|
||||||
|
pass.EndPass();
|
||||||
|
|
||||||
|
commands = encoder.Finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
queue.Submit(1, &commands);
|
||||||
|
|
||||||
|
constexpr uint32_t kExpected = 1u;
|
||||||
|
EXPECT_BUFFER_U32_EQ(kExpected, ssbo, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify CreateReadyComputePipeline() works as expected when there is any error that happens during
|
||||||
|
// the creation of the compute pipeline. The SPEC requires that during the call of
|
||||||
|
// CreateReadyComputePipeline() any error won't be forwarded to the error scope / unhandled error
|
||||||
|
// callback.
|
||||||
|
TEST_P(CreateReadyPipelineTest, CreateComputePipelineFailed) {
|
||||||
|
DAWN_SKIP_TEST_IF(IsDawnValidationSkipped());
|
||||||
|
|
||||||
|
const char* computeShader = R"(
|
||||||
|
#version 450
|
||||||
|
layout(std140, set = 0, binding = 0) buffer SSBO { uint value; } ssbo;
|
||||||
|
void main() {
|
||||||
|
ssbo.value = 1u;
|
||||||
|
})";
|
||||||
|
|
||||||
|
wgpu::ComputePipelineDescriptor csDesc;
|
||||||
|
csDesc.computeStage.module =
|
||||||
|
utils::CreateShaderModule(device, utils::SingleShaderStage::Compute, computeShader);
|
||||||
|
csDesc.computeStage.entryPoint = "main0";
|
||||||
|
|
||||||
|
CreateReadyPipelineTask task;
|
||||||
|
device.CreateReadyComputePipeline(
|
||||||
|
&csDesc,
|
||||||
|
[](WGPUCreateReadyPipelineStatus status, WGPUComputePipeline returnPipeline,
|
||||||
|
const char* message, void* userdata) {
|
||||||
|
ASSERT_EQ(WGPUCreateReadyPipelineStatus::WGPUCreateReadyPipelineStatus_Error, status);
|
||||||
|
|
||||||
|
CreateReadyPipelineTask* task = static_cast<CreateReadyPipelineTask*>(userdata);
|
||||||
|
task->computePipeline = wgpu::ComputePipeline::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,
|
||||||
|
D3D12Backend(),
|
||||||
|
MetalBackend(),
|
||||||
|
OpenGLBackend(),
|
||||||
|
VulkanBackend());
|
|
@ -0,0 +1,127 @@
|
||||||
|
// Copyright 2020 The Dawn Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "tests/unittests/wire/WireTest.h"
|
||||||
|
|
||||||
|
using namespace testing;
|
||||||
|
using namespace dawn_wire;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// Mock class to add expectations on the wire calling callbacks
|
||||||
|
class MockCreateReadyComputePipelineCallback {
|
||||||
|
public:
|
||||||
|
MOCK_METHOD(void,
|
||||||
|
Call,
|
||||||
|
(WGPUCreateReadyPipelineStatus status,
|
||||||
|
WGPUComputePipeline pipeline,
|
||||||
|
const char* message,
|
||||||
|
void* userdata));
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<StrictMock<MockCreateReadyComputePipelineCallback>>
|
||||||
|
mockCreateReadyComputePipelineCallback;
|
||||||
|
void ToMockCreateReadyComputePipelineCallback(WGPUCreateReadyPipelineStatus status,
|
||||||
|
WGPUComputePipeline pipeline,
|
||||||
|
const char* message,
|
||||||
|
void* userdata) {
|
||||||
|
mockCreateReadyComputePipelineCallback->Call(status, pipeline, message, userdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
|
class WireCreateReadyPipelineTest : public WireTest {
|
||||||
|
public:
|
||||||
|
void SetUp() override {
|
||||||
|
WireTest::SetUp();
|
||||||
|
|
||||||
|
mockCreateReadyComputePipelineCallback =
|
||||||
|
std::make_unique<StrictMock<MockCreateReadyComputePipelineCallback>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TearDown() override {
|
||||||
|
WireTest::TearDown();
|
||||||
|
|
||||||
|
// Delete mock so that expectations are checked
|
||||||
|
mockCreateReadyComputePipelineCallback = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlushClient() {
|
||||||
|
WireTest::FlushClient();
|
||||||
|
Mock::VerifyAndClearExpectations(&mockCreateReadyComputePipelineCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlushServer() {
|
||||||
|
WireTest::FlushServer();
|
||||||
|
Mock::VerifyAndClearExpectations(&mockCreateReadyComputePipelineCallback);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Test when creating a compute pipeline with CreateReadyComputePipeline() successfully.
|
||||||
|
TEST_F(WireCreateReadyPipelineTest, CreateReadyComputePipelineSuccess) {
|
||||||
|
WGPUShaderModuleDescriptor csDescriptor{};
|
||||||
|
WGPUShaderModule csModule = wgpuDeviceCreateShaderModule(device, &csDescriptor);
|
||||||
|
WGPUShaderModule apiCsModule = api.GetNewShaderModule();
|
||||||
|
EXPECT_CALL(api, DeviceCreateShaderModule(apiDevice, _)).WillOnce(Return(apiCsModule));
|
||||||
|
|
||||||
|
WGPUComputePipelineDescriptor descriptor{};
|
||||||
|
descriptor.computeStage.module = csModule;
|
||||||
|
descriptor.computeStage.entryPoint = "main";
|
||||||
|
|
||||||
|
wgpuDeviceCreateReadyComputePipeline(device, &descriptor,
|
||||||
|
ToMockCreateReadyComputePipelineCallback, this);
|
||||||
|
|
||||||
|
EXPECT_CALL(api, OnDeviceCreateReadyComputePipelineCallback(apiDevice, _, _, _))
|
||||||
|
.WillOnce(InvokeWithoutArgs([&]() {
|
||||||
|
api.CallDeviceCreateReadyComputePipelineCallback(
|
||||||
|
apiDevice, WGPUCreateReadyPipelineStatus_Success, nullptr, "");
|
||||||
|
}));
|
||||||
|
|
||||||
|
FlushClient();
|
||||||
|
|
||||||
|
EXPECT_CALL(*mockCreateReadyComputePipelineCallback,
|
||||||
|
Call(WGPUCreateReadyPipelineStatus_Success, _, StrEq(""), this))
|
||||||
|
.Times(1);
|
||||||
|
|
||||||
|
FlushServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test when creating a compute pipeline with CreateReadyComputePipeline() results in an error.
|
||||||
|
TEST_F(WireCreateReadyPipelineTest, CreateReadyComputePipelineError) {
|
||||||
|
WGPUShaderModuleDescriptor csDescriptor{};
|
||||||
|
WGPUShaderModule csModule = wgpuDeviceCreateShaderModule(device, &csDescriptor);
|
||||||
|
WGPUShaderModule apiCsModule = api.GetNewShaderModule();
|
||||||
|
EXPECT_CALL(api, DeviceCreateShaderModule(apiDevice, _)).WillOnce(Return(apiCsModule));
|
||||||
|
|
||||||
|
WGPUComputePipelineDescriptor descriptor{};
|
||||||
|
descriptor.computeStage.module = csModule;
|
||||||
|
descriptor.computeStage.entryPoint = "main";
|
||||||
|
|
||||||
|
wgpuDeviceCreateReadyComputePipeline(device, &descriptor,
|
||||||
|
ToMockCreateReadyComputePipelineCallback, this);
|
||||||
|
|
||||||
|
EXPECT_CALL(api, OnDeviceCreateReadyComputePipelineCallback(apiDevice, _, _, _))
|
||||||
|
.WillOnce(InvokeWithoutArgs([&]() {
|
||||||
|
api.CallDeviceCreateReadyComputePipelineCallback(
|
||||||
|
apiDevice, WGPUCreateReadyPipelineStatus_Error, nullptr, "Some error message");
|
||||||
|
}));
|
||||||
|
|
||||||
|
FlushClient();
|
||||||
|
|
||||||
|
EXPECT_CALL(*mockCreateReadyComputePipelineCallback,
|
||||||
|
Call(WGPUCreateReadyPipelineStatus_Error, _, StrEq("Some error message"), this))
|
||||||
|
.Times(1);
|
||||||
|
|
||||||
|
FlushServer();
|
||||||
|
}
|
Loading…
Reference in New Issue