/* * Copyright (c) 2023 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "tvgWgPipelines.h" #include "tvgWgShaderSrc.h" #define ARRAY_ELEMENTS_COUNT(arr) sizeof(arr)/sizeof(arr[0]) //************************************************************************ // graphics pipelines //************************************************************************ void WgPipelineFillShape::initialize(WGPUDevice device) { // vertex attributes settings WGPUVertexAttribute vertexAttributesPos = { WGPUVertexFormat_Float32x2, sizeof(float) * 0, 0 }; WGPUVertexBufferLayout vertexBufferLayouts[] = { makeVertexBufferLayout(&vertexAttributesPos, 1, sizeof(float) * 2) }; // bind groups WGPUBindGroupLayout bindGroupLayouts[] = { WgBindGroupCanvas::getLayout(device), WgBindGroupPaint::getLayout(device) }; // stencil function WGPUCompareFunction stencilFuncion = WGPUCompareFunction_Always; WGPUStencilOperation stencilOperation = WGPUStencilOperation_Invert; // sheder source and labels auto shaderSource = cShaderSource_PipelineFill; auto shaderLabel = "The shader fill"; auto pipelineLabel = "The render pipeline fill shape"; // allocate all pipeline handles allocate(device, vertexBufferLayouts, ARRAY_ELEMENTS_COUNT(vertexBufferLayouts), bindGroupLayouts, ARRAY_ELEMENTS_COUNT(bindGroupLayouts), stencilFuncion, stencilOperation, shaderSource, shaderLabel, pipelineLabel); } void WgPipelineFillStroke::initialize(WGPUDevice device) { // vertex and buffers settings WGPUVertexAttribute vertexAttributesPos = { WGPUVertexFormat_Float32x2, sizeof(float) * 0, 0 }; WGPUVertexBufferLayout vertexBufferLayouts[] = { makeVertexBufferLayout(&vertexAttributesPos, 1, sizeof(float) * 2) }; // bind groups and layouts WGPUBindGroupLayout bindGroupLayouts[] = { WgBindGroupCanvas::getLayout(device), WgBindGroupPaint::getLayout(device) }; // stencil function WGPUCompareFunction stencilFuncion = WGPUCompareFunction_Always; WGPUStencilOperation stencilOperation = WGPUStencilOperation_Replace; // sheder source and labels auto shaderSource = cShaderSource_PipelineFill; auto shaderLabel = "The shader fill"; auto pipelineLabel = "The render pipeline fill stroke"; // allocate all pipeline handles allocate(device, vertexBufferLayouts, ARRAY_ELEMENTS_COUNT(vertexBufferLayouts), bindGroupLayouts, ARRAY_ELEMENTS_COUNT(bindGroupLayouts), stencilFuncion, stencilOperation, shaderSource, shaderLabel, pipelineLabel); } void WgPipelineSolid::initialize(WGPUDevice device) { // vertex and buffers settings WGPUVertexAttribute vertexAttributesPos = { WGPUVertexFormat_Float32x2, sizeof(float) * 0, 0 }; WGPUVertexBufferLayout vertexBufferLayouts[] = { makeVertexBufferLayout(&vertexAttributesPos, 1, sizeof(float) * 2) }; // bind groups and layouts WGPUBindGroupLayout bindGroupLayouts[] = { WgBindGroupCanvas::getLayout(device), WgBindGroupPaint::getLayout(device), WgBindGroupSolidColor::getLayout(device) }; // stencil function WGPUCompareFunction stencilFuncion = WGPUCompareFunction_NotEqual; WGPUStencilOperation stencilOperation = WGPUStencilOperation_Zero; // sheder source and labels auto shaderSource = cShaderSource_PipelineSolid; auto shaderLabel = "The shader solid color"; auto pipelineLabel = "The render pipeline solid color"; // allocate all pipeline handles allocate(device, vertexBufferLayouts, ARRAY_ELEMENTS_COUNT(vertexBufferLayouts), bindGroupLayouts, ARRAY_ELEMENTS_COUNT(bindGroupLayouts), stencilFuncion, stencilOperation, shaderSource, shaderLabel, pipelineLabel); } void WgPipelineLinear::initialize(WGPUDevice device) { // vertex and buffers settings WGPUVertexAttribute vertexAttributesPos = { WGPUVertexFormat_Float32x2, sizeof(float) * 0, 0 }; WGPUVertexBufferLayout vertexBufferLayouts[] = { makeVertexBufferLayout(&vertexAttributesPos, 1, sizeof(float) * 2) }; // bind groups and layouts WGPUBindGroupLayout bindGroupLayouts[] = { WgBindGroupCanvas::getLayout(device), WgBindGroupPaint::getLayout(device), WgBindGroupLinearGradient::getLayout(device) }; // stencil function WGPUCompareFunction stencilFuncion = WGPUCompareFunction_NotEqual; WGPUStencilOperation stencilOperation = WGPUStencilOperation_Zero; // sheder source and labels auto shaderSource = cShaderSource_PipelineLinear; auto shaderLabel = "The shader linear gradient"; auto pipelineLabel = "The render pipeline linear gradient"; // allocate all pipeline handles allocate(device, vertexBufferLayouts, ARRAY_ELEMENTS_COUNT(vertexBufferLayouts), bindGroupLayouts, ARRAY_ELEMENTS_COUNT(bindGroupLayouts), stencilFuncion, stencilOperation, shaderSource, shaderLabel, pipelineLabel); } void WgPipelineRadial::initialize(WGPUDevice device) { // vertex and buffers settings WGPUVertexAttribute vertexAttributesPos = { WGPUVertexFormat_Float32x2, sizeof(float) * 0, 0 }; WGPUVertexBufferLayout vertexBufferLayouts[] = { makeVertexBufferLayout(&vertexAttributesPos, 1, sizeof(float) * 2) }; // bind groups and layouts WGPUBindGroupLayout bindGroupLayouts[] = { WgBindGroupCanvas::getLayout(device), WgBindGroupPaint::getLayout(device), WgBindGroupRadialGradient::getLayout(device) }; // stencil function WGPUCompareFunction stencilFuncion = WGPUCompareFunction_NotEqual; WGPUStencilOperation stencilOperation = WGPUStencilOperation_Zero; // sheder source and labels auto shaderSource = cShaderSource_PipelineRadial; auto shaderLabel = "The shader radial gradient"; auto pipelineLabel = "The render pipeline radial gradient"; // allocate all pipeline handles allocate(device, vertexBufferLayouts, ARRAY_ELEMENTS_COUNT(vertexBufferLayouts), bindGroupLayouts, ARRAY_ELEMENTS_COUNT(bindGroupLayouts), stencilFuncion, stencilOperation, shaderSource, shaderLabel, pipelineLabel); } void WgPipelineImage::initialize(WGPUDevice device) { // vertex and buffers settings WGPUVertexAttribute vertexAttributesPos = { WGPUVertexFormat_Float32x2, sizeof(float) * 0, 0 }; WGPUVertexAttribute vertexAttributesTex = { WGPUVertexFormat_Float32x2, sizeof(float) * 0, 1 }; WGPUVertexBufferLayout vertexBufferLayouts[] = { makeVertexBufferLayout(&vertexAttributesPos, 1, sizeof(float) * 2), makeVertexBufferLayout(&vertexAttributesTex, 1, sizeof(float) * 2) }; // bind groups and layouts WGPUBindGroupLayout bindGroupLayouts[] = { WgBindGroupCanvas::getLayout(device), WgBindGroupPaint::getLayout(device), WgBindGroupPicture::getLayout(device) }; // stencil function WGPUCompareFunction stencilFuncion = WGPUCompareFunction_Always; WGPUStencilOperation stencilOperation = WGPUStencilOperation_Zero; // sheder source and labels auto shaderSource = cShaderSource_PipelineImage; auto shaderLabel = "The shader image"; auto pipelineLabel = "The render pipeline image"; // allocate all pipeline handles allocate(device, vertexBufferLayouts, ARRAY_ELEMENTS_COUNT(vertexBufferLayouts), bindGroupLayouts, ARRAY_ELEMENTS_COUNT(bindGroupLayouts), stencilFuncion, stencilOperation, shaderSource, shaderLabel, pipelineLabel); } //************************************************************************ // compute pipelines //************************************************************************ void WgPipelineClear::initialize(WGPUDevice device) { // bind groups and layouts WGPUBindGroupLayout bindGroupLayouts[] = { WgBindGroupTextureStorage::getLayout(device) }; // sheder source and labels auto shaderSource = cShaderSource_PipelineComputeClear; auto shaderLabel = "The compute shader clear"; auto pipelineLabel = "The compute pipeline clear"; // allocate all pipeline handles allocate(device, bindGroupLayouts, ARRAY_ELEMENTS_COUNT(bindGroupLayouts), shaderSource, shaderLabel, pipelineLabel); } void WgPipelineBlend::initialize(WGPUDevice device) { // bind groups and layouts WGPUBindGroupLayout bindGroupLayouts[] = { WgBindGroupTextureStorage::getLayout(device), WgBindGroupTextureStorage::getLayout(device), WgBindGroupBlendMethod::getLayout(device) }; // sheder source and labels auto shaderSource = cShaderSource_PipelineComputeBlend; auto shaderLabel = "The compute shader blend"; auto pipelineLabel = "The compute pipeline blend"; // allocate all pipeline handles allocate(device, bindGroupLayouts, ARRAY_ELEMENTS_COUNT(bindGroupLayouts), shaderSource, shaderLabel, pipelineLabel); } void WgPipelineCompose::initialize(WGPUDevice device) { // bind groups and layouts WGPUBindGroupLayout bindGroupLayouts[] = { WgBindGroupTextureStorage::getLayout(device), WgBindGroupTextureStorage::getLayout(device), WgBindGroupCompositeMethod::getLayout(device), WgBindGroupOpacity::getLayout(device) }; // sheder source and labels auto shaderSource = cShaderSource_PipelineComputeCompose; auto shaderLabel = "The compute shader compose"; auto pipelineLabel = "The compute pipeline compose"; // allocate all pipeline handles allocate(device, bindGroupLayouts, ARRAY_ELEMENTS_COUNT(bindGroupLayouts), shaderSource, shaderLabel, pipelineLabel); } void WgPipelineAntiAliasing::initialize(WGPUDevice device) { // bind groups and layouts WGPUBindGroupLayout bindGroupLayouts[] = { WgBindGroupTextureStorage::getLayout(device), WgBindGroupTextureStorage::getLayout(device) }; // sheder source and labels auto shaderSource = cShaderSource_PipelineComputeAntiAlias; auto shaderLabel = "The compute shader anti-aliasing"; auto pipelineLabel = "The compute pipeline anti-aliasing"; // allocate all pipeline handles allocate(device, bindGroupLayouts, ARRAY_ELEMENTS_COUNT(bindGroupLayouts), shaderSource, shaderLabel, pipelineLabel); } //************************************************************************ // pipelines //************************************************************************ void WgPipelines::initialize(WgContext& context) { // fill pipelines fillShape.initialize(context.device); fillStroke.initialize(context.device); solid.initialize(context.device); linear.initialize(context.device); radial.initialize(context.device); image.initialize(context.device); // compute pipelines computeClear.initialize(context.device); computeBlend.initialize(context.device); computeCompose.initialize(context.device); computeAntiAliasing.initialize(context.device); // store pipelines to context context.pipelines = this; } void WgPipelines::release() { WgBindGroupTextureSampled::releaseLayout(); WgBindGroupTextureStorage::releaseLayout(); WgBindGroupTexture::releaseLayout(); WgBindGroupOpacity::releaseLayout(); WgBindGroupPicture::releaseLayout(); WgBindGroupRadialGradient::releaseLayout(); WgBindGroupLinearGradient::releaseLayout(); WgBindGroupSolidColor::releaseLayout(); WgBindGroupPaint::releaseLayout(); WgBindGroupCanvas::releaseLayout(); // compute pipelines computeAntiAliasing.release(); computeCompose.release(); computeBlend.release(); computeClear.release(); // fill pipelines image.release(); radial.release(); linear.release(); solid.release(); fillStroke.release(); fillShape.release(); }