/* -*- 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/. */
// Generate an error on the Device timeline for this device. // // aMessage is interpreted as UTF-8. void Device::GenerateValidationError(const nsCString& aMessage) { if (!IsBridgeAlive()) { return; // Just drop it?
}
mBridge->SendGenerateError(Some(mId), dom::GPUErrorFilter::Validation,
aMessage);
}
webgpu::StringHelper label(aDesc.mLabel);
desc.label = label.Get();
ffi::WGPURawQueryType type; switch (aDesc.mType) { case dom::GPUQueryType::Occlusion:
type = ffi::WGPURawQueryType_Occlusion; break; case dom::GPUQueryType::Timestamp:
type = ffi::WGPURawQueryType_Timestamp; if (!mFeatures->Features().count(dom::GPUFeatureName::Timestamp_query)) {
aRv.ThrowTypeError( "requested query set of type `timestamp`, but the " "`timestamp-query` feature is not enabled on the device"); return nullptr;
} break;
};
desc.ty = type;
desc.count = aDesc.mCount;
RawId id = ffi::wgpu_client_create_query_set(mBridge->GetClient(), &desc,
ToFFI(&bb)); if (mBridge->CanSend()) {
mBridge->SendDeviceAction(mId, std::move(bb));
}
RefPtr<QuerySet> querySet = new QuerySet(this, aDesc, id); return querySet.forget();
}
already_AddRefed<BindGroupLayout> Device::CreateBindGroupLayout( const dom::GPUBindGroupLayoutDescriptor& aDesc) { struct OptionalData {
ffi::WGPUTextureViewDimension dim;
ffi::WGPURawTextureSampleType type;
ffi::WGPUTextureFormat format;
};
nsTArray<OptionalData> optional(aDesc.mEntries.Length()); for (constauto& entry : aDesc.mEntries) {
OptionalData data = {}; if (entry.mTexture.WasPassed()) { constauto& texture = entry.mTexture.Value();
data.dim = ffi::WGPUTextureViewDimension(texture.mViewDimension); switch (texture.mSampleType) { case dom::GPUTextureSampleType::Float:
data.type = ffi::WGPURawTextureSampleType_Float; break; case dom::GPUTextureSampleType::Unfilterable_float:
data.type = ffi::WGPURawTextureSampleType_UnfilterableFloat; break; case dom::GPUTextureSampleType::Uint:
data.type = ffi::WGPURawTextureSampleType_Uint; break; case dom::GPUTextureSampleType::Sint:
data.type = ffi::WGPURawTextureSampleType_Sint; break; case dom::GPUTextureSampleType::Depth:
data.type = ffi::WGPURawTextureSampleType_Depth; break;
}
} if (entry.mStorageTexture.WasPassed()) { constauto& texture = entry.mStorageTexture.Value();
data.dim = ffi::WGPUTextureViewDimension(texture.mViewDimension);
data.format = ConvertTextureFormat(texture.mFormat);
}
optional.AppendElement(data);
}
nsTArray<ffi::WGPUBindGroupLayoutEntry> entries(aDesc.mEntries.Length()); for (size_t i = 0; i < aDesc.mEntries.Length(); ++i) { constauto& entry = aDesc.mEntries[i];
ffi::WGPUBindGroupLayoutEntry e = {};
e.binding = entry.mBinding;
e.visibility = entry.mVisibility; if (entry.mBuffer.WasPassed()) { switch (entry.mBuffer.Value().mType) { case dom::GPUBufferBindingType::Uniform:
e.ty = ffi::WGPURawBindingType_UniformBuffer; break; case dom::GPUBufferBindingType::Storage:
e.ty = ffi::WGPURawBindingType_StorageBuffer; break; case dom::GPUBufferBindingType::Read_only_storage:
e.ty = ffi::WGPURawBindingType_ReadonlyStorageBuffer; break;
}
e.has_dynamic_offset = entry.mBuffer.Value().mHasDynamicOffset;
} if (entry.mTexture.WasPassed()) {
e.ty = ffi::WGPURawBindingType_SampledTexture;
e.view_dimension = &optional[i].dim;
e.texture_sample_type = &optional[i].type;
e.multisampled = entry.mTexture.Value().mMultisampled;
} if (entry.mStorageTexture.WasPassed()) { switch (entry.mStorageTexture.Value().mAccess) { case dom::GPUStorageTextureAccess::Write_only: {
e.ty = ffi::WGPURawBindingType_WriteonlyStorageTexture; break;
} case dom::GPUStorageTextureAccess::Read_only: {
e.ty = ffi::WGPURawBindingType_ReadonlyStorageTexture; break;
} case dom::GPUStorageTextureAccess::Read_write: {
e.ty = ffi::WGPURawBindingType_ReadWriteStorageTexture; break;
} default: {
MOZ_ASSERT_UNREACHABLE();
}
}
e.view_dimension = &optional[i].dim;
e.storage_texture_format = &optional[i].format;
} if (entry.mSampler.WasPassed()) {
e.ty = ffi::WGPURawBindingType_Sampler; switch (entry.mSampler.Value().mType) { case dom::GPUSamplerBindingType::Filtering:
e.sampler_filter = true; break; case dom::GPUSamplerBindingType::Non_filtering: break; case dom::GPUSamplerBindingType::Comparison:
e.sampler_compare = true; break;
}
}
entries.AppendElement(e);
}
ipc::ByteBuf bb;
RawId id = ffi::wgpu_client_create_pipeline_layout(mBridge->GetClient(),
&desc, ToFFI(&bb)); if (mBridge->CanSend()) {
mBridge->SendDeviceAction(mId, std::move(bb));
}
RefPtr<PipelineLayout> object = new PipelineLayout(this, id); return object.forget();
}
already_AddRefed<BindGroup> Device::CreateBindGroup( const dom::GPUBindGroupDescriptor& aDesc) {
nsTArray<ffi::WGPUBindGroupEntry> entries(aDesc.mEntries.Length()); for (constauto& entry : aDesc.mEntries) {
ffi::WGPUBindGroupEntry e = {};
e.binding = entry.mBinding; if (entry.mResource.IsGPUBufferBinding()) { constauto& bufBinding = entry.mResource.GetAsGPUBufferBinding(); if (!bufBinding.mBuffer->mId) {
NS_WARNING("Buffer binding has no id -- ignoring."); continue;
}
e.buffer = bufBinding.mBuffer->mId;
e.offset = bufBinding.mOffset;
e.size = bufBinding.mSize.WasPassed() ? bufBinding.mSize.Value() : 0;
} elseif (entry.mResource.IsGPUTextureView()) {
e.texture_view = entry.mResource.GetAsGPUTextureView()->mId;
} elseif (entry.mResource.IsGPUSampler()) {
e.sampler = entry.mResource.GetAsGPUSampler()->mId;
} else { // Not a buffer, nor a texture view, nor a sampler. If we pass // this to wgpu_client, it'll panic. Log a warning instead and // ignore this entry.
NS_WARNING("Bind group entry has unknown type."); continue;
}
entries.AppendElement(e);
}
nsString label;
aShaderModule->GetLabel(label); auto appendNiceLabelIfPresent = [&label](nsString* buf) MOZ_CAN_RUN_SCRIPT { if (!label.IsEmpty()) {
buf->AppendLiteral(u" \"");
buf->Append(label);
buf->AppendLiteral(u"\"");
}
};
// We haven't actually inspected a message for severity, but // it doesn't actually matter, since we don't do anything at // this level. auto highestSeveritySeen = WebGPUCompilationMessageType::Info;
uint64_t errorCount = 0;
uint64_t warningCount = 0;
uint64_t infoCount = 0; for (constauto& message : aMessages) { bool higherThanSeen = static_cast<std::underlying_type_t<WebGPUCompilationMessageType>>(
message.messageType) < static_cast<std::underlying_type_t<WebGPUCompilationMessageType>>(
highestSeveritySeen); if (higherThanSeen) {
highestSeveritySeen = message.messageType;
} switch (message.messageType) { case WebGPUCompilationMessageType::Error:
errorCount += 1; break; case WebGPUCompilationMessageType::Warning:
warningCount += 1; break; case WebGPUCompilationMessageType::Info:
infoCount += 1; break;
}
} switch (highestSeveritySeen) { case WebGPUCompilationMessageType::Info: // shouldn't happen, but :shrug: break; case WebGPUCompilationMessageType::Warning: {
nsString msg(
u"Encountered one or more warnings while creating shader module");
appendNiceLabelIfPresent(&msg);
SetSingleStrAsArgs(msg, &args);
dom::Console::Warn(globalObj, args); break;
} case WebGPUCompilationMessageType::Error: {
nsString msg(
u"Encountered one or more errors while creating shader module");
appendNiceLabelIfPresent(&msg);
SetSingleStrAsArgs(msg, &args);
dom::Console::Error(globalObj, args); break;
}
}
// Note: we pre-collect the blend states into a different array // so that we can have non-stale pointers into it. for (constauto& colorState : stage.mTargets) {
ffi::WGPUColorTargetState desc = {};
desc.format = ConvertTextureFormat(colorState.mFormat);
desc.write_mask = colorState.mWriteMask;
colorStates.AppendElement(desc);
ffi::WGPUBlendState bs = {}; if (colorState.mBlend.WasPassed()) { constauto& blend = colorState.mBlend.Value();
bs.alpha = ConvertBlendComponent(blend.mAlpha);
bs.color = ConvertBlendComponent(blend.mColor);
}
blendStates.AppendElement(bs);
} for (size_t i = 0; i < colorStates.Length(); ++i) { if (stage.mTargets[i].mBlend.WasPassed()) {
colorStates[i].blend = &blendStates[i];
}
}
// Check that aCanvasSize and aFormat will generate a texture stride // within limits. constauto bufferStrideWithMask = BufferStrideWithMask(aCanvasSize, aFormat); if (!bufferStrideWithMask.isValid()) { return nullptr;
}
const layers::RGBDescriptor rgbDesc(aCanvasSize, aFormat); // buffer count doesn't matter much, will be created on demand const size_t maxBufferCount = 10;
mBridge->DeviceCreateSwapChain(mId, rgbDesc, maxBufferCount, aOwnerId,
aUseExternalTextureInSwapChain);
void Device::Destroy() { // Unmap all buffers from this device, as specified by // https://gpuweb.github.io/gpuweb/#dom-gpudevice-destroy.
dom::AutoJSAPI jsapi; if (jsapi.Init(GetOwnerGlobal())) {
IgnoredErrorResult rv; for (constauto& buffer : mTrackedBuffers) {
buffer->Unmap(jsapi.cx(), rv);
}
mTrackedBuffers.Clear();
}
if (!IsBridgeAlive()) { // Resolve our lost promise in the same way as if we had a successful // round-trip through the bridge.
ResolveLost(Some(dom::GPUDeviceLostReason::Destroyed), u""_ns); return;
}
already_AddRefed<dom::Promise> Device::PopErrorScope(ErrorResult& aRv) { /* https://www.w3.org/TR/webgpu/#errors-and-debugging: > After a device is lost (described below), errors are no longer surfaced. > At this point, implementations do not need to run validation or error tracking: > popErrorScope() and uncapturederror stop reporting errors, > and the validity of objects on the device becomes unobservable.
*/
RefPtr<dom::Promise> promise = dom::Promise::Create(GetParentObject(), aRv); if (NS_WARN_IF(aRv.Failed())) { return nullptr;
}
if (!IsBridgeAlive()) {
WebGPUChild::JsWarning(
GetOwnerGlobal(), "popErrorScope resolving to null because device is already lost."_ns);
promise->MaybeResolve(JS::NullHandleValue); return promise.forget();
}
auto errorPromise = mBridge->SendDevicePopErrorScope(mId);
switch (aResult.resultType) { case PopErrorScopeResultType::NoError:
promise->MaybeResolve(JS::NullHandleValue); return;
case PopErrorScopeResultType::DeviceLost:
WebGPUChild::JsWarning(
self->GetOwnerGlobal(), "popErrorScope resolving to null because device was lost."_ns);
promise->MaybeResolve(JS::NullHandleValue); return;
case PopErrorScopeResultType::ThrowOperationError:
promise->MaybeRejectWithOperationError(aResult.message); return;
case PopErrorScopeResultType::OutOfMemory:
error = new OutOfMemoryError(self->GetParentObject(), aResult.message); break;
case PopErrorScopeResultType::ValidationError:
error = new ValidationError(self->GetParentObject(), aResult.message); break;
case PopErrorScopeResultType::InternalError:
error = new InternalError(self->GetParentObject(), aResult.message); break;
}
promise->MaybeResolve(std::move(error));
},
[self = RefPtr{this}, promise](const ipc::ResponseRejectReason&) { // Device was lost.
WebGPUChild::JsWarning(
self->GetOwnerGlobal(), "popErrorScope resolving to null because device was just lost."_ns);
promise->MaybeResolve(JS::NullHandleValue);
});
return promise.forget();
}
} // namespace mozilla::webgpu
¤ Dauer der Verarbeitung: 0.23 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.