/* * Copyright (c) 2023 - 2025 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" #include #include WGPUShaderModule WgPipelines::createShaderModule(WGPUDevice device, const char* label, const char* code) { WGPUShaderModuleWGSLDescriptor shaderModuleWGSLDesc{}; shaderModuleWGSLDesc.chain.sType = WGPUSType_ShaderModuleWGSLDescriptor; shaderModuleWGSLDesc.code = code; const WGPUShaderModuleDescriptor shaderModuleDesc { .nextInChain = &shaderModuleWGSLDesc.chain, .label = label }; return wgpuDeviceCreateShaderModule(device, &shaderModuleDesc); } WGPUPipelineLayout WgPipelines::createPipelineLayout(WGPUDevice device, const WGPUBindGroupLayout* bindGroupLayouts, const uint32_t bindGroupLayoutsCount) { const WGPUPipelineLayoutDescriptor pipelineLayoutDesc { .bindGroupLayoutCount = bindGroupLayoutsCount, .bindGroupLayouts = bindGroupLayouts }; return wgpuDeviceCreatePipelineLayout(device, &pipelineLayoutDesc); } WGPURenderPipeline WgPipelines::createRenderPipeline( WGPUDevice device, const char* pipelineLabel, const WGPUShaderModule shaderModule, const char* vsEntryPoint, const char* fsEntryPoint, const WGPUPipelineLayout pipelineLayout, const WGPUVertexBufferLayout *vertexBufferLayouts, const uint32_t vertexBufferLayoutsCount, const WGPUColorWriteMaskFlags writeMask, const WGPUTextureFormat colorTargetFormat, const WGPUBlendState blendState, const WGPUDepthStencilState depthStencilState, const WGPUMultisampleState multisampleState) { const WGPUColorTargetState colorTargetState { .format = colorTargetFormat, .blend = &blendState, .writeMask = writeMask }; const WGPUColorTargetState colorTargetStates[] { colorTargetState }; const WGPUPrimitiveState primitiveState { .topology = WGPUPrimitiveTopology_TriangleList }; const WGPUVertexState vertexState { .module = shaderModule, .entryPoint = vsEntryPoint, .bufferCount = vertexBufferLayoutsCount, .buffers = vertexBufferLayouts }; const WGPUFragmentState fragmentState { .module = shaderModule, .entryPoint = fsEntryPoint, .targetCount = 1, .targets = colorTargetStates }; const WGPURenderPipelineDescriptor renderPipelineDesc { .label = pipelineLabel, .layout = pipelineLayout, .vertex = vertexState, .primitive = primitiveState, .depthStencil = &depthStencilState, .multisample = multisampleState, .fragment = &fragmentState }; return wgpuDeviceCreateRenderPipeline(device, &renderPipelineDesc); } WGPUComputePipeline WgPipelines::createComputePipeline( WGPUDevice device, const char* pipelineLabel, const WGPUShaderModule shaderModule, const char* entryPoint, const WGPUPipelineLayout pipelineLayout) { const WGPUComputePipelineDescriptor computePipelineDesc{ .label = pipelineLabel, .layout = pipelineLayout, .compute = { .module = shaderModule, .entryPoint = entryPoint } }; return wgpuDeviceCreateComputePipeline(device, &computePipelineDesc); } void WgPipelines::releaseComputePipeline(WGPUComputePipeline& computePipeline) { if (computePipeline) { wgpuComputePipelineRelease(computePipeline); computePipeline = nullptr; } } void WgPipelines::releaseRenderPipeline(WGPURenderPipeline& renderPipeline) { if (renderPipeline) { wgpuRenderPipelineRelease(renderPipeline); renderPipeline = nullptr; } } void WgPipelines::releasePipelineLayout(WGPUPipelineLayout& pipelineLayout) { if (pipelineLayout) { wgpuPipelineLayoutRelease(pipelineLayout); pipelineLayout = nullptr; } } void WgPipelines::releaseShaderModule(WGPUShaderModule& shaderModule) { if (shaderModule) { wgpuShaderModuleRelease(shaderModule); shaderModule = nullptr; } } WGPUDepthStencilState WgPipelines::makeDepthStencilState( const WGPUCompareFunction depthCompare, WGPUBool depthWriteEnabled, const WGPUCompareFunction stencilFunction, const WGPUStencilOperation stencilOperation) { return makeDepthStencilState(depthCompare, depthWriteEnabled, stencilFunction, stencilOperation, stencilFunction, stencilOperation); } WGPUDepthStencilState WgPipelines::makeDepthStencilState( const WGPUCompareFunction depthCompare, WGPUBool depthWriteEnabled, const WGPUCompareFunction stencilFunctionFrnt, const WGPUStencilOperation stencilOperationFrnt, const WGPUCompareFunction stencilFunctionBack, const WGPUStencilOperation stencilOperationBack) { const WGPUDepthStencilState depthStencilState { .format = WGPUTextureFormat_Depth24PlusStencil8, .depthWriteEnabled = depthWriteEnabled, .depthCompare = depthCompare, .stencilFront = { .compare = stencilFunctionFrnt, .failOp = stencilOperationFrnt, .depthFailOp = WGPUStencilOperation_Zero, .passOp = stencilOperationFrnt }, .stencilBack = { .compare = stencilFunctionBack, .failOp = stencilOperationBack, .depthFailOp = WGPUStencilOperation_Zero, .passOp = stencilOperationBack }, .stencilReadMask = 0xFFFFFFFF, .stencilWriteMask = 0xFFFFFFFF }; return depthStencilState; } void WgPipelines::initialize(WgContext& context) { // common pipeline settings const WGPUVertexAttribute vertexAttributePos { .format = WGPUVertexFormat_Float32x2, .offset = 0, .shaderLocation = 0 }; const WGPUVertexAttribute vertexAttributeTex { .format = WGPUVertexFormat_Float32x2, .offset = 0, .shaderLocation = 1 }; const WGPUVertexAttribute vertexAttributesPos[] { vertexAttributePos }; const WGPUVertexAttribute vertexAttributesTex[] { vertexAttributeTex }; const WGPUVertexBufferLayout vertexBufferLayoutPos { .arrayStride = 8, .stepMode = WGPUVertexStepMode_Vertex, .attributeCount = 1, .attributes = vertexAttributesPos }; const WGPUVertexBufferLayout vertexBufferLayoutTex { .arrayStride = 8, .stepMode = WGPUVertexStepMode_Vertex, .attributeCount = 1, .attributes = vertexAttributesTex }; const WGPUVertexBufferLayout vertexBufferLayoutsShape[] { vertexBufferLayoutPos }; const WGPUVertexBufferLayout vertexBufferLayoutsImage[] { vertexBufferLayoutPos, vertexBufferLayoutTex }; const WGPUMultisampleState multisampleState { .count = 4, .mask = 0xFFFFFFFF, .alphaToCoverageEnabled = false }; const WGPUMultisampleState multisampleStateX1 { .count = 1, .mask = 0xFFFFFFFF, .alphaToCoverageEnabled = false }; const WGPUTextureFormat offscreenTargetFormat = WGPUTextureFormat_RGBA8Unorm; // blend states WGPUBlendComponent blendComponentSrc { .operation = WGPUBlendOperation_Add, .srcFactor = WGPUBlendFactor_One, .dstFactor = WGPUBlendFactor_Zero }; WGPUBlendComponent blendComponentNrm { .operation = WGPUBlendOperation_Add, .srcFactor = WGPUBlendFactor_One, .dstFactor = WGPUBlendFactor_OneMinusSrcAlpha }; const WGPUBlendState blendStateSrc { .color = blendComponentSrc, .alpha = blendComponentSrc }; const WGPUBlendState blendStateNrm { .color = blendComponentNrm, .alpha = blendComponentNrm }; const WgBindGroupLayouts& layouts = context.layouts; // bind group layouts helpers const WGPUBindGroupLayout bindGroupLayoutsStencil[] { layouts.layoutBuffer1Un, layouts.layoutBuffer2Un }; const WGPUBindGroupLayout bindGroupLayoutsDepth[] { layouts.layoutBuffer1Un, layouts.layoutBuffer2Un, layouts.layoutBuffer1Un }; // bind group layouts normal blend const WGPUBindGroupLayout bindGroupLayoutsSolid[] { layouts.layoutBuffer1Un, layouts.layoutBuffer2Un, layouts.layoutBuffer1Un }; const WGPUBindGroupLayout bindGroupLayoutsGradient[] { layouts.layoutBuffer1Un, layouts.layoutBuffer2Un, layouts.layoutTexSampledBuff2Un }; const WGPUBindGroupLayout bindGroupLayoutsImage[] { layouts.layoutBuffer1Un, layouts.layoutBuffer2Un, layouts.layoutTexSampled }; const WGPUBindGroupLayout bindGroupLayoutsScene[] { layouts.layoutTexSampled, layouts.layoutBuffer1Un }; // bind group layouts custom blend const WGPUBindGroupLayout bindGroupLayoutsSolidBlend[] { layouts.layoutBuffer1Un, layouts.layoutBuffer2Un, layouts.layoutBuffer1Un, layouts.layoutTexSampled }; const WGPUBindGroupLayout bindGroupLayoutsGradientBlend[] { layouts.layoutBuffer1Un, layouts.layoutBuffer2Un, layouts.layoutTexSampledBuff2Un, layouts.layoutTexSampled }; const WGPUBindGroupLayout bindGroupLayoutsImageBlend[] { layouts.layoutBuffer1Un, layouts.layoutBuffer2Un, layouts.layoutTexSampled, layouts.layoutTexSampled }; const WGPUBindGroupLayout bindGroupLayoutsSceneBlend[] { layouts.layoutTexSampled, layouts.layoutTexSampled, layouts.layoutBuffer1Un }; // bind group layouts scene compose const WGPUBindGroupLayout bindGroupLayoutsSceneCompose[] { layouts.layoutTexSampled, layouts.layoutTexSampled }; // bind group layouts blit const WGPUBindGroupLayout bindGroupLayoutsBlit[] { layouts.layoutTexSampled }; // bind group layouts effects const WGPUBindGroupLayout bindGroupLayoutsGauss[] { layouts.layoutTexStrorage1RO, layouts.layoutTexStrorage1WO, layouts.layoutBuffer1Un, layouts.layoutBuffer1Un }; const WGPUBindGroupLayout bindGroupLayoutsEffects[] { layouts.layoutTexStrorage2RO, layouts.layoutTexStrorage1WO, layouts.layoutBuffer1Un, layouts.layoutBuffer1Un }; // depth stencil state markup const WGPUDepthStencilState depthStencilStateNonZero = makeDepthStencilState(WGPUCompareFunction_Always, false, WGPUCompareFunction_Always, WGPUStencilOperation_IncrementWrap, WGPUCompareFunction_Always, WGPUStencilOperation_DecrementWrap); const WGPUDepthStencilState depthStencilStateEvenOdd = makeDepthStencilState(WGPUCompareFunction_Always, false, WGPUCompareFunction_Always, WGPUStencilOperation_Invert); const WGPUDepthStencilState depthStencilStateDirect = makeDepthStencilState(WGPUCompareFunction_Always, false, WGPUCompareFunction_Always, WGPUStencilOperation_Replace); // depth stencil state clip path const WGPUDepthStencilState depthStencilStateCopyStencilToDepth = makeDepthStencilState(WGPUCompareFunction_Always, true, WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero); const WGPUDepthStencilState depthStencilStateCopyStencilToDepthInt = makeDepthStencilState(WGPUCompareFunction_Greater, true, WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero); const WGPUDepthStencilState depthStencilStateCopyDepthToStencil = makeDepthStencilState(WGPUCompareFunction_Equal, false, WGPUCompareFunction_Always, WGPUStencilOperation_Replace); const WGPUDepthStencilState depthStencilStateMergeDepthStencil = makeDepthStencilState(WGPUCompareFunction_Equal, true, WGPUCompareFunction_Always, WGPUStencilOperation_Keep); const WGPUDepthStencilState depthStencilStateClearDepth = makeDepthStencilState(WGPUCompareFunction_Always, true, WGPUCompareFunction_Always, WGPUStencilOperation_Keep); // depth stencil state blend, compose and blit const WGPUDepthStencilState depthStencilStateShape = makeDepthStencilState(WGPUCompareFunction_Always, false, WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero); const WGPUDepthStencilState depthStencilStateScene = makeDepthStencilState(WGPUCompareFunction_Always, false, WGPUCompareFunction_Always, WGPUStencilOperation_Zero); // shaders char shaderSourceBuff[16384]{}; shader_stencil = createShaderModule(context.device, "The shader stencil", cShaderSrc_Stencil); shader_depth = createShaderModule(context.device, "The shader depth", cShaderSrc_Depth); // shader normal blend shader_solid = createShaderModule(context.device, "The shader solid", cShaderSrc_Solid); shader_radial = createShaderModule(context.device, "The shader radial", cShaderSrc_Radial); shader_linear = createShaderModule(context.device, "The shader linear", cShaderSrc_Linear); shader_image = createShaderModule(context.device, "The shader image", cShaderSrc_Image); shader_scene = createShaderModule(context.device, "The shader scene", cShaderSrc_Scene); // shader custom blend shader_solid_blend = createShaderModule(context.device, "The shader blend solid", strcat(strcpy(shaderSourceBuff, cShaderSrc_Solid_Blend), cShaderSrc_BlendFuncs)); shader_linear_blend = createShaderModule(context.device, "The shader blend linear", strcat(strcpy(shaderSourceBuff, cShaderSrc_Linear_Blend), cShaderSrc_BlendFuncs)); shader_radial_blend = createShaderModule(context.device, "The shader blend radial", strcat(strcpy(shaderSourceBuff, cShaderSrc_Radial_Blend), cShaderSrc_BlendFuncs)); shader_image_blend = createShaderModule(context.device, "The shader blend image", strcat(strcpy(shaderSourceBuff, cShaderSrc_Image_Blend), cShaderSrc_BlendFuncs)); shader_scene_blend = createShaderModule(context.device, "The shader blend scene", strcat(strcpy(shaderSourceBuff, cShaderSrc_Scene_Blend), cShaderSrc_BlendFuncs)); // shader compose shader_scene_compose = createShaderModule(context.device, "The shader scene composition", cShaderSrc_Scene_Compose); // shader blit shader_blit = createShaderModule(context.device, "The shader blit", cShaderSrc_Blit); // shader effects shader_gauss = createShaderModule(context.device, "The shader effects", cShaderSrc_GaussianBlur); shader_effects = createShaderModule(context.device, "The shader effects", cShaderSrc_Effects); // layouts layout_stencil = createPipelineLayout(context.device, bindGroupLayoutsStencil, 2); layout_depth = createPipelineLayout(context.device, bindGroupLayoutsDepth, 3); // layouts normal blend layout_solid = createPipelineLayout(context.device, bindGroupLayoutsSolid, 3); layout_gradient = createPipelineLayout(context.device, bindGroupLayoutsGradient, 3); layout_image = createPipelineLayout(context.device, bindGroupLayoutsImage, 3); layout_scene = createPipelineLayout(context.device, bindGroupLayoutsScene, 2); // layouts custom blend layout_solid_blend = createPipelineLayout(context.device, bindGroupLayoutsSolidBlend, 4); layout_gradient_blend = createPipelineLayout(context.device, bindGroupLayoutsGradientBlend, 4); layout_image_blend = createPipelineLayout(context.device, bindGroupLayoutsImageBlend, 4); layout_scene_blend = createPipelineLayout(context.device, bindGroupLayoutsSceneBlend, 3); // layout compose layout_scene_compose = createPipelineLayout(context.device, bindGroupLayoutsSceneCompose, 2); // layout blit layout_blit = createPipelineLayout(context.device, bindGroupLayoutsBlit, 1); // layout effects layout_gauss = createPipelineLayout(context.device, bindGroupLayoutsGauss, 4); layout_effects = createPipelineLayout(context.device, bindGroupLayoutsEffects, 4); // render pipeline nonzero nonzero = createRenderPipeline( context.device, "The render pipeline nonzero", shader_stencil, "vs_main", "fs_main", layout_stencil, vertexBufferLayoutsShape, 1, WGPUColorWriteMask_None, offscreenTargetFormat, blendStateSrc, depthStencilStateNonZero, multisampleState); // render pipeline even-odd evenodd = createRenderPipeline( context.device, "The render pipeline even-odd", shader_stencil, "vs_main", "fs_main", layout_stencil, vertexBufferLayoutsShape, 1, WGPUColorWriteMask_None, offscreenTargetFormat, blendStateSrc, depthStencilStateEvenOdd, multisampleState); // render pipeline direct direct = createRenderPipeline( context.device, "The render pipeline direct", shader_stencil, "vs_main", "fs_main", layout_stencil, vertexBufferLayoutsShape, 1, WGPUColorWriteMask_None, offscreenTargetFormat, blendStateSrc, depthStencilStateDirect, multisampleState); // render pipeline copy stencil to depth (front) copy_stencil_to_depth = createRenderPipeline( context.device, "The render pipeline copy stencil to depth front", shader_depth, "vs_main", "fs_main", layout_depth, vertexBufferLayoutsShape, 1, WGPUColorWriteMask_None, offscreenTargetFormat, blendStateSrc, depthStencilStateCopyStencilToDepth , multisampleState); // render pipeline copy stencil to depth (intermidiate) copy_stencil_to_depth_interm = createRenderPipeline( context.device, "The render pipeline copy stencil to depth intermidiate", shader_depth, "vs_main", "fs_main", layout_depth, vertexBufferLayoutsShape, 1, WGPUColorWriteMask_None, offscreenTargetFormat, blendStateSrc, depthStencilStateCopyStencilToDepthInt, multisampleState); // render pipeline depth to stencil copy_depth_to_stencil = createRenderPipeline( context.device, "The render pipeline depth to stencil", shader_depth, "vs_main", "fs_main", layout_depth, vertexBufferLayoutsShape, 1, WGPUColorWriteMask_None, offscreenTargetFormat, blendStateSrc, depthStencilStateCopyDepthToStencil, multisampleState); // render pipeline merge depth with stencil merge_depth_stencil = createRenderPipeline( context.device, "The render pipeline merge depth with stencil", shader_depth, "vs_main", "fs_main", layout_depth, vertexBufferLayoutsShape, 1, WGPUColorWriteMask_None, offscreenTargetFormat, blendStateSrc, depthStencilStateMergeDepthStencil, multisampleState); // render pipeline clear depth clear_depth = createRenderPipeline( context.device, "The render pipeline clear depth", shader_depth, "vs_main", "fs_main", layout_depth, vertexBufferLayoutsShape, 1, WGPUColorWriteMask_None, offscreenTargetFormat, blendStateSrc, depthStencilStateClearDepth, multisampleState); // render pipeline solid solid = createRenderPipeline( context.device, "The render pipeline solid", shader_solid, "vs_main", "fs_main", layout_solid, vertexBufferLayoutsShape, 1, WGPUColorWriteMask_All, offscreenTargetFormat, blendStateNrm, depthStencilStateShape, multisampleState); // render pipeline radial radial = createRenderPipeline( context.device, "The render pipeline radial", shader_radial, "vs_main", "fs_main", layout_gradient, vertexBufferLayoutsShape, 1, WGPUColorWriteMask_All, offscreenTargetFormat, blendStateNrm, depthStencilStateShape, multisampleState); // render pipeline linear linear = createRenderPipeline( context.device, "The render pipeline linear", shader_linear, "vs_main", "fs_main", layout_gradient, vertexBufferLayoutsShape, 1, WGPUColorWriteMask_All, offscreenTargetFormat, blendStateNrm, depthStencilStateShape, multisampleState); // render pipeline image image = createRenderPipeline( context.device, "The render pipeline image", shader_image, "vs_main", "fs_main", layout_image, vertexBufferLayoutsImage, 2, WGPUColorWriteMask_All, offscreenTargetFormat, blendStateNrm, depthStencilStateShape, multisampleState); // render pipeline scene scene = createRenderPipeline( context.device, "The render pipeline scene", shader_scene, "vs_main", "fs_main", layout_scene, vertexBufferLayoutsImage, 2, WGPUColorWriteMask_All, offscreenTargetFormat, blendStateNrm, depthStencilStateScene, multisampleState); // blend shader names const char* shaderBlendNames[] { "fs_main_Normal", "fs_main_Multiply", "fs_main_Screen", "fs_main_Overlay", "fs_main_Darken", "fs_main_Lighten", "fs_main_ColorDodge", "fs_main_ColorBurn", "fs_main_HardLight", "fs_main_SoftLight", "fs_main_Difference", "fs_main_Exclusion", "fs_main_Normal", //TODO: a padding for reserved Hue. "fs_main_Normal", //TODO: a padding for reserved Saturation. "fs_main_Normal", //TODO: a padding for reserved Color. "fs_main_Normal", //TODO: a padding for reserved Luminosity. "fs_main_Add", "fs_main_Normal" //TODO: a padding for reserved Hardmix. }; // render pipeline shape blend for (uint32_t i = 0; i < 18; i++) { // blend solid solid_blend[i] = createRenderPipeline( context.device, "The render pipeline solid blend", shader_solid_blend, "vs_main", shaderBlendNames[i], layout_solid_blend, vertexBufferLayoutsShape, 1, WGPUColorWriteMask_All, offscreenTargetFormat, blendStateSrc, depthStencilStateShape, multisampleState); // blend radial radial_blend[i] = createRenderPipeline( context.device, "The render pipeline radial blend", shader_radial_blend, "vs_main", shaderBlendNames[i], layout_gradient_blend, vertexBufferLayoutsShape, 1, WGPUColorWriteMask_All, offscreenTargetFormat, blendStateSrc, depthStencilStateShape, multisampleState); // blend linear linear_blend[i] = createRenderPipeline( context.device, "The render pipeline linear blend", shader_linear_blend, "vs_main", shaderBlendNames[i], layout_gradient_blend, vertexBufferLayoutsShape, 1, WGPUColorWriteMask_All, offscreenTargetFormat, blendStateSrc, depthStencilStateShape, multisampleState); // blend image image_blend[i] = createRenderPipeline( context.device, "The render pipeline image blend", shader_image_blend, "vs_main", shaderBlendNames[i], layout_image_blend, vertexBufferLayoutsImage, 2, WGPUColorWriteMask_All, offscreenTargetFormat, blendStateSrc, depthStencilStateShape, multisampleState); // blend scene scene_blend[i] = createRenderPipeline( context.device, "The render pipeline scene blend", shader_scene_blend, "vs_main", shaderBlendNames[i], layout_scene_blend, vertexBufferLayoutsImage, 2, WGPUColorWriteMask_All, offscreenTargetFormat, blendStateSrc, depthStencilStateScene, multisampleState); } // compose shader names const char* shaderComposeNames[] { "fs_main_None", "fs_main_AlphaMask", "fs_main_InvAlphaMask", "fs_main_LumaMask", "fs_main_InvLumaMask", "fs_main_AddMask", "fs_main_SubtractMask", "fs_main_IntersectMask", "fs_main_DifferenceMask", "fs_main_LightenMask", "fs_main_DarkenMask" }; // compose shader blend states const WGPUBlendState composeBlends[] { blendStateNrm, // None blendStateNrm, // AlphaMask blendStateNrm, // InvAlphaMask blendStateNrm, // LumaMask blendStateNrm, // InvLumaMask blendStateSrc, // AddMask blendStateSrc, // SubtractMask blendStateSrc, // IntersectMask blendStateSrc, // DifferenceMask blendStateSrc, // LightenMask blendStateSrc // DarkenMask }; // render pipeline scene composition for (uint32_t i = 0; i < 11; i++) { scene_compose[i] = createRenderPipeline( context.device, "The render pipeline scene composition", shader_scene_compose, "vs_main", shaderComposeNames[i], layout_scene_compose, vertexBufferLayoutsImage, 2, WGPUColorWriteMask_All, offscreenTargetFormat, composeBlends[i], depthStencilStateScene, multisampleState); } // render pipeline blit blit = createRenderPipeline( context.device, "The render pipeline blit", shader_blit, "vs_main", "fs_main", layout_blit, vertexBufferLayoutsImage, 2, WGPUColorWriteMask_All, context.preferredFormat, blendStateSrc, // must be preferred screen pixel format depthStencilStateScene, multisampleStateX1); // compute pipeline gaussian blur gaussian_horz = createComputePipeline(context.device, "The compute pipeline gaussian blur horizontal", shader_gauss, "cs_main_horz", layout_gauss); gaussian_vert = createComputePipeline(context.device, "The compute pipeline gaussian blur vertical", shader_gauss, "cs_main_vert", layout_gauss); dropshadow = createComputePipeline(context.device, "The compute pipeline drop shadow blend", shader_effects, "cs_main_drop_shadow", layout_effects); fill_effect = createComputePipeline(context.device, "The compute pipeline fill effect", shader_effects, "cs_main_fill", layout_effects); tint_effect = createComputePipeline(context.device, "The compute pipeline tint effect", shader_effects, "cs_main_tint", layout_effects); tritone_effect= createComputePipeline(context.device, "The compute pipeline tritone effect", shader_effects, "cs_main_tritone", layout_effects); } void WgPipelines::releaseGraphicHandles(WgContext& context) { // pipeline effects releaseComputePipeline(tritone_effect); releaseComputePipeline(tint_effect); releaseComputePipeline(fill_effect); releaseComputePipeline(dropshadow); releaseComputePipeline(gaussian_vert); releaseComputePipeline(gaussian_horz); // pipeline blit releaseRenderPipeline(blit); // pipelines compose for (uint32_t i = 0; i < 11; i++) releaseRenderPipeline(scene_compose[i]); // pipelines custom blend for (uint32_t i = 0; i < 18; i++) { releaseRenderPipeline(scene_blend[i]); releaseRenderPipeline(image_blend[i]); releaseRenderPipeline(linear_blend[i]); releaseRenderPipeline(radial_blend[i]); releaseRenderPipeline(solid_blend[i]); } // pipelines normal blend releaseRenderPipeline(scene); releaseRenderPipeline(image); releaseRenderPipeline(linear); releaseRenderPipeline(radial); releaseRenderPipeline(solid); // pipelines clip path markup releaseRenderPipeline(clear_depth); releaseRenderPipeline(merge_depth_stencil); releaseRenderPipeline(copy_depth_to_stencil); releaseRenderPipeline(copy_stencil_to_depth_interm); releaseRenderPipeline(copy_stencil_to_depth); // pipelines stencil markup releaseRenderPipeline(direct); releaseRenderPipeline(evenodd); releaseRenderPipeline(nonzero); // layouts releasePipelineLayout(layout_effects); releasePipelineLayout(layout_gauss); releasePipelineLayout(layout_blit); releasePipelineLayout(layout_scene_compose); releasePipelineLayout(layout_scene_blend); releasePipelineLayout(layout_image_blend); releasePipelineLayout(layout_gradient_blend); releasePipelineLayout(layout_solid_blend); releasePipelineLayout(layout_scene); releasePipelineLayout(layout_image); releasePipelineLayout(layout_gradient); releasePipelineLayout(layout_solid); releasePipelineLayout(layout_depth); releasePipelineLayout(layout_stencil); // shaders releaseShaderModule(shader_effects); releaseShaderModule(shader_gauss); releaseShaderModule(shader_blit); releaseShaderModule(shader_scene_compose); releaseShaderModule(shader_scene_blend); releaseShaderModule(shader_image_blend); releaseShaderModule(shader_linear_blend); releaseShaderModule(shader_radial_blend); releaseShaderModule(shader_solid_blend); releaseShaderModule(shader_scene); releaseShaderModule(shader_image); releaseShaderModule(shader_linear); releaseShaderModule(shader_radial); releaseShaderModule(shader_solid); releaseShaderModule(shader_depth); releaseShaderModule(shader_stencil); } void WgPipelines::release(WgContext& context) { releaseGraphicHandles(context); }