mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-05-13 19:01:24 +00:00
This implements requestAdapter and requestDevice by forwarding commands the the server and relaying back replies. After an adapter or device is created, limits/properties/features are queried and also sent back to the client. Bug: dawn:689 Change-Id: Ie0c2984b8ebb661efb0c284a14ae8b74ae4af2ea Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/71522 Reviewed-by: Corentin Wallez <cwallez@chromium.org> Reviewed-by: Loko Kung <lokokung@google.com> Commit-Queue: Austin Eng <enga@chromium.org>
343 lines
13 KiB
C++
343 lines
13 KiB
C++
// Copyright 2019 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_wire/client/Device.h"
|
|
|
|
#include "common/Assert.h"
|
|
#include "common/Log.h"
|
|
#include "dawn_wire/client/ApiObjects_autogen.h"
|
|
#include "dawn_wire/client/Client.h"
|
|
#include "dawn_wire/client/ObjectAllocator.h"
|
|
|
|
namespace dawn_wire { namespace client {
|
|
|
|
Device::Device(Client* clientIn, uint32_t initialRefcount, uint32_t initialId)
|
|
: ObjectBase(clientIn, initialRefcount, initialId), mIsAlive(std::make_shared<bool>()) {
|
|
#if defined(DAWN_ENABLE_ASSERTS)
|
|
mErrorCallback = [](WGPUErrorType, char const*, void*) {
|
|
static bool calledOnce = false;
|
|
if (!calledOnce) {
|
|
calledOnce = true;
|
|
dawn::WarningLog() << "No Dawn device uncaptured error callback was set. This is "
|
|
"probably not intended. If you really want to ignore errors "
|
|
"and suppress this message, set the callback to null.";
|
|
}
|
|
};
|
|
|
|
mDeviceLostCallback = [](WGPUDeviceLostReason, char const*, void*) {
|
|
static bool calledOnce = false;
|
|
if (!calledOnce) {
|
|
calledOnce = true;
|
|
dawn::WarningLog() << "No Dawn device lost callback was set. This is probably not "
|
|
"intended. If you really want to ignore device lost "
|
|
"and suppress this message, set the callback to null.";
|
|
}
|
|
};
|
|
#endif // DAWN_ENABLE_ASSERTS
|
|
}
|
|
|
|
Device::~Device() {
|
|
mErrorScopes.CloseAll([](ErrorScopeData* request) {
|
|
request->callback(WGPUErrorType_Unknown, "Device destroyed before callback",
|
|
request->userdata);
|
|
});
|
|
|
|
mCreatePipelineAsyncRequests.CloseAll([](CreatePipelineAsyncRequest* request) {
|
|
if (request->createComputePipelineAsyncCallback != nullptr) {
|
|
request->createComputePipelineAsyncCallback(
|
|
WGPUCreatePipelineAsyncStatus_DeviceDestroyed, nullptr,
|
|
"Device destroyed before callback", request->userdata);
|
|
} else {
|
|
ASSERT(request->createRenderPipelineAsyncCallback != nullptr);
|
|
request->createRenderPipelineAsyncCallback(
|
|
WGPUCreatePipelineAsyncStatus_DeviceDestroyed, nullptr,
|
|
"Device destroyed before callback", request->userdata);
|
|
}
|
|
});
|
|
}
|
|
|
|
bool Device::GetLimits(WGPUSupportedLimits* limits) const {
|
|
return mLimitsAndFeatures.GetLimits(limits);
|
|
}
|
|
|
|
bool Device::HasFeature(WGPUFeatureName feature) const {
|
|
return mLimitsAndFeatures.HasFeature(feature);
|
|
}
|
|
|
|
uint32_t Device::EnumerateFeatures(WGPUFeatureName* features) const {
|
|
return mLimitsAndFeatures.EnumerateFeatures(features);
|
|
}
|
|
|
|
void Device::SetLimits(const WGPUSupportedLimits* limits) {
|
|
return mLimitsAndFeatures.SetLimits(limits);
|
|
}
|
|
|
|
void Device::SetFeatures(const WGPUFeatureName* features, uint32_t featuresCount) {
|
|
return mLimitsAndFeatures.SetFeatures(features, featuresCount);
|
|
}
|
|
|
|
void Device::HandleError(WGPUErrorType errorType, const char* message) {
|
|
if (mErrorCallback) {
|
|
mErrorCallback(errorType, message, mErrorUserdata);
|
|
}
|
|
}
|
|
|
|
void Device::HandleLogging(WGPULoggingType loggingType, const char* message) {
|
|
if (mLoggingCallback) {
|
|
// Since client always run in single thread, calling the callback directly is safe.
|
|
mLoggingCallback(loggingType, message, mLoggingUserdata);
|
|
}
|
|
}
|
|
|
|
void Device::HandleDeviceLost(WGPUDeviceLostReason reason, const char* message) {
|
|
if (mDeviceLostCallback && !mDidRunLostCallback) {
|
|
mDidRunLostCallback = true;
|
|
mDeviceLostCallback(reason, message, mDeviceLostUserdata);
|
|
}
|
|
}
|
|
|
|
void Device::CancelCallbacksForDisconnect() {
|
|
mErrorScopes.CloseAll([](ErrorScopeData* request) {
|
|
request->callback(WGPUErrorType_DeviceLost, "Device lost", request->userdata);
|
|
});
|
|
|
|
mCreatePipelineAsyncRequests.CloseAll([](CreatePipelineAsyncRequest* request) {
|
|
if (request->createComputePipelineAsyncCallback != nullptr) {
|
|
request->createComputePipelineAsyncCallback(
|
|
WGPUCreatePipelineAsyncStatus_DeviceLost, nullptr, "Device lost",
|
|
request->userdata);
|
|
} else {
|
|
ASSERT(request->createRenderPipelineAsyncCallback != nullptr);
|
|
request->createRenderPipelineAsyncCallback(WGPUCreatePipelineAsyncStatus_DeviceLost,
|
|
nullptr, "Device lost",
|
|
request->userdata);
|
|
}
|
|
});
|
|
}
|
|
|
|
std::weak_ptr<bool> Device::GetAliveWeakPtr() {
|
|
return mIsAlive;
|
|
}
|
|
|
|
void Device::SetUncapturedErrorCallback(WGPUErrorCallback errorCallback, void* errorUserdata) {
|
|
mErrorCallback = errorCallback;
|
|
mErrorUserdata = errorUserdata;
|
|
}
|
|
|
|
void Device::SetLoggingCallback(WGPULoggingCallback callback, void* userdata) {
|
|
mLoggingCallback = callback;
|
|
mLoggingUserdata = userdata;
|
|
}
|
|
|
|
void Device::SetDeviceLostCallback(WGPUDeviceLostCallback callback, void* userdata) {
|
|
mDeviceLostCallback = callback;
|
|
mDeviceLostUserdata = userdata;
|
|
}
|
|
|
|
void Device::PushErrorScope(WGPUErrorFilter filter) {
|
|
mErrorScopeStackSize++;
|
|
|
|
DevicePushErrorScopeCmd cmd;
|
|
cmd.self = ToAPI(this);
|
|
cmd.filter = filter;
|
|
|
|
client->SerializeCommand(cmd);
|
|
}
|
|
|
|
bool Device::PopErrorScope(WGPUErrorCallback callback, void* userdata) {
|
|
if (mErrorScopeStackSize == 0) {
|
|
return false;
|
|
}
|
|
mErrorScopeStackSize--;
|
|
|
|
if (client->IsDisconnected()) {
|
|
callback(WGPUErrorType_DeviceLost, "GPU device disconnected", userdata);
|
|
return true;
|
|
}
|
|
|
|
uint64_t serial = mErrorScopes.Add({callback, userdata});
|
|
|
|
DevicePopErrorScopeCmd cmd;
|
|
cmd.deviceId = this->id;
|
|
cmd.requestSerial = serial;
|
|
|
|
client->SerializeCommand(cmd);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Device::OnPopErrorScopeCallback(uint64_t requestSerial,
|
|
WGPUErrorType type,
|
|
const char* message) {
|
|
switch (type) {
|
|
case WGPUErrorType_NoError:
|
|
case WGPUErrorType_Validation:
|
|
case WGPUErrorType_OutOfMemory:
|
|
case WGPUErrorType_Unknown:
|
|
case WGPUErrorType_DeviceLost:
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
ErrorScopeData request;
|
|
if (!mErrorScopes.Acquire(requestSerial, &request)) {
|
|
return false;
|
|
}
|
|
|
|
request.callback(type, message, request.userdata);
|
|
return true;
|
|
}
|
|
|
|
void Device::InjectError(WGPUErrorType type, const char* message) {
|
|
DeviceInjectErrorCmd cmd;
|
|
cmd.self = ToAPI(this);
|
|
cmd.type = type;
|
|
cmd.message = message;
|
|
client->SerializeCommand(cmd);
|
|
}
|
|
|
|
WGPUBuffer Device::CreateBuffer(const WGPUBufferDescriptor* descriptor) {
|
|
return Buffer::Create(this, descriptor);
|
|
}
|
|
|
|
WGPUBuffer Device::CreateErrorBuffer() {
|
|
return Buffer::CreateError(this);
|
|
}
|
|
|
|
WGPUQueue Device::GetQueue() {
|
|
// The queue is lazily created because if a Device is created by
|
|
// Reserve/Inject, we cannot send the GetQueue message until
|
|
// it has been injected on the Server. It cannot happen immediately
|
|
// on construction.
|
|
if (mQueue == nullptr) {
|
|
// Get the primary queue for this device.
|
|
auto* allocation = client->QueueAllocator().New(client);
|
|
mQueue = allocation->object.get();
|
|
|
|
DeviceGetQueueCmd cmd;
|
|
cmd.self = ToAPI(this);
|
|
cmd.result = ObjectHandle{allocation->object->id, allocation->generation};
|
|
|
|
client->SerializeCommand(cmd);
|
|
}
|
|
|
|
mQueue->refcount++;
|
|
return ToAPI(mQueue);
|
|
}
|
|
|
|
void Device::CreateComputePipelineAsync(WGPUComputePipelineDescriptor const* descriptor,
|
|
WGPUCreateComputePipelineAsyncCallback callback,
|
|
void* userdata) {
|
|
if (client->IsDisconnected()) {
|
|
return callback(WGPUCreatePipelineAsyncStatus_DeviceLost, nullptr,
|
|
"GPU device disconnected", userdata);
|
|
}
|
|
|
|
auto* allocation = client->ComputePipelineAllocator().New(client);
|
|
|
|
CreatePipelineAsyncRequest request = {};
|
|
request.createComputePipelineAsyncCallback = callback;
|
|
request.userdata = userdata;
|
|
request.pipelineObjectID = allocation->object->id;
|
|
|
|
uint64_t serial = mCreatePipelineAsyncRequests.Add(std::move(request));
|
|
|
|
DeviceCreateComputePipelineAsyncCmd cmd;
|
|
cmd.deviceId = this->id;
|
|
cmd.descriptor = descriptor;
|
|
cmd.requestSerial = serial;
|
|
cmd.pipelineObjectHandle = ObjectHandle{allocation->object->id, allocation->generation};
|
|
|
|
client->SerializeCommand(cmd);
|
|
}
|
|
|
|
bool Device::OnCreateComputePipelineAsyncCallback(uint64_t requestSerial,
|
|
WGPUCreatePipelineAsyncStatus status,
|
|
const char* message) {
|
|
CreatePipelineAsyncRequest request;
|
|
if (!mCreatePipelineAsyncRequests.Acquire(requestSerial, &request)) {
|
|
return false;
|
|
}
|
|
|
|
auto pipelineAllocation =
|
|
client->ComputePipelineAllocator().GetObject(request.pipelineObjectID);
|
|
|
|
// If the return status is a failure we should give a null pipeline to the callback and
|
|
// free the allocation.
|
|
if (status != WGPUCreatePipelineAsyncStatus_Success) {
|
|
client->ComputePipelineAllocator().Free(pipelineAllocation);
|
|
request.createComputePipelineAsyncCallback(status, nullptr, message, request.userdata);
|
|
return true;
|
|
}
|
|
|
|
WGPUComputePipeline pipeline = reinterpret_cast<WGPUComputePipeline>(pipelineAllocation);
|
|
request.createComputePipelineAsyncCallback(status, pipeline, message, request.userdata);
|
|
|
|
return true;
|
|
}
|
|
|
|
void Device::CreateRenderPipelineAsync(WGPURenderPipelineDescriptor const* descriptor,
|
|
WGPUCreateRenderPipelineAsyncCallback callback,
|
|
void* userdata) {
|
|
if (client->IsDisconnected()) {
|
|
return callback(WGPUCreatePipelineAsyncStatus_DeviceLost, nullptr,
|
|
"GPU device disconnected", userdata);
|
|
}
|
|
|
|
auto* allocation = client->RenderPipelineAllocator().New(client);
|
|
|
|
CreatePipelineAsyncRequest request = {};
|
|
request.createRenderPipelineAsyncCallback = callback;
|
|
request.userdata = userdata;
|
|
request.pipelineObjectID = allocation->object->id;
|
|
|
|
uint64_t serial = mCreatePipelineAsyncRequests.Add(std::move(request));
|
|
|
|
DeviceCreateRenderPipelineAsyncCmd cmd;
|
|
cmd.deviceId = this->id;
|
|
cmd.descriptor = descriptor;
|
|
cmd.requestSerial = serial;
|
|
cmd.pipelineObjectHandle = ObjectHandle(allocation->object->id, allocation->generation);
|
|
|
|
client->SerializeCommand(cmd);
|
|
}
|
|
|
|
bool Device::OnCreateRenderPipelineAsyncCallback(uint64_t requestSerial,
|
|
WGPUCreatePipelineAsyncStatus status,
|
|
const char* message) {
|
|
CreatePipelineAsyncRequest request;
|
|
if (!mCreatePipelineAsyncRequests.Acquire(requestSerial, &request)) {
|
|
return false;
|
|
}
|
|
|
|
auto pipelineAllocation =
|
|
client->RenderPipelineAllocator().GetObject(request.pipelineObjectID);
|
|
|
|
// If the return status is a failure we should give a null pipeline to the callback and
|
|
// free the allocation.
|
|
if (status != WGPUCreatePipelineAsyncStatus_Success) {
|
|
client->RenderPipelineAllocator().Free(pipelineAllocation);
|
|
request.createRenderPipelineAsyncCallback(status, nullptr, message, request.userdata);
|
|
return true;
|
|
}
|
|
|
|
WGPURenderPipeline pipeline = reinterpret_cast<WGPURenderPipeline>(pipelineAllocation);
|
|
request.createRenderPipelineAsyncCallback(status, pipeline, message, request.userdata);
|
|
|
|
return true;
|
|
}
|
|
|
|
}} // namespace dawn_wire::client
|