wg_engine: pipelines and bind groups refactoring

- shader and system types synchronized
- pipelens and bind groups description separated
- pipelines description simplified
This commit is contained in:
Sergii Liebodkin 2023-12-13 12:37:58 +02:00 committed by Hermet Park
parent f173b45e04
commit 9742cfe293
29 changed files with 1748 additions and 2539 deletions

View file

@ -1,14 +1,20 @@
source_file = [
'tvgWgBindGroups.h',
'tvgWgCommon.h',
'tvgWgGeometry.h',
'tvgWgPipelines.h',
'tvgWgRenderData.h',
'tvgWgRenderer.h',
'tvgWgShaderSrc.h',
'tvgWgShaderTypes.h'
'tvgWgBindGroups.cpp',
'tvgWgCommon.cpp',
'tvgWgGeometry.cpp',
'tvgWgPipelineBase.cpp',
'tvgWgPipelineEmpty.cpp',
'tvgWgPipelineLinear.cpp',
'tvgWgPipelineSolid.cpp',
'tvgWgPipelineRadial.cpp',
'tvgWgPipelineStroke.cpp',
'tvgWgPipelines.cpp',
'tvgWgRenderData.cpp',
'tvgWgRenderer.cpp',
'tvgWgShaderSrc.cpp'
'tvgWgShaderSrc.cpp',
'tvgWgShaderTypes.cpp'
]
engine_dep += [declare_dependency(

View file

@ -0,0 +1,239 @@
/*
* 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 "tvgWgBindGroups.h"
WGPUBindGroupLayout WgBindGroupCanvas::layout = nullptr;
WGPUBindGroupLayout WgBindGroupCanvas::getLayout(WGPUDevice device) {
if (layout) return layout;
const WGPUBindGroupLayoutEntry bindGroupLayoutEntries[] {
makeBindGroupLayoutEntryBuffer(0)
};
layout = createBindGroupLayout(device, bindGroupLayoutEntries, 1);
assert(layout);
return layout;
}
void WgBindGroupCanvas::releaseLayout() {
releaseBindGroupLayout(layout);
};
void WgBindGroupCanvas::initialize(WGPUDevice device, WGPUQueue queue, WgShaderTypeMat4x4f& uViewMat) {
release();
uBufferViewMat = createBuffer(device, queue, &uViewMat, sizeof(uViewMat));
const WGPUBindGroupEntry bindGroupEntries[] {
makeBindGroupEntryBuffer(0, uBufferViewMat)
};
mBindGroup = createBindGroup(device, getLayout(device), bindGroupEntries, 1);
assert(mBindGroup);
}
void WgBindGroupCanvas::release() {
releaseBindGroup(mBindGroup);
releaseBuffer(uBufferViewMat);
}
WGPUBindGroupLayout WgBindGroupPaint::layout = nullptr;
WGPUBindGroupLayout WgBindGroupPaint::getLayout(WGPUDevice device) {
if (layout) return layout;
const WGPUBindGroupLayoutEntry bindGroupLayoutEntries[] {
makeBindGroupLayoutEntryBuffer(0),
makeBindGroupLayoutEntryBuffer(1)
};
layout = createBindGroupLayout(device, bindGroupLayoutEntries, 2);
assert(layout);
return layout;
}
void WgBindGroupPaint::releaseLayout() {
releaseBindGroupLayout(layout);
};
void WgBindGroupPaint::initialize(WGPUDevice device, WGPUQueue queue, WgShaderTypeMat4x4f& uModelMat, WgShaderTypeBlendSettings& uBlendSettings) {
release();
uBufferModelMat = createBuffer(device, queue, &uModelMat, sizeof(uModelMat));
uBufferBlendSettings = createBuffer(device, queue, &uBlendSettings, sizeof(uBlendSettings));
const WGPUBindGroupEntry bindGroupEntries[] {
makeBindGroupEntryBuffer(0, uBufferModelMat),
makeBindGroupEntryBuffer(1, uBufferBlendSettings)
};
mBindGroup = createBindGroup(device, getLayout(device), bindGroupEntries, 2);
assert(mBindGroup);
}
void WgBindGroupPaint::release() {
releaseBindGroup(mBindGroup);
releaseBuffer(uBufferBlendSettings);
releaseBuffer(uBufferModelMat);
}
WGPUBindGroupLayout WgBindGroupSolidColor::layout = nullptr;
WGPUBindGroupLayout WgBindGroupSolidColor::getLayout(WGPUDevice device) {
if (layout) return layout;
const WGPUBindGroupLayoutEntry bindGroupLayoutEntries[] {
makeBindGroupLayoutEntryBuffer(0)
};
layout = createBindGroupLayout(device, bindGroupLayoutEntries, 1);
assert(layout);
return layout;
}
void WgBindGroupSolidColor::releaseLayout() {
releaseBindGroupLayout(layout);
};
void WgBindGroupSolidColor::initialize(WGPUDevice device, WGPUQueue queue, WgShaderTypeSolidColor &uSolidColor) {
release();
uBufferSolidColor = createBuffer(device, queue, &uSolidColor, sizeof(uSolidColor));
const WGPUBindGroupEntry bindGroupEntries[] {
makeBindGroupEntryBuffer(0, uBufferSolidColor)
};
mBindGroup = createBindGroup(device, getLayout(device), bindGroupEntries, 1);
assert(mBindGroup);
}
void WgBindGroupSolidColor::release() {
releaseBindGroup(mBindGroup);
releaseBuffer(uBufferSolidColor);
}
WGPUBindGroupLayout WgBindGroupLinearGradient::layout = nullptr;
WGPUBindGroupLayout WgBindGroupLinearGradient::getLayout(WGPUDevice device) {
if (layout) return layout;
const WGPUBindGroupLayoutEntry bindGroupLayoutEntries[] {
makeBindGroupLayoutEntryBuffer(0)
};
layout = createBindGroupLayout(device, bindGroupLayoutEntries, 1);
assert(layout);
return layout;
}
void WgBindGroupLinearGradient::releaseLayout() {
releaseBindGroupLayout(layout);
};
void WgBindGroupLinearGradient::initialize(WGPUDevice device, WGPUQueue queue, WgShaderTypeLinearGradient &uLinearGradient) {
release();
uBufferLinearGradient = createBuffer(device, queue, &uLinearGradient, sizeof(uLinearGradient));
const WGPUBindGroupEntry bindGroupEntries[] {
makeBindGroupEntryBuffer(0, uBufferLinearGradient)
};
mBindGroup = createBindGroup(device, getLayout(device), bindGroupEntries, 1);
assert(mBindGroup);
}
void WgBindGroupLinearGradient::release() {
releaseBindGroup(mBindGroup);
releaseBuffer(uBufferLinearGradient);
}
WGPUBindGroupLayout WgBindGroupRadialGradient::layout = nullptr;
WGPUBindGroupLayout WgBindGroupRadialGradient::getLayout(WGPUDevice device) {
if (layout) return layout;
const WGPUBindGroupLayoutEntry bindGroupLayoutEntries[] {
makeBindGroupLayoutEntryBuffer(0)
};
layout = createBindGroupLayout(device, bindGroupLayoutEntries, 1);
assert(layout);
return layout;
}
void WgBindGroupRadialGradient::releaseLayout() {
releaseBindGroupLayout(layout);
};
void WgBindGroupRadialGradient::initialize(WGPUDevice device, WGPUQueue queue, WgShaderTypeRadialGradient &uRadialGradient) {
release();
uBufferRadialGradient = createBuffer(device, queue, &uRadialGradient, sizeof(uRadialGradient));
const WGPUBindGroupEntry bindGroupEntries[] {
makeBindGroupEntryBuffer(0, uBufferRadialGradient)
};
mBindGroup = createBindGroup(device, getLayout(device), bindGroupEntries, 1);
assert(mBindGroup);
}
void WgBindGroupRadialGradient::release() {
releaseBuffer(uBufferRadialGradient);
releaseBindGroup(mBindGroup);
}
WGPUBindGroupLayout WgBindGroupPicture::layout = nullptr;
WGPUBindGroupLayout WgBindGroupPicture::getLayout(WGPUDevice device) {
if (layout) return layout;
const WGPUBindGroupLayoutEntry bindGroupLayoutEntries[] {
makeBindGroupLayoutEntrySampler(0),
makeBindGroupLayoutEntryTextureView(1)
};
layout = createBindGroupLayout(device, bindGroupLayoutEntries, 2);
assert(layout);
return layout;
}
void WgBindGroupPicture::releaseLayout() {
releaseBindGroupLayout(layout);
};
void WgBindGroupPicture::initialize(WGPUDevice device, WGPUQueue queue, WGPUSampler uSampler, WGPUTextureView uTextureView) {
release();
const WGPUBindGroupEntry bindGroupEntries[] {
makeBindGroupEntrySampler(0, uSampler),
makeBindGroupEntryTextureView(1, uTextureView)
};
mBindGroup = createBindGroup(device, getLayout(device), bindGroupEntries, 2);
assert(mBindGroup);
}
void WgBindGroupPicture::release() {
releaseBindGroup(mBindGroup);
}
WGPUBindGroupLayout WgBindGroupCompose::layout = nullptr;
WGPUBindGroupLayout WgBindGroupCompose::getLayout(WGPUDevice device) {
if (layout) return layout;
const WGPUBindGroupLayoutEntry bindGroupLayoutEntries[] {
makeBindGroupLayoutEntrySampler(0),
makeBindGroupLayoutEntryTextureView(1),
makeBindGroupLayoutEntryTextureView(2)
};
layout = createBindGroupLayout(device, bindGroupLayoutEntries, 3);
assert(layout);
return layout;
}
void WgBindGroupCompose::releaseLayout() {
releaseBindGroupLayout(layout);
};
void WgBindGroupCompose::initialize(WGPUDevice device, WGPUQueue queue, WGPUSampler uSampler, WGPUTextureView uTextureSrc, WGPUTextureView uTextureDst) {
release();
const WGPUBindGroupEntry bindGroupEntries[] {
makeBindGroupEntrySampler(0, uSampler),
makeBindGroupEntryTextureView(1, uTextureSrc),
makeBindGroupEntryTextureView(2, uTextureDst)
};
mBindGroup = createBindGroup(device, getLayout(device), bindGroupEntries, 3);
assert(mBindGroup);
}
void WgBindGroupCompose::release() {
releaseBindGroup(mBindGroup);
}

View file

@ -0,0 +1,116 @@
/*
* 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_BIND_GROUPS_H_
#define _TVG_WG_BIND_GROUPS_H_
#include "tvgWgCommon.h"
#include "tvgWgShaderTypes.h"
// @group(0)
struct WgBindGroupCanvas: public WgBindGroup {
static WGPUBindGroupLayout layout;
static WGPUBindGroupLayout getLayout(WGPUDevice device);
static void releaseLayout();
WGPUBuffer uBufferViewMat{};
void initialize(WGPUDevice device, WGPUQueue queue,
WgShaderTypeMat4x4f& uViewMat);
void release();
};
// @group(1)
struct WgBindGroupPaint: public WgBindGroup {
static WGPUBindGroupLayout layout;
static WGPUBindGroupLayout getLayout(WGPUDevice device);
static void releaseLayout();
WGPUBuffer uBufferModelMat{};
WGPUBuffer uBufferBlendSettings{};
void initialize(WGPUDevice device, WGPUQueue queue,
WgShaderTypeMat4x4f& uModelMat,
WgShaderTypeBlendSettings& uBlendSettings);
void release();
};
// @group(2)
struct WgBindGroupSolidColor: public WgBindGroup {
static WGPUBindGroupLayout layout;
static WGPUBindGroupLayout getLayout(WGPUDevice device);
static void releaseLayout();
WGPUBuffer uBufferSolidColor;
void initialize(WGPUDevice device, WGPUQueue queue,
WgShaderTypeSolidColor &uSolidColor);
void release();
};
// @group(2)
struct WgBindGroupLinearGradient: public WgBindGroup {
static WGPUBindGroupLayout layout;
static WGPUBindGroupLayout getLayout(WGPUDevice device);
static void releaseLayout();
WGPUBuffer uBufferLinearGradient;
void initialize(WGPUDevice device, WGPUQueue queue,
WgShaderTypeLinearGradient &uLinearGradient);
void release();
};
// @group(2)
struct WgBindGroupRadialGradient: public WgBindGroup {
static WGPUBindGroupLayout layout;
static WGPUBindGroupLayout getLayout(WGPUDevice device);
static void releaseLayout();
WGPUBuffer uBufferRadialGradient;
void initialize(WGPUDevice device, WGPUQueue queue,
WgShaderTypeRadialGradient &uRadialGradient);
void release();
};
// @group(2)
struct WgBindGroupPicture: public WgBindGroup {
static WGPUBindGroupLayout layout;
static WGPUBindGroupLayout getLayout(WGPUDevice device);
static void releaseLayout();
void initialize(WGPUDevice device, WGPUQueue queue,
WGPUSampler uSampler,
WGPUTextureView uTextureView);
void release();
};
// @group(2)
struct WgBindGroupCompose: public WgBindGroup {
static WGPUBindGroupLayout layout;
static WGPUBindGroupLayout getLayout(WGPUDevice device);
static void releaseLayout();
void initialize(WGPUDevice device, WGPUQueue queue,
WGPUSampler uSampler,
WGPUTextureView uTextureSrc,
WGPUTextureView uTextureDst);
void release();
};
#endif // _TVG_WG_BIND_GROUPS_H_

View file

@ -0,0 +1,343 @@
/*
* 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 "tvgWgCommon.h"
//*****************************************************************************
// bind group
//*****************************************************************************
void WgBindGroup::set(WGPURenderPassEncoder encoder, uint32_t groupIndex) {
wgpuRenderPassEncoderSetBindGroup(encoder, groupIndex, mBindGroup, 0, nullptr);
}
WGPUBindGroupEntry WgBindGroup::makeBindGroupEntryBuffer(uint32_t binding, WGPUBuffer buffer) {
WGPUBindGroupEntry bindGroupEntry{};
bindGroupEntry.nextInChain = nullptr;
bindGroupEntry.binding = binding;
bindGroupEntry.buffer = buffer;
bindGroupEntry.offset = 0;
bindGroupEntry.size = wgpuBufferGetSize(buffer);
bindGroupEntry.sampler = nullptr;
bindGroupEntry.textureView = nullptr;
return bindGroupEntry;
}
WGPUBindGroupEntry WgBindGroup::makeBindGroupEntrySampler(uint32_t binding, WGPUSampler sampler) {
WGPUBindGroupEntry bindGroupEntry{};
bindGroupEntry.nextInChain = nullptr;
bindGroupEntry.binding = binding;
bindGroupEntry.buffer = nullptr;
bindGroupEntry.offset = 0;
bindGroupEntry.size = 0;
bindGroupEntry.sampler = sampler;
bindGroupEntry.textureView = nullptr;
return bindGroupEntry;
}
WGPUBindGroupEntry WgBindGroup::makeBindGroupEntryTextureView(uint32_t binding, WGPUTextureView textureView) {
WGPUBindGroupEntry bindGroupEntry{};
bindGroupEntry.nextInChain = nullptr;
bindGroupEntry.binding = binding;
bindGroupEntry.buffer = nullptr;
bindGroupEntry.offset = 0;
bindGroupEntry.size = 0;
bindGroupEntry.sampler = nullptr;
bindGroupEntry.textureView = textureView;
return bindGroupEntry;
}
WGPUBindGroupLayoutEntry WgBindGroup::makeBindGroupLayoutEntryBuffer(uint32_t binding) {
WGPUBindGroupLayoutEntry bindGroupLayoutEntry{};
bindGroupLayoutEntry.nextInChain = nullptr;
bindGroupLayoutEntry.binding = binding;
bindGroupLayoutEntry.visibility = WGPUShaderStage_Vertex | WGPUShaderStage_Fragment;
bindGroupLayoutEntry.buffer.nextInChain = nullptr;
bindGroupLayoutEntry.buffer.type = WGPUBufferBindingType_Uniform;
bindGroupLayoutEntry.buffer.hasDynamicOffset = false;
bindGroupLayoutEntry.buffer.minBindingSize = 0;
return bindGroupLayoutEntry;
}
WGPUBindGroupLayoutEntry WgBindGroup::makeBindGroupLayoutEntrySampler(uint32_t binding) {
WGPUBindGroupLayoutEntry bindGroupLayoutEntry{};
bindGroupLayoutEntry.nextInChain = nullptr;
bindGroupLayoutEntry.binding = binding;
bindGroupLayoutEntry.visibility = WGPUShaderStage_Fragment;
bindGroupLayoutEntry.sampler.nextInChain = nullptr;
bindGroupLayoutEntry.sampler.type = WGPUSamplerBindingType_Filtering;
return bindGroupLayoutEntry;
}
WGPUBindGroupLayoutEntry WgBindGroup::makeBindGroupLayoutEntryTextureView(uint32_t binding) {
WGPUBindGroupLayoutEntry bindGroupLayoutEntry{};
bindGroupLayoutEntry.nextInChain = nullptr;
bindGroupLayoutEntry.binding = binding;
bindGroupLayoutEntry.visibility = WGPUShaderStage_Fragment;
bindGroupLayoutEntry.texture.nextInChain = nullptr;
bindGroupLayoutEntry.texture.sampleType = WGPUTextureSampleType_Float;
bindGroupLayoutEntry.texture.viewDimension = WGPUTextureViewDimension_2D;
bindGroupLayoutEntry.texture.multisampled = false;
return bindGroupLayoutEntry;
}
WGPUBuffer WgBindGroup::createBuffer(WGPUDevice device, WGPUQueue queue, const void *data, size_t size) {
WGPUBufferDescriptor bufferDescriptor{};
bufferDescriptor.nextInChain = nullptr;
bufferDescriptor.label = "The uniform buffer";
bufferDescriptor.usage = WGPUBufferUsage_CopyDst | WGPUBufferUsage_Uniform;
bufferDescriptor.size = size;
bufferDescriptor.mappedAtCreation = false;
WGPUBuffer buffer = wgpuDeviceCreateBuffer(device, &bufferDescriptor);
assert(buffer);
wgpuQueueWriteBuffer(queue, buffer, 0, data, size);
return buffer;
}
WGPUBindGroup WgBindGroup::createBindGroup(WGPUDevice device, WGPUBindGroupLayout layout, const WGPUBindGroupEntry* bindGroupEntries, uint32_t count) {
WGPUBindGroupDescriptor bindGroupDesc{};
bindGroupDesc.nextInChain = nullptr;
bindGroupDesc.label = "The binding group sampler";
bindGroupDesc.layout = layout;
bindGroupDesc.entryCount = count;
bindGroupDesc.entries = bindGroupEntries;
return wgpuDeviceCreateBindGroup(device, &bindGroupDesc);
}
WGPUBindGroupLayout WgBindGroup::createBindGroupLayout(WGPUDevice device, const WGPUBindGroupLayoutEntry* bindGroupLayoutEntries, uint32_t count) {
WGPUBindGroupLayoutDescriptor bindGroupLayoutDesc{};
bindGroupLayoutDesc.nextInChain = nullptr;
bindGroupLayoutDesc.label = "The bind group layout";
bindGroupLayoutDesc.entryCount = count;
bindGroupLayoutDesc.entries = bindGroupLayoutEntries; // @binding
return wgpuDeviceCreateBindGroupLayout(device, &bindGroupLayoutDesc);
}
void WgBindGroup::releaseBuffer(WGPUBuffer& buffer) {
if (buffer) {
wgpuBufferDestroy(buffer);
wgpuBufferRelease(buffer);
buffer = nullptr;
}
}
void WgBindGroup::releaseBindGroup(WGPUBindGroup& bindGroup) {
if (bindGroup) wgpuBindGroupRelease(bindGroup);
bindGroup = nullptr;
}
void WgBindGroup::releaseBindGroupLayout(WGPUBindGroupLayout& bindGroupLayout) {
if (bindGroupLayout) wgpuBindGroupLayoutRelease(bindGroupLayout);
bindGroupLayout = nullptr;
}
//*****************************************************************************
// pipeline
//*****************************************************************************
void WgPipeline::allocate(WGPUDevice device,
WGPUVertexBufferLayout vertexBufferLayouts[], uint32_t attribsCount,
WGPUBindGroupLayout bindGroupLayouts[], uint32_t bindGroupsCount,
WGPUCompareFunction stencilCompareFunction, WGPUStencilOperation stencilOperation,
const char* shaderSource, const char* shaderLabel, const char* pipelineLabel)
{
mShaderModule = createShaderModule(device, shaderSource, shaderLabel);
assert(mShaderModule);
mPipelineLayout = createPipelineLayout(device, bindGroupLayouts, bindGroupsCount);
assert(mPipelineLayout);
mRenderPipeline = createRenderPipeline(device,
vertexBufferLayouts, attribsCount,
stencilCompareFunction, stencilOperation,
mPipelineLayout, mShaderModule, pipelineLabel);
assert(mRenderPipeline);
}
void WgPipeline::release() {
destroyRenderPipeline(mRenderPipeline);
destroyShaderModule(mShaderModule);
destroyPipelineLayout(mPipelineLayout);
}
void WgPipeline::set(WGPURenderPassEncoder renderPassEncoder) {
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, mRenderPipeline);
};
WGPUBlendState WgPipeline::makeBlendState() {
WGPUBlendState blendState{};
blendState.color.operation = WGPUBlendOperation_Add;
blendState.color.srcFactor = WGPUBlendFactor_SrcAlpha;
blendState.color.dstFactor = WGPUBlendFactor_OneMinusSrcAlpha;
blendState.alpha.operation = WGPUBlendOperation_Add;
blendState.alpha.srcFactor = WGPUBlendFactor_Zero;
blendState.alpha.dstFactor = WGPUBlendFactor_One;
return blendState;
}
WGPUColorTargetState WgPipeline::makeColorTargetState(const WGPUBlendState* blendState) {
WGPUColorTargetState colorTargetState{};
colorTargetState.nextInChain = nullptr;
colorTargetState.format = WGPUTextureFormat_BGRA8Unorm; // (WGPUTextureFormat_BGRA8UnormSrgb)
colorTargetState.blend = blendState;
colorTargetState.writeMask = WGPUColorWriteMask_All;
return colorTargetState;
}
WGPUVertexBufferLayout WgPipeline::makeVertexBufferLayout(const WGPUVertexAttribute* vertexAttributes, uint32_t count, uint64_t stride) {
WGPUVertexBufferLayout vertexBufferLayoutPos{};
vertexBufferLayoutPos.arrayStride = stride;
vertexBufferLayoutPos.stepMode = WGPUVertexStepMode_Vertex;
vertexBufferLayoutPos.attributeCount = count;
vertexBufferLayoutPos.attributes = vertexAttributes;
return vertexBufferLayoutPos;
}
WGPUVertexState WgPipeline::makeVertexState(WGPUShaderModule shaderModule, const WGPUVertexBufferLayout* buffers, uint32_t count) {
WGPUVertexState vertexState{};
vertexState.nextInChain = nullptr;
vertexState.module = shaderModule;
vertexState.entryPoint = "vs_main";
vertexState.constantCount = 0;
vertexState.constants = nullptr;
vertexState.bufferCount = count;
vertexState.buffers = buffers;
return vertexState;
}
WGPUPrimitiveState WgPipeline::makePrimitiveState() {
WGPUPrimitiveState primitiveState{};
primitiveState.nextInChain = nullptr;
primitiveState.topology = WGPUPrimitiveTopology_TriangleList;
primitiveState.stripIndexFormat = WGPUIndexFormat_Undefined;
primitiveState.frontFace = WGPUFrontFace_CCW;
primitiveState.cullMode = WGPUCullMode_None;
return primitiveState;
}
WGPUDepthStencilState WgPipeline::makeDepthStencilState(WGPUCompareFunction compare, WGPUStencilOperation operation) {
WGPUDepthStencilState depthStencilState{};
depthStencilState.nextInChain = nullptr;
depthStencilState.format = WGPUTextureFormat_Stencil8;
depthStencilState.depthWriteEnabled = false;
depthStencilState.depthCompare = WGPUCompareFunction_Always;
depthStencilState.stencilFront.compare = compare;
depthStencilState.stencilFront.failOp = operation;
depthStencilState.stencilFront.depthFailOp = operation;
depthStencilState.stencilFront.passOp = operation;
depthStencilState.stencilBack.compare = compare;
depthStencilState.stencilBack.failOp = operation;
depthStencilState.stencilBack.depthFailOp = operation;
depthStencilState.stencilBack.passOp = operation;
depthStencilState.stencilReadMask = 0xFFFFFFFF;
depthStencilState.stencilWriteMask = 0xFFFFFFFF;
depthStencilState.depthBias = 0;
depthStencilState.depthBiasSlopeScale = 0.0f;
depthStencilState.depthBiasClamp = 0.0f;
return depthStencilState;
}
WGPUMultisampleState WgPipeline::makeMultisampleState() {
WGPUMultisampleState multisampleState{};
multisampleState.nextInChain = nullptr;
multisampleState.count = 1;
multisampleState.mask = 0xFFFFFFFF;
multisampleState.alphaToCoverageEnabled = false;
return multisampleState;
}
WGPUFragmentState WgPipeline::makeFragmentState(WGPUShaderModule shaderModule, WGPUColorTargetState* targets, uint32_t size) {
WGPUFragmentState fragmentState{};
fragmentState.nextInChain = nullptr;
fragmentState.module = shaderModule;
fragmentState.entryPoint = "fs_main";
fragmentState.constantCount = 0;
fragmentState.constants = nullptr;
fragmentState.targetCount = size;
fragmentState.targets = targets;
return fragmentState;
}
WGPUPipelineLayout WgPipeline::createPipelineLayout(WGPUDevice device, const WGPUBindGroupLayout* bindGroupLayouts, uint32_t count) {
WGPUPipelineLayoutDescriptor pipelineLayoutDesc{};
pipelineLayoutDesc.nextInChain = nullptr;
pipelineLayoutDesc.label = "The Pipeline layout";
pipelineLayoutDesc.bindGroupLayoutCount = count;
pipelineLayoutDesc.bindGroupLayouts = bindGroupLayouts;
return wgpuDeviceCreatePipelineLayout(device, &pipelineLayoutDesc);
}
WGPUShaderModule WgPipeline::createShaderModule(WGPUDevice device, const char* code, const char* label) {
WGPUShaderModuleWGSLDescriptor shaderModuleWGSLDesc{};
shaderModuleWGSLDesc.chain.next = nullptr;
shaderModuleWGSLDesc.chain.sType = WGPUSType_ShaderModuleWGSLDescriptor;
shaderModuleWGSLDesc.code = code;
WGPUShaderModuleDescriptor shaderModuleDesc{};
shaderModuleDesc.nextInChain = &shaderModuleWGSLDesc.chain;
shaderModuleDesc.label = label;
shaderModuleDesc.hintCount = 0;
shaderModuleDesc.hints = nullptr;
return wgpuDeviceCreateShaderModule(device, &shaderModuleDesc);
}
WGPURenderPipeline WgPipeline::createRenderPipeline(WGPUDevice device,
WGPUVertexBufferLayout vertexBufferLayouts[], uint32_t attribsCount,
WGPUCompareFunction stencilCompareFunction, WGPUStencilOperation stencilOperation,
WGPUPipelineLayout pipelineLayout, WGPUShaderModule shaderModule,
const char* pipelineName) {
WGPUBlendState blendState = makeBlendState();
WGPUColorTargetState colorTargetStates[] = {
makeColorTargetState(&blendState)
};
WGPUVertexState vertexState = makeVertexState(shaderModule, vertexBufferLayouts, attribsCount);
WGPUPrimitiveState primitiveState = makePrimitiveState();
WGPUDepthStencilState depthStencilState = makeDepthStencilState(stencilCompareFunction, stencilOperation);
WGPUMultisampleState multisampleState = makeMultisampleState();
WGPUFragmentState fragmentState = makeFragmentState(shaderModule, colorTargetStates, 1);
WGPURenderPipelineDescriptor renderPipelineDesc{};
renderPipelineDesc.nextInChain = nullptr;
renderPipelineDesc.label = pipelineName;
renderPipelineDesc.layout = pipelineLayout;
renderPipelineDesc.vertex = vertexState;
renderPipelineDesc.primitive = primitiveState;
renderPipelineDesc.depthStencil = &depthStencilState;
renderPipelineDesc.multisample = multisampleState;
renderPipelineDesc.fragment = &fragmentState;
return wgpuDeviceCreateRenderPipeline(device, &renderPipelineDesc);
}
void WgPipeline::destroyPipelineLayout(WGPUPipelineLayout& pipelineLayout) {
if (pipelineLayout) wgpuPipelineLayoutRelease(pipelineLayout);
pipelineLayout = nullptr;
}
void WgPipeline::destroyShaderModule(WGPUShaderModule& shaderModule) {
if (shaderModule) wgpuShaderModuleRelease(shaderModule);
shaderModule = nullptr;
}
void WgPipeline::destroyRenderPipeline(WGPURenderPipeline& renderPipeline) {
if (renderPipeline) wgpuRenderPipelineRelease(renderPipeline);
renderPipeline = nullptr;
}

View file

@ -28,4 +28,63 @@
#include "tvgCommon.h"
#include "tvgRender.h"
struct WgBindGroup {
WGPUBindGroup mBindGroup{};
void set(WGPURenderPassEncoder encoder, uint32_t groupIndex);
static WGPUBindGroupEntry makeBindGroupEntryBuffer(uint32_t binding, WGPUBuffer buffer);
static WGPUBindGroupEntry makeBindGroupEntrySampler(uint32_t binding, WGPUSampler sampler);
static WGPUBindGroupEntry makeBindGroupEntryTextureView(uint32_t binding, WGPUTextureView textureView);
static WGPUBindGroupLayoutEntry makeBindGroupLayoutEntryBuffer(uint32_t binding);
static WGPUBindGroupLayoutEntry makeBindGroupLayoutEntrySampler(uint32_t binding);
static WGPUBindGroupLayoutEntry makeBindGroupLayoutEntryTextureView(uint32_t binding);
static WGPUBuffer createBuffer(WGPUDevice device, WGPUQueue queue, const void *data, size_t size);
static WGPUBindGroup createBindGroup(WGPUDevice device, WGPUBindGroupLayout layout, const WGPUBindGroupEntry* bindGroupEntries, uint32_t count);
static WGPUBindGroupLayout createBindGroupLayout(WGPUDevice device, const WGPUBindGroupLayoutEntry* bindGroupLayoutEntries, uint32_t count);
static void releaseBuffer(WGPUBuffer& buffer);
static void releaseBindGroup(WGPUBindGroup& bindGroup);
static void releaseBindGroupLayout(WGPUBindGroupLayout& bindGroupLayout);
};
struct WgPipeline {
protected:
void allocate(WGPUDevice device,
WGPUVertexBufferLayout vertexBufferLayouts[], uint32_t attribsCount,
WGPUBindGroupLayout bindGroupLayouts[], uint32_t bindGroupsCount,
WGPUCompareFunction stencilCompareFunction, WGPUStencilOperation stencilOperation,
const char* shaderSource, const char* shaderLabel, const char* pipelineLabel);
WGPUPipelineLayout mPipelineLayout{};
WGPUShaderModule mShaderModule{};
WGPURenderPipeline mRenderPipeline{};
public:
virtual void initialize(WGPUDevice device) = 0;
virtual void release();
void set(WGPURenderPassEncoder renderPassEncoder);
static WGPUBlendState makeBlendState();
static WGPUColorTargetState makeColorTargetState(const WGPUBlendState* blendState);
static WGPUVertexBufferLayout makeVertexBufferLayout(const WGPUVertexAttribute* vertexAttributes, uint32_t count, uint64_t stride);
static WGPUVertexState makeVertexState(WGPUShaderModule shaderModule, const WGPUVertexBufferLayout* buffers, uint32_t count);
static WGPUPrimitiveState makePrimitiveState();
static WGPUDepthStencilState makeDepthStencilState(WGPUCompareFunction compare, WGPUStencilOperation operation);
static WGPUMultisampleState makeMultisampleState();
static WGPUFragmentState makeFragmentState(WGPUShaderModule shaderModule, WGPUColorTargetState* targets, uint32_t size);
static WGPUPipelineLayout createPipelineLayout(WGPUDevice device, const WGPUBindGroupLayout* bindGroupLayouts, uint32_t count);
static WGPUShaderModule createShaderModule(WGPUDevice device, const char* code, const char* label);
static WGPURenderPipeline createRenderPipeline(
WGPUDevice device,
WGPUVertexBufferLayout vertexBufferLayouts[], uint32_t attribsCount,
WGPUCompareFunction stencilCompareFunction, WGPUStencilOperation stencilOperation,
WGPUPipelineLayout pipelineLayout, WGPUShaderModule shaderModule,
const char* pipelineLabel);
static void destroyPipelineLayout(WGPUPipelineLayout& pipelineLayout);
static void destroyShaderModule(WGPUShaderModule& shaderModule);
static void destroyRenderPipeline(WGPURenderPipeline& renderPipeline);
};
#endif // _TVG_WG_COMMON_H_

View file

@ -1,73 +0,0 @@
/*
* 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 "tvgWgPipelineBase.h"
/************************************************************************/
// WgPipelineData
/************************************************************************/
void WgPipelineData::updateMatrix(const float* viewMatrix, const RenderTransform* transform) {
float modelMatrix[16]{};
if (transform) {
modelMatrix[0] = transform->m.e11;
modelMatrix[1] = transform->m.e21;
modelMatrix[3] = transform->m.e31;
modelMatrix[4] = transform->m.e12;
modelMatrix[5] = transform->m.e22;
modelMatrix[7] = transform->m.e32;
modelMatrix[10] = 1.0f;
modelMatrix[12] = transform->m.e13;
modelMatrix[13] = transform->m.e23;
modelMatrix[15] = transform->m.e33;
} else {
modelMatrix[0] = 1.0f;
modelMatrix[5] = 1.0f;
modelMatrix[10] = 1.0f;
modelMatrix[15] = 1.0f;
}
// matrix multiply
for(auto i = 0; i < 4; ++i) {
for(auto j = 0; j < 4; ++j) {
float sum = 0.0;
for (auto k = 0; k < 4; ++k)
sum += viewMatrix[k*4+i] * modelMatrix[j*4+k];
uMatrix.transform[j*4+i] = sum;
}
}
}
/************************************************************************/
// WgPipelineBindGroup
/************************************************************************/
void WgPipelineBindGroup::bind(WGPURenderPassEncoder renderPassEncoder, uint32_t groupIndex) {
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, groupIndex, mBindGroup, 0, nullptr);
}
/************************************************************************/
// WgPipelinePipeline
/************************************************************************/
void WgPipelineBase::set(WGPURenderPassEncoder renderPassEncoder) {
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, mRenderPipeline);
}

View file

@ -1,56 +0,0 @@
/*
* 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_BASE_H_
#define _TVG_WG_PIPELINE_BASE_H_
#include "tvgWgCommon.h"
struct WgPipelineMatrix {
float transform[4*4]{};
};
struct WgPipelineData {
WgPipelineMatrix uMatrix{}; // @binding(0)
void updateMatrix(const float* viewMatrix, const RenderTransform* transform);
};
struct WgPipelineBindGroup {
WGPUBuffer uBufferMatrix{};
WGPUBindGroup mBindGroup{};
void bind(WGPURenderPassEncoder renderPassEncoder, uint32_t groupIndex);
};
class WgPipelineBase {
public:
WGPUBindGroupLayout mBindGroupLayout{}; // @group(0)
WGPUPipelineLayout mPipelineLayout{};
WGPUShaderModule mShaderModule{};
WGPURenderPipeline mRenderPipeline{};
public:
virtual void initialize(WGPUDevice device) = 0;
virtual void release() = 0;
void set(WGPURenderPassEncoder renderPassEncoder);
};
#endif // _TVG_WG_PIPELINE_BASE_H_

View file

@ -1,243 +0,0 @@
/*
* 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 "tvgWgPipelineEmpty.h"
#include "tvgWgShaderSrc.h"
//************************************************************************
// WgPipelineBindGroupEmpty
//************************************************************************
void WgPipelineBindGroupEmpty::initialize(WGPUDevice device, WgPipelineEmpty& pipelinePipelineEmpty) {
// buffer uniform uMatrix
WGPUBufferDescriptor bufferUniformDesc_uMatrix{};
bufferUniformDesc_uMatrix.nextInChain = nullptr;
bufferUniformDesc_uMatrix.label = "Buffer uniform pipeline empty uMatrix";
bufferUniformDesc_uMatrix.usage = WGPUBufferUsage_CopyDst | WGPUBufferUsage_Uniform;
bufferUniformDesc_uMatrix.size = sizeof(WgPipelineMatrix);
bufferUniformDesc_uMatrix.mappedAtCreation = false;
uBufferMatrix = wgpuDeviceCreateBuffer(device, &bufferUniformDesc_uMatrix);
assert(uBufferMatrix);
// 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 entries
WGPUBindGroupEntry bindGroupEntries[] {
bindGroupEntry_uMatrix // @binding(0) uMatrix
};
// bind group descriptor
WGPUBindGroupDescriptor bindGroupDescPipeline{};
bindGroupDescPipeline.nextInChain = nullptr;
bindGroupDescPipeline.label = "The binding group pipeline empty";
bindGroupDescPipeline.layout = pipelinePipelineEmpty.mBindGroupLayout;
bindGroupDescPipeline.entryCount = 1;
bindGroupDescPipeline.entries = bindGroupEntries;
mBindGroup = wgpuDeviceCreateBindGroup(device, &bindGroupDescPipeline);
assert(mBindGroup);
}
void WgPipelineBindGroupEmpty::release() {
if (uBufferMatrix) {
wgpuBufferDestroy(uBufferMatrix);
wgpuBufferRelease(uBufferMatrix);
uBufferMatrix = nullptr;
}
if (mBindGroup) {
wgpuBindGroupRelease(mBindGroup);
mBindGroup = nullptr;
}
}
void WgPipelineBindGroupEmpty::update(WGPUQueue queue, WgPipelineDataEmpty& pipelineDataEmpty) {
wgpuQueueWriteBuffer(queue, uBufferMatrix, 0, &pipelineDataEmpty.uMatrix, sizeof(pipelineDataEmpty.uMatrix));
}
//************************************************************************
// WgPipelineEmpty
//************************************************************************
void WgPipelineEmpty::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 entries @group(0)
WGPUBindGroupLayoutEntry bindGroupLayoutEntries[] {
bindGroupLayoutEntry_uMatrix
};
// bind group layout descriptor scene @group(0)
WGPUBindGroupLayoutDescriptor bindGroupLayoutDesc{};
bindGroupLayoutDesc.nextInChain = nullptr;
bindGroupLayoutDesc.label = "Bind group layout pipeline empty";
bindGroupLayoutDesc.entryCount = 1;
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 empty";
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_Always;
depthStencilState.stencilFront.failOp = WGPUStencilOperation_Invert;
depthStencilState.stencilFront.depthFailOp = WGPUStencilOperation_Invert;
depthStencilState.stencilFront.passOp = WGPUStencilOperation_Invert;
// depthStencilState.stencilBack
depthStencilState.stencilBack.compare = WGPUCompareFunction_Always;
depthStencilState.stencilBack.failOp = WGPUStencilOperation_Invert;
depthStencilState.stencilBack.depthFailOp = WGPUStencilOperation_Invert;
depthStencilState.stencilBack.passOp = WGPUStencilOperation_Invert;
// 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_PipelineEmpty;
// shader module descriptor
WGPUShaderModuleDescriptor shaderModuleDesc{};
shaderModuleDesc.nextInChain = &shaderModuleWGSLDesc.chain;
shaderModuleDesc.label = "The shader module pipeline empty";
shaderModuleDesc.hintCount = 0;
shaderModuleDesc.hints = nullptr;
mShaderModule = wgpuDeviceCreateShaderModule(device, &shaderModuleDesc);
assert(mShaderModule);
// vertex attributes
WGPUVertexAttribute vertexAttributes[] = {
{ WGPUVertexFormat_Float32x2, sizeof(float) * 0, 0 }, // position
};
// vertex buffer layout
WGPUVertexBufferLayout vertexBufferLayout{};
vertexBufferLayout.arrayStride = sizeof(float) * 2; // 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 empty";
// 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 WgPipelineEmpty::release() {
wgpuRenderPipelineRelease(mRenderPipeline);
wgpuShaderModuleRelease(mShaderModule);
wgpuPipelineLayoutRelease(mPipelineLayout);
wgpuBindGroupLayoutRelease(mBindGroupLayout);
}

View file

@ -1,63 +0,0 @@
/*
* 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_EMPTY_H_
#define _TVG_WG_PIPELINE_EMPTY_H_
#include "tvgWgPipelineBase.h"
class WgPipelineEmpty;
struct WgPipelineDataEmpty: WgPipelineData {};
class WgPipelineBindGroupEmpty: public WgPipelineBindGroup {
public:
void initialize(WGPUDevice device, WgPipelineEmpty& pipelinePipelineEmpty);
void release();
void update(WGPUQueue mQueue, WgPipelineDataEmpty& pipelineDataSolid);
};
/*
* This pipeline is used for drawing filled, concave polygons using the stencil buffer
* This can be done using the stencil buffer, with a two-pass algorithm.
*
* First, clear the stencil buffer and disable writing into the color buffer. Next, draw each of the triangles in turn, using the INVERT function in the stencil buffer. (For best performance, use triangle fans.)
* This flips the value between zero and a nonzero value every time a triangle is drawn that covers a pixel.
*
* After all the triangles are drawn, if a pixel is covered an even number of times, the value in the stencil buffers is zero; otherwise, it's nonzero.
* Finally, draw a large polygon over the whole region (or redraw the triangles), but allow drawing only where the stencil buffer is nonzero.
*
* There is a link to the solution, how to draw filled, concave polygons using the stencil buffer:
* https://www.glprogramming.com/red/chapter14.html#name13
*
* The benefit of this solution is to don`t use complex tesselation to fill self intersected or concave poligons.
*
* This pipeline implements the first pass of this solution. It`s did not write anything into color buffer but fills the stencil buffer using invert strategy
*/
class WgPipelineEmpty: public WgPipelineBase {
public:
void initialize(WGPUDevice device) override;
void release() override;
};
#endif // _TVG_WG_PIPELINE_EMPTY_H_

View file

@ -1,415 +0,0 @@
/*
* 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 "tvgWgPipelineImage.h"
#include "tvgWgShaderSrc.h"
//************************************************************************
// WgPipelineDataImage
//************************************************************************
void WgPipelineDataImage::updateFormat(const ColorSpace format) {
uColorInfo.format = (uint32_t)format;
}
void WgPipelineDataImage::updateOpacity(const uint8_t opacity) {
uColorInfo.opacity = opacity / 255.0f; // alpha
}
//************************************************************************
// WgPipelineBindGroupImage
//************************************************************************
void WgPipelineBindGroupImage::initialize(WGPUDevice device, WgPipelineImage& pipelineImage, Surface* surface) {
// buffer uniform uMatrix
WGPUBufferDescriptor bufferUniformDesc_uMatrix{};
bufferUniformDesc_uMatrix.nextInChain = nullptr;
bufferUniformDesc_uMatrix.label = "Buffer uniform pipeline image 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_uColorInfo{};
bufferUniformDesc_uColorInfo.nextInChain = nullptr;
bufferUniformDesc_uColorInfo.label = "Buffer uniform pipeline image uColorInfo";
bufferUniformDesc_uColorInfo.usage = WGPUBufferUsage_CopyDst | WGPUBufferUsage_Uniform;
bufferUniformDesc_uColorInfo.size = sizeof(WgPipelineImageColorInfo);
bufferUniformDesc_uColorInfo.mappedAtCreation = false;
uBufferColorInfo = wgpuDeviceCreateBuffer(device, &bufferUniformDesc_uColorInfo);
assert(uBufferColorInfo);
// sampler uniform uSamplerBase
WGPUSamplerDescriptor samplerDesc_uSamplerBase{};
samplerDesc_uSamplerBase.nextInChain = nullptr;
samplerDesc_uSamplerBase.label = "Sampler uniform pipeline image uSamplerBase";
samplerDesc_uSamplerBase.addressModeU = WGPUAddressMode_ClampToEdge;
samplerDesc_uSamplerBase.addressModeV = WGPUAddressMode_ClampToEdge;
samplerDesc_uSamplerBase.addressModeW = WGPUAddressMode_ClampToEdge;
samplerDesc_uSamplerBase.magFilter = WGPUFilterMode_Nearest;
samplerDesc_uSamplerBase.minFilter = WGPUFilterMode_Nearest;
samplerDesc_uSamplerBase.mipmapFilter = WGPUMipmapFilterMode_Nearest;
samplerDesc_uSamplerBase.lodMinClamp = 0.0f;
samplerDesc_uSamplerBase.lodMaxClamp = 32.0f;
samplerDesc_uSamplerBase.compare = WGPUCompareFunction_Undefined;
samplerDesc_uSamplerBase.maxAnisotropy = 1;
uSamplerBase = wgpuDeviceCreateSampler(device, &samplerDesc_uSamplerBase);
assert(uSamplerBase);
// webgpu texture data holder
WGPUTextureDescriptor textureDesc{};
textureDesc.nextInChain = nullptr;
textureDesc.label = "Texture base pipeline image";
textureDesc.usage = WGPUTextureUsage_TextureBinding | WGPUTextureUsage_CopyDst;
textureDesc.dimension = WGPUTextureDimension_2D;
textureDesc.size = { surface->w, surface->h, 1 };
textureDesc.format = WGPUTextureFormat_RGBA8Unorm;
textureDesc.mipLevelCount = 1;
textureDesc.sampleCount = 1;
textureDesc.viewFormatCount = 0;
textureDesc.viewFormats = nullptr;
mTextureBase = wgpuDeviceCreateTexture(device, &textureDesc);
assert(mTextureBase);
// texture view uniform uTextureViewBase
WGPUTextureViewDescriptor textureViewDesc{};
textureViewDesc.nextInChain = nullptr;
textureViewDesc.label = "The depth-stencil texture view";
textureViewDesc.format = WGPUTextureFormat_RGBA8Unorm;
textureViewDesc.dimension = WGPUTextureViewDimension_2D;
textureViewDesc.baseMipLevel = 0;
textureViewDesc.mipLevelCount = 1;
textureViewDesc.baseArrayLayer = 0;
textureViewDesc.arrayLayerCount = 1;
textureViewDesc.aspect = WGPUTextureAspect_All;
uTextureViewBase = wgpuTextureCreateView(mTextureBase, &textureViewDesc);
assert(uTextureViewBase);
// 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) uColorInfo
WGPUBindGroupEntry bindGroupEntry_uColorInfo{};
bindGroupEntry_uColorInfo.nextInChain = nullptr;
bindGroupEntry_uColorInfo.binding = 1;
bindGroupEntry_uColorInfo.buffer = uBufferColorInfo;
bindGroupEntry_uColorInfo.offset = 0;
bindGroupEntry_uColorInfo.size = sizeof(WgPipelineImageColorInfo);
bindGroupEntry_uColorInfo.sampler = nullptr;
bindGroupEntry_uColorInfo.textureView = nullptr;
// bind group entry @binding(2) uSamplerBase
WGPUBindGroupEntry bindGroupEntry_uSamplerBase{};
bindGroupEntry_uSamplerBase.nextInChain = nullptr;
bindGroupEntry_uSamplerBase.binding = 2;
bindGroupEntry_uSamplerBase.buffer = nullptr;
bindGroupEntry_uSamplerBase.offset = 0;
bindGroupEntry_uSamplerBase.size = 0;
bindGroupEntry_uSamplerBase.sampler = uSamplerBase;
bindGroupEntry_uSamplerBase.textureView = nullptr;
// bind group entry @binding(3) uTextureViewBase
WGPUBindGroupEntry bindGroupEntry_uTextureViewBase{};
bindGroupEntry_uTextureViewBase.nextInChain = nullptr;
bindGroupEntry_uTextureViewBase.binding = 3;
bindGroupEntry_uTextureViewBase.buffer = nullptr;
bindGroupEntry_uTextureViewBase.offset = 0;
bindGroupEntry_uTextureViewBase.size = 0;
bindGroupEntry_uTextureViewBase.sampler = nullptr;
bindGroupEntry_uTextureViewBase.textureView = uTextureViewBase;
// bind group entries
WGPUBindGroupEntry bindGroupEntries[] {
bindGroupEntry_uMatrix, // @binding(0) uMatrix
bindGroupEntry_uColorInfo, // @binding(1) uColorInfo
bindGroupEntry_uSamplerBase, // @binding(2) uSamplerBase
bindGroupEntry_uTextureViewBase // @binding(3) uTextureViewBase
};
// bind group descriptor
WGPUBindGroupDescriptor bindGroupDescPipeline{};
bindGroupDescPipeline.nextInChain = nullptr;
bindGroupDescPipeline.label = "The binding group pipeline image";
bindGroupDescPipeline.layout = pipelineImage.mBindGroupLayout;
bindGroupDescPipeline.entryCount = 4;
bindGroupDescPipeline.entries = bindGroupEntries;
mBindGroup = wgpuDeviceCreateBindGroup(device, &bindGroupDescPipeline);
assert(mBindGroup);
}
void WgPipelineBindGroupImage::release() {
if (uTextureViewBase) {
wgpuTextureViewRelease(uTextureViewBase);
uTextureViewBase = nullptr;
}
if (mTextureBase) {
wgpuTextureDestroy(mTextureBase);
wgpuTextureRelease(mTextureBase);
mTextureBase = nullptr;
}
if (uSamplerBase) {
wgpuSamplerRelease(uSamplerBase);
uSamplerBase = nullptr;
}
if (uBufferColorInfo) {
wgpuBufferDestroy(uBufferColorInfo);
wgpuBufferRelease(uBufferColorInfo);
uBufferColorInfo = nullptr;
}
if (uBufferMatrix) {
wgpuBufferDestroy(uBufferMatrix);
wgpuBufferRelease(uBufferMatrix);
uBufferMatrix = nullptr;
}
if (mBindGroup) {
wgpuBindGroupRelease(mBindGroup);
mBindGroup = nullptr;
}
}
void WgPipelineBindGroupImage::update(WGPUQueue queue, WgPipelineDataImage& pipelineDataImage, Surface* surface) {
wgpuQueueWriteBuffer(queue, uBufferMatrix, 0, &pipelineDataImage.uMatrix, sizeof(pipelineDataImage.uMatrix));
wgpuQueueWriteBuffer(queue, uBufferColorInfo, 0, &pipelineDataImage.uColorInfo, sizeof(pipelineDataImage.uColorInfo));
WGPUImageCopyTexture imageCopyTexture{};
imageCopyTexture.nextInChain = nullptr;
imageCopyTexture.texture = mTextureBase;
imageCopyTexture.mipLevel = 0;
imageCopyTexture.origin = { 0, 0, 0 };
imageCopyTexture.aspect = WGPUTextureAspect_All;
WGPUTextureDataLayout textureDataLayout{};
textureDataLayout.nextInChain = nullptr;
textureDataLayout.offset = 0;
textureDataLayout.bytesPerRow = 4 * surface->w;
textureDataLayout.rowsPerImage = surface->h;
WGPUExtent3D writeSize{};
writeSize.width = surface->w;
writeSize.height = surface->h;
writeSize.depthOrArrayLayers = 1;
wgpuQueueWriteTexture(queue, &imageCopyTexture, surface->data, 4 * surface->w * surface->h, &textureDataLayout, &writeSize);
}
//************************************************************************
// WgPipelineImage
//************************************************************************
void WgPipelineImage::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 descriptor @group(0) @binding(2) uSamplerBase
WGPUBindGroupLayoutEntry bindGroupLayoutEntry_uSamplerBase{};
bindGroupLayoutEntry_uSamplerBase.nextInChain = nullptr;
bindGroupLayoutEntry_uSamplerBase.binding = 2;
bindGroupLayoutEntry_uSamplerBase.visibility = WGPUShaderStage_Fragment;
bindGroupLayoutEntry_uSamplerBase.sampler.nextInChain = nullptr;
bindGroupLayoutEntry_uSamplerBase.sampler.type = WGPUSamplerBindingType_Filtering;
// bind group layout descriptor @group(0) @binding(3) uTextureViewBase
WGPUBindGroupLayoutEntry bindGroupLayoutEntry_uTextureViewBase{};
bindGroupLayoutEntry_uTextureViewBase.nextInChain = nullptr;
bindGroupLayoutEntry_uTextureViewBase.binding = 3;
bindGroupLayoutEntry_uTextureViewBase.visibility = WGPUShaderStage_Fragment;
bindGroupLayoutEntry_uTextureViewBase.texture.nextInChain = nullptr;
bindGroupLayoutEntry_uTextureViewBase.texture.sampleType = WGPUTextureSampleType_Float;
bindGroupLayoutEntry_uTextureViewBase.texture.viewDimension = WGPUTextureViewDimension_2D;
bindGroupLayoutEntry_uTextureViewBase.texture.multisampled = false;
// bind group layout entries @group(0)
WGPUBindGroupLayoutEntry bindGroupLayoutEntries[] {
bindGroupLayoutEntry_uMatrix,
bindGroupLayoutEntry_uColorInfo,
bindGroupLayoutEntry_uSamplerBase,
bindGroupLayoutEntry_uTextureViewBase
};
// bind group layout descriptor scene @group(0)
WGPUBindGroupLayoutDescriptor bindGroupLayoutDesc{};
bindGroupLayoutDesc.nextInChain = nullptr;
bindGroupLayoutDesc.label = "Bind group layout pipeline image";
bindGroupLayoutDesc.entryCount = 4;
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 image";
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_Always;
depthStencilState.stencilFront.failOp = WGPUStencilOperation_Zero;
depthStencilState.stencilFront.depthFailOp = WGPUStencilOperation_Zero;
depthStencilState.stencilFront.passOp = WGPUStencilOperation_Zero;
// depthStencilState.stencilBack
depthStencilState.stencilBack.compare = WGPUCompareFunction_Always;
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_PipelineImage;
// shader module descriptor
WGPUShaderModuleDescriptor shaderModuleDesc{};
shaderModuleDesc.nextInChain = &shaderModuleWGSLDesc.chain;
shaderModuleDesc.label = "The shader module pipeline image";
shaderModuleDesc.hintCount = 0;
shaderModuleDesc.hints = nullptr;
mShaderModule = wgpuDeviceCreateShaderModule(device, &shaderModuleDesc);
assert(mShaderModule);
// vertex attributes
WGPUVertexAttribute vertexAttributesPos[] = {
{ WGPUVertexFormat_Float32x2, sizeof(float) * 0, 0 } // position
};
// vertex buffer layout position
WGPUVertexBufferLayout vertexBufferLayoutPos{};
vertexBufferLayoutPos.arrayStride = sizeof(float) * 2; // position
vertexBufferLayoutPos.stepMode = WGPUVertexStepMode_Vertex;
vertexBufferLayoutPos.attributeCount = 1; // position
vertexBufferLayoutPos.attributes = vertexAttributesPos;
// vertex attributes
WGPUVertexAttribute vertexAttributesTex[] = {
{ WGPUVertexFormat_Float32x2, sizeof(float) * 0, 1 } // tex coords
};
// vertex buffer layout tex coords
WGPUVertexBufferLayout vertexBufferLayoutTex{};
vertexBufferLayoutTex.arrayStride = sizeof(float) * 2; // tex coords
vertexBufferLayoutTex.stepMode = WGPUVertexStepMode_Vertex;
vertexBufferLayoutTex.attributeCount = 1; // tex coords
vertexBufferLayoutTex.attributes = vertexAttributesTex;
// vertex attributes
WGPUVertexBufferLayout vertexBufferLayouts[] = {
vertexBufferLayoutPos,
vertexBufferLayoutTex
};
// 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 image";
// 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 = 2;
renderPipelineDesc.vertex.buffers = vertexBufferLayouts; // 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 WgPipelineImage::release() {
wgpuRenderPipelineRelease(mRenderPipeline);
wgpuShaderModuleRelease(mShaderModule);
wgpuPipelineLayoutRelease(mPipelineLayout);
wgpuBindGroupLayoutRelease(mBindGroupLayout);
}

View file

@ -1,63 +0,0 @@
/*
* 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_IMAGE_H_
#define _TVG_WG_PIPELINE_IMAGE_H_
#include "tvgWgPipelineBase.h"
class WgPipelineImage;
struct WgPipelineImageColorInfo {
uint32_t format{};
float dummy0{};
float dummy1{};
float opacity{};
};
struct WgPipelineDataImage: WgPipelineData {
WgPipelineImageColorInfo uColorInfo{}; // @binding(1)
void updateFormat(const ColorSpace format);
void updateOpacity(const uint8_t opacity);
};
class WgPipelineBindGroupImage: public WgPipelineBindGroup {
private:
WGPUBuffer uBufferColorInfo{}; // @binding(1)
WGPUSampler uSamplerBase{}; // @binding(2)
WGPUTextureView uTextureViewBase{}; // @binding(3)
WGPUTexture mTextureBase{}; // gpu texture data
public:
void initialize(WGPUDevice device, WgPipelineImage& pipelineImage, Surface* surface);
void release();
void update(WGPUQueue mQueue, WgPipelineDataImage& pipelineDataImage, Surface* surface);
};
class WgPipelineImage: public WgPipelineBase {
public:
void initialize(WGPUDevice device) override;
void release() override;
};
#endif //_TVG_WG_PIPELINE_IMAGE_H_

View file

@ -1,305 +0,0 @@
/*
* 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_Float32x2, sizeof(float) * 0, 0 }, // position
};
// vertex buffer layout
WGPUVertexBufferLayout vertexBufferLayout{};
vertexBufferLayout.arrayStride = sizeof(float) * 2; // 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);
}

View file

@ -1,61 +0,0 @@
/*
* 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_

View file

@ -1,303 +0,0 @@
/*
* 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 "tvgWgPipelineRadial.h"
#include "tvgWgShaderSrc.h"
//************************************************************************
// WgPipelineBindGroupRadial
//************************************************************************
void WgPipelineDataRadial::updateGradient(RadialGradient* radialGradient) {
const Fill::ColorStop* stops = nullptr;
auto stopCnt = radialGradient->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;
}
radialGradient->radial(
&uGradientInfo.centerPos[0],
&uGradientInfo.centerPos[1],
&uGradientInfo.radius[0]);
}
//************************************************************************
// WgPipelineBindGroupRadial
//************************************************************************
void WgPipelineBindGroupRadial::initialize(WGPUDevice device, WgPipelineRadial& pipelinePipelineRadial) {
// buffer uniform uMatrix
WGPUBufferDescriptor bufferUniformDesc_uMatrix{};
bufferUniformDesc_uMatrix.nextInChain = nullptr;
bufferUniformDesc_uMatrix.label = "Buffer uniform pipeline radial 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 radial uGradientInfo";
bufferUniformDesc_uGradientInfo.usage = WGPUBufferUsage_CopyDst | WGPUBufferUsage_Uniform;
bufferUniformDesc_uGradientInfo.size = sizeof(WgPipelineRadialGradientInfo);
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(WgPipelineRadialGradientInfo);
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 radial";
bindGroupDescPipeline.layout = pipelinePipelineRadial.mBindGroupLayout;
bindGroupDescPipeline.entryCount = 2;
bindGroupDescPipeline.entries = bindGroupEntries;
mBindGroup = wgpuDeviceCreateBindGroup(device, &bindGroupDescPipeline);
assert(mBindGroup);
}
void WgPipelineBindGroupRadial::release() {
if (uBufferGradientInfo) {
wgpuBufferDestroy(uBufferGradientInfo);
wgpuBufferRelease(uBufferGradientInfo);
uBufferGradientInfo = nullptr;
}
if (uBufferMatrix) {
wgpuBufferDestroy(uBufferMatrix);
wgpuBufferRelease(uBufferMatrix);
uBufferMatrix = nullptr;
}
if (mBindGroup) {
wgpuBindGroupRelease(mBindGroup);
mBindGroup = nullptr;
}
}
void WgPipelineBindGroupRadial::update(WGPUQueue queue, WgPipelineDataRadial& pipelineDataRadial) {
wgpuQueueWriteBuffer(queue, uBufferMatrix, 0, &pipelineDataRadial.uMatrix, sizeof(pipelineDataRadial.uMatrix));
wgpuQueueWriteBuffer(queue, uBufferGradientInfo, 0, &pipelineDataRadial.uGradientInfo, sizeof(pipelineDataRadial.uGradientInfo));
}
//************************************************************************
// WgPipelineRadial
//************************************************************************
void WgPipelineRadial::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 radial";
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 radial";
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_PipelineRadial;
// shader module descriptor
WGPUShaderModuleDescriptor shaderModuleDesc{};
shaderModuleDesc.nextInChain = &shaderModuleWGSLDesc.chain;
shaderModuleDesc.label = "The shader module pipeline radial";
shaderModuleDesc.hintCount = 0;
shaderModuleDesc.hints = nullptr;
mShaderModule = wgpuDeviceCreateShaderModule(device, &shaderModuleDesc);
assert(mShaderModule);
// vertex attributes
WGPUVertexAttribute vertexAttributes[] = {
{ WGPUVertexFormat_Float32x2, sizeof(float) * 0, 0 }, // position
};
// vertex buffer layout
WGPUVertexBufferLayout vertexBufferLayout{};
vertexBufferLayout.arrayStride = sizeof(float) * 2; // 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 radial";
// 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 WgPipelineRadial::release() {
wgpuRenderPipelineRelease(mRenderPipeline);
wgpuShaderModuleRelease(mShaderModule);
wgpuPipelineLayoutRelease(mPipelineLayout);
wgpuBindGroupLayoutRelease(mBindGroupLayout);
}

View file

@ -1,61 +0,0 @@
/*
* 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_RADIAL_H_
#define _TVG_WG_PIPELINE_RADIAL_H_
#include "tvgWgPipelineBase.h"
class WgPipelineRadial;
#define MAX_RADIAL_GRADIENT_STOPS 4
struct WgPipelineRadialGradientInfo {
alignas(16) float nStops[4]{};
alignas(16) float centerPos[2]{};
alignas(8) float radius[2]{};
alignas(8) float stopPoints[MAX_RADIAL_GRADIENT_STOPS]{};
alignas(16) float stopColors[4 * MAX_RADIAL_GRADIENT_STOPS]{};
};
struct WgPipelineDataRadial: WgPipelineData {
WgPipelineRadialGradientInfo uGradientInfo{}; // @binding(1)
void updateGradient(RadialGradient* radialGradient);
};
class WgPipelineBindGroupRadial: public WgPipelineBindGroup {
private:
WGPUBuffer uBufferGradientInfo{}; // @binding(1)
public:
void initialize(WGPUDevice device, WgPipelineRadial& pipelinePipelineRadial);
void release();
void update(WGPUQueue mQueue, WgPipelineDataRadial& pipelineDataRadial);
};
class WgPipelineRadial: public WgPipelineBase {
public:
void initialize(WGPUDevice device) override;
void release() override;
};
#endif //_TVG_WG_PIPELINE_RADIAL_H_

View file

@ -1,289 +0,0 @@
/*
* 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 "tvgWgPipelineSolid.h"
#include "tvgWgShaderSrc.h"
//************************************************************************
// WgPipelineDataSolid
//************************************************************************
void WgPipelineDataSolid::updateColor(const uint8_t* color) {
uColorInfo.color[0] = color[0] / 255.0f; // red
uColorInfo.color[1] = color[1] / 255.0f; // green
uColorInfo.color[2] = color[2] / 255.0f; // blue
uColorInfo.color[3] = color[3] / 255.0f; // alpha
}
//************************************************************************
// WgPipelineBindGroupSolid
//************************************************************************
void WgPipelineBindGroupSolid::initialize(WGPUDevice device, WgPipelineSolid& pipelinePipelineSolid) {
// buffer uniform uMatrix
WGPUBufferDescriptor bufferUniformDesc_uMatrix{};
bufferUniformDesc_uMatrix.nextInChain = nullptr;
bufferUniformDesc_uMatrix.label = "Buffer uniform pipeline solid 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_uColorInfo{};
bufferUniformDesc_uColorInfo.nextInChain = nullptr;
bufferUniformDesc_uColorInfo.label = "Buffer uniform pipeline solid uColorInfo";
bufferUniformDesc_uColorInfo.usage = WGPUBufferUsage_CopyDst | WGPUBufferUsage_Uniform;
bufferUniformDesc_uColorInfo.size = sizeof(WgPipelineSolidColorInfo);
bufferUniformDesc_uColorInfo.mappedAtCreation = false;
uBufferColorInfo = wgpuDeviceCreateBuffer(device, &bufferUniformDesc_uColorInfo);
assert(uBufferColorInfo);
// 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) uColorInfo
WGPUBindGroupEntry bindGroupEntry_uColorInfo{};
bindGroupEntry_uColorInfo.nextInChain = nullptr;
bindGroupEntry_uColorInfo.binding = 1;
bindGroupEntry_uColorInfo.buffer = uBufferColorInfo;
bindGroupEntry_uColorInfo.offset = 0;
bindGroupEntry_uColorInfo.size = sizeof(WgPipelineSolidColorInfo);
bindGroupEntry_uColorInfo.sampler = nullptr;
bindGroupEntry_uColorInfo.textureView = nullptr;
// bind group entries
WGPUBindGroupEntry bindGroupEntries[] {
bindGroupEntry_uMatrix, // @binding(0) uMatrix
bindGroupEntry_uColorInfo // @binding(1) uColorInfo
};
// bind group descriptor
WGPUBindGroupDescriptor bindGroupDescPipeline{};
bindGroupDescPipeline.nextInChain = nullptr;
bindGroupDescPipeline.label = "The binding group pipeline solid";
bindGroupDescPipeline.layout = pipelinePipelineSolid.mBindGroupLayout;
bindGroupDescPipeline.entryCount = 2;
bindGroupDescPipeline.entries = bindGroupEntries;
mBindGroup = wgpuDeviceCreateBindGroup(device, &bindGroupDescPipeline);
assert(mBindGroup);
}
void WgPipelineBindGroupSolid::release() {
if (uBufferColorInfo) {
wgpuBufferDestroy(uBufferColorInfo);
wgpuBufferRelease(uBufferColorInfo);
uBufferColorInfo = nullptr;
}
if (uBufferMatrix) {
wgpuBufferDestroy(uBufferMatrix);
wgpuBufferRelease(uBufferMatrix);
uBufferMatrix = nullptr;
}
if (mBindGroup) {
wgpuBindGroupRelease(mBindGroup);
mBindGroup = nullptr;
}
}
void WgPipelineBindGroupSolid::update(WGPUQueue queue, WgPipelineDataSolid& pipelineDataSolid) {
wgpuQueueWriteBuffer(queue, uBufferMatrix, 0, &pipelineDataSolid.uMatrix, sizeof(pipelineDataSolid.uMatrix));
wgpuQueueWriteBuffer(queue, uBufferColorInfo, 0, &pipelineDataSolid.uColorInfo, sizeof(pipelineDataSolid.uColorInfo));
}
//************************************************************************
// WgPipelineSolid
//************************************************************************
void WgPipelineSolid::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 solid";
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 solid";
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_PipelineSolid;
// shader module descriptor
WGPUShaderModuleDescriptor shaderModuleDesc{};
shaderModuleDesc.nextInChain = &shaderModuleWGSLDesc.chain;
shaderModuleDesc.label = "The shader module pipeline solid";
shaderModuleDesc.hintCount = 0;
shaderModuleDesc.hints = nullptr;
mShaderModule = wgpuDeviceCreateShaderModule(device, &shaderModuleDesc);
assert(mShaderModule);
// vertex attributes
WGPUVertexAttribute vertexAttributes[] = {
{ WGPUVertexFormat_Float32x2, sizeof(float) * 0, 0 }, // position
};
// vertex buffer layout
WGPUVertexBufferLayout vertexBufferLayout{};
vertexBufferLayout.arrayStride = sizeof(float) * 2; // 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 solid";
// 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 WgPipelineSolid::release() {
wgpuRenderPipelineRelease(mRenderPipeline);
wgpuShaderModuleRelease(mShaderModule);
wgpuPipelineLayoutRelease(mPipelineLayout);
wgpuBindGroupLayoutRelease(mBindGroupLayout);
}

View file

@ -1,56 +0,0 @@
/*
* 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_SOLID_H_
#define _TVG_WG_PIPELINE_SOLID_H_
#include "tvgWgPipelineBase.h"
class WgPipelineSolid;
struct WgPipelineSolidColorInfo {
float color[4]{};
};
struct WgPipelineDataSolid: WgPipelineData {
WgPipelineSolidColorInfo uColorInfo{}; // @binding(1)
void updateColor(const uint8_t* color);
};
class WgPipelineBindGroupSolid: public WgPipelineBindGroup {
private:
WGPUBuffer uBufferColorInfo{}; // @binding(1)
public:
void initialize(WGPUDevice device, WgPipelineSolid& pipelinePipelineSolid);
void release();
void update(WGPUQueue mQueue, WgPipelineDataSolid& pipelineDataSolid);
};
class WgPipelineSolid: public WgPipelineBase {
public:
void initialize(WGPUDevice device) override;
void release() override;
};
#endif //_TVG_WG_PIPELINE_SOLID_H_

View file

@ -1,243 +0,0 @@
/*
* 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 "tvgWgPipelineStroke.h"
#include "tvgWgShaderSrc.h"
//************************************************************************
// WgPipelineBindGroupStroke
//************************************************************************
void WgPipelineBindGroupStroke::initialize(WGPUDevice device, WgPipelineStroke& pipelinePipelineStroke) {
// buffer uniform uMatrix
WGPUBufferDescriptor bufferUniformDesc_uMatrix{};
bufferUniformDesc_uMatrix.nextInChain = nullptr;
bufferUniformDesc_uMatrix.label = "Buffer uniform pipeline Stroke uMatrix";
bufferUniformDesc_uMatrix.usage = WGPUBufferUsage_CopyDst | WGPUBufferUsage_Uniform;
bufferUniformDesc_uMatrix.size = sizeof(WgPipelineMatrix);
bufferUniformDesc_uMatrix.mappedAtCreation = false;
uBufferMatrix = wgpuDeviceCreateBuffer(device, &bufferUniformDesc_uMatrix);
assert(uBufferMatrix);
// 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 entries
WGPUBindGroupEntry bindGroupEntries[] {
bindGroupEntry_uMatrix // @binding(0) uMatrix
};
// bind group descriptor
WGPUBindGroupDescriptor bindGroupDescPipeline{};
bindGroupDescPipeline.nextInChain = nullptr;
bindGroupDescPipeline.label = "The binding group pipeline stroke";
bindGroupDescPipeline.layout = pipelinePipelineStroke.mBindGroupLayout;
bindGroupDescPipeline.entryCount = 1;
bindGroupDescPipeline.entries = bindGroupEntries;
mBindGroup = wgpuDeviceCreateBindGroup(device, &bindGroupDescPipeline);
assert(mBindGroup);
}
void WgPipelineBindGroupStroke::release() {
if (uBufferMatrix) {
wgpuBufferDestroy(uBufferMatrix);
wgpuBufferRelease(uBufferMatrix);
uBufferMatrix = nullptr;
}
if (mBindGroup) {
wgpuBindGroupRelease(mBindGroup);
mBindGroup = nullptr;
}
}
void WgPipelineBindGroupStroke::update(WGPUQueue queue, WgPipelineDataStroke& pipelineDataStroke) {
wgpuQueueWriteBuffer(queue, uBufferMatrix, 0, &pipelineDataStroke.uMatrix, sizeof(pipelineDataStroke.uMatrix));
}
//************************************************************************
// WgPipelineStroke
//************************************************************************
void WgPipelineStroke::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 entries @group(0)
WGPUBindGroupLayoutEntry bindGroupLayoutEntries[] {
bindGroupLayoutEntry_uMatrix
};
// bind group layout descriptor scene @group(0)
WGPUBindGroupLayoutDescriptor bindGroupLayoutDesc{};
bindGroupLayoutDesc.nextInChain = nullptr;
bindGroupLayoutDesc.label = "Bind group layout pipeline stroke";
bindGroupLayoutDesc.entryCount = 1;
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 stroke";
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_Always;
depthStencilState.stencilFront.failOp = WGPUStencilOperation_Replace;
depthStencilState.stencilFront.depthFailOp = WGPUStencilOperation_Replace;
depthStencilState.stencilFront.passOp = WGPUStencilOperation_Replace;
// depthStencilState.stencilBack
depthStencilState.stencilBack.compare = WGPUCompareFunction_Always;
depthStencilState.stencilBack.failOp = WGPUStencilOperation_Replace;
depthStencilState.stencilBack.depthFailOp = WGPUStencilOperation_Replace;
depthStencilState.stencilBack.passOp = WGPUStencilOperation_Replace;
// 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_PipelineEmpty;
// shader module descriptor
WGPUShaderModuleDescriptor shaderModuleDesc{};
shaderModuleDesc.nextInChain = &shaderModuleWGSLDesc.chain;
shaderModuleDesc.label = "The shader module pipeline Stroke";
shaderModuleDesc.hintCount = 0;
shaderModuleDesc.hints = nullptr;
mShaderModule = wgpuDeviceCreateShaderModule(device, &shaderModuleDesc);
assert(mShaderModule);
// vertex attributes
WGPUVertexAttribute vertexAttributes[] = {
{ WGPUVertexFormat_Float32x2, sizeof(float) * 0, 0 }, // position
};
// vertex buffer layout
WGPUVertexBufferLayout vertexBufferLayout{};
vertexBufferLayout.arrayStride = sizeof(float) * 2; // 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 stroke";
// 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 WgPipelineStroke::release() {
wgpuRenderPipelineRelease(mRenderPipeline);
wgpuShaderModuleRelease(mShaderModule);
wgpuPipelineLayoutRelease(mPipelineLayout);
wgpuBindGroupLayoutRelease(mBindGroupLayout);
}

View file

@ -1,46 +0,0 @@
/*
* 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_STROKE_H_
#define _TVG_WG_PIPELINE_STROKE_H_
#include "tvgWgPipelineBase.h"
class WgPipelineStroke;
struct WgPipelineDataStroke: WgPipelineData {};
class WgPipelineBindGroupStroke: public WgPipelineBindGroup {
public:
void initialize(WGPUDevice device, WgPipelineStroke& pipelinePipelineStroke);
void release();
void update(WGPUQueue mQueue, WgPipelineDataStroke& pipelineDataSolid);
};
class WgPipelineStroke: public WgPipelineBase {
public:
void initialize(WGPUDevice device) override;
void release() override;
};
#endif // _TVG_WG_PIPELINE_STROKE_H_

View file

@ -0,0 +1,246 @@
/*
* 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 "tvgWgPipelines.h"
#include "tvgWgShaderSrc.h"
#define ARRAY_ELEMENTS_COUNT(arr) sizeof(arr)/sizeof(arr[0])
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
const char* shaderSource = cShaderSource_PipelineFill;
const char* shaderLabel = "The shader fill";
const char* 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
const char* shaderSource = cShaderSource_PipelineFill;
const char* shaderLabel = "The shader fill";
const char* 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
const char* shaderSource = cShaderSource_PipelineSolid;
const char* shaderLabel = "The shader solid color";
const char* 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
const char* shaderSource = cShaderSource_PipelineLinear;
const char* shaderLabel = "The shader linear gradient";
const char* 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
const char* shaderSource = cShaderSource_PipelineRadial;
const char* shaderLabel = "The shader radial gradient";
const char* 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
const char* shaderSource = cShaderSource_PipelineImage;
const char* shaderLabel = "The shader image";
const char* 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);
};
//************************************************************************
// pipelines
//************************************************************************
void WgPipelines::initialize(WGPUDevice device) {
mPipelineFillShape.initialize(device);
mPipelineFillStroke.initialize(device);
mPipelineSolid.initialize(device);
mPipelineLinear.initialize(device);
mPipelineRadial.initialize(device);
mPipelineImage.initialize(device);
}
void WgPipelines::release() {
WgBindGroupCompose::releaseLayout();
WgBindGroupPicture::releaseLayout();
WgBindGroupRadialGradient::releaseLayout();
WgBindGroupLinearGradient::releaseLayout();
WgBindGroupSolidColor::releaseLayout();
WgBindGroupCanvas::releaseLayout();
mPipelineImage.release();
mPipelineRadial.release();
mPipelineLinear.release();
mPipelineSolid.release();
mPipelineFillStroke.release();
mPipelineFillShape.release();
}

View file

@ -0,0 +1,114 @@
/*
* 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_PIPELINES_H_
#define _TVG_WG_PIPELINES_H_
#include "tvgWgBindGroups.h"
struct WgPipelineFillShape: public WgPipeline {
void initialize(WGPUDevice device) override;
void use(WGPURenderPassEncoder encoder,
WgBindGroupCanvas& groupCanvas,
WgBindGroupPaint& groupPaint) {
set(encoder);
groupCanvas.set(encoder, 0);
groupPaint.set(encoder, 1);
}
};
struct WgPipelineFillStroke: public WgPipeline {
void initialize(WGPUDevice device) override;
void use(WGPURenderPassEncoder encoder,
WgBindGroupCanvas& groupCanvas,
WgBindGroupPaint& groupPaint) {
set(encoder);
groupCanvas.set(encoder, 0);
groupPaint.set(encoder, 1);
}
};
struct WgPipelineSolid: public WgPipeline {
void initialize(WGPUDevice device) override;
void use(WGPURenderPassEncoder encoder,
WgBindGroupCanvas& groupCanvas,
WgBindGroupPaint& groupPaint,
WgBindGroupSolidColor& groupSolid) {
set(encoder);
groupCanvas.set(encoder, 0);
groupPaint.set(encoder, 1);
groupSolid.set(encoder, 2);
}
};
struct WgPipelineLinear: public WgPipeline {
void initialize(WGPUDevice device) override;
void use(WGPURenderPassEncoder encoder,
WgBindGroupCanvas& groupCanvas,
WgBindGroupPaint& groupPaint,
WgBindGroupLinearGradient& groupLinear) {
set(encoder);
groupCanvas.set(encoder, 0);
groupPaint.set(encoder, 1);
groupLinear.set(encoder, 2);
}
};
struct WgPipelineRadial: public WgPipeline {
void initialize(WGPUDevice device) override;
void use(WGPURenderPassEncoder encoder,
WgBindGroupCanvas& groupCanvas,
WgBindGroupPaint& groupPaint,
WgBindGroupRadialGradient& groupRadial) {
set(encoder);
groupCanvas.set(encoder, 0);
groupPaint.set(encoder, 1);
groupRadial.set(encoder, 2);
}
};
struct WgPipelineImage: public WgPipeline {
void initialize(WGPUDevice device) override;
void use(WGPURenderPassEncoder encoder,
WgBindGroupCanvas& groupCanvas,
WgBindGroupPaint& groupPaint,
WgBindGroupPicture& groupPicture) {
set(encoder);
groupCanvas.set(encoder, 0);
groupPaint.set(encoder, 1);
groupPicture.set(encoder, 2);
}
};
struct WgPipelines {
WgPipelineFillShape mPipelineFillShape;
WgPipelineFillStroke mPipelineFillStroke;
WgPipelineSolid mPipelineSolid;
WgPipelineLinear mPipelineLinear;
WgPipelineRadial mPipelineRadial;
WgPipelineImage mPipelineImage;
void initialize(WGPUDevice device);
void release();
};
#endif // _TVG_WG_PIPELINES_H_

View file

@ -108,51 +108,121 @@ void WgGeometryData::release() {
}
}
//***********************************************************************
// WgImageData
//***********************************************************************
void WgImageData::update(WGPUDevice device, WGPUQueue queue, Surface* surface) {
release();
// sampler descriptor
WGPUSamplerDescriptor samplerDesc{};
samplerDesc.nextInChain = nullptr;
samplerDesc.label = "The shape sampler";
samplerDesc.addressModeU = WGPUAddressMode_ClampToEdge;
samplerDesc.addressModeV = WGPUAddressMode_ClampToEdge;
samplerDesc.addressModeW = WGPUAddressMode_ClampToEdge;
samplerDesc.magFilter = WGPUFilterMode_Nearest;
samplerDesc.minFilter = WGPUFilterMode_Nearest;
samplerDesc.mipmapFilter = WGPUMipmapFilterMode_Nearest;
samplerDesc.lodMinClamp = 0.0f;
samplerDesc.lodMaxClamp = 32.0f;
samplerDesc.compare = WGPUCompareFunction_Undefined;
samplerDesc.maxAnisotropy = 1;
mSampler = wgpuDeviceCreateSampler(device, &samplerDesc);
assert(mSampler);
// texture descriptor
WGPUTextureDescriptor textureDesc{};
textureDesc.nextInChain = nullptr;
textureDesc.label = "The shape texture";
textureDesc.usage = WGPUTextureUsage_TextureBinding | WGPUTextureUsage_CopyDst;
textureDesc.dimension = WGPUTextureDimension_2D;
textureDesc.size = { surface->w, surface->h, 1 };
textureDesc.format = WGPUTextureFormat_RGBA8Unorm;
textureDesc.mipLevelCount = 1;
textureDesc.sampleCount = 1;
textureDesc.viewFormatCount = 0;
textureDesc.viewFormats = nullptr;
mTexture = wgpuDeviceCreateTexture(device, &textureDesc);
assert(mTexture);
// texture view descriptor
WGPUTextureViewDescriptor textureViewDesc{};
textureViewDesc.nextInChain = nullptr;
textureViewDesc.label = "The shape texture view";
textureViewDesc.format = WGPUTextureFormat_RGBA8Unorm;
textureViewDesc.dimension = WGPUTextureViewDimension_2D;
textureViewDesc.baseMipLevel = 0;
textureViewDesc.mipLevelCount = 1;
textureViewDesc.baseArrayLayer = 0;
textureViewDesc.arrayLayerCount = 1;
textureViewDesc.aspect = WGPUTextureAspect_All;
mTextureView = wgpuTextureCreateView(mTexture, &textureViewDesc);
assert(mTextureView);
// update texture data
WGPUImageCopyTexture imageCopyTexture{};
imageCopyTexture.nextInChain = nullptr;
imageCopyTexture.texture = mTexture;
imageCopyTexture.mipLevel = 0;
imageCopyTexture.origin = { 0, 0, 0 };
imageCopyTexture.aspect = WGPUTextureAspect_All;
WGPUTextureDataLayout textureDataLayout{};
textureDataLayout.nextInChain = nullptr;
textureDataLayout.offset = 0;
textureDataLayout.bytesPerRow = 4 * surface->w;
textureDataLayout.rowsPerImage = surface->h;
WGPUExtent3D writeSize{};
writeSize.width = surface->w;
writeSize.height = surface->h;
writeSize.depthOrArrayLayers = 1;
wgpuQueueWriteTexture(queue, &imageCopyTexture, surface->data, 4 * surface->w * surface->h, &textureDataLayout, &writeSize);
}
void WgImageData::release() {
if (mTexture) {
wgpuTextureDestroy(mTexture);
wgpuTextureRelease(mTexture);
mTexture = nullptr;
}
if (mTextureView) {
wgpuTextureViewRelease(mTextureView);
mTextureView = nullptr;
}
if (mSampler) {
wgpuSamplerRelease(mSampler);
mSampler = nullptr;
}
}
//***********************************************************************
// WgRenderDataShapeSettings
//***********************************************************************
void WgRenderDataShapeSettings::update(WGPUQueue queue, const Fill* fill, const RenderUpdateFlag flags,
const RenderTransform* transform, const float* viewMatrix, const uint8_t* color,
WgPipelineLinear& linear, WgPipelineRadial& radial, WgPipelineSolid& solid)
void WgRenderDataShapeSettings::update(WGPUDevice device, WGPUQueue queue,
const Fill* fill, const uint8_t* color,
const RenderUpdateFlag flags)
{
// setup fill properties
if ((flags & (RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform)) && fill) {
if ((flags & (RenderUpdateFlag::Gradient)) && fill) {
// setup linear fill properties
if (fill->identifier() == TVG_CLASS_ID_LINEAR) {
WgPipelineDataLinear brushDataLinear{};
brushDataLinear.updateMatrix(viewMatrix, transform);
brushDataLinear.updateGradient((LinearGradient*)fill);
mPipelineBindGroupLinear.update(queue, brushDataLinear);
mPipelineBindGroup = &mPipelineBindGroupLinear;
mPipelineBase = &linear;
} // setup radial fill properties
else if (fill->identifier() == TVG_CLASS_ID_RADIAL) {
WgPipelineDataRadial brushDataRadial{};
brushDataRadial.updateMatrix(viewMatrix, transform);
brushDataRadial.updateGradient((RadialGradient*)fill);
mPipelineBindGroupRadial.update(queue, brushDataRadial);
mPipelineBindGroup = &mPipelineBindGroupRadial;
mPipelineBase = &radial;
WgShaderTypeLinearGradient linearGradient((LinearGradient*)fill);
mBindGroupLinear.initialize(device, queue, linearGradient);
mFillType = WgRenderDataShapeFillType::Linear;
} else if (fill->identifier() == TVG_CLASS_ID_RADIAL) {
WgShaderTypeRadialGradient radialGradient((RadialGradient*)fill);
mBindGroupRadial.initialize(device, queue, radialGradient);
mFillType = WgRenderDataShapeFillType::Radial;
}
} // setup solid fill properties
else if ((flags & (RenderUpdateFlag::Color | RenderUpdateFlag::Transform)) && !fill) {
WgPipelineDataSolid pipelineDataSolid{};
pipelineDataSolid.updateMatrix(viewMatrix, transform);
pipelineDataSolid.updateColor(color);
mPipelineBindGroupSolid.update(queue, pipelineDataSolid);
mPipelineBindGroup = &mPipelineBindGroupSolid;
mPipelineBase = &solid;
} else if ((flags & (RenderUpdateFlag::Color)) && !fill) {
WgShaderTypeSolidColor solidColor(color);
mBindGroupSolid.initialize(device, queue, solidColor);
mFillType = WgRenderDataShapeFillType::Solid;
}
}
void WgRenderDataShapeSettings::release() {
mPipelineBindGroupSolid.release();
mPipelineBindGroupLinear.release();
mPipelineBindGroupRadial.release();
mBindGroupSolid.release();
mBindGroupLinear.release();
mBindGroupRadial.release();
}
//***********************************************************************
@ -161,9 +231,11 @@ void WgRenderDataShapeSettings::release() {
void WgRenderDataShape::release() {
releaseRenderData();
mImageData.release();
mBindGroupPaint.release();
mRenderSettingsShape.release();
mRenderSettingsStroke.release();
mPipelineBindGroupImage.release();
mBindGroupPicture.release();
}
void WgRenderDataShape::releaseRenderData() {
@ -227,6 +299,9 @@ void WgRenderDataShape::tesselate(WGPUDevice device, WGPUQueue queue, Surface* s
(float *)vertexList.data, (float *)texCoordsList.data, vertexList.count,
indexList.data, indexList.count);
mGeometryDataImage.push(geometryData);
// update image data
mImageData.update(device, queue, surface);
}
void WgRenderDataShape::tesselate(WGPUDevice device, WGPUQueue queue, const RenderShape& rshape) {
@ -479,4 +554,4 @@ void WgRenderDataShape::strokeSublines(const RenderShape& rshape, Array<WgVertex
}
}
}
}
}

View file

@ -23,20 +23,16 @@
#ifndef _TVG_WG_RENDER_DATA_H_
#define _TVG_WG_RENDER_DATA_H_
#include "tvgWgPipelineSolid.h"
#include "tvgWgPipelineLinear.h"
#include "tvgWgPipelineRadial.h"
#include "tvgWgPipelineImage.h"
#include "tvgWgPipelines.h"
#include "tvgWgGeometry.h"
class WgGeometryData {
public:
struct WgGeometryData {
WGPUBuffer mBufferVertex{};
WGPUBuffer mBufferTexCoords{};
WGPUBuffer mBufferIndex{};
size_t mVertexCount{};
size_t mIndexCount{};
public:
WgGeometryData() {}
virtual ~WgGeometryData() { release(); }
@ -49,36 +45,51 @@ public:
void release();
};
struct WgImageData {
WGPUSampler mSampler{};
WGPUTexture mTexture{};
WGPUTextureView mTextureView{};
WgImageData() {}
virtual ~WgImageData() { release(); }
void initialize(WGPUDevice device) {};
void update(WGPUDevice device, WGPUQueue queue, Surface* surface);
void release();
};
class WgRenderData {
public:
virtual void initialize(WGPUDevice device) {};
virtual void release() = 0;
};
enum class WgRenderDataShapeFillType { None = 0, Solid = 1, Linear = 2, Radial = 3 };
struct WgRenderDataShapeSettings {
WgPipelineBindGroupSolid mPipelineBindGroupSolid{};
WgPipelineBindGroupLinear mPipelineBindGroupLinear{};
WgPipelineBindGroupRadial mPipelineBindGroupRadial{};
WgPipelineBase* mPipelineBase{}; // external
WgPipelineBindGroup* mPipelineBindGroup{}; // external
WgBindGroupSolidColor mBindGroupSolid{};
WgBindGroupLinearGradient mBindGroupLinear{};
WgBindGroupRadialGradient mBindGroupRadial{};
WgRenderDataShapeFillType mFillType{}; // Default: None
// update render shape settings defined by flags and fill settings
void update(WGPUQueue queue, const Fill* fill, const RenderUpdateFlag flags,
const RenderTransform* transform, const float* viewMatrix, const uint8_t* color,
WgPipelineLinear& linear, WgPipelineRadial& radial, WgPipelineSolid& solid);
void update(WGPUDevice device, WGPUQueue queue,
const Fill* fill, const uint8_t* color, const RenderUpdateFlag flags);
void release();
};
class WgRenderDataShape: public WgRenderData {
public:
// geometry data for shapes, strokes and image
Array<WgGeometryData*> mGeometryDataShape;
Array<WgGeometryData*> mGeometryDataStroke;
Array<WgGeometryData*> mGeometryDataImage;
WgImageData mImageData;
// shader settings
WgBindGroupPaint mBindGroupPaint;
WgRenderDataShapeSettings mRenderSettingsShape;
WgRenderDataShapeSettings mRenderSettingsStroke;
WgPipelineBindGroupImage mPipelineBindGroupImage;
WgBindGroupPicture mBindGroupPicture;
public:
WgRenderDataShape() {}

View file

@ -103,15 +103,7 @@ void WgRenderer::initialize() {
assert(mQueue);
// create pipelines
mPipelineEmpty.initialize(mDevice);
mPipelineStroke.initialize(mDevice);
mPipelineSolid.initialize(mDevice);
mPipelineLinear.initialize(mDevice);
mPipelineRadial.initialize(mDevice);
mPipelineImage.initialize(mDevice);
mPipelineBindGroupEmpty.initialize(mDevice, mPipelineEmpty);
mPipelineBindGroupStroke.initialize(mDevice, mPipelineStroke);
mGeometryDataWindow.initialize(mDevice);
mPipelines.initialize(mDevice);
}
void WgRenderer::release() {
@ -122,15 +114,10 @@ void WgRenderer::release() {
if (mStencilTexView) wgpuTextureViewRelease(mStencilTexView);
if (mSwapChain) wgpuSwapChainRelease(mSwapChain);
if (mSurface) wgpuSurfaceRelease(mSurface);
mGeometryDataWindow.release();
mPipelineBindGroupStroke.release();
mPipelineBindGroupEmpty.release();
mPipelineImage.release();
mPipelineRadial.release();
mPipelineLinear.release();
mPipelineSolid.release();
mPipelineStroke.release();
mPipelineEmpty.release();
mBindGroupCanvasWnd.release();
mBindGroupPaintWnd.release();
mGeometryDataWnd.release();
mPipelines.release();
if (mDevice) {
wgpuDeviceDestroy(mDevice);
wgpuDeviceRelease(mDevice);
@ -145,31 +132,26 @@ RenderData WgRenderer::prepare(const RenderShape& rshape, RenderData data, const
if (!renderDataShape) {
renderDataShape = new WgRenderDataShape();
renderDataShape->initialize(mDevice);
renderDataShape->mRenderSettingsShape.mPipelineBindGroupSolid.initialize(mDevice, mPipelineSolid);
renderDataShape->mRenderSettingsShape.mPipelineBindGroupLinear.initialize(mDevice, mPipelineLinear);
renderDataShape->mRenderSettingsShape.mPipelineBindGroupRadial.initialize(mDevice, mPipelineRadial);
renderDataShape->mRenderSettingsStroke.mPipelineBindGroupSolid.initialize(mDevice, mPipelineSolid);
renderDataShape->mRenderSettingsStroke.mPipelineBindGroupLinear.initialize(mDevice, mPipelineLinear);
renderDataShape->mRenderSettingsStroke.mPipelineBindGroupRadial.initialize(mDevice, mPipelineRadial);
}
if (flags & (RenderUpdateFlag::Path | RenderUpdateFlag::Stroke))
// update geometry
if (flags & (RenderUpdateFlag::Path | RenderUpdateFlag::Stroke)) {
renderDataShape->releaseRenderData();
if (flags & RenderUpdateFlag::Path)
renderDataShape->tesselate(mDevice, mQueue, rshape);
if (flags & RenderUpdateFlag::Stroke)
renderDataShape->stroke(mDevice, mQueue, rshape);
}
// setup shape fill properties
renderDataShape->mRenderSettingsShape.update(mQueue, rshape.fill, flags, transform, mViewMatrix, rshape.color,
mPipelineLinear, mPipelineRadial, mPipelineSolid);
// update paint settings
if (flags & (RenderUpdateFlag::Transform | RenderUpdateFlag::Blend)) {
WgShaderTypeMat4x4f modelMat(transform);
WgShaderTypeBlendSettings blendSettings(mTargetSurface.cs);
renderDataShape->mBindGroupPaint.initialize(mDevice, mQueue, modelMat, blendSettings);
}
// setup stroke fill properties
// setup fill settings
renderDataShape->mRenderSettingsShape.update(mDevice, mQueue, rshape.fill, rshape.color, flags);
if (rshape.stroke)
renderDataShape->mRenderSettingsStroke.update(mQueue, rshape.stroke->fill, flags, transform, mViewMatrix, rshape.stroke->color,
mPipelineLinear, mPipelineRadial, mPipelineSolid);
renderDataShape->mRenderSettingsStroke.update(mDevice, mQueue, rshape.stroke->fill, rshape.stroke->color, flags);
return renderDataShape;
}
@ -184,16 +166,25 @@ RenderData WgRenderer::prepare(Surface* surface, const RenderMesh* mesh, RenderD
if (!renderDataShape) {
renderDataShape = new WgRenderDataShape();
renderDataShape->initialize(mDevice);
renderDataShape->mPipelineBindGroupImage.initialize(mDevice, mPipelineImage, surface);
}
if (flags & (RenderUpdateFlag::Color | RenderUpdateFlag::Image | RenderUpdateFlag::Transform)) {
WgPipelineDataImage pipelineDataImage{};
pipelineDataImage.updateMatrix(mViewMatrix, transform);
pipelineDataImage.updateFormat(surface->cs);
pipelineDataImage.updateOpacity(opacity);
renderDataShape->mPipelineBindGroupImage.update(mQueue, pipelineDataImage, surface);
// update paint settings
if (flags & (RenderUpdateFlag::Transform | RenderUpdateFlag::Blend)) {
WgShaderTypeMat4x4f modelMat(transform);
WgShaderTypeBlendSettings blendSettings(surface->cs);
renderDataShape->mBindGroupPaint.initialize(mDevice, mQueue, modelMat, blendSettings);
}
// update image data
if (flags & (RenderUpdateFlag::Path | RenderUpdateFlag::Image)) {
renderDataShape->releaseRenderData();
renderDataShape->tesselate(mDevice, mQueue, surface, mesh);
renderDataShape->mBindGroupPicture.initialize(
mDevice, mQueue,
renderDataShape->mImageData.mSampler,
renderDataShape->mImageData.mTextureView);
}
return renderDataShape;
}
@ -274,7 +265,12 @@ bool WgRenderer::sync() {
WGPURenderPassColorAttachment colorAttachment{};
colorAttachment.view = backBufferView;
colorAttachment.resolveTarget = nullptr;
colorAttachment.loadOp = WGPULoadOp_Clear;
if (mClearBuffer) {
colorAttachment.loadOp = WGPULoadOp_Clear;
colorAttachment.clearValue = {0, 0, 0, 0};
} else {
colorAttachment.loadOp = WGPULoadOp_Load;
}
colorAttachment.storeOp = WGPUStoreOp_Store;
colorAttachment.clearValue = { 0.0f, 0.0f, 0.0f, 1.0 };
// render pass descriptor
@ -298,39 +294,50 @@ bool WgRenderer::sync() {
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
for (uint32_t j = 0; j < renderData->mGeometryDataShape.count; j++) {
// draw to stencil (first pass)
mPipelineEmpty.set(renderPassEncoder);
mPipelineBindGroupEmpty.bind(renderPassEncoder, 0);
mPipelines.mPipelineFillShape.use(renderPassEncoder, mBindGroupCanvasWnd, renderData->mBindGroupPaint);
renderData->mGeometryDataShape[j]->draw(renderPassEncoder);
// fill shape (second pass)
renderData->mRenderSettingsShape.mPipelineBase->set(renderPassEncoder);
renderData->mRenderSettingsShape.mPipelineBindGroup->bind(renderPassEncoder, 0);
mGeometryDataWindow.draw(renderPassEncoder);
WgRenderDataShapeSettings& settings = renderData->mRenderSettingsShape;
if (settings.mFillType == WgRenderDataShapeFillType::Solid)
mPipelines.mPipelineSolid.use(renderPassEncoder, mBindGroupCanvasWnd, mBindGroupPaintWnd, settings.mBindGroupSolid);
else if (settings.mFillType == WgRenderDataShapeFillType::Linear)
mPipelines.mPipelineLinear.use(renderPassEncoder, mBindGroupCanvasWnd, mBindGroupPaintWnd, settings.mBindGroupLinear);
else if (settings.mFillType == WgRenderDataShapeFillType::Radial)
mPipelines.mPipelineRadial.use(renderPassEncoder, mBindGroupCanvasWnd, mBindGroupPaintWnd, settings.mBindGroupRadial);
mGeometryDataWnd.draw(renderPassEncoder);
}
// draw stroke geometry
if (renderData->mRenderSettingsStroke.mPipelineBase) {
if (renderData->mGeometryDataStroke.count > 0) {
// draw strokes to stencil (first pass)
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 255);
for (uint32_t j = 0; j < renderData->mGeometryDataStroke.count; j++) {
mPipelineStroke.set(renderPassEncoder);
mPipelineBindGroupStroke.bind(renderPassEncoder, 0);
mPipelines.mPipelineFillStroke.use(renderPassEncoder, mBindGroupCanvasWnd, renderData->mBindGroupPaint);
renderData->mGeometryDataStroke[j]->draw(renderPassEncoder);
}
// fill strokes (second pass)
// fill shape (second pass)
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
renderData->mRenderSettingsStroke.mPipelineBase->set(renderPassEncoder);
renderData->mRenderSettingsStroke.mPipelineBindGroup->bind(renderPassEncoder, 0);
mGeometryDataWindow.draw(renderPassEncoder);
WgRenderDataShapeSettings& settings = renderData->mRenderSettingsStroke;
if (settings.mFillType == WgRenderDataShapeFillType::Solid)
mPipelines.mPipelineSolid.use(renderPassEncoder, mBindGroupCanvasWnd, mBindGroupPaintWnd, settings.mBindGroupSolid);
else if (settings.mFillType == WgRenderDataShapeFillType::Linear)
mPipelines.mPipelineLinear.use(renderPassEncoder, mBindGroupCanvasWnd, mBindGroupPaintWnd, settings.mBindGroupLinear);
else if (settings.mFillType == WgRenderDataShapeFillType::Radial)
mPipelines.mPipelineRadial.use(renderPassEncoder, mBindGroupCanvasWnd, mBindGroupPaintWnd, settings.mBindGroupRadial);
mGeometryDataWnd.draw(renderPassEncoder);
}
// draw image geometry
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
for (uint32_t j = 0; j < renderData->mGeometryDataImage.count; j++) {
mPipelineImage.set(renderPassEncoder);
renderData->mPipelineBindGroupImage.bind(renderPassEncoder, 0);
renderData->mGeometryDataImage[j]->drawImage(renderPassEncoder);
// render image
if (renderData->mGeometryDataImage.count > 0) {
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
for (uint32_t j = 0; j < renderData->mGeometryDataImage.count; j++) {
mPipelines.mPipelineImage.use(
renderPassEncoder,
mBindGroupCanvasWnd,
renderData->mBindGroupPaint,
renderData->mBindGroupPicture);
renderData->mGeometryDataImage[j]->drawImage(renderPassEncoder);
}
}
}
}
@ -439,22 +446,16 @@ bool WgRenderer::target(void* window, uint32_t w, uint32_t h) {
mStencilTexView = wgpuTextureCreateView(mStencilTex, &textureViewDesc);
assert(mStencilTexView);
// initialize window binding groups
WgShaderTypeMat4x4f viewMat(w, h);
mBindGroupCanvasWnd.initialize(mDevice, mQueue, viewMat);
WgShaderTypeMat4x4f modelMat;
WgShaderTypeBlendSettings blendSettings(ColorSpace::ABGR8888);
mBindGroupPaintWnd.initialize(mDevice, mQueue, modelMat, blendSettings);
// update pipeline geometry data
WgVertexList wnd;
wnd.appendRect(
WgPoint(0.0f, 0.0f), WgPoint(w, 0.0f),
WgPoint(0.0f, h), WgPoint(w, h)
);
// update render data pipeline empty and stroke
mGeometryDataWindow.update(mDevice, mQueue, &wnd);
// update bind group pipeline empty
WgPipelineDataEmpty pipelineDataEmpty{};
pipelineDataEmpty.updateMatrix(mViewMatrix, nullptr);
mPipelineBindGroupEmpty.update(mQueue, pipelineDataEmpty);
// update bind group pipeline stroke
WgPipelineDataStroke pipelineDataStroke{};
pipelineDataStroke.updateMatrix(mViewMatrix, nullptr);
mPipelineBindGroupStroke.update(mQueue, pipelineDataStroke);
wnd.appendRect(WgPoint(0.0f, 0.0f), WgPoint(w, 0.0f), WgPoint(0.0f, h), WgPoint(w, h));
mGeometryDataWnd.update(mDevice, mQueue, &wnd);
return true;
}

View file

@ -23,8 +23,6 @@
#ifndef _TVG_WG_RENDERER_H_
#define _TVG_WG_RENDERER_H_
#include "tvgWgPipelineEmpty.h"
#include "tvgWgPipelineStroke.h"
#include "tvgWgRenderData.h"
class WgRenderer : public RenderMethod
@ -77,16 +75,13 @@ private:
WGPUSwapChain mSwapChain{};
WGPUTexture mStencilTex{};
WGPUTextureView mStencilTexView{};
WgBindGroupCanvas mBindGroupCanvasWnd;
WgBindGroupPaint mBindGroupPaintWnd;
WgGeometryData mGeometryDataWnd;
private:
WgPipelineEmpty mPipelineEmpty;
WgPipelineStroke mPipelineStroke;
WgPipelineSolid mPipelineSolid;
WgPipelineLinear mPipelineLinear;
WgPipelineRadial mPipelineRadial;
WgPipelineImage mPipelineImage;
WgGeometryData mGeometryDataWindow;
WgPipelineBindGroupEmpty mPipelineBindGroupEmpty;
WgPipelineBindGroupStroke mPipelineBindGroupStroke;
WgPipelines mPipelines;
bool mClearBuffer;
};
#endif /* _TVG_WG_RENDERER_H_ */

View file

@ -24,18 +24,21 @@
#include <string>
//************************************************************************
// cShaderSource_PipelineEmpty
// shader pipeline fill
//************************************************************************
const char* cShaderSource_PipelineEmpty = R"(
const char* cShaderSource_PipelineFill = R"(
// vertex input
struct VertexInput {
@location(0) position: vec2f
};
// Matrix
struct Matrix {
transform: mat4x4f
// BlendSettigs
struct BlendSettigs {
format : u32, // ColorSpace
dummy0 : f32,
dummy1 : f32,
dummy2 : f32
};
// vertex output
@ -43,24 +46,27 @@ struct VertexOutput {
@builtin(position) position: vec4f
};
// uMatrix
@group(0) @binding(0) var<uniform> uMatrix: Matrix;
// uniforms
@group(0) @binding(0) var<uniform> uViewMat : mat4x4f;
@group(1) @binding(0) var<uniform> uModelMat : mat4x4f;
@group(1) @binding(1) var<uniform> uBlendSettigs : BlendSettigs;
@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.position = uViewMat * uModelMat * vec4f(in.position.xy, 0.0, 1.0);
return out;
}
@fragment
fn fs_main(in: VertexOutput) -> void {
// nothing to draw, just stencil value
})";
}
)";
//************************************************************************
// cShaderSource_PipelineSolid
// shader pipeline solid
//************************************************************************
const char* cShaderSource_PipelineSolid = R"(
@ -69,14 +75,12 @@ struct VertexInput {
@location(0) position: vec2f
};
// Matrix
struct Matrix {
transform: mat4x4f
};
// ColorInfo
struct ColorInfo {
color: vec4f
// BlendSettigs
struct BlendSettigs {
format : u32, // ColorSpace
dummy0 : f32,
dummy1 : f32,
dummy2 : f32
};
// vertex output
@ -84,27 +88,34 @@ struct VertexOutput {
@builtin(position) position: vec4f
};
// uMatrix
@group(0) @binding(0) var<uniform> uMatrix: Matrix;
// uColorInfo
@group(0) @binding(1) var<uniform> uColorInfo: ColorInfo;
// uniforms
@group(0) @binding(0) var<uniform> uViewMat : mat4x4f;
@group(1) @binding(0) var<uniform> uModelMat : mat4x4f;
@group(1) @binding(1) var<uniform> uBlendSettigs : BlendSettigs;
@group(2) @binding(0) var<uniform> uSolidColor : vec4f;
@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.position = vec4f(in.position.xy, 0.0, 1.0);
out.position = uViewMat * uModelMat * vec4f(in.position.xy, 0.0, 1.0);
return out;
}
@fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4f {
return uColorInfo.color;
})";
// resulting color
var color = vec4(1.0);
// get color
color = uSolidColor;
return vec4f(color.rgb, color.a);
}
)";
//************************************************************************
// cShaderSource_PipelineLinear
// shader pipeline linear
//************************************************************************
const char* cShaderSource_PipelineLinear = R"(
@ -113,46 +124,53 @@ struct VertexInput {
@location(0) position: vec2f
};
// Matrix
struct Matrix {
transform: mat4x4f
// BlendSettigs
struct BlendSettigs {
format : u32, // ColorSpace
dummy0 : f32,
dummy1 : f32,
dummy2 : f32
};
// GradientInfo
const MAX_STOP_COUNT = 4;
struct GradientInfo {
// LinearGradient
const MAX_LINEAR_GRADIENT_STOPS = 4;
struct LinearGradient {
nStops : vec4f,
gradStartPos : vec2f,
gradEndPos : vec2f,
stopPoints : vec4f,
stopColors : array<vec4f, MAX_STOP_COUNT>
stopColors : array<vec4f, MAX_LINEAR_GRADIENT_STOPS>
};
// vertex output
struct VertexOutput {
@builtin(position) position: vec4f,
@location(0) vScreenCoord: vec2f
@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;
// uniforms
@group(0) @binding(0) var<uniform> uViewMat : mat4x4f;
@group(1) @binding(0) var<uniform> uModelMat : mat4x4f;
@group(1) @binding(1) var<uniform> uBlendSettigs : BlendSettigs;
@group(2) @binding(0) var<uniform> uLinearGradient : LinearGradient;
@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.position = uViewMat * uModelMat * vec4f(in.position.xy, 0.0, 1.0);
out.vScreenCoord = in.position.xy;
return out;
}
@fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4f {
// resulting color
var color = vec4(1.0);
let pos: vec2f = in.vScreenCoord;
let st: vec2f = uGradientInfo.gradStartPos;
let ed: vec2f = uGradientInfo.gradEndPos;
let st: vec2f = uLinearGradient.gradStartPos;
let ed: vec2f = uLinearGradient.gradEndPos;
let ba: vec2f = ed - st;
@ -160,36 +178,34 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4f {
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);
let last: i32 = i32(uLinearGradient.nStops[0]) - 1;
// closer than first stop
if (t <= uGradientInfo.stopPoints[0]) {
color = uGradientInfo.stopColors[0];
if (t <= uLinearGradient.stopPoints[0]) {
color = uLinearGradient.stopColors[0];
}
// further than last stop
if (t >= uGradientInfo.stopPoints[last]) {
color = uGradientInfo.stopColors[last];
if (t >= uLinearGradient.stopPoints[last]) {
color = uLinearGradient.stopColors[last];
}
// look in the middle
for (var i = 0i; i < last; i++) {
let strt = uGradientInfo.stopPoints[i];
let stop = uGradientInfo.stopPoints[i+1];
let strt = uLinearGradient.stopPoints[i];
let stop = uLinearGradient.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);
color = mix(uLinearGradient.stopColors[i], uLinearGradient.stopColors[i+1], step);
}
}
return color;
})";
return vec4f(color.rgb, color.a);
}
)";
//************************************************************************
// cShaderSource_PipelineRadial
// shader pipeline radial
//************************************************************************
const char* cShaderSource_PipelineRadial = R"(
@ -198,125 +214,125 @@ struct VertexInput {
@location(0) position: vec2f
};
// Matrix
struct Matrix {
transform: mat4x4f
// BlendSettigs
struct BlendSettigs {
format : u32, // ColorSpace
dummy0 : f32,
dummy1 : f32,
dummy2 : f32
};
// GradientInfo
const MAX_STOP_COUNT = 4;
struct GradientInfo {
// RadialGradient
const MAX_RADIAL_GRADIENT_STOPS = 4;
struct RadialGradient {
nStops : vec4f,
centerPos : vec2f,
radius : vec2f,
stopPoints : vec4f,
stopColors : array<vec4f, MAX_STOP_COUNT>
stopColors : array<vec4f, MAX_RADIAL_GRADIENT_STOPS>
};
// vertex output
struct VertexOutput {
@builtin(position) position: vec4f,
@location(0) vScreenCoord: vec2f
@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;
// uniforms
@group(0) @binding(0) var<uniform> uViewMat : mat4x4f;
@group(1) @binding(0) var<uniform> uModelMat : mat4x4f;
@group(1) @binding(1) var<uniform> uBlendSettigs : BlendSettigs;
@group(2) @binding(0) var<uniform> uRadialGradient : RadialGradient;
@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.position = uViewMat * uModelMat * vec4f(in.position.xy, 0.0, 1.0);
out.vScreenCoord = in.position.xy;
return out;
}
@fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4f {
// get interpolation factor
let t: f32 = clamp(distance(uGradientInfo.centerPos, in.vScreenCoord) / uGradientInfo.radius.x, 0.0, 1.0);
// get stops count
let last: i32 = i32(uGradientInfo.nStops[0]) - 1;
// resulting color
var color = vec4(1.0);
// get interpolation factor
let t: f32 = clamp(distance(uRadialGradient.centerPos, in.vScreenCoord) / uRadialGradient.radius.x, 0.0, 1.0);
// get stops count
let last: i32 = i32(uRadialGradient.nStops[0]) - 1;
// closer than first stop
if (t <= uGradientInfo.stopPoints[0]) {
color = uGradientInfo.stopColors[0];
if (t <= uRadialGradient.stopPoints[0]) {
color = uRadialGradient.stopColors[0];
}
// further than last stop
if (t >= uGradientInfo.stopPoints[last]) {
color = uGradientInfo.stopColors[last];
if (t >= uRadialGradient.stopPoints[last]) {
color = uRadialGradient.stopColors[last];
}
// look in the middle
for (var i = 0i; i < last; i++) {
let strt = uGradientInfo.stopPoints[i];
let stop = uGradientInfo.stopPoints[i+1];
let strt = uRadialGradient.stopPoints[i];
let stop = uRadialGradient.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);
color = mix(uRadialGradient.stopColors[i], uRadialGradient.stopColors[i+1], step);
}
}
return color;
})";
return vec4f(color.rgb, color.a);
}
)";
//************************************************************************
// cShaderSource_PipelineImage
//************************************************************************
const char* cShaderSource_PipelineImage = R"(
// vertex input
struct VertexInput {
@location(0) position: vec2f,
@location(1) texCoords: vec2f
@location(1) texCoord: vec2f
};
// Matrix
struct Matrix {
transform: mat4x4f
};
// ColorInfo
struct ColorInfo {
format: u32,
dummy0: f32,
dummy1: f32,
opacity: f32
// BlendSettigs
struct BlendSettigs {
format : u32, // ColorSpace
dummy0 : f32,
dummy1 : f32,
dummy2 : f32
};
// vertex output
struct VertexOutput {
@builtin(position) position: vec4f,
@location(0) texCoords: vec2f,
@location(0) texCoord: vec2f
};
// uMatrix
@group(0) @binding(0) var<uniform> uMatrix: Matrix;
// uColorInfo
@group(0) @binding(1) var<uniform> uColorInfo: ColorInfo;
// uSamplerBase
@group(0) @binding(2) var uSamplerBase: sampler;
// uTextureViewBase
@group(0) @binding(3) var uTextureViewBase: texture_2d<f32>;
@group(0) @binding(0) var<uniform> uViewMat : mat4x4f;
@group(1) @binding(0) var<uniform> uModelMat : mat4x4f;
@group(1) @binding(1) var<uniform> uBlendSettigs : BlendSettigs;
@group(2) @binding(0) var uSampler : sampler;
@group(2) @binding(1) var uTextureView : texture_2d<f32>;
@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.texCoords = in.texCoords;
out.position = uViewMat * uModelMat * vec4f(in.position.xy, 0.0, 1.0);
out.texCoord = in.texCoord;
return out;
}
@fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4f {
var color: vec4f = textureSample(uTextureViewBase, uSamplerBase, in.texCoords.xy);
var color: vec4f = textureSample(uTextureView, uSampler, in.texCoord.xy);
var result: vec4f = color;
var format: u32 = uColorInfo.format;
var format: u32 = uBlendSettigs.format;
if (format == 1u) { /* FMT_ARGB8888 */
result = color.bgra;
} else if (format == 2u) { /* FMT_ABGR8888S */
@ -324,5 +340,6 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4f {
} else if (format == 3u) { /* FMT_ARGB8888S */
result = vec4(color.bgr * color.a, color.a);
}
return vec4f(result.rgb, result.a * uColorInfo.opacity);
})";
return vec4f(result.rgb, result.a);
};
)";

View file

@ -25,8 +25,8 @@
#ifndef _TVG_WG_SHADER_SRC_H_
#define _TVG_WG_SHADER_SRC_H_
// pipeline shader module empty
extern const char* cShaderSource_PipelineEmpty;
// pipeline shader module fill
extern const char* cShaderSource_PipelineFill;
// pipeline shader module solid
extern const char* cShaderSource_PipelineSolid;
@ -40,4 +40,16 @@ extern const char* cShaderSource_PipelineRadial;
// pipeline shader module image
extern const char* cShaderSource_PipelineImage;
extern const char* MASK_ALPHA_FRAG_SHADER;
extern const char* MASK_INV_ALPHA_FRAG_SHADER;
extern const char* MASK_LUMA_FRAG_SHADER;
extern const char* MASK_INV_LUMA_FRAG_SHADER;
extern const char* MASK_ADD_FRAG_SHADER;
extern const char* MASK_SUB_FRAG_SHADER;
extern const char* MASK_INTERSECT_FRAG_SHADER;
extern const char* MASK_DIFF_FRAG_SHADER;
// pipeline shader module compose
extern const char* cShaderSource_Pipeline;
#endif // _TVG_WG_SHADER_SRC_H_

View file

@ -0,0 +1,141 @@
/*
* 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 "tvgWgShaderTypes.h"
///////////////////////////////////////////////////////////////////////////////
// shader types
///////////////////////////////////////////////////////////////////////////////
WgShaderTypeMat4x4f::WgShaderTypeMat4x4f() {
identity();
}
WgShaderTypeMat4x4f::WgShaderTypeMat4x4f(const RenderTransform* transform) {
update(transform);
}
void WgShaderTypeMat4x4f::identity() {
mat[0] = 1.0f; mat[1] = 0.0f; mat[2] = 0.0f; mat[3] = 0.0f;
mat[4] = 0.0f; mat[5] = 1.0f; mat[6] = 0.0f; mat[7] = 0.0f;
mat[8] = 0.0f; mat[9] = 0.0f; mat[10] = 1.0f; mat[11] = 0.0f;
mat[12] = 0.0f; mat[13] = 0.0f; mat[14] = 0.0f; mat[15] = 1.0f;
}
WgShaderTypeMat4x4f::WgShaderTypeMat4x4f(size_t w, size_t h) {
update(w, h);
}
void WgShaderTypeMat4x4f::update(const RenderTransform* transform) {
identity();
if (transform) {
mat[0] = transform->m.e11;
mat[1] = transform->m.e21;
mat[2] = 0.0f;
mat[3] = transform->m.e31;
mat[4] = transform->m.e12;
mat[5] = transform->m.e22;
mat[6] = 0.0f;
mat[7] = transform->m.e32;
mat[8] = 0.0f;
mat[9] = 0.0f;
mat[10] = 1.0f;
mat[11] = 0.0f;
mat[12] = transform->m.e13;
mat[13] = transform->m.e23;
mat[14] = 0.0f;
mat[15] = transform->m.e33;
};
};
void WgShaderTypeMat4x4f::update(size_t w, size_t h) {
mat[0] = +2.0f / w; mat[1] = +0.0f; mat[2] = +0.0f; mat[3] = +0.0f;
mat[4] = +0.0f; mat[5] = -2.0f / h; mat[6] = +0.0f; mat[7] = +0.0f;
mat[8] = +0.0f; mat[9] = +0.0f; mat[10] = -1.0f; mat[11] = +0.0f;
mat[12] = -1.0f; mat[13] = +1.0f; mat[14] = +0.0f; mat[15] = +1.0f;
};
WgShaderTypeBlendSettings::WgShaderTypeBlendSettings(const ColorSpace colorSpace) {
update(colorSpace);
}
void WgShaderTypeBlendSettings::update(const ColorSpace colorSpace) {
format = (uint32_t)colorSpace;
dummy0 = 0.0f;
dummy1 = 0.0f;
dummy2 = 0.0f;
};
WgShaderTypeSolidColor::WgShaderTypeSolidColor(const uint8_t* c) {
update(c);
}
void WgShaderTypeSolidColor::update(const uint8_t* c) {
color[0] = c[0] / 255.0f; // red
color[1] = c[1] / 255.0f; // green
color[2] = c[2] / 255.0f; // blue
color[3] = c[3] / 255.0f; // alpha
};
WgShaderTypeLinearGradient::WgShaderTypeLinearGradient(const LinearGradient* linearGradient) {
update(linearGradient);
}
void WgShaderTypeLinearGradient::update(const LinearGradient* linearGradient) {
const Fill::ColorStop* stops = nullptr;
auto stopCnt = linearGradient->colorStops(&stops);
nStops[0] = stopCnt;
nStops[1] = 0.5f;
for (uint32_t i = 0; i < stopCnt; ++i) {
stopPoints[i] = stops[i].offset;
stopColors[i * 4 + 0] = stops[i].r / 255.f;
stopColors[i * 4 + 1] = stops[i].g / 255.f;
stopColors[i * 4 + 2] = stops[i].b / 255.f;
stopColors[i * 4 + 3] = stops[i].a / 255.f;
}
linearGradient->linear(&startPos[0], &startPos[1], &endPos[0], &endPos[1]);
};
WgShaderTypeRadialGradient::WgShaderTypeRadialGradient(const RadialGradient* radialGradient) {
update(radialGradient);
}
void WgShaderTypeRadialGradient::update(const RadialGradient* radialGradient) {
const Fill::ColorStop* stops = nullptr;
auto stopCnt = radialGradient->colorStops(&stops);
nStops[0] = stopCnt;
nStops[1] = 0.5f;
for (uint32_t i = 0; i < stopCnt; ++i) {
stopPoints[i] = stops[i].offset;
stopColors[i * 4 + 0] = stops[i].r / 255.f;
stopColors[i * 4 + 1] = stops[i].g / 255.f;
stopColors[i * 4 + 2] = stops[i].b / 255.f;
stopColors[i * 4 + 3] = stops[i].a / 255.f;
}
radialGradient->radial(&centerPos[0], &centerPos[1], &radius[0]);
};

View file

@ -0,0 +1,111 @@
/*
* 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_SHADER_TYPES_H_
#define _TVG_WG_SHADER_TYPES_H_
#include "tvgWgCommon.h"
///////////////////////////////////////////////////////////////////////////////
// shader types
///////////////////////////////////////////////////////////////////////////////
// mat4x4f
struct WgShaderTypeMat4x4f {
float mat[16]{};
WgShaderTypeMat4x4f();
WgShaderTypeMat4x4f(const RenderTransform* transform);
WgShaderTypeMat4x4f(size_t w, size_t h);
void identity();
void update(const RenderTransform* transform);
void update(size_t w, size_t h);
};
// struct BlendSettigs {
// format : u32, // ColorSpace
// dummy0 : f32,
// dummy1 : f32,
// opacity : f32
// };
struct WgShaderTypeBlendSettings {
uint32_t format{}; // ColorSpace
float dummy0{};
float dummy1{};
float dummy2{};
WgShaderTypeBlendSettings() {};
WgShaderTypeBlendSettings(const ColorSpace colorSpace);
void update(const ColorSpace colorSpace);
};
// struct SolidColor {
// color: vec4f
// };
struct WgShaderTypeSolidColor {
float color[4]{};
WgShaderTypeSolidColor(const uint8_t* c);
void update(const uint8_t* c);
};
// const MAX_LINEAR_GRADIENT_STOPS = 4;
// struct LinearGradient {
// nStops : vec4f,
// gradStartPos : vec2f,
// gradEndPos : vec2f,
// stopPoints : vec4f,
// stopColors : array<vec4f, MAX_LINEAR_GRADIENT_STOPS>
// };
#define MAX_LINEAR_GRADIENT_STOPS 4
struct WgShaderTypeLinearGradient {
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]{};
WgShaderTypeLinearGradient(const LinearGradient* linearGradient);
void update(const LinearGradient* linearGradient);
};
// const MAX_RADIAL_GRADIENT_STOPS = 4;
// struct RadialGradient {
// nStops : vec4f,
// centerPos : vec2f,
// radius : vec2f,
// stopPoints : vec4f,
// stopColors : array<vec4f, MAX_RADIAL_GRADIENT_STOPS>
// };
#define MAX_RADIAL_GRADIENT_STOPS 4
struct WgShaderTypeRadialGradient {
alignas(16) float nStops[4]{};
alignas(16) float centerPos[2]{};
alignas(8) float radius[2]{};
alignas(8) float stopPoints[MAX_RADIAL_GRADIENT_STOPS]{};
alignas(16) float stopColors[4 * MAX_RADIAL_GRADIENT_STOPS]{};
WgShaderTypeRadialGradient(const RadialGradient* radialGradient);
void update(const RadialGradient* radialGradient);
};
#endif // _TVG_WG_SHADER_TYPES_H_