/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
void AdapterInfo::GetWgpuDeviceType(nsString& s) const { switch (mAboutSupportInfo->device_type) { case ffi::WGPUDeviceType_Cpu:
s.AssignLiteral("Cpu"); return; case ffi::WGPUDeviceType_DiscreteGpu:
s.AssignLiteral("DiscreteGpu"); return; case ffi::WGPUDeviceType_IntegratedGpu:
s.AssignLiteral("IntegratedGpu"); return; case ffi::WGPUDeviceType_VirtualGpu:
s.AssignLiteral("VirtualGpu"); return; case ffi::WGPUDeviceType_Other:
s.AssignLiteral("Other"); return; case ffi::WGPUDeviceType_Sentinel: break;
}
MOZ_CRASH("Bad `ffi::WGPUDeviceType`");
}
void AdapterInfo::GetWgpuDriver(nsString& s) const {
s = mAboutSupportInfo->driver;
}
void AdapterInfo::GetWgpuDriverInfo(nsString& s) const {
s = mAboutSupportInfo->driver_info;
}
void AdapterInfo::GetWgpuBackend(nsString& s) const { switch (mAboutSupportInfo->backend) { case ffi::WGPUBackend_Empty:
s.AssignLiteral("Empty"); return; case ffi::WGPUBackend_Vulkan:
s.AssignLiteral("Vulkan"); return; case ffi::WGPUBackend_Metal:
s.AssignLiteral("Metal"); return; case ffi::WGPUBackend_Dx12:
s.AssignLiteral("Dx12"); return; case ffi::WGPUBackend_Gl:
s.AssignLiteral("Gl"); return; case ffi::WGPUBackend_BrowserWebGpu: // This should never happen, because // we _are_ the browser. case ffi::WGPUBackend_Sentinel: break;
}
MOZ_CRASH("Bad `ffi::WGPUBackend`");
}
double GetLimitDefault(Limit aLimit) { switch (aLimit) { // clang-format off case Limit::MaxTextureDimension1D: return 8192; case Limit::MaxTextureDimension2D: return 8192; case Limit::MaxTextureDimension3D: return 2048; case Limit::MaxTextureArrayLayers: return 256; case Limit::MaxBindGroups: return 4; case Limit::MaxBindGroupsPlusVertexBuffers: return 24; case Limit::MaxBindingsPerBindGroup: return 1000; case Limit::MaxDynamicUniformBuffersPerPipelineLayout: return 8; case Limit::MaxDynamicStorageBuffersPerPipelineLayout: return 4; case Limit::MaxSampledTexturesPerShaderStage: return 16; case Limit::MaxSamplersPerShaderStage: return 16; case Limit::MaxStorageBuffersPerShaderStage: return 8; case Limit::MaxStorageTexturesPerShaderStage: return 4; case Limit::MaxUniformBuffersPerShaderStage: return 12; case Limit::MaxUniformBufferBindingSize: return 65536; case Limit::MaxStorageBufferBindingSize: return 134217728; case Limit::MinUniformBufferOffsetAlignment: return 256; case Limit::MinStorageBufferOffsetAlignment: return 256; case Limit::MaxVertexBuffers: return 8; case Limit::MaxBufferSize: return 268435456; case Limit::MaxVertexAttributes: return 16; case Limit::MaxVertexBufferArrayStride: return 2048; case Limit::MaxInterStageShaderVariables: return 16; case Limit::MaxColorAttachments: return 8; case Limit::MaxColorAttachmentBytesPerSample: return 32; case Limit::MaxComputeWorkgroupStorageSize: return 16384; case Limit::MaxComputeInvocationsPerWorkgroup: return 256; case Limit::MaxComputeWorkgroupSizeX: return 256; case Limit::MaxComputeWorkgroupSizeY: return 256; case Limit::MaxComputeWorkgroupSizeZ: return 64; case Limit::MaxComputeWorkgroupsPerDimension: return 65535; // clang-format on
}
MOZ_CRASH("Bad Limit");
}
Adapter::Adapter(Instance* const aParent, WebGPUChild* const aBridge, const std::shared_ptr<ffi::WGPUAdapterInformation>& aInfo)
: ChildOf(aParent),
mBridge(aBridge),
mId(aInfo->id),
mFeatures(new SupportedFeatures(this)),
mLimits(new SupportedLimits(this, aInfo->limits)),
mInfo(new AdapterInfo(this, aInfo)),
mInfoInner(aInfo) {
ErrorResult ignoredRv; // It's onerous to plumb this in from outside in this // case, and we don't really need to.
staticconstauto FEATURE_BY_BIT = []() { auto ret = std::unordered_map<ffi::WGPUFeatures, dom::GPUFeatureName>{};
for (constauto feature :
dom::MakeWebIDLEnumeratedRange<dom::GPUFeatureName>()) { constauto status = FeatureImplementationStatus::fromDomFeature(feature); switch (status.tag) { case FeatureImplementationStatusTag::Implemented:
ret[status.value.implemented.wgpuBit] = feature; break; case FeatureImplementationStatusTag::NotImplemented: break;
}
}
return ret;
}();
auto remainingFeatureBits = aInfo->features; auto bitMask = decltype(remainingFeatureBits){0}; while (remainingFeatureBits) { if (bitMask) {
bitMask <<= 1;
} else {
bitMask = 1;
} constauto bit = remainingFeatureBits & bitMask;
remainingFeatureBits &= ~bitMask; // Clear bit. if (!bit) { continue;
}
constauto featureForBit = FEATURE_BY_BIT.find(bit); if (featureForBit != FEATURE_BY_BIT.end()) {
mFeatures->Add(featureForBit->second, ignoredRv);
} else { // One of two cases: // // 1. WGPU claims to implement this, but we've explicitly marked this as // not implemented. // 2. We don't recognize that bit, but maybe it's a wpgu-native-only // feature.
}
}
// We clamp limits to defaults when requestDevice is called, but // we return the actual limits when only requestAdapter is called. // So, we should clamp the limits here too if we should RFP. if (GetParentObject()->ShouldResistFingerprinting(RFPTarget::WebGPULimits)) { for (constauto limit : MakeInclusiveEnumeratedRange(Limit::_LAST)) {
SetLimit(mLimits->mFfi.get(), limit, GetLimitDefault(limit));
}
}
}
bool Adapter::IsFallbackAdapter() const { if (GetParentObject()->ShouldResistFingerprinting(
RFPTarget::WebGPUIsFallbackAdapter)) { // Always report hardware support for WebGPU. // This behaviour matches with media capabilities API. returnfalse;
}
static std::string_view ToJsKey(const Limit limit) { switch (limit) { case Limit::MaxTextureDimension1D: return"maxTextureDimension1D"; case Limit::MaxTextureDimension2D: return"maxTextureDimension2D"; case Limit::MaxTextureDimension3D: return"maxTextureDimension3D"; case Limit::MaxTextureArrayLayers: return"maxTextureArrayLayers"; case Limit::MaxBindGroups: return"maxBindGroups"; case Limit::MaxBindGroupsPlusVertexBuffers: return"maxBindGroupsPlusVertexBuffers"; case Limit::MaxBindingsPerBindGroup: return"maxBindingsPerBindGroup"; case Limit::MaxDynamicUniformBuffersPerPipelineLayout: return"maxDynamicUniformBuffersPerPipelineLayout"; case Limit::MaxDynamicStorageBuffersPerPipelineLayout: return"maxDynamicStorageBuffersPerPipelineLayout"; case Limit::MaxSampledTexturesPerShaderStage: return"maxSampledTexturesPerShaderStage"; case Limit::MaxSamplersPerShaderStage: return"maxSamplersPerShaderStage"; case Limit::MaxStorageBuffersPerShaderStage: return"maxStorageBuffersPerShaderStage"; case Limit::MaxStorageTexturesPerShaderStage: return"maxStorageTexturesPerShaderStage"; case Limit::MaxUniformBuffersPerShaderStage: return"maxUniformBuffersPerShaderStage"; case Limit::MaxUniformBufferBindingSize: return"maxUniformBufferBindingSize"; case Limit::MaxStorageBufferBindingSize: return"maxStorageBufferBindingSize"; case Limit::MinUniformBufferOffsetAlignment: return"minUniformBufferOffsetAlignment"; case Limit::MinStorageBufferOffsetAlignment: return"minStorageBufferOffsetAlignment"; case Limit::MaxVertexBuffers: return"maxVertexBuffers"; case Limit::MaxBufferSize: return"maxBufferSize"; case Limit::MaxVertexAttributes: return"maxVertexAttributes"; case Limit::MaxVertexBufferArrayStride: return"maxVertexBufferArrayStride"; case Limit::MaxInterStageShaderVariables: return"maxInterStageShaderVariables"; case Limit::MaxColorAttachments: return"maxColorAttachments"; case Limit::MaxColorAttachmentBytesPerSample: return"maxColorAttachmentBytesPerSample"; case Limit::MaxComputeWorkgroupStorageSize: return"maxComputeWorkgroupStorageSize"; case Limit::MaxComputeInvocationsPerWorkgroup: return"maxComputeInvocationsPerWorkgroup"; case Limit::MaxComputeWorkgroupSizeX: return"maxComputeWorkgroupSizeX"; case Limit::MaxComputeWorkgroupSizeY: return"maxComputeWorkgroupSizeY"; case Limit::MaxComputeWorkgroupSizeZ: return"maxComputeWorkgroupSizeZ"; case Limit::MaxComputeWorkgroupsPerDimension: return"maxComputeWorkgroupsPerDimension";
}
MOZ_CRASH("Bad Limit");
}
// Turn on all implemented features. for (constauto feature :
dom::MakeWebIDLEnumeratedRange<dom::GPUFeatureName>()) { constauto status = FeatureImplementationStatus::fromDomFeature(feature); switch (status.tag) { case FeatureImplementationStatusTag::Implemented:
missingFeatures |= status.value.implemented.wgpuBit; break; case FeatureImplementationStatusTag::NotImplemented: break;
}
}
// Turn off features that are supported by the adapter. for (auto feature : mFeatures->Features()) { constauto status = FeatureImplementationStatus::fromDomFeature(feature); switch (status.tag) { case FeatureImplementationStatusTag::Implemented:
missingFeatures &= ~status.value.implemented.wgpuBit; break; case FeatureImplementationStatusTag::NotImplemented: break;
}
}
[&]() { // So that we can `return;` instead of `return promise.forget();`. if (!mBridge->CanSend()) {
promise->MaybeRejectWithInvalidStateError( "WebGPUChild cannot send, must recreate Adapter"); return;
}
// - // Validate Features
ffi::WGPUFeatures featureBits = 0; for (constauto requested : aDesc.mRequiredFeatures) { auto status = FeatureImplementationStatus::fromDomFeature(requested); switch (status.tag) { case FeatureImplementationStatusTag::Implemented:
featureBits |= status.value.implemented.wgpuBit; break; case FeatureImplementationStatusTag::NotImplemented: { constauto featureStr = dom::GetEnumString(requested);
(void)featureStr;
nsPrintfCString msg( "`GPUAdapter.requestDevice`: '%s' was requested in " "`requiredFeatures`, but it is not supported by Firefox." "Follow <%s> for updates.",
featureStr.get(), status.value.unimplemented.bugzillaUrlAscii);
promise->MaybeRejectWithTypeError(msg); return;
}
}
constbool supportedByAdapter = mFeatures->Features().count(requested); if (!supportedByAdapter) { constauto fstr = dom::GetEnumString(requested); constauto astr = this->LabelOrId();
nsPrintfCString msg( "`GPUAdapter.requestDevice`: '%s' was requested in " "`requiredFeatures`, but it is not supported by adapter %s.",
fstr.get(), astr.get());
promise->MaybeRejectWithTypeError(msg); return;
}
}
constauto& limit = itr->second;
uint64_t requestedValue = entry.mValue; constauto supportedValue = GetLimit(*mLimits->mFfi, limit); if (StringBeginsWith(keyU8, "max"_ns)) { if (requestedValue > supportedValue) {
nsPrintfCString msg( "requestDevice: Request for limit '%s' must be <= supported " "%s, was %s.",
keyU8.get(), std::to_string(supportedValue).c_str(),
std::to_string(requestedValue).c_str());
promise->MaybeRejectWithOperationError(msg); return;
} // Clamp to default if lower than default
requestedValue =
std::max(requestedValue, GetLimit(deviceLimits, limit));
} else {
MOZ_ASSERT(StringBeginsWith(keyU8, "min"_ns)); if (requestedValue < supportedValue) {
nsPrintfCString msg( "requestDevice: Request for limit '%s' must be >= supported " "%s, was %s.",
keyU8.get(), std::to_string(supportedValue).c_str(),
std::to_string(requestedValue).c_str());
promise->MaybeRejectWithOperationError(msg); return;
} if (StringEndsWith(keyU8, "Alignment"_ns)) { if (!IsPowerOfTwo(requestedValue)) {
nsPrintfCString msg( "requestDevice: Request for limit '%s' must be a power of " "two, " "was %s.",
keyU8.get(), std::to_string(requestedValue).c_str());
promise->MaybeRejectWithOperationError(msg); return;
}
} /// Clamp to default if higher than default /// Changing implementation in a way that increases fingerprinting /// surface? Please create a bug in [Core::Privacy: Anti /// Tracking](https://bugzilla.mozilla.org/enter_bug.cgi?product=Core&component=Privacy%3A%20Anti-Tracking)
requestedValue =
std::min(requestedValue, GetLimit(deviceLimits, limit));
}
ffi::WGPUFfiDeviceDescriptor ffiDesc = {};
ffiDesc.required_features = featureBits;
ffiDesc.required_limits = deviceLimits; auto request = mBridge->AdapterRequestDevice(mId, ffiDesc); if (!request) {
promise->MaybeRejectWithNotSupportedError( "Unable to instantiate a Device"); return;
}
RefPtr<Device> device = new Device( this, request->mDeviceId, request->mQueueId, ffiDesc.required_limits); for (constauto& feature : aDesc.mRequiredFeatures) {
device->mFeatures->Add(feature, aRv);
}
request->mPromise->Then(
GetCurrentSerialEventTarget(), __func__,
[promise, device](bool aSuccess) { if (aSuccess) {
promise->MaybeResolve(device);
} else {
device->CleanupUnregisteredInParent();
promise->MaybeRejectWithInvalidStateError( "Unable to fulfill requested features and limits");
}
},
[promise, device](const ipc::ResponseRejectReason& aReason) { // We can't be sure how far along the WebGPUParent got in handling // our AdapterRequestDevice message, but we can't communicate with it, // so clear up our client state for this Device without trying to // communicate with the parent about it.
device->CleanupUnregisteredInParent();
promise->MaybeRejectWithNotSupportedError("IPC error");
});
}();
return promise.forget();
}
} // namespace mozilla::webgpu
¤ Dauer der Verarbeitung: 0.3 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.