From 1eab070d62cce2d9eacc07cad1e9afc7abf115e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Cruz?= Date: Tue, 24 Oct 2023 11:00:34 +0100 Subject: [PATCH 1/2] webgpu: rely on Dawn defaults Dawn already includes default values for most objects, rely on those instead of duplicating those values in workerd as well. --- src/workerd/api/gpu/gpu-bindgroup-layout.c++ | 10 +- .../api/gpu/gpu-compute-pass-encoder.c++ | 4 +- src/workerd/api/gpu/gpu-device.c++ | 107 ++++++++++++------ 3 files changed, 82 insertions(+), 39 deletions(-) diff --git a/src/workerd/api/gpu/gpu-bindgroup-layout.c++ b/src/workerd/api/gpu/gpu-bindgroup-layout.c++ index 7a2e9e36a5b..d060aa104d5 100644 --- a/src/workerd/api/gpu/gpu-bindgroup-layout.c++ +++ b/src/workerd/api/gpu/gpu-bindgroup-layout.c++ @@ -25,9 +25,15 @@ wgpu::BufferBindingType parseBufferBindingType(kj::StringPtr bType) { wgpu::BufferBindingLayout parseBufferBindingLayout(GPUBufferBindingLayout& buffer) { wgpu::BufferBindingLayout l; + // the Dawn default here is Undefined, so we stick with what's in the spec l.type = parseBufferBindingType(buffer.type.orDefault([] { return "uniform"_kj; })); - l.hasDynamicOffset = buffer.hasDynamicOffset.orDefault(false); - l.minBindingSize = buffer.minBindingSize.orDefault(0); + + KJ_IF_SOME(hasDynamicOffset, buffer.hasDynamicOffset) { + l.hasDynamicOffset = hasDynamicOffset; + } + KJ_IF_SOME(minBindingSize, buffer.minBindingSize) { + l.minBindingSize = minBindingSize; + } return kj::mv(l); } diff --git a/src/workerd/api/gpu/gpu-compute-pass-encoder.c++ b/src/workerd/api/gpu/gpu-compute-pass-encoder.c++ index 4dc61b10442..de60879933f 100644 --- a/src/workerd/api/gpu/gpu-compute-pass-encoder.c++ +++ b/src/workerd/api/gpu/gpu-compute-pass-encoder.c++ @@ -29,14 +29,14 @@ void GPUComputePassEncoder::setBindGroup( jsg::Optional> dynamicOffsets) { wgpu::BindGroup bg = nullptr; - KJ_IF_SOME (bgroup, bindGroup) { + KJ_IF_SOME(bgroup, bindGroup) { bg = *bgroup; } uint32_t* offsets = nullptr; uint32_t num_offsets = 0; - KJ_IF_SOME (dos, dynamicOffsets) { + KJ_IF_SOME(dos, dynamicOffsets) { offsets = dos.begin(); num_offsets = dos.size(); } diff --git a/src/workerd/api/gpu/gpu-device.c++ b/src/workerd/api/gpu/gpu-device.c++ index ef1b40d9179..1b9b8d195b3 100644 --- a/src/workerd/api/gpu/gpu-device.c++ +++ b/src/workerd/api/gpu/gpu-device.c++ @@ -168,20 +168,34 @@ wgpu::MipmapFilterMode parseMipmapFilterMode(kj::StringPtr mode) { jsg::Ref GPUDevice::createSampler(GPUSamplerDescriptor descriptor) { wgpu::SamplerDescriptor desc{}; - desc.addressModeU = - parseAddressMode(descriptor.addressModeU.orDefault([] { return "clamp-to-edge"_kj; })); - desc.addressModeV = - parseAddressMode(descriptor.addressModeV.orDefault([] { return "clamp-to-edge"_kj; })); - desc.addressModeW = - parseAddressMode(descriptor.addressModeW.orDefault([] { return "clamp-to-edge"_kj; })); - desc.magFilter = parseFilterMode(descriptor.magFilter.orDefault([] { return "nearest"_kj; })); - desc.minFilter = parseFilterMode(descriptor.minFilter.orDefault([] { return "nearest"_kj; })); - desc.mipmapFilter = - parseMipmapFilterMode(descriptor.mipmapFilter.orDefault([] { return "nearest"_kj; })); - desc.lodMinClamp = descriptor.lodMinClamp.orDefault(0); - desc.lodMaxClamp = descriptor.lodMaxClamp.orDefault(32); + KJ_IF_SOME(addressModeU, descriptor.addressModeU) { + desc.addressModeU = parseAddressMode(addressModeU); + } + KJ_IF_SOME(addressModeV, descriptor.addressModeV) { + desc.addressModeV = parseAddressMode(addressModeV); + } + KJ_IF_SOME(addressModeW, descriptor.addressModeW) { + desc.addressModeW = parseAddressMode(addressModeW); + } + KJ_IF_SOME(magFilter, descriptor.magFilter) { + desc.magFilter = parseFilterMode(magFilter); + } + KJ_IF_SOME(minFilter, descriptor.minFilter) { + desc.minFilter = parseFilterMode(minFilter); + } + KJ_IF_SOME(mipmapFilter, descriptor.mipmapFilter) { + desc.mipmapFilter = parseMipmapFilterMode(mipmapFilter); + } + KJ_IF_SOME(lodMinClamp, descriptor.lodMinClamp) { + desc.lodMinClamp = lodMinClamp; + } + KJ_IF_SOME(lodMaxClamp, descriptor.lodMaxClamp) { + desc.lodMaxClamp = lodMaxClamp; + } desc.compare = parseCompareFunction(descriptor.compare); - desc.maxAnisotropy = descriptor.maxAnisotropy.orDefault(1); + KJ_IF_SOME(maxAnisotropy, descriptor.maxAnisotropy) { + desc.maxAnisotropy = maxAnisotropy; + } KJ_IF_SOME(label, descriptor.label) { desc.label = label.cStr(); @@ -255,11 +269,18 @@ struct ParsedRenderPipelineDescriptor { void parseStencilFaceState(wgpu::StencilFaceState& out, jsg::Optional& in) { KJ_IF_SOME(stencilFront, in) { - out.compare = parseCompareFunction(stencilFront.compare.orDefault([] { return "always"_kj; })); - out.failOp = parseStencilOperation(stencilFront.failOp.orDefault([] { return "keep"_kj; })); - out.depthFailOp = - parseStencilOperation(stencilFront.depthFailOp.orDefault([] { return "keep"_kj; })); - out.passOp = parseStencilOperation(stencilFront.passOp.orDefault([] { return "keep"_kj; })); + KJ_IF_SOME(compare, stencilFront.compare) { + out.compare = parseCompareFunction(compare); + } + KJ_IF_SOME(failOp, stencilFront.failOp) { + out.failOp = parseStencilOperation(failOp); + } + KJ_IF_SOME(depthFailOp, stencilFront.depthFailOp) { + out.depthFailOp = parseStencilOperation(depthFailOp); + } + KJ_IF_SOME(passOp, stencilFront.passOp) { + out.passOp = parseStencilOperation(passOp); + } } } @@ -308,17 +329,18 @@ parseRenderPipelineDescriptor(GPURenderPipelineDescriptor& descriptor) { parsedDesc.desc.nextInChain = parsedDesc.depthClip; } - parsedDesc.desc.primitive.topology = - parsePrimitiveTopology(primitive.topology.orDefault([] { return "triangle-list"_kj; })); - + KJ_IF_SOME(topology, primitive.topology) { + parsedDesc.desc.primitive.topology = parsePrimitiveTopology(topology); + } KJ_IF_SOME(indexFormat, primitive.stripIndexFormat) { parsedDesc.desc.primitive.stripIndexFormat = parseIndexFormat(indexFormat); } - - parsedDesc.desc.primitive.frontFace = - parseFrontFace(primitive.frontFace.orDefault([] { return "ccw"_kj; })); - parsedDesc.desc.primitive.cullMode = - parseCullMode(primitive.cullMode.orDefault([] { return "none"_kj; })); + KJ_IF_SOME(frontFace, primitive.frontFace) { + parsedDesc.desc.primitive.frontFace = parseFrontFace(frontFace); + } + KJ_IF_SOME(cullMode, primitive.cullMode) { + parsedDesc.desc.primitive.cullMode = parseCullMode(cullMode); + } } KJ_IF_SOME(depthStencil, descriptor.depthStencil) { @@ -329,21 +351,36 @@ parseRenderPipelineDescriptor(GPURenderPipelineDescriptor& descriptor) { parseStencilFaceState(depthStencilState->stencilFront, depthStencil.stencilFront); parseStencilFaceState(depthStencilState->stencilBack, depthStencil.stencilBack); - depthStencilState->stencilReadMask = depthStencil.stencilReadMask.orDefault(0xFFFFFFFF); - depthStencilState->stencilWriteMask = depthStencil.stencilWriteMask.orDefault(0xFFFFFFFF); - depthStencilState->depthBias = depthStencil.depthBias.orDefault(0); - depthStencilState->depthBiasSlopeScale = depthStencil.depthBiasSlopeScale.orDefault(0); - depthStencilState->depthBiasClamp = depthStencil.depthBiasClamp.orDefault(0); + KJ_IF_SOME(stencilReadMask, depthStencil.stencilReadMask) { + depthStencilState->stencilReadMask = stencilReadMask; + } + KJ_IF_SOME(stencilWriteMask, depthStencil.stencilWriteMask) { + depthStencilState->stencilWriteMask = stencilWriteMask; + } + KJ_IF_SOME(depthBias, depthStencil.depthBias) { + depthStencilState->depthBias = depthBias; + } + KJ_IF_SOME(depthBiasSlopeScale, depthStencil.depthBiasSlopeScale) { + depthStencilState->depthBiasSlopeScale = depthBiasSlopeScale; + } + KJ_IF_SOME(depthBiasClamp, depthStencil.depthBiasClamp) { + depthStencilState->depthBiasClamp = depthBiasClamp; + } parsedDesc.stencilState = kj::mv(depthStencilState); parsedDesc.desc.depthStencil = parsedDesc.stencilState; } KJ_IF_SOME(multisample, descriptor.multisample) { - parsedDesc.desc.multisample.count = multisample.count.orDefault(1); - parsedDesc.desc.multisample.mask = multisample.mask.orDefault(0xFFFFFFFF); - parsedDesc.desc.multisample.alphaToCoverageEnabled = - multisample.alphaToCoverageEnabled.orDefault(false); + KJ_IF_SOME(count, multisample.count) { + parsedDesc.desc.multisample.count = count; + } + KJ_IF_SOME(mask, multisample.mask) { + parsedDesc.desc.multisample.mask = mask; + } + KJ_IF_SOME(alphaToCoverageEnabled, multisample.alphaToCoverageEnabled) { + parsedDesc.desc.multisample.alphaToCoverageEnabled = alphaToCoverageEnabled; + } } KJ_IF_SOME(fragment, descriptor.fragment) { From 60ccf6be7b2398becc93a5bc4e6150842f77979c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Cruz?= Date: Tue, 24 Oct 2023 15:55:12 +0100 Subject: [PATCH 2/2] webgpu: continue work on createRenderPipeline() Parse additional fields of RenderPipelineDescriptor. --- src/workerd/api/gpu/gpu-bindgroup-layout.c++ | 54 ++--- src/workerd/api/gpu/gpu-device.c++ | 109 ++++++++-- src/workerd/api/gpu/gpu-utils.c++ | 186 ++++++++++++++++++ src/workerd/api/gpu/gpu-utils.h | 4 + src/workerd/api/gpu/webgpu-windowless-test.js | 15 ++ 5 files changed, 326 insertions(+), 42 deletions(-) diff --git a/src/workerd/api/gpu/gpu-bindgroup-layout.c++ b/src/workerd/api/gpu/gpu-bindgroup-layout.c++ index d060aa104d5..3e258352648 100644 --- a/src/workerd/api/gpu/gpu-bindgroup-layout.c++ +++ b/src/workerd/api/gpu/gpu-bindgroup-layout.c++ @@ -23,19 +23,19 @@ wgpu::BufferBindingType parseBufferBindingType(kj::StringPtr bType) { } wgpu::BufferBindingLayout parseBufferBindingLayout(GPUBufferBindingLayout& buffer) { - wgpu::BufferBindingLayout l; + wgpu::BufferBindingLayout layout; // the Dawn default here is Undefined, so we stick with what's in the spec - l.type = parseBufferBindingType(buffer.type.orDefault([] { return "uniform"_kj; })); + layout.type = parseBufferBindingType(buffer.type.orDefault([] { return "uniform"_kj; })); KJ_IF_SOME(hasDynamicOffset, buffer.hasDynamicOffset) { - l.hasDynamicOffset = hasDynamicOffset; + layout.hasDynamicOffset = hasDynamicOffset; } KJ_IF_SOME(minBindingSize, buffer.minBindingSize) { - l.minBindingSize = minBindingSize; + layout.minBindingSize = minBindingSize; } - return kj::mv(l); + return kj::mv(layout); } wgpu::SamplerBindingType parseSamplerBindingType(kj::StringPtr bType) { @@ -55,10 +55,9 @@ wgpu::SamplerBindingType parseSamplerBindingType(kj::StringPtr bType) { } wgpu::SamplerBindingLayout parseSamplerBindingLayout(GPUSamplerBindingLayout& sampler) { - wgpu::SamplerBindingLayout s; - s.type = parseSamplerBindingType(sampler.type.orDefault([] { return "filtering"_kj; })); - - return kj::mv(s); + wgpu::SamplerBindingLayout layout; + layout.type = parseSamplerBindingType(sampler.type.orDefault([] { return "filtering"_kj; })); + return kj::mv(layout); } wgpu::TextureSampleType parseTextureSampleType(kj::StringPtr sType) { @@ -86,49 +85,50 @@ wgpu::TextureSampleType parseTextureSampleType(kj::StringPtr sType) { } wgpu::TextureBindingLayout parseTextureBindingLayout(GPUTextureBindingLayout& texture) { - wgpu::TextureBindingLayout t; - t.sampleType = parseTextureSampleType(texture.sampleType.orDefault([] { return "float"_kj; })); - t.viewDimension = + wgpu::TextureBindingLayout layout; + layout.sampleType = + parseTextureSampleType(texture.sampleType.orDefault([] { return "float"_kj; })); + layout.viewDimension = parseTextureViewDimension(texture.viewDimension.orDefault([] { return "2d"_kj; })); - t.multisampled = texture.multisampled.orDefault(false); + layout.multisampled = texture.multisampled.orDefault(false); - return kj::mv(t); + return kj::mv(layout); } wgpu::StorageTextureBindingLayout parseStorageTextureBindingLayout(GPUStorageTextureBindingLayout& storage) { - wgpu::StorageTextureBindingLayout s; - s.access = parseStorageAccess(storage.access.orDefault([] { return "write-only"_kj; })); - s.format = parseTextureFormat(storage.format); - s.viewDimension = + wgpu::StorageTextureBindingLayout layout; + layout.access = parseStorageAccess(storage.access.orDefault([] { return "write-only"_kj; })); + layout.format = parseTextureFormat(storage.format); + layout.viewDimension = parseTextureViewDimension(storage.viewDimension.orDefault([] { return "2d"_kj; })); - return kj::mv(s); + return kj::mv(layout); } wgpu::BindGroupLayoutEntry parseBindGroupLayoutEntry(GPUBindGroupLayoutEntry& entry) { - wgpu::BindGroupLayoutEntry e; - e.binding = entry.binding; - e.visibility = static_cast(entry.visibility); + wgpu::BindGroupLayoutEntry layoutEntry; + layoutEntry.binding = entry.binding; + layoutEntry.visibility = static_cast(entry.visibility); KJ_IF_SOME(buffer, entry.buffer) { - e.buffer = parseBufferBindingLayout(buffer); + layoutEntry.buffer = parseBufferBindingLayout(buffer); } KJ_IF_SOME(sampler, entry.sampler) { - e.sampler = parseSamplerBindingLayout(sampler); + layoutEntry.sampler = parseSamplerBindingLayout(sampler); } KJ_IF_SOME(texture, entry.texture) { - e.texture = parseTextureBindingLayout(texture); + layoutEntry.texture = parseTextureBindingLayout(texture); } KJ_IF_SOME(storage, entry.storageTexture) { - e.storageTexture = parseStorageTextureBindingLayout(storage); + layoutEntry.storageTexture = parseStorageTextureBindingLayout(storage); } - return kj::mv(e); + return kj::mv(layoutEntry); }; } // namespace workerd::api::gpu diff --git a/src/workerd/api/gpu/gpu-device.c++ b/src/workerd/api/gpu/gpu-device.c++ index 1b9b8d195b3..bef6efcfd88 100644 --- a/src/workerd/api/gpu/gpu-device.c++ +++ b/src/workerd/api/gpu/gpu-device.c++ @@ -260,13 +260,6 @@ jsg::Ref GPUDevice::createShaderModule(GPUShaderModuleDescripto return jsg::alloc(kj::mv(shader), kj::addRef(*async_)); } -struct ParsedRenderPipelineDescriptor { - wgpu::RenderPipelineDescriptor desc; - kj::Own depthClip; - kj::Own stencilState; - kj::Own fragment; -}; - void parseStencilFaceState(wgpu::StencilFaceState& out, jsg::Optional& in) { KJ_IF_SOME(stencilFront, in) { KJ_IF_SOME(compare, stencilFront.compare) { @@ -284,6 +277,21 @@ void parseStencilFaceState(wgpu::StencilFaceState& out, jsg::Optional depthClip; + kj::Own stencilState; + kj::Own fragment; + kj::Vector> constantLists; + kj::Array buffers; + kj::Vector> attributeLists; + kj::Array targets; + kj::Vector blends; +}; + ParsedRenderPipelineDescriptor parseRenderPipelineDescriptor(GPURenderPipelineDescriptor& descriptor) { ParsedRenderPipelineDescriptor parsedDesc{}; @@ -295,20 +303,51 @@ parseRenderPipelineDescriptor(GPURenderPipelineDescriptor& descriptor) { parsedDesc.desc.vertex.module = *descriptor.vertex.module; parsedDesc.desc.vertex.entryPoint = descriptor.vertex.entryPoint.cStr(); - kj::Vector constants; KJ_IF_SOME(cDict, descriptor.vertex.constants) { + kj::Vector constants; + for (auto& f : cDict.fields) { wgpu::ConstantEntry e; e.key = f.name.cStr(); e.value = f.value; constants.add(kj::mv(e)); } + auto constantsArray = constants.releaseAsArray(); + parsedDesc.desc.vertex.constants = constantsArray.begin(); + parsedDesc.desc.vertex.constantCount = constantsArray.size(); + parsedDesc.constantLists.add(kj::mv(constantsArray)); } - parsedDesc.desc.vertex.constants = constants.begin(); - parsedDesc.desc.vertex.constantCount = constants.size(); + KJ_IF_SOME(bList, descriptor.vertex.buffers) { + kj::Vector buffers; - // TODO(soon): descriptor.vertex.buffers + for (auto& b : bList) { + wgpu::VertexBufferLayout bLayout; + bLayout.arrayStride = b.arrayStride; + + KJ_IF_SOME(stepMode, b.stepMode) { + bLayout.stepMode = parseVertexStepMode(stepMode); + } + + kj::Vector attributes; + for (auto& a : b.attributes) { + wgpu::VertexAttribute attr; + attr.format = parseVertexFormat(a.format); + attr.offset = a.offset; + attr.shaderLocation = a.shaderLocation; + attributes.add(kj::mv(attr)); + } + auto attrArray = attributes.releaseAsArray(); + bLayout.attributes = attrArray.begin(); + bLayout.attributeCount = attrArray.size(); + parsedDesc.attributeLists.add(kj::mv(attrArray)); + + buffers.add(kj::mv(bLayout)); + } + parsedDesc.buffers = buffers.releaseAsArray(); + parsedDesc.desc.vertex.buffers = parsedDesc.buffers.begin(); + parsedDesc.desc.vertex.bufferCount = parsedDesc.buffers.size(); + } KJ_SWITCH_ONEOF(descriptor.layout) { KJ_CASE_ONEOF(autoLayoutMode, jsg::NonCoercible) { @@ -388,20 +427,56 @@ parseRenderPipelineDescriptor(GPURenderPipelineDescriptor& descriptor) { fragmentState->module = *fragment.module; fragmentState->entryPoint = fragment.entryPoint.cStr(); - kj::Vector constants; KJ_IF_SOME(cDict, fragment.constants) { + kj::Vector constants; + for (auto& f : cDict.fields) { wgpu::ConstantEntry e; e.key = f.name.cStr(); e.value = f.value; constants.add(kj::mv(e)); } + auto constantsArray = constants.releaseAsArray(); + fragmentState->constants = constantsArray.begin(); + fragmentState->constantCount = constantsArray.size(); + parsedDesc.constantLists.add(kj::mv(constantsArray)); } - fragmentState->constants = constants.begin(); - fragmentState->constantCount = constants.size(); + kj::Vector targets; + for (auto& t : fragment.targets) { + wgpu::ColorTargetState target; - // TODO(soon): fragment.targets + wgpu::BlendState blend; + KJ_IF_SOME(dstFactor, t.blend.alpha.dstFactor) { + blend.alpha.dstFactor = parseBlendFactor(dstFactor); + } + KJ_IF_SOME(srcFactor, t.blend.alpha.srcFactor) { + blend.alpha.srcFactor = parseBlendFactor(srcFactor); + } + KJ_IF_SOME(operation, t.blend.alpha.operation) { + blend.alpha.operation = parseBlendOperation(operation); + } + KJ_IF_SOME(dstFactor, t.blend.color.dstFactor) { + blend.color.dstFactor = parseBlendFactor(dstFactor); + } + KJ_IF_SOME(srcFactor, t.blend.color.srcFactor) { + blend.color.srcFactor = parseBlendFactor(srcFactor); + } + KJ_IF_SOME(operation, t.blend.color.operation) { + blend.color.operation = parseBlendOperation(operation); + } + parsedDesc.blends.add(kj::mv(blend)); + target.blend = &parsedDesc.blends.back(); + + target.format = parseTextureFormat(t.format); + KJ_IF_SOME(mask, t.writeMask) { + target.writeMask = static_cast(mask); + } + } + auto targetsArray = targets.releaseAsArray(); + fragmentState->targets = targetsArray.begin(); + fragmentState->targetCount = targetsArray.size(); + parsedDesc.targets = kj::mv(targetsArray); parsedDesc.fragment = kj::mv(fragmentState); parsedDesc.desc.fragment = parsedDesc.fragment; @@ -453,6 +528,10 @@ GPUDevice::createCommandEncoder(jsg::Optional descr return jsg::alloc(kj::mv(encoder), kj::mv(label)); } +// TODO(soon): checks the allocations that are done during this method for dangling refs. +// Will problably need to implement some allocator that will keep track of what needs +// to be deallocated as it's being done in parseRenderPipelineDescriptor(). The constants +// vector jumps to mind since we're just returning a pointer to a local variable. wgpu::ComputePipelineDescriptor parseComputePipelineDescriptor(GPUComputePipelineDescriptor& descriptor) { wgpu::ComputePipelineDescriptor desc{}; diff --git a/src/workerd/api/gpu/gpu-utils.c++ b/src/workerd/api/gpu/gpu-utils.c++ index 5c2d001378a..654b330ffed 100644 --- a/src/workerd/api/gpu/gpu-utils.c++ +++ b/src/workerd/api/gpu/gpu-utils.c++ @@ -7,6 +7,8 @@ namespace workerd::api::gpu { +// TODO(soon): use a static std::map for most of these functions, as seen +// in kj::StringPtr CryptoImpl::getAsymmetricKeyType(). wgpu::FeatureName parseFeatureName(GPUFeatureName& str) { if (str == "depth-clip-control") { return wgpu::FeatureName::DepthClipControl; @@ -929,4 +931,188 @@ wgpu::StencilOperation parseStencilOperation(kj::StringPtr operation) { JSG_FAIL_REQUIRE(TypeError, "unknown stencil operation: ", operation); } +wgpu::VertexStepMode parseVertexStepMode(kj::StringPtr stepMode) { + if (stepMode == "vertex") { + return wgpu::VertexStepMode::Vertex; + } + + if (stepMode == "instance") { + return wgpu::VertexStepMode::Instance; + } + + JSG_FAIL_REQUIRE(TypeError, "unknown vertex step mode: ", stepMode); +} + +wgpu::VertexFormat parseVertexFormat(kj::StringPtr format) { + if (format == "uint8x2") { + return wgpu::VertexFormat::Uint8x2; + } + if (format == "uint8x4") { + return wgpu::VertexFormat::Uint8x4; + } + if (format == "sint8x2") { + return wgpu::VertexFormat::Sint8x2; + } + if (format == "sint8x4") { + return wgpu::VertexFormat::Sint8x2; + } + if (format == "unorm8x2") { + return wgpu::VertexFormat::Unorm8x2; + } + if (format == "unorm8x4") { + return wgpu::VertexFormat::Unorm8x4; + } + if (format == "snorm8x2") { + return wgpu::VertexFormat::Snorm8x2; + } + if (format == "snorm8x4") { + return wgpu::VertexFormat::Snorm8x4; + } + if (format == "uint16x2") { + return wgpu::VertexFormat::Uint16x2; + } + if (format == "uint16x4") { + return wgpu::VertexFormat::Uint16x4; + } + if (format == "sint16x2") { + return wgpu::VertexFormat::Sint16x2; + } + if (format == "sint16x4") { + return wgpu::VertexFormat::Sint16x4; + } + if (format == "unorm16x2") { + return wgpu::VertexFormat::Unorm16x2; + } + if (format == "unorm16x4") { + return wgpu::VertexFormat::Unorm16x4; + } + if (format == "snorm16x2") { + return wgpu::VertexFormat::Snorm16x2; + } + if (format == "snorm16x4") { + return wgpu::VertexFormat::Snorm16x4; + } + if (format == "float16x2") { + return wgpu::VertexFormat::Float16x2; + } + if (format == "float16x4") { + return wgpu::VertexFormat::Float16x4; + } + if (format == "float32") { + return wgpu::VertexFormat::Float32; + } + if (format == "float32x2") { + return wgpu::VertexFormat::Float32x2; + } + if (format == "float32x3") { + return wgpu::VertexFormat::Float32x3; + } + if (format == "float32x4") { + return wgpu::VertexFormat::Float32x4; + } + if (format == "uint32") { + return wgpu::VertexFormat::Uint32; + } + if (format == "uint32x2") { + return wgpu::VertexFormat::Uint32x2; + } + if (format == "uint32x3") { + return wgpu::VertexFormat::Uint32x3; + } + if (format == "uint32x4") { + return wgpu::VertexFormat::Uint32x4; + } + if (format == "sint32") { + return wgpu::VertexFormat::Sint32; + } + if (format == "sint32x2") { + return wgpu::VertexFormat::Sint32x2; + } + if (format == "sint32x3") { + return wgpu::VertexFormat::Sint32x3; + } + if (format == "sint32x4") { + return wgpu::VertexFormat::Sint32x4; + } + + JSG_FAIL_REQUIRE(TypeError, "unknown vertex format: ", format); +} + +wgpu::BlendFactor parseBlendFactor(kj::StringPtr factor) { + + if (factor == "zero") { + return wgpu::BlendFactor::Zero; + } + + if (factor == "one") { + return wgpu::BlendFactor::One; + } + + if (factor == "src") { + return wgpu::BlendFactor::Src; + } + + if (factor == "one-minus-src") { + return wgpu::BlendFactor::OneMinusSrc; + } + + if (factor == "src-alpha") { + return wgpu::BlendFactor::SrcAlpha; + } + + if (factor == "one-minus-src-alpha") { + return wgpu::BlendFactor::OneMinusSrcAlpha; + } + + if (factor == "dst") { + return wgpu::BlendFactor::Dst; + } + + if (factor == "one-minus-dst") { + return wgpu::BlendFactor::OneMinusDst; + } + + if (factor == "dst-alpha") { + return wgpu::BlendFactor::DstAlpha; + } + + if (factor == "one-minus-dst-alpha") { + return wgpu::BlendFactor::OneMinusDstAlpha; + } + + if (factor == "src-alpha-saturated") { + return wgpu::BlendFactor::SrcAlphaSaturated; + } + + if (factor == "constant") { + return wgpu::BlendFactor::Constant; + } + + if (factor == "one-minus-constant") { + return wgpu::BlendFactor::OneMinusConstant; + } + + JSG_FAIL_REQUIRE(TypeError, "unknown blend factor: ", factor); +} + +wgpu::BlendOperation parseBlendOperation(kj::StringPtr operation) { + if (operation == "add") { + return wgpu::BlendOperation::Add; + } + if (operation == "subtract") { + return wgpu::BlendOperation::Subtract; + } + if (operation == "reverse-subtract") { + return wgpu::BlendOperation::ReverseSubtract; + } + if (operation == "min") { + return wgpu::BlendOperation::Min; + } + if (operation == "max") { + return wgpu::BlendOperation::Max; + } + + JSG_FAIL_REQUIRE(TypeError, "unknown blend operation: ", operation); +} + } // namespace workerd::api::gpu diff --git a/src/workerd/api/gpu/gpu-utils.h b/src/workerd/api/gpu/gpu-utils.h index 42b1c156edc..69c860902c0 100644 --- a/src/workerd/api/gpu/gpu-utils.h +++ b/src/workerd/api/gpu/gpu-utils.h @@ -146,5 +146,9 @@ wgpu::IndexFormat parseIndexFormat(kj::StringPtr format); wgpu::FrontFace parseFrontFace(kj::StringPtr frontFace); wgpu::CullMode parseCullMode(kj::StringPtr mode); wgpu::StencilOperation parseStencilOperation(kj::StringPtr operation); +wgpu::VertexStepMode parseVertexStepMode(kj::StringPtr stepMode); +wgpu::VertexFormat parseVertexFormat(kj::StringPtr format); +wgpu::BlendFactor parseBlendFactor(kj::StringPtr factor); +wgpu::BlendOperation parseBlendOperation(kj::StringPtr operation); } // namespace workerd::api::gpu diff --git a/src/workerd/api/gpu/webgpu-windowless-test.js b/src/workerd/api/gpu/webgpu-windowless-test.js index 9eb767a1441..bffad4ab557 100644 --- a/src/workerd/api/gpu/webgpu-windowless-test.js +++ b/src/workerd/api/gpu/webgpu-windowless-test.js @@ -106,6 +106,21 @@ export class DurableObjectExample { }); ok(renderPipeline); + const encoder = device.createCommandEncoder(); + + const renderPassDescriptor = { + colorAttachments: [ + { + clearValue: { r: 0.1, g: 0.2, b: 0.3, a: 1.0 }, + loadOp: "clear", + storeOp: "store", + view: textureView, + }, + ], + }; + const renderPass = encoder.beginRenderPass(renderPassDescriptor); + ok(renderPass); + return new Response("OK"); } }