blob: e713bb401301a95f08a13f2667b5255e5fcd2203 [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/modules/webgpu/gpu_shader_module.h"
#include <dawn/webgpu.h>
#include "gpu/command_buffer/client/webgpu_interface.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_union_usvstring_uint32array.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_shader_module_descriptor.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/modules/webgpu/dawn_callback.h"
#include "third_party/blink/renderer/modules/webgpu/gpu_compilation_info.h"
#include "third_party/blink/renderer/modules/webgpu/gpu_compilation_message.h"
#include "third_party/blink/renderer/modules/webgpu/gpu_device.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
namespace blink {
// static
GPUShaderModule* GPUShaderModule::Create(
GPUDevice* device,
const GPUShaderModuleDescriptor* webgpu_desc,
ExceptionState& exception_state) {
DCHECK(device);
DCHECK(webgpu_desc);
std::string wgsl_code;
WGPUShaderModuleWGSLDescriptor wgsl_desc = {};
WGPUShaderModuleSPIRVDescriptor spirv_desc = {};
std::string label;
WGPUShaderModuleDescriptor dawn_desc = {};
const auto* wgsl_or_spirv = webgpu_desc->code();
switch (wgsl_or_spirv->GetContentType()) {
case V8UnionUSVStringOrUint32Array::ContentType::kUSVString: {
wgsl_code = wgsl_or_spirv->GetAsUSVString().Utf8();
wgsl_desc.chain.sType = WGPUSType_ShaderModuleWGSLDescriptor;
wgsl_desc.source = wgsl_code.c_str();
dawn_desc.nextInChain = reinterpret_cast<WGPUChainedStruct*>(&wgsl_desc);
break;
}
case V8UnionUSVStringOrUint32Array::ContentType::kUint32Array: {
NotShared<DOMUint32Array> code = wgsl_or_spirv->GetAsUint32Array();
uint32_t length_words = 0;
if (!base::CheckedNumeric<uint32_t>(code->length())
.AssignIfValid(&length_words)) {
exception_state.ThrowRangeError(
"The provided ArrayBuffer exceeds the maximum supported size "
"(4294967295)");
return nullptr;
}
spirv_desc.chain.sType = WGPUSType_ShaderModuleSPIRVDescriptor;
spirv_desc.code = code->Data();
spirv_desc.codeSize = length_words;
dawn_desc.nextInChain = reinterpret_cast<WGPUChainedStruct*>(&spirv_desc);
break;
}
}
if (webgpu_desc->hasLabel()) {
label = webgpu_desc->label().Utf8();
dawn_desc.label = label.c_str();
}
GPUShaderModule* shader = MakeGarbageCollected<GPUShaderModule>(
device, device->GetProcs().deviceCreateShaderModule(device->GetHandle(),
&dawn_desc));
if (webgpu_desc->hasLabel())
shader->setLabel(webgpu_desc->label());
return shader;
}
GPUShaderModule::GPUShaderModule(GPUDevice* device,
WGPUShaderModule shader_module)
: DawnObject<WGPUShaderModule>(device, shader_module) {}
void GPUShaderModule::OnCompilationInfoCallback(
ScriptPromiseResolver* resolver,
WGPUCompilationInfoRequestStatus status,
const WGPUCompilationInfo* info) {
if (status != WGPUCompilationInfoRequestStatus_Success || !info) {
resolver->Reject(
MakeGarbageCollected<DOMException>(DOMExceptionCode::kOperationError));
return;
}
// Temporarily immediately create the CompilationInfo info and resolve the
// promise.
GPUCompilationInfo* result = MakeGarbageCollected<GPUCompilationInfo>();
for (uint32_t i = 0; i < info->messageCount; ++i) {
const WGPUCompilationMessage* message = &info->messages[i];
result->AppendMessage(MakeGarbageCollected<GPUCompilationMessage>(
message->message, message->type, message->lineNum, message->linePos,
message->offset, message->length));
}
resolver->Resolve(result);
}
ScriptPromise GPUShaderModule::compilationInfo(ScriptState* script_state) {
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
ScriptPromise promise = resolver->Promise();
auto* callback =
BindDawnCallback(&GPUShaderModule::OnCompilationInfoCallback,
WrapPersistent(this), WrapPersistent(resolver));
GetProcs().shaderModuleGetCompilationInfo(
GetHandle(), callback->UnboundCallback(), callback->AsUserdata());
// WebGPU guarantees that promises are resolved in finite time so we
// need to ensure commands are flushed.
EnsureFlush();
return promise;
}
} // namespace blink