blob: 1171629502e797ce06c99a823e79c8779f9de181 [file] [log] [blame]
// Copyright 2019 The Chromium Authors
// 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/dawn_conversions.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_color_dict.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_extent_3d_dict.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_index_format.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_origin_2d_dict.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_origin_3d_dict.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_programmable_stage.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_texel_copy_buffer_layout.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_texel_copy_texture_info.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_union_doublesequence_gpucolordict.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_union_gpuautolayoutmode_gpupipelinelayout.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_union_gpuextent3ddict_unsignedlongenforcerangesequence.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_union_gpuorigin2ddict_unsignedlongenforcerangesequence.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_union_gpuorigin3ddict_unsignedlongenforcerangesequence.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/modules/webgpu/gpu_shader_module.h"
#include "third_party/blink/renderer/modules/webgpu/gpu_texture.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
namespace blink {
bool ConvertToDawn(const V8GPUColor* in,
wgpu::Color* out,
ExceptionState& exception_state) {
switch (in->GetContentType()) {
case V8GPUColor::ContentType::kGPUColorDict: {
const GPUColorDict* dict = in->GetAsGPUColorDict();
*out = {dict->r(), dict->g(), dict->b(), dict->a()};
return true;
}
case V8GPUColor::ContentType::kDoubleSequence: {
const Vector<double>& sequence = in->GetAsDoubleSequence();
if (sequence.size() != 4) {
exception_state.ThrowTypeError(
"A sequence of number used as a GPUColor must have exactly 4 "
"elements.");
return false;
}
*out = {sequence[0], sequence[1], sequence[2], sequence[3]};
return true;
}
}
}
bool ConvertToDawn(const V8GPUExtent3D* in,
wgpu::Extent3D* out,
GPUDevice* device,
ExceptionState& exception_state) {
switch (in->GetContentType()) {
case V8GPUExtent3D::ContentType::kGPUExtent3DDict: {
const GPUExtent3DDict* dict = in->GetAsGPUExtent3DDict();
*out = {dict->width(), dict->height(), dict->depthOrArrayLayers()};
if (dict->hasDepth()) {
device->AddSingletonWarning(GPUSingletonWarning::kDepthKey);
}
return true;
}
case V8GPUExtent3D::ContentType::kUnsignedLongEnforceRangeSequence: {
const Vector<uint32_t>& sequence =
in->GetAsUnsignedLongEnforceRangeSequence();
// The WebGPU spec states that height and depthOrArrayLayers default to 1
// when the sequence isn't big enough.
switch (sequence.size()) {
case 1:
*out = {sequence[0], 1, 1};
return true;
case 2:
*out = {sequence[0], sequence[1], 1};
return true;
case 3:
*out = {sequence[0], sequence[1], sequence[2]};
return true;
default:
exception_state.ThrowTypeError(
"A sequence of number used as a GPUExtent3D must have between 1 "
"and 3 elements.");
return false;
}
}
}
}
bool ConvertToDawn(const V8GPUOrigin3D* in,
wgpu::Origin3D* out,
ExceptionState& exception_state) {
switch (in->GetContentType()) {
case V8GPUOrigin3D::ContentType::kGPUOrigin3DDict: {
const GPUOrigin3DDict* dict = in->GetAsGPUOrigin3DDict();
*out = {dict->x(), dict->y(), dict->z()};
return true;
}
case V8GPUOrigin3D::ContentType::kUnsignedLongEnforceRangeSequence: {
const Vector<uint32_t>& sequence =
in->GetAsUnsignedLongEnforceRangeSequence();
// The WebGPU spec states that coordinates default to 0 when the sequence
// isn't big enough.
switch (sequence.size()) {
case 0:
*out = {0, 0, 0};
return true;
case 1:
*out = {sequence[0], 0, 0};
return true;
case 2:
*out = {sequence[0], sequence[1], 0};
return true;
case 3:
*out = {sequence[0], sequence[1], sequence[2]};
return true;
default:
exception_state.ThrowTypeError(
"A sequence of number used as a GPUOrigin3D must have at most 3 "
"elements.");
return false;
}
}
}
}
bool ConvertToDawn(const V8GPUOrigin2D* in,
wgpu::Origin2D* out,
ExceptionState& exception_state) {
switch (in->GetContentType()) {
case V8GPUOrigin2D::ContentType::kGPUOrigin2DDict: {
const GPUOrigin2DDict* dict = in->GetAsGPUOrigin2DDict();
*out = {dict->x(), dict->y()};
return true;
}
case V8GPUOrigin2D::ContentType::kUnsignedLongEnforceRangeSequence: {
const Vector<uint32_t>& sequence =
in->GetAsUnsignedLongEnforceRangeSequence();
// The WebGPU spec states that coordinates default to 0 when the sequence
// isn't big enough.
switch (sequence.size()) {
case 0:
*out = {0, 0};
return true;
case 1:
*out = {sequence[0], 0};
return true;
case 2:
*out = {sequence[0], sequence[1]};
return true;
default:
exception_state.ThrowTypeError(
"A sequence of number used as a GPUOrigin2D must have at most 2 "
"elements.");
return false;
}
}
}
}
bool ConvertToDawn(const GPUTexelCopyTextureInfo* in,
wgpu::TexelCopyTextureInfo* out,
ExceptionState& exception_state) {
DCHECK(in);
DCHECK(in->texture());
*out = {
.texture = in->texture()->GetHandle(),
.mipLevel = in->mipLevel(),
.aspect = AsDawnEnum(in->aspect()),
};
return ConvertToDawn(in->origin(), &out->origin, exception_state);
}
// Dawn represents `undefined` as the special uint32_t value
// wgpu::kCopyStrideUndefined (0xFFFF'FFFF). Blink must make sure that an
// actual value of 0xFFFF'FFFF coming in from JS is not treated as
// wgpu::kCopyStrideUndefined, so it injects an error in that case.
const char* ValidateTexelCopyBufferLayout(
const GPUTexelCopyBufferLayout* webgpu_layout,
wgpu::TexelCopyBufferLayout* dawn_layout) {
DCHECK(webgpu_layout);
uint32_t bytesPerRow = 0;
if (webgpu_layout->hasBytesPerRow()) {
bytesPerRow = webgpu_layout->bytesPerRow();
if (bytesPerRow == wgpu::kCopyStrideUndefined) {
return "bytesPerRow must be a multiple of 256";
}
} else {
bytesPerRow = wgpu::kCopyStrideUndefined;
}
uint32_t rowsPerImage = 0;
if (webgpu_layout->hasRowsPerImage()) {
rowsPerImage = webgpu_layout->rowsPerImage();
if (rowsPerImage == wgpu::kCopyStrideUndefined) {
return "rowsPerImage is too large";
}
} else {
rowsPerImage = wgpu::kCopyStrideUndefined;
}
*dawn_layout = {
.offset = webgpu_layout->offset(),
.bytesPerRow = bytesPerRow,
.rowsPerImage = rowsPerImage,
};
return nullptr;
}
wgpu::PipelineLayout AsDawnType(
V8UnionGPUAutoLayoutModeOrGPUPipelineLayout* webgpu_layout) {
DCHECK(webgpu_layout);
switch (webgpu_layout->GetContentType()) {
case V8UnionGPUAutoLayoutModeOrGPUPipelineLayout::ContentType::
kGPUPipelineLayout:
return AsDawnType(webgpu_layout->GetAsGPUPipelineLayout());
case V8UnionGPUAutoLayoutModeOrGPUPipelineLayout::ContentType::
kGPUAutoLayoutMode:
return nullptr;
}
NOTREACHED();
}
} // namespace blink