// Copyright 2021 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/server/Server.h" #include "dawn_wire/SupportedFeatures.h" namespace dawn_wire::server { bool Server::DoAdapterRequestDevice(ObjectId adapterId, uint64_t requestSerial, ObjectHandle deviceHandle, const WGPUDeviceDescriptor* descriptor) { auto* adapter = AdapterObjects().Get(adapterId); if (adapter == nullptr) { return false; } auto* resultData = DeviceObjects().Allocate(deviceHandle.id, AllocationState::Reserved); if (resultData == nullptr) { return false; } resultData->generation = deviceHandle.generation; auto userdata = MakeUserdata(); userdata->adapter = ObjectHandle{adapterId, adapter->generation}; userdata->requestSerial = requestSerial; userdata->deviceObjectId = deviceHandle.id; mProcs.adapterRequestDevice(adapter->handle, descriptor, ForwardToServer<&Server::OnRequestDeviceCallback>, userdata.release()); return true; } void Server::OnRequestDeviceCallback(RequestDeviceUserdata* data, WGPURequestDeviceStatus status, WGPUDevice device, const char* message) { auto* deviceObject = DeviceObjects().Get(data->deviceObjectId, AllocationState::Reserved); // Should be impossible to fail. ObjectIds can't be freed by a destroy command until // they move from Reserved to Allocated, or if they are destroyed here. ASSERT(deviceObject != nullptr); ReturnAdapterRequestDeviceCallbackCmd cmd = {}; cmd.adapter = data->adapter; cmd.requestSerial = data->requestSerial; cmd.status = status; cmd.message = message; if (status != WGPURequestDeviceStatus_Success) { // Free the ObjectId which will make it unusable. DeviceObjects().Free(data->deviceObjectId); ASSERT(device == nullptr); SerializeCommand(cmd); return; } std::vector features; uint32_t featuresCount = mProcs.deviceEnumerateFeatures(device, nullptr); features.resize(featuresCount); mProcs.deviceEnumerateFeatures(device, features.data()); // The client should only be able to request supported features, so all enumerated // features that were enabled must also be supported by the wire. // Note: We fail the callback here, instead of immediately upon receiving // the request to preserve callback ordering. for (WGPUFeatureName f : features) { if (!IsFeatureSupported(f)) { // Release the device. mProcs.deviceRelease(device); // Free the ObjectId which will make it unusable. DeviceObjects().Free(data->deviceObjectId); cmd.status = WGPURequestDeviceStatus_Error; cmd.message = "Requested feature not supported."; SerializeCommand(cmd); return; } } cmd.featuresCount = features.size(); cmd.features = features.data(); WGPUSupportedLimits limits = {}; mProcs.deviceGetLimits(device, &limits); cmd.limits = &limits; // Assign the handle and allocated status if the device is created successfully. deviceObject->state = AllocationState::Allocated; deviceObject->handle = device; SetForwardingDeviceCallbacks(deviceObject); SerializeCommand(cmd); } } // namespace dawn_wire::server