mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 13:43:43 +00:00
wg_engine: Added ability to draw multiple linear gradient filled shapes
[issues 1479: LinearGradient](thorvg#1479) In order to build you need third party libraries. Before you start please read this: [LearnWebGPU](https://eliemichel.github.io/LearnWebGPU/getting-started/hello-webgpu.html) Usage example: // init glfw glfwInit(); // create a windowed mode window and its opengl context glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); GLFWwindow* window = glfwCreateWindow(800, 800, "WebGPU base app", nullptr, nullptr); // get window size int width{}, height{}; glfwGetWindowSize(window, &width, &height); // init engine webgpu tvg::Initializer::init(tvg::CanvasEngine::Wg, 0); // create wg canvas auto canvasWg = tvg::WgCanvas::gen(); canvas_wg->target(glfwGetWin32Window(window), width, height); // gradient color stops tvg::Fill::ColorStop colorStops[2]; colorStops[0] = {0, 0, 0, 0, 255}; colorStops[1] = {1, 255, 255, 255, 255}; // linear gradient auto fill = tvg::LinearGradient::gen(); fill->linear(0, 0, 400, 400); fill->colorStops(colorStops, 2); // prepare rectangle auto shape1 = tvg::Shape::gen(); shape1->appendRect(0, 0, 400, 400); //x, y, w, h shape1->fill(std::move(fill)); canvas_wg->push(std::move(shape1)); // gradient color stops tvg::Fill::ColorStop colorStops2[3]; colorStops2[0] = { 0, 255, 0, 0, 255 }; colorStops2[1] = { 0.5, 255, 255, 0, 255 }; colorStops2[2] = { 1, 255, 255, 255, 255 }; // linear gradient auto fill2 = tvg::LinearGradient::gen(); fill2->linear(400, 200, 400, 600); fill2->colorStops(colorStops2, 3); // prepare circle auto shape2 = tvg::Shape::gen(); shape2->appendCircle(400, 400, 200, 200); //cx, cy, radiusW, radiusH shape2->fill(std::move(fill2)); canvas_wg->push(std::move(shape2)); // gradient color stops tvg::Fill::ColorStop colorStops3[4]; colorStops3[0] = { 0, 0, 127, 0, 127 }; colorStops3[1] = { 0.25, 0, 170, 170, 170 }; colorStops3[2] = { 0.5, 200, 0, 200, 200 }; colorStops3[3] = { 1, 255, 255, 255, 255 }; // linear gradient auto fill3 = tvg::LinearGradient::gen(); fill3->linear(450, 600, 750, 600); fill3->colorStops(colorStops3, 4); // prepare ellipse auto shape3 = tvg::Shape::gen(); shape3->appendCircle(600, 600, 150, 100); //cx, cy, radiusW, radiusH shape3->fill(std::move(fill3)); canvas_wg->push(std::move(shape3)); while (!glfwWindowShouldClose(window)) { // webgpu canvas_wg->draw(); canvas_wg->sync(); // pull events glfwPollEvents(); } // terminate engine and window tvg::Initializer::term(tvg::CanvasEngine::Wg); glfwDestroyWindow(window); glfwTerminate();
This commit is contained in:
parent
891c7d1139
commit
94eabc609c
8 changed files with 474 additions and 2 deletions
|
@ -1,6 +1,7 @@
|
||||||
source_file = [
|
source_file = [
|
||||||
'tvgWgPipelineBase.cpp',
|
'tvgWgPipelineBase.cpp',
|
||||||
'tvgWgPipelineEmpty.cpp',
|
'tvgWgPipelineEmpty.cpp',
|
||||||
|
'tvgWgPipelineLinear.cpp',
|
||||||
'tvgWgPipelineSolid.cpp',
|
'tvgWgPipelineSolid.cpp',
|
||||||
'tvgWgRenderData.cpp',
|
'tvgWgRenderData.cpp',
|
||||||
'tvgWgRenderer.cpp',
|
'tvgWgRenderer.cpp',
|
||||||
|
|
305
src/renderer/wg_engine/tvgWgPipelineLinear.cpp
Normal file
305
src/renderer/wg_engine/tvgWgPipelineLinear.cpp
Normal file
|
@ -0,0 +1,305 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 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 "tvgWgPipelineLinear.h"
|
||||||
|
#include "tvgWgShaderSrc.h"
|
||||||
|
|
||||||
|
//************************************************************************
|
||||||
|
// WgPipelineBindGroupLinear
|
||||||
|
//************************************************************************
|
||||||
|
|
||||||
|
void WgPipelineDataLinear::updateGradient(LinearGradient* linearGradient) {
|
||||||
|
|
||||||
|
const Fill::ColorStop* stops = nullptr;
|
||||||
|
auto stopCnt = linearGradient->colorStops(&stops);
|
||||||
|
|
||||||
|
uGradientInfo.nStops[0] = stopCnt;
|
||||||
|
uGradientInfo.nStops[1] = 0.5f;
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < stopCnt; ++i) {
|
||||||
|
uGradientInfo.stopPoints[i] = stops[i].offset;
|
||||||
|
uGradientInfo.stopColors[i * 4 + 0] = stops[i].r / 255.f;
|
||||||
|
uGradientInfo.stopColors[i * 4 + 1] = stops[i].g / 255.f;
|
||||||
|
uGradientInfo.stopColors[i * 4 + 2] = stops[i].b / 255.f;
|
||||||
|
uGradientInfo.stopColors[i * 4 + 3] = stops[i].a / 255.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
linearGradient->linear(
|
||||||
|
&uGradientInfo.startPos[0],
|
||||||
|
&uGradientInfo.startPos[1],
|
||||||
|
&uGradientInfo.endPos[0],
|
||||||
|
&uGradientInfo.endPos[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
//************************************************************************
|
||||||
|
// WgPipelineBindGroupLinear
|
||||||
|
//************************************************************************
|
||||||
|
|
||||||
|
void WgPipelineBindGroupLinear::initialize(WGPUDevice device, WgPipelineLinear& pipelinePipelineLinear) {
|
||||||
|
// buffer uniform uMatrix
|
||||||
|
WGPUBufferDescriptor bufferUniformDesc_uMatrix{};
|
||||||
|
bufferUniformDesc_uMatrix.nextInChain = nullptr;
|
||||||
|
bufferUniformDesc_uMatrix.label = "Buffer uniform pipeline linear uMatrix";
|
||||||
|
bufferUniformDesc_uMatrix.usage = WGPUBufferUsage_CopyDst | WGPUBufferUsage_Uniform;
|
||||||
|
bufferUniformDesc_uMatrix.size = sizeof(WgPipelineMatrix);
|
||||||
|
bufferUniformDesc_uMatrix.mappedAtCreation = false;
|
||||||
|
uBufferMatrix = wgpuDeviceCreateBuffer(device, &bufferUniformDesc_uMatrix);
|
||||||
|
assert(uBufferMatrix);
|
||||||
|
// buffer uniform uColorInfo
|
||||||
|
WGPUBufferDescriptor bufferUniformDesc_uGradientInfo{};
|
||||||
|
bufferUniformDesc_uGradientInfo.nextInChain = nullptr;
|
||||||
|
bufferUniformDesc_uGradientInfo.label = "Buffer uniform pipeline linear uGradientInfo";
|
||||||
|
bufferUniformDesc_uGradientInfo.usage = WGPUBufferUsage_CopyDst | WGPUBufferUsage_Uniform;
|
||||||
|
bufferUniformDesc_uGradientInfo.size = sizeof(WgPipelineLinearGradientInfo);
|
||||||
|
bufferUniformDesc_uGradientInfo.mappedAtCreation = false;
|
||||||
|
uBufferGradientInfo = wgpuDeviceCreateBuffer(device, &bufferUniformDesc_uGradientInfo);
|
||||||
|
assert(uBufferGradientInfo);
|
||||||
|
|
||||||
|
// bind group entry @binding(0) uMatrix
|
||||||
|
WGPUBindGroupEntry bindGroupEntry_uMatrix{};
|
||||||
|
bindGroupEntry_uMatrix.nextInChain = nullptr;
|
||||||
|
bindGroupEntry_uMatrix.binding = 0;
|
||||||
|
bindGroupEntry_uMatrix.buffer = uBufferMatrix;
|
||||||
|
bindGroupEntry_uMatrix.offset = 0;
|
||||||
|
bindGroupEntry_uMatrix.size = sizeof(WgPipelineMatrix);
|
||||||
|
bindGroupEntry_uMatrix.sampler = nullptr;
|
||||||
|
bindGroupEntry_uMatrix.textureView = nullptr;
|
||||||
|
// bind group entry @binding(1) uGradientInfo
|
||||||
|
WGPUBindGroupEntry bindGroupEntry_uGradientInfo{};
|
||||||
|
bindGroupEntry_uGradientInfo.nextInChain = nullptr;
|
||||||
|
bindGroupEntry_uGradientInfo.binding = 1;
|
||||||
|
bindGroupEntry_uGradientInfo.buffer = uBufferGradientInfo;
|
||||||
|
bindGroupEntry_uGradientInfo.offset = 0;
|
||||||
|
bindGroupEntry_uGradientInfo.size = sizeof(WgPipelineLinearGradientInfo);
|
||||||
|
bindGroupEntry_uGradientInfo.sampler = nullptr;
|
||||||
|
bindGroupEntry_uGradientInfo.textureView = nullptr;
|
||||||
|
// bind group entries
|
||||||
|
WGPUBindGroupEntry bindGroupEntries[] {
|
||||||
|
bindGroupEntry_uMatrix, // @binding(0) uMatrix
|
||||||
|
bindGroupEntry_uGradientInfo // @binding(1) uGradientInfo
|
||||||
|
};
|
||||||
|
// bind group descriptor
|
||||||
|
WGPUBindGroupDescriptor bindGroupDescPipeline{};
|
||||||
|
bindGroupDescPipeline.nextInChain = nullptr;
|
||||||
|
bindGroupDescPipeline.label = "The binding group pipeline linear";
|
||||||
|
bindGroupDescPipeline.layout = pipelinePipelineLinear.mBindGroupLayout;
|
||||||
|
bindGroupDescPipeline.entryCount = 2;
|
||||||
|
bindGroupDescPipeline.entries = bindGroupEntries;
|
||||||
|
mBindGroup = wgpuDeviceCreateBindGroup(device, &bindGroupDescPipeline);
|
||||||
|
assert(mBindGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WgPipelineBindGroupLinear::release() {
|
||||||
|
if (uBufferGradientInfo) {
|
||||||
|
wgpuBufferDestroy(uBufferGradientInfo);
|
||||||
|
wgpuBufferRelease(uBufferGradientInfo);
|
||||||
|
uBufferGradientInfo = nullptr;
|
||||||
|
}
|
||||||
|
if (uBufferMatrix) {
|
||||||
|
wgpuBufferDestroy(uBufferMatrix);
|
||||||
|
wgpuBufferRelease(uBufferMatrix);
|
||||||
|
uBufferMatrix = nullptr;
|
||||||
|
}
|
||||||
|
if (mBindGroup) {
|
||||||
|
wgpuBindGroupRelease(mBindGroup);
|
||||||
|
mBindGroup = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WgPipelineBindGroupLinear::update(WGPUQueue queue, WgPipelineDataLinear& pipelineDataLinear) {
|
||||||
|
wgpuQueueWriteBuffer(queue, uBufferMatrix, 0, &pipelineDataLinear.uMatrix, sizeof(pipelineDataLinear.uMatrix));
|
||||||
|
wgpuQueueWriteBuffer(queue, uBufferGradientInfo, 0, &pipelineDataLinear.uGradientInfo, sizeof(pipelineDataLinear.uGradientInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
//************************************************************************
|
||||||
|
// WgPipelineLinear
|
||||||
|
//************************************************************************
|
||||||
|
|
||||||
|
void WgPipelineLinear::initialize(WGPUDevice device) {
|
||||||
|
// bind group layout group 0
|
||||||
|
// bind group layout descriptor @group(0) @binding(0) uMatrix
|
||||||
|
WGPUBindGroupLayoutEntry bindGroupLayoutEntry_uMatrix{};
|
||||||
|
bindGroupLayoutEntry_uMatrix.nextInChain = nullptr;
|
||||||
|
bindGroupLayoutEntry_uMatrix.binding = 0;
|
||||||
|
bindGroupLayoutEntry_uMatrix.visibility = WGPUShaderStage_Vertex | WGPUShaderStage_Fragment;
|
||||||
|
bindGroupLayoutEntry_uMatrix.buffer.nextInChain = nullptr;
|
||||||
|
bindGroupLayoutEntry_uMatrix.buffer.type = WGPUBufferBindingType_Uniform;
|
||||||
|
bindGroupLayoutEntry_uMatrix.buffer.hasDynamicOffset = false;
|
||||||
|
bindGroupLayoutEntry_uMatrix.buffer.minBindingSize = 0;
|
||||||
|
// bind group layout descriptor @group(0) @binding(1) uColorInfo
|
||||||
|
WGPUBindGroupLayoutEntry bindGroupLayoutEntry_uColorInfo{};
|
||||||
|
bindGroupLayoutEntry_uColorInfo.nextInChain = nullptr;
|
||||||
|
bindGroupLayoutEntry_uColorInfo.binding = 1;
|
||||||
|
bindGroupLayoutEntry_uColorInfo.visibility = WGPUShaderStage_Vertex | WGPUShaderStage_Fragment;
|
||||||
|
bindGroupLayoutEntry_uColorInfo.buffer.nextInChain = nullptr;
|
||||||
|
bindGroupLayoutEntry_uColorInfo.buffer.type = WGPUBufferBindingType_Uniform;
|
||||||
|
bindGroupLayoutEntry_uColorInfo.buffer.hasDynamicOffset = false;
|
||||||
|
bindGroupLayoutEntry_uColorInfo.buffer.minBindingSize = 0;
|
||||||
|
// bind group layout entries @group(0)
|
||||||
|
WGPUBindGroupLayoutEntry bindGroupLayoutEntries[] {
|
||||||
|
bindGroupLayoutEntry_uMatrix,
|
||||||
|
bindGroupLayoutEntry_uColorInfo
|
||||||
|
};
|
||||||
|
// bind group layout descriptor scene @group(0)
|
||||||
|
WGPUBindGroupLayoutDescriptor bindGroupLayoutDesc{};
|
||||||
|
bindGroupLayoutDesc.nextInChain = nullptr;
|
||||||
|
bindGroupLayoutDesc.label = "Bind group layout pipeline linear";
|
||||||
|
bindGroupLayoutDesc.entryCount = 2;
|
||||||
|
bindGroupLayoutDesc.entries = bindGroupLayoutEntries; // @binding
|
||||||
|
mBindGroupLayout = wgpuDeviceCreateBindGroupLayout(device, &bindGroupLayoutDesc);
|
||||||
|
assert(mBindGroupLayout);
|
||||||
|
|
||||||
|
// pipeline layout
|
||||||
|
|
||||||
|
// bind group layout descriptors
|
||||||
|
WGPUBindGroupLayout mBindGroupLayouts[] {
|
||||||
|
mBindGroupLayout
|
||||||
|
};
|
||||||
|
// pipeline layout descriptor
|
||||||
|
WGPUPipelineLayoutDescriptor pipelineLayoutDesc{};
|
||||||
|
pipelineLayoutDesc.nextInChain = nullptr;
|
||||||
|
pipelineLayoutDesc.label = "Pipeline pipeline layout linear";
|
||||||
|
pipelineLayoutDesc.bindGroupLayoutCount = 1;
|
||||||
|
pipelineLayoutDesc.bindGroupLayouts = mBindGroupLayouts;
|
||||||
|
mPipelineLayout = wgpuDeviceCreatePipelineLayout(device, &pipelineLayoutDesc);
|
||||||
|
assert(mPipelineLayout);
|
||||||
|
|
||||||
|
// depth stencil state
|
||||||
|
WGPUDepthStencilState depthStencilState{};
|
||||||
|
depthStencilState.nextInChain = nullptr;
|
||||||
|
depthStencilState.format = WGPUTextureFormat_Stencil8;
|
||||||
|
depthStencilState.depthWriteEnabled = false;
|
||||||
|
depthStencilState.depthCompare = WGPUCompareFunction_Always;
|
||||||
|
// depthStencilState.stencilFront
|
||||||
|
depthStencilState.stencilFront.compare = WGPUCompareFunction_NotEqual;
|
||||||
|
depthStencilState.stencilFront.failOp = WGPUStencilOperation_Zero;
|
||||||
|
depthStencilState.stencilFront.depthFailOp = WGPUStencilOperation_Zero;
|
||||||
|
depthStencilState.stencilFront.passOp = WGPUStencilOperation_Zero;
|
||||||
|
// depthStencilState.stencilBack
|
||||||
|
depthStencilState.stencilBack.compare = WGPUCompareFunction_NotEqual;
|
||||||
|
depthStencilState.stencilBack.failOp = WGPUStencilOperation_Zero;
|
||||||
|
depthStencilState.stencilBack.depthFailOp = WGPUStencilOperation_Zero;
|
||||||
|
depthStencilState.stencilBack.passOp = WGPUStencilOperation_Zero;
|
||||||
|
// stencil mask
|
||||||
|
depthStencilState.stencilReadMask = 0xFFFFFFFF;
|
||||||
|
depthStencilState.stencilWriteMask = 0xFFFFFFFF;
|
||||||
|
// depth bias
|
||||||
|
depthStencilState.depthBias = 0;
|
||||||
|
depthStencilState.depthBiasSlopeScale = 0.0f;
|
||||||
|
depthStencilState.depthBiasClamp = 0.0f;
|
||||||
|
|
||||||
|
// shader module wgsl descriptor
|
||||||
|
WGPUShaderModuleWGSLDescriptor shaderModuleWGSLDesc{};
|
||||||
|
shaderModuleWGSLDesc.chain.next = nullptr;
|
||||||
|
shaderModuleWGSLDesc.chain.sType = WGPUSType_ShaderModuleWGSLDescriptor;
|
||||||
|
shaderModuleWGSLDesc.code = cShaderSource_PipelineLinear;
|
||||||
|
// shader module descriptor
|
||||||
|
WGPUShaderModuleDescriptor shaderModuleDesc{};
|
||||||
|
shaderModuleDesc.nextInChain = &shaderModuleWGSLDesc.chain;
|
||||||
|
shaderModuleDesc.label = "The shader module pipeline linear";
|
||||||
|
shaderModuleDesc.hintCount = 0;
|
||||||
|
shaderModuleDesc.hints = nullptr;
|
||||||
|
mShaderModule = wgpuDeviceCreateShaderModule(device, &shaderModuleDesc);
|
||||||
|
assert(mShaderModule);
|
||||||
|
|
||||||
|
// vertex attributes
|
||||||
|
WGPUVertexAttribute vertexAttributes[] = {
|
||||||
|
{ WGPUVertexFormat_Float32x3, sizeof(float) * 0, 0 }, // position
|
||||||
|
};
|
||||||
|
// vertex buffer layout
|
||||||
|
WGPUVertexBufferLayout vertexBufferLayout{};
|
||||||
|
vertexBufferLayout.arrayStride = sizeof(float) * 3; // position
|
||||||
|
vertexBufferLayout.stepMode = WGPUVertexStepMode_Vertex;
|
||||||
|
vertexBufferLayout.attributeCount = 1; // position
|
||||||
|
vertexBufferLayout.attributes = vertexAttributes;
|
||||||
|
|
||||||
|
// blend state
|
||||||
|
WGPUBlendState blendState{};
|
||||||
|
// blendState.color
|
||||||
|
blendState.color.operation = WGPUBlendOperation_Add;
|
||||||
|
blendState.color.srcFactor = WGPUBlendFactor_SrcAlpha;
|
||||||
|
blendState.color.dstFactor = WGPUBlendFactor_OneMinusSrcAlpha;
|
||||||
|
// blendState.alpha
|
||||||
|
blendState.alpha.operation = WGPUBlendOperation_Add;
|
||||||
|
blendState.alpha.srcFactor = WGPUBlendFactor_Zero;
|
||||||
|
blendState.alpha.dstFactor = WGPUBlendFactor_One;
|
||||||
|
|
||||||
|
// color target state (WGPUTextureFormat_BGRA8UnormSrgb)
|
||||||
|
WGPUColorTargetState colorTargetState0{};
|
||||||
|
colorTargetState0.nextInChain = nullptr;
|
||||||
|
colorTargetState0.format = WGPUTextureFormat_BGRA8Unorm;
|
||||||
|
//colorTargetState0.format = WGPUTextureFormat_BGRA8UnormSrgb;
|
||||||
|
colorTargetState0.blend = &blendState;
|
||||||
|
colorTargetState0.writeMask = WGPUColorWriteMask_All;
|
||||||
|
// color target states
|
||||||
|
WGPUColorTargetState colorTargetStates[] = {
|
||||||
|
colorTargetState0
|
||||||
|
};
|
||||||
|
// fragmanet state
|
||||||
|
WGPUFragmentState fragmentState{};
|
||||||
|
fragmentState.nextInChain = nullptr;
|
||||||
|
fragmentState.module = mShaderModule;
|
||||||
|
fragmentState.entryPoint = "fs_main";
|
||||||
|
fragmentState.constantCount = 0;
|
||||||
|
fragmentState.constants = nullptr;
|
||||||
|
fragmentState.targetCount = 1;
|
||||||
|
fragmentState.targets = colorTargetStates; // render target index
|
||||||
|
|
||||||
|
// render pipeline descriptor
|
||||||
|
WGPURenderPipelineDescriptor renderPipelineDesc{};
|
||||||
|
renderPipelineDesc.nextInChain = nullptr;
|
||||||
|
renderPipelineDesc.label = "Render pipeline pipeline linear";
|
||||||
|
// renderPipelineDesc.layout
|
||||||
|
renderPipelineDesc.layout = mPipelineLayout;
|
||||||
|
// renderPipelineDesc.vertex
|
||||||
|
renderPipelineDesc.vertex.nextInChain = nullptr;
|
||||||
|
renderPipelineDesc.vertex.module = mShaderModule;
|
||||||
|
renderPipelineDesc.vertex.entryPoint = "vs_main";
|
||||||
|
renderPipelineDesc.vertex.constantCount = 0;
|
||||||
|
renderPipelineDesc.vertex.constants = nullptr;
|
||||||
|
renderPipelineDesc.vertex.bufferCount = 1;
|
||||||
|
renderPipelineDesc.vertex.buffers = &vertexBufferLayout; // buffer index
|
||||||
|
// renderPipelineDesc.primitive
|
||||||
|
renderPipelineDesc.primitive.nextInChain = nullptr;
|
||||||
|
renderPipelineDesc.primitive.topology = WGPUPrimitiveTopology_TriangleList;
|
||||||
|
renderPipelineDesc.primitive.stripIndexFormat = WGPUIndexFormat_Undefined;
|
||||||
|
renderPipelineDesc.primitive.frontFace = WGPUFrontFace_CCW;
|
||||||
|
renderPipelineDesc.primitive.cullMode = WGPUCullMode_None;
|
||||||
|
// renderPipelineDesc.depthStencil
|
||||||
|
renderPipelineDesc.depthStencil = &depthStencilState;
|
||||||
|
// renderPipelineDesc.multisample
|
||||||
|
renderPipelineDesc.multisample.nextInChain = nullptr;
|
||||||
|
renderPipelineDesc.multisample.count = 1;
|
||||||
|
renderPipelineDesc.multisample.mask = 0xFFFFFFFF;
|
||||||
|
renderPipelineDesc.multisample.alphaToCoverageEnabled = false;
|
||||||
|
// renderPipelineDesc.fragment
|
||||||
|
renderPipelineDesc.fragment = &fragmentState;
|
||||||
|
mRenderPipeline = wgpuDeviceCreateRenderPipeline(device, &renderPipelineDesc);
|
||||||
|
assert(mRenderPipeline);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WgPipelineLinear::release() {
|
||||||
|
wgpuRenderPipelineRelease(mRenderPipeline);
|
||||||
|
wgpuShaderModuleRelease(mShaderModule);
|
||||||
|
wgpuPipelineLayoutRelease(mPipelineLayout);
|
||||||
|
wgpuBindGroupLayoutRelease(mBindGroupLayout);
|
||||||
|
}
|
61
src/renderer/wg_engine/tvgWgPipelineLinear.h
Normal file
61
src/renderer/wg_engine/tvgWgPipelineLinear.h
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TVG_WG_PIPELINE_LINEAR_H_
|
||||||
|
#define _TVG_WG_PIPELINE_LINEAR_H_
|
||||||
|
|
||||||
|
#include "tvgWgPipelineBase.h"
|
||||||
|
|
||||||
|
class WgPipelineLinear;
|
||||||
|
|
||||||
|
#define MAX_LINEAR_GRADIENT_STOPS 4
|
||||||
|
struct WgPipelineLinearGradientInfo {
|
||||||
|
alignas(16) float nStops[4]{};
|
||||||
|
alignas(16) float startPos[2]{};
|
||||||
|
alignas(8) float endPos[2]{};
|
||||||
|
alignas(8) float stopPoints[MAX_LINEAR_GRADIENT_STOPS]{};
|
||||||
|
alignas(16) float stopColors[4 * MAX_LINEAR_GRADIENT_STOPS]{};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WgPipelineDataLinear: WgPipelineData {
|
||||||
|
WgPipelineLinearGradientInfo uGradientInfo{}; // @binding(1)
|
||||||
|
|
||||||
|
void updateGradient(LinearGradient* linearGradient);
|
||||||
|
};
|
||||||
|
|
||||||
|
class WgPipelineBindGroupLinear: public WgPipelineBindGroup {
|
||||||
|
private:
|
||||||
|
WGPUBuffer uBufferGradientInfo{}; // @binding(1)
|
||||||
|
public:
|
||||||
|
void initialize(WGPUDevice device, WgPipelineLinear& pipelinePipelineLinear);
|
||||||
|
void release();
|
||||||
|
|
||||||
|
void update(WGPUQueue mQueue, WgPipelineDataLinear& pipelineDataLinear);
|
||||||
|
};
|
||||||
|
|
||||||
|
class WgPipelineLinear: public WgPipelineBase {
|
||||||
|
public:
|
||||||
|
void initialize(WGPUDevice device) override;
|
||||||
|
void release() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //_TVG_WG_PIPELINE_LINEAR_H_
|
|
@ -21,6 +21,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "tvgWgPipelineSolid.h"
|
#include "tvgWgPipelineSolid.h"
|
||||||
|
#include "tvgWgPipelineLinear.h"
|
||||||
|
|
||||||
#ifndef _TVG_WG_RENDER_DATA_H_
|
#ifndef _TVG_WG_RENDER_DATA_H_
|
||||||
#define _TVG_WG_RENDER_DATA_H_
|
#define _TVG_WG_RENDER_DATA_H_
|
||||||
|
@ -53,6 +54,7 @@ public:
|
||||||
Array<WgGeometryData*> mGeometryDataStroke;
|
Array<WgGeometryData*> mGeometryDataStroke;
|
||||||
|
|
||||||
WgPipelineBindGroupSolid mPipelineBindGroupSolid{};
|
WgPipelineBindGroupSolid mPipelineBindGroupSolid{};
|
||||||
|
WgPipelineBindGroupLinear mPipelineBindGroupLinear{};
|
||||||
|
|
||||||
WgPipelineBase* mPipelineBase{}; // external
|
WgPipelineBase* mPipelineBase{}; // external
|
||||||
WgPipelineBindGroup* mPipelineBindGroup{}; // external
|
WgPipelineBindGroup* mPipelineBindGroup{}; // external
|
||||||
|
|
|
@ -103,6 +103,7 @@ void WgRenderer::initialize() {
|
||||||
// create pipelines
|
// create pipelines
|
||||||
mPipelineEmpty.initialize(mDevice);
|
mPipelineEmpty.initialize(mDevice);
|
||||||
mPipelineSolid.initialize(mDevice);
|
mPipelineSolid.initialize(mDevice);
|
||||||
|
mPipelineLinear.initialize(mDevice);
|
||||||
mPipelineBindGroupEmpty.initialize(mDevice, mPipelineEmpty);
|
mPipelineBindGroupEmpty.initialize(mDevice, mPipelineEmpty);
|
||||||
mGeometryDataPipeline.initialize(mDevice);
|
mGeometryDataPipeline.initialize(mDevice);
|
||||||
}
|
}
|
||||||
|
@ -117,6 +118,7 @@ void WgRenderer::release() {
|
||||||
if (mSurface) wgpuSurfaceRelease(mSurface);
|
if (mSurface) wgpuSurfaceRelease(mSurface);
|
||||||
mGeometryDataPipeline.release();
|
mGeometryDataPipeline.release();
|
||||||
mPipelineBindGroupEmpty.release();
|
mPipelineBindGroupEmpty.release();
|
||||||
|
mPipelineLinear.release();
|
||||||
mPipelineSolid.release();
|
mPipelineSolid.release();
|
||||||
mPipelineEmpty.release();
|
mPipelineEmpty.release();
|
||||||
if (mDevice) {
|
if (mDevice) {
|
||||||
|
@ -134,11 +136,25 @@ RenderData WgRenderer::prepare(const RenderShape& rshape, RenderData data, const
|
||||||
renderDataShape = new WgRenderDataShape();
|
renderDataShape = new WgRenderDataShape();
|
||||||
renderDataShape->initialize(mDevice);
|
renderDataShape->initialize(mDevice);
|
||||||
renderDataShape->mPipelineBindGroupSolid.initialize(mDevice, mPipelineSolid);
|
renderDataShape->mPipelineBindGroupSolid.initialize(mDevice, mPipelineSolid);
|
||||||
|
renderDataShape->mPipelineBindGroupLinear.initialize(mDevice, mPipelineLinear);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & RenderUpdateFlag::Path)
|
if (flags & RenderUpdateFlag::Path)
|
||||||
renderDataShape->tesselate(mDevice, mQueue, rshape);
|
renderDataShape->tesselate(mDevice, mQueue, rshape);
|
||||||
|
|
||||||
|
// setup fill properties
|
||||||
|
if ((flags & (RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform)) && (rshape.fill)) {
|
||||||
|
// setup linear fill properties
|
||||||
|
if (rshape.fill->identifier() == TVG_CLASS_ID_LINEAR) {
|
||||||
|
WgPipelineDataLinear brushDataLinear{};
|
||||||
|
brushDataLinear.updateMatrix(mViewMatrix, transform);
|
||||||
|
brushDataLinear.updateGradient((LinearGradient*)rshape.fill);
|
||||||
|
renderDataShape->mPipelineBindGroupLinear.update(mQueue, brushDataLinear);
|
||||||
|
renderDataShape->mPipelineBindGroup = &renderDataShape->mPipelineBindGroupLinear;
|
||||||
|
renderDataShape->mPipelineBase = &mPipelineLinear;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// setup solid fill properties
|
// setup solid fill properties
|
||||||
if ((flags & (RenderUpdateFlag::Color | RenderUpdateFlag::Transform)) && (!rshape.fill)) {
|
if ((flags & (RenderUpdateFlag::Color | RenderUpdateFlag::Transform)) && (!rshape.fill)) {
|
||||||
WgPipelineDataSolid pipelineDataSolid{};
|
WgPipelineDataSolid pipelineDataSolid{};
|
||||||
|
|
|
@ -24,7 +24,6 @@
|
||||||
#define _TVG_WG_RENDERER_H_
|
#define _TVG_WG_RENDERER_H_
|
||||||
|
|
||||||
#include "tvgWgPipelineEmpty.h"
|
#include "tvgWgPipelineEmpty.h"
|
||||||
#include "tvgWgPipelineSolid.h"
|
|
||||||
#include "tvgWgRenderData.h"
|
#include "tvgWgRenderData.h"
|
||||||
|
|
||||||
class WgRenderer : public RenderMethod
|
class WgRenderer : public RenderMethod
|
||||||
|
@ -80,6 +79,7 @@ private:
|
||||||
private:
|
private:
|
||||||
WgPipelineEmpty mPipelineEmpty;
|
WgPipelineEmpty mPipelineEmpty;
|
||||||
WgPipelineSolid mPipelineSolid;
|
WgPipelineSolid mPipelineSolid;
|
||||||
|
WgPipelineLinear mPipelineLinear;
|
||||||
WgGeometryData mGeometryDataPipeline;
|
WgGeometryData mGeometryDataPipeline;
|
||||||
WgPipelineBindGroupEmpty mPipelineBindGroupEmpty;
|
WgPipelineBindGroupEmpty mPipelineBindGroupEmpty;
|
||||||
};
|
};
|
||||||
|
|
|
@ -99,4 +99,88 @@ fn vs_main(in: VertexInput) -> VertexOutput {
|
||||||
@fragment
|
@fragment
|
||||||
fn fs_main(in: VertexOutput) -> @location(0) vec4f {
|
fn fs_main(in: VertexOutput) -> @location(0) vec4f {
|
||||||
return uColorInfo.color;
|
return uColorInfo.color;
|
||||||
})";
|
})";
|
||||||
|
|
||||||
|
//************************************************************************
|
||||||
|
// cShaderSource_PipelineRadial
|
||||||
|
//************************************************************************
|
||||||
|
const char* cShaderSource_PipelineLinear = R"(
|
||||||
|
// vertex input
|
||||||
|
struct VertexInput {
|
||||||
|
@location(0) position: vec3f
|
||||||
|
};
|
||||||
|
|
||||||
|
// Matrix
|
||||||
|
struct Matrix {
|
||||||
|
transform: mat4x4f
|
||||||
|
};
|
||||||
|
|
||||||
|
// GradientInfo
|
||||||
|
const MAX_STOP_COUNT = 4;
|
||||||
|
struct GradientInfo {
|
||||||
|
nStops : vec4f,
|
||||||
|
gradStartPos : vec2f,
|
||||||
|
gradEndPos : vec2f,
|
||||||
|
stopPoints : vec4f,
|
||||||
|
stopColors : array<vec4f, MAX_STOP_COUNT>
|
||||||
|
};
|
||||||
|
|
||||||
|
// vertex output
|
||||||
|
struct VertexOutput {
|
||||||
|
@builtin(position) position: vec4f,
|
||||||
|
@location(0) vScreenCoord: vec2f
|
||||||
|
};
|
||||||
|
|
||||||
|
// uMatrix
|
||||||
|
@group(0) @binding(0) var<uniform> uMatrix: Matrix;
|
||||||
|
// uGradientInfo
|
||||||
|
@group(0) @binding(1) var<uniform> uGradientInfo: GradientInfo;
|
||||||
|
|
||||||
|
@vertex
|
||||||
|
fn vs_main(in: VertexInput) -> VertexOutput {
|
||||||
|
// fill output
|
||||||
|
var out: VertexOutput;
|
||||||
|
out.position = uMatrix.transform * vec4f(in.position.xy, 0.0, 1.0);
|
||||||
|
out.vScreenCoord = in.position.xy;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@fragment
|
||||||
|
fn fs_main(in: VertexOutput) -> @location(0) vec4f {
|
||||||
|
let pos: vec2f = in.vScreenCoord;
|
||||||
|
let st: vec2f = uGradientInfo.gradStartPos;
|
||||||
|
let ed: vec2f = uGradientInfo.gradEndPos;
|
||||||
|
|
||||||
|
let ba: vec2f = ed - st;
|
||||||
|
|
||||||
|
// get interpolation factor
|
||||||
|
let t: f32 = clamp(dot(pos - st, ba) / dot(ba, ba), 0.0, 1.0);
|
||||||
|
|
||||||
|
// get stops count
|
||||||
|
let last: i32 = i32(uGradientInfo.nStops[0]) - 1;
|
||||||
|
|
||||||
|
// resulting color
|
||||||
|
var color = vec4(1.0);
|
||||||
|
|
||||||
|
// closer than first stop
|
||||||
|
if (t <= uGradientInfo.stopPoints[0]) {
|
||||||
|
color = uGradientInfo.stopColors[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// further than last stop
|
||||||
|
if (t >= uGradientInfo.stopPoints[last]) {
|
||||||
|
color = uGradientInfo.stopColors[last];
|
||||||
|
}
|
||||||
|
|
||||||
|
// look in the middle
|
||||||
|
for (var i = 0i; i < last; i++) {
|
||||||
|
let strt = uGradientInfo.stopPoints[i];
|
||||||
|
let stop = uGradientInfo.stopPoints[i+1];
|
||||||
|
if ((t > strt) && (t < stop)) {
|
||||||
|
let step: f32 = (t - strt) / (stop - strt);
|
||||||
|
color = mix(uGradientInfo.stopColors[i], uGradientInfo.stopColors[i+1], step);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return color;
|
||||||
|
})";
|
||||||
|
|
|
@ -31,4 +31,7 @@ extern const char* cShaderSource_PipelineEmpty;
|
||||||
// pipeline shader module solid
|
// pipeline shader module solid
|
||||||
extern const char* cShaderSource_PipelineSolid;
|
extern const char* cShaderSource_PipelineSolid;
|
||||||
|
|
||||||
|
// pipeline shader module linear
|
||||||
|
extern const char* cShaderSource_PipelineLinear;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Reference in a new issue