blob: f9032a7dc7f74c2b0635f7e27b1ca269153698db [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_render_pipeline.h"
#include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_blend_state.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_color_target_state.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_depth_stencil_state.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_rasterization_state_descriptor.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_render_pipeline_descriptor.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_stencil_face_state.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_vertex_attribute_descriptor.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_vertex_buffer_layout_descriptor.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_vertex_state_descriptor.h"
#include "third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout.h"
#include "third_party/blink/renderer/modules/webgpu/gpu_device.h"
#include "third_party/blink/renderer/modules/webgpu/gpu_pipeline_layout.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
namespace blink {
namespace {
WGPUBlendDescriptor AsDawnType(const GPUBlendState* webgpu_desc) {
DCHECK(webgpu_desc);
WGPUBlendDescriptor dawn_desc = {};
dawn_desc.dstFactor = AsDawnEnum<WGPUBlendFactor>(webgpu_desc->dstFactor());
dawn_desc.srcFactor = AsDawnEnum<WGPUBlendFactor>(webgpu_desc->srcFactor());
dawn_desc.operation =
AsDawnEnum<WGPUBlendOperation>(webgpu_desc->operation());
return dawn_desc;
}
} // anonymous namespace
WGPUColorStateDescriptor AsDawnType(const GPUColorTargetState* webgpu_desc) {
DCHECK(webgpu_desc);
WGPUColorStateDescriptor dawn_desc = {};
dawn_desc.nextInChain = nullptr;
dawn_desc.alphaBlend = AsDawnType(webgpu_desc->alphaBlend());
dawn_desc.colorBlend = AsDawnType(webgpu_desc->colorBlend());
dawn_desc.writeMask =
AsDawnEnum<WGPUColorWriteMask>(webgpu_desc->writeMask());
dawn_desc.format = AsDawnEnum<WGPUTextureFormat>(webgpu_desc->format());
return dawn_desc;
}
namespace {
WGPUStencilStateFaceDescriptor AsDawnType(
const GPUStencilFaceState* webgpu_desc) {
DCHECK(webgpu_desc);
WGPUStencilStateFaceDescriptor dawn_desc = {};
dawn_desc.compare = AsDawnEnum<WGPUCompareFunction>(webgpu_desc->compare());
dawn_desc.depthFailOp =
AsDawnEnum<WGPUStencilOperation>(webgpu_desc->depthFailOp());
dawn_desc.failOp = AsDawnEnum<WGPUStencilOperation>(webgpu_desc->failOp());
dawn_desc.passOp = AsDawnEnum<WGPUStencilOperation>(webgpu_desc->passOp());
return dawn_desc;
}
WGPUDepthStencilStateDescriptor AsDawnType(
const GPUDepthStencilState* webgpu_desc) {
DCHECK(webgpu_desc);
WGPUDepthStencilStateDescriptor dawn_desc = {};
dawn_desc.nextInChain = nullptr;
dawn_desc.depthCompare =
AsDawnEnum<WGPUCompareFunction>(webgpu_desc->depthCompare());
dawn_desc.depthWriteEnabled = webgpu_desc->depthWriteEnabled();
dawn_desc.format = AsDawnEnum<WGPUTextureFormat>(webgpu_desc->format());
dawn_desc.stencilBack = AsDawnType(webgpu_desc->stencilBack());
dawn_desc.stencilFront = AsDawnType(webgpu_desc->stencilFront());
dawn_desc.stencilReadMask = webgpu_desc->stencilReadMask();
dawn_desc.stencilWriteMask = webgpu_desc->stencilWriteMask();
return dawn_desc;
}
void GPUVertexStateAsWGPUVertexState(
v8::Isolate* isolate,
const GPUVertexStateDescriptor* descriptor,
WGPUVertexStateDescriptor* dawn_desc,
Vector<WGPUVertexBufferLayoutDescriptor>* dawn_vertex_buffers,
Vector<WGPUVertexAttributeDescriptor>* dawn_vertex_attributes,
ExceptionState& exception_state) {
DCHECK(isolate);
DCHECK(descriptor);
DCHECK(dawn_desc);
DCHECK(dawn_vertex_buffers);
DCHECK(dawn_vertex_attributes);
*dawn_desc = {};
dawn_desc->indexFormat =
AsDawnEnum<WGPUIndexFormat>(descriptor->indexFormat());
dawn_desc->vertexBufferCount = 0;
dawn_desc->vertexBuffers = nullptr;
if (descriptor->hasVertexBuffers()) {
// TODO(crbug.com/951629): Use a sequence of nullable descriptors.
v8::Local<v8::Value> vertex_buffers_value =
descriptor->vertexBuffers().V8Value();
if (!vertex_buffers_value->IsArray()) {
exception_state.ThrowTypeError("vertexBuffers must be an array");
return;
}
v8::Local<v8::Context> context = isolate->GetCurrentContext();
v8::Local<v8::Array> vertex_buffers = vertex_buffers_value.As<v8::Array>();
// First we collect all the descriptors but we don't set
// WGPUVertexBufferLayoutDescriptor::attributes
// TODO(cwallez@chromium.org): Should we validate the Length() first so we
// don't risk creating HUGE vectors of WGPUVertexBufferLayoutDescriptor from
// the sparse array?
for (uint32_t i = 0; i < vertex_buffers->Length(); ++i) {
// This array can be sparse. Skip empty slots.
v8::MaybeLocal<v8::Value> maybe_value = vertex_buffers->Get(context, i);
v8::Local<v8::Value> value;
if (!maybe_value.ToLocal(&value) || value.IsEmpty() ||
value->IsNullOrUndefined()) {
WGPUVertexBufferLayoutDescriptor dawn_vertex_buffer = {};
dawn_vertex_buffer.arrayStride = 0;
dawn_vertex_buffer.stepMode = WGPUInputStepMode_Vertex;
dawn_vertex_buffer.attributeCount = 0;
dawn_vertex_buffer.attributes = nullptr;
dawn_vertex_buffers->push_back(dawn_vertex_buffer);
continue;
}
GPUVertexBufferLayoutDescriptor* vertex_buffer =
NativeValueTraits<GPUVertexBufferLayoutDescriptor>::NativeValue(
isolate, value, exception_state);
if (exception_state.HadException()) {
return;
}
WGPUVertexBufferLayoutDescriptor dawn_vertex_buffer = {};
dawn_vertex_buffer.arrayStride = vertex_buffer->arrayStride();
dawn_vertex_buffer.stepMode =
AsDawnEnum<WGPUInputStepMode>(vertex_buffer->stepMode());
dawn_vertex_buffer.attributeCount =
static_cast<uint32_t>(vertex_buffer->attributes().size());
dawn_vertex_buffer.attributes = nullptr;
dawn_vertex_buffers->push_back(dawn_vertex_buffer);
for (wtf_size_t j = 0; j < vertex_buffer->attributes().size(); ++j) {
const GPUVertexAttributeDescriptor* attribute =
vertex_buffer->attributes()[j];
WGPUVertexAttributeDescriptor dawn_vertex_attribute = {};
dawn_vertex_attribute.shaderLocation = attribute->shaderLocation();
dawn_vertex_attribute.offset = attribute->offset();
dawn_vertex_attribute.format =
AsDawnEnum<WGPUVertexFormat>(attribute->format());
dawn_vertex_attributes->push_back(dawn_vertex_attribute);
}
}
// Set up pointers in DawnVertexBufferLayoutDescriptor::attributes only
// after we stopped appending to the vector so the pointers aren't
// invalidated.
uint32_t attributeIndex = 0;
for (WGPUVertexBufferLayoutDescriptor& buffer : *dawn_vertex_buffers) {
if (buffer.attributeCount == 0) {
continue;
}
buffer.attributes = &(*dawn_vertex_attributes)[attributeIndex];
attributeIndex += buffer.attributeCount;
}
}
dawn_desc->vertexBufferCount =
static_cast<uint32_t>(dawn_vertex_buffers->size());
dawn_desc->vertexBuffers = dawn_vertex_buffers->data();
}
WGPURasterizationStateDescriptor AsDawnType(
const GPURasterizationStateDescriptor* webgpu_desc) {
DCHECK(webgpu_desc);
WGPURasterizationStateDescriptor dawn_desc = {};
dawn_desc.nextInChain = nullptr;
dawn_desc.frontFace = AsDawnEnum<WGPUFrontFace>(webgpu_desc->frontFace());
dawn_desc.cullMode = AsDawnEnum<WGPUCullMode>(webgpu_desc->cullMode());
dawn_desc.depthBias = webgpu_desc->depthBias();
dawn_desc.depthBiasSlopeScale = webgpu_desc->depthBiasSlopeScale();
dawn_desc.depthBiasClamp = webgpu_desc->depthBiasClamp();
return dawn_desc;
}
} // anonymous namespace
void ConvertToDawnType(v8::Isolate* isolate,
const GPURenderPipelineDescriptor* webgpu_desc,
OwnedRenderPipelineDescriptor* dawn_desc_info,
ExceptionState& exception_state) {
DCHECK(isolate);
DCHECK(webgpu_desc);
DCHECK(dawn_desc_info);
GPUVertexStateAsWGPUVertexState(
isolate, webgpu_desc->vertexState(), &dawn_desc_info->vertex_state,
&dawn_desc_info->vertex_buffer_layouts,
&dawn_desc_info->vertex_attributes, exception_state);
if (exception_state.HadException()) {
return;
}
dawn_desc_info->dawn_desc.vertexState = &dawn_desc_info->vertex_state;
if (webgpu_desc->hasLayout()) {
dawn_desc_info->dawn_desc.layout = AsDawnType(webgpu_desc->layout());
}
if (webgpu_desc->hasLabel()) {
dawn_desc_info->label = webgpu_desc->label().Utf8();
dawn_desc_info->dawn_desc.label = dawn_desc_info->label.c_str();
}
dawn_desc_info->vertex_stage_info = AsDawnType(webgpu_desc->vertexStage());
dawn_desc_info->dawn_desc.vertexStage =
std::get<0>(dawn_desc_info->vertex_stage_info);
if (webgpu_desc->hasFragmentStage()) {
dawn_desc_info->fragment_stage_info =
AsDawnType(webgpu_desc->fragmentStage());
dawn_desc_info->dawn_desc.fragmentStage =
&std::get<0>(dawn_desc_info->fragment_stage_info);
}
dawn_desc_info->dawn_desc.primitiveTopology =
AsDawnEnum<WGPUPrimitiveTopology>(webgpu_desc->primitiveTopology());
dawn_desc_info->rasterization_state =
AsDawnType(webgpu_desc->rasterizationState());
dawn_desc_info->dawn_desc.rasterizationState =
&dawn_desc_info->rasterization_state;
dawn_desc_info->dawn_desc.sampleCount = webgpu_desc->sampleCount();
if (webgpu_desc->hasDepthStencilState()) {
dawn_desc_info->depth_stencil_state =
AsDawnType(webgpu_desc->depthStencilState());
dawn_desc_info->dawn_desc.depthStencilState =
&dawn_desc_info->depth_stencil_state;
}
dawn_desc_info->color_states = AsDawnType(webgpu_desc->colorStates());
dawn_desc_info->dawn_desc.colorStateCount =
static_cast<uint32_t>(webgpu_desc->colorStates().size());
dawn_desc_info->dawn_desc.colorStates = dawn_desc_info->color_states.get();
dawn_desc_info->dawn_desc.sampleMask = webgpu_desc->sampleMask();
dawn_desc_info->dawn_desc.alphaToCoverageEnabled =
webgpu_desc->alphaToCoverageEnabled();
}
// static
GPURenderPipeline* GPURenderPipeline::Create(
ScriptState* script_state,
GPUDevice* device,
const GPURenderPipelineDescriptor* webgpu_desc) {
DCHECK(device);
DCHECK(webgpu_desc);
OwnedRenderPipelineDescriptor dawn_desc_info;
v8::Isolate* isolate = script_state->GetIsolate();
ExceptionState exception_state(isolate, ExceptionState::kConstructionContext,
"GPUVertexStateDescriptor");
ConvertToDawnType(isolate, webgpu_desc, &dawn_desc_info, exception_state);
if (exception_state.HadException()) {
return nullptr;
}
GPURenderPipeline* pipeline = MakeGarbageCollected<GPURenderPipeline>(
device, device->GetProcs().deviceCreateRenderPipeline(
device->GetHandle(), &dawn_desc_info.dawn_desc));
pipeline->setLabel(webgpu_desc->label());
return pipeline;
}
GPURenderPipeline::GPURenderPipeline(GPUDevice* device,
WGPURenderPipeline render_pipeline)
: DawnObject<WGPURenderPipeline>(device, render_pipeline) {}
GPUBindGroupLayout* GPURenderPipeline::getBindGroupLayout(uint32_t index) {
return MakeGarbageCollected<GPUBindGroupLayout>(
device_, GetProcs().renderPipelineGetBindGroupLayout(GetHandle(), index));
}
} // namespace blink