mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-14 12:04:29 +00:00
webgpu: shaders refactoring
Deep shader refactoring for the following purposes: * used pre-calculated gradient texture instead of per-pixel gradient map computation * used HW wrap samples for fill spread setting * unified gradient shader types * used single shader module for composition instead of signle module per composition type * used single shader module for blending for each of fill type (solid, gradient, image) instaed of signle module per blend type * much easier add new composition and blend equations * get rided std::string uasge * shaders code is more readable
This commit is contained in:
parent
a25366b283
commit
9efab30b00
15 changed files with 633 additions and 715 deletions
|
@ -33,6 +33,18 @@ WGPUBindGroup WgBindGroupLayouts::createBindGroupTexSampled(WGPUSampler sampler,
|
|||
}
|
||||
|
||||
|
||||
WGPUBindGroup WgBindGroupLayouts::createBindGroupTexSampledBuff1Un(WGPUSampler sampler, WGPUTextureView texView, WGPUBuffer buff)
|
||||
{
|
||||
const WGPUBindGroupEntry bindGroupEntrys[] = {
|
||||
{ .binding = 0, .sampler = sampler },
|
||||
{ .binding = 1, .textureView = texView },
|
||||
{ .binding = 2, .buffer = buff, .size = wgpuBufferGetSize(buff) }
|
||||
};
|
||||
const WGPUBindGroupDescriptor bindGroupDesc { .layout = layoutTexSampledBuff1Un, .entryCount = 3, .entries = bindGroupEntrys };
|
||||
return wgpuDeviceCreateBindGroup(device, &bindGroupDesc);
|
||||
}
|
||||
|
||||
|
||||
WGPUBindGroup WgBindGroupLayouts::createBindGroupScreen1WO(WGPUTextureView texView) {
|
||||
const WGPUBindGroupEntry bindGroupEntrys[] = {
|
||||
{ .binding = 0, .textureView = texView }
|
||||
|
@ -151,6 +163,17 @@ void WgBindGroupLayouts::initialize(WgContext& context)
|
|||
assert(layoutTexSampled);
|
||||
}
|
||||
|
||||
{ // bind group layout tex sampled with buffer uniform
|
||||
const WGPUBindGroupLayoutEntry bindGroupLayoutEntries[] {
|
||||
{ .binding = 0, .visibility = visibility_frag, .sampler = sampler },
|
||||
{ .binding = 1, .visibility = visibility_frag, .texture = texture },
|
||||
{ .binding = 2, .visibility = visibility_vert, .buffer = bufferUniform }
|
||||
};
|
||||
const WGPUBindGroupLayoutDescriptor bindGroupLayoutDesc { .entryCount = 3, .entries = bindGroupLayoutEntries };
|
||||
layoutTexSampledBuff1Un = wgpuDeviceCreateBindGroupLayout(device, &bindGroupLayoutDesc);
|
||||
assert(layoutTexSampledBuff1Un);
|
||||
}
|
||||
|
||||
{ // bind group layout tex screen 1 RO
|
||||
const WGPUBindGroupLayoutEntry bindGroupLayoutEntries[] {
|
||||
{ .binding = 0, .visibility = visibility_frag, .storageTexture = storageScreenWO }
|
||||
|
@ -241,6 +264,7 @@ void WgBindGroupLayouts::release(WgContext& context)
|
|||
wgpuBindGroupLayoutRelease(layoutTexStrorage2RO);
|
||||
wgpuBindGroupLayoutRelease(layoutTexStrorage1RO);
|
||||
wgpuBindGroupLayoutRelease(layoutTexStrorage1WO);
|
||||
wgpuBindGroupLayoutRelease(layoutTexSampledBuff1Un);
|
||||
wgpuBindGroupLayoutRelease(layoutTexSampled);
|
||||
device = nullptr;
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ private:
|
|||
WGPUDevice device{};
|
||||
public:
|
||||
WGPUBindGroupLayout layoutTexSampled{};
|
||||
WGPUBindGroupLayout layoutTexSampledBuff1Un{};
|
||||
WGPUBindGroupLayout layoutTexScreen1WO{};
|
||||
WGPUBindGroupLayout layoutTexStrorage1WO{};
|
||||
WGPUBindGroupLayout layoutTexStrorage1RO{};
|
||||
|
@ -40,6 +41,7 @@ public:
|
|||
WGPUBindGroupLayout layoutBuffer3Un{};
|
||||
public:
|
||||
WGPUBindGroup createBindGroupTexSampled(WGPUSampler sampler, WGPUTextureView texView);
|
||||
WGPUBindGroup createBindGroupTexSampledBuff1Un(WGPUSampler sampler, WGPUTextureView texView, WGPUBuffer buff);
|
||||
WGPUBindGroup createBindGroupScreen1WO(WGPUTextureView texView);
|
||||
WGPUBindGroup createBindGroupStrorage1WO(WGPUTextureView texView);
|
||||
WGPUBindGroup createBindGroupStrorage1RO(WGPUTextureView texView);
|
||||
|
|
|
@ -69,26 +69,33 @@ void WgContext::initialize(WGPUInstance instance, WGPUSurface surface)
|
|||
|
||||
// create shared webgpu assets
|
||||
allocateBufferIndexFan(32768);
|
||||
samplerNearest = createSampler(WGPUFilterMode_Nearest, WGPUMipmapFilterMode_Nearest);
|
||||
samplerLinear = createSampler(WGPUFilterMode_Linear, WGPUMipmapFilterMode_Linear);
|
||||
assert(samplerNearest);
|
||||
assert(samplerLinear);
|
||||
samplerNearestRepeat = createSampler(WGPUFilterMode_Nearest, WGPUMipmapFilterMode_Nearest, WGPUAddressMode_Repeat);
|
||||
samplerLinearRepeat = createSampler(WGPUFilterMode_Linear, WGPUMipmapFilterMode_Linear, WGPUAddressMode_Repeat);
|
||||
samplerLinearMirror = createSampler(WGPUFilterMode_Linear, WGPUMipmapFilterMode_Linear, WGPUAddressMode_MirrorRepeat);
|
||||
samplerLinearClamp = createSampler(WGPUFilterMode_Linear, WGPUMipmapFilterMode_Linear, WGPUAddressMode_ClampToEdge);
|
||||
assert(samplerNearestRepeat);
|
||||
assert(samplerLinearRepeat);
|
||||
assert(samplerLinearMirror);
|
||||
assert(samplerLinearClamp);
|
||||
}
|
||||
|
||||
|
||||
void WgContext::release()
|
||||
{
|
||||
releaseSampler(samplerNearest);
|
||||
releaseSampler(samplerLinear);
|
||||
releaseSampler(samplerLinearClamp);
|
||||
releaseSampler(samplerLinearMirror);
|
||||
releaseSampler(samplerLinearRepeat);
|
||||
releaseSampler(samplerNearestRepeat);
|
||||
releaseBuffer(bufferIndexFan);
|
||||
wgpuDeviceRelease(device);
|
||||
wgpuAdapterRelease(adapter);
|
||||
}
|
||||
|
||||
|
||||
WGPUSampler WgContext::createSampler(WGPUFilterMode filter, WGPUMipmapFilterMode mipmapFilter)
|
||||
WGPUSampler WgContext::createSampler(WGPUFilterMode filter, WGPUMipmapFilterMode mipmapFilter, WGPUAddressMode addrMode)
|
||||
{
|
||||
const WGPUSamplerDescriptor samplerDesc {
|
||||
.addressModeU = addrMode, .addressModeV = addrMode, .addressModeW = addrMode,
|
||||
.magFilter = filter, .minFilter = filter, .mipmapFilter = mipmapFilter,
|
||||
.lodMinClamp = 0.0f, .lodMaxClamp = 32.0f, .maxAnisotropy = 1
|
||||
};
|
||||
|
@ -96,6 +103,31 @@ WGPUSampler WgContext::createSampler(WGPUFilterMode filter, WGPUMipmapFilterMode
|
|||
}
|
||||
|
||||
|
||||
bool WgContext::allocateTexture(WGPUTexture& texture, uint32_t width, uint32_t height, WGPUTextureFormat format, void* data)
|
||||
{
|
||||
if ((texture) && (wgpuTextureGetWidth(texture) == width) && (wgpuTextureGetHeight(texture) == height)) {
|
||||
// update texture data
|
||||
const WGPUImageCopyTexture imageCopyTexture{ .texture = texture };
|
||||
const WGPUTextureDataLayout textureDataLayout{ .bytesPerRow = 4 * width, .rowsPerImage = height };
|
||||
const WGPUExtent3D writeSize{ .width = width, .height = height, .depthOrArrayLayers = 1 };
|
||||
wgpuQueueWriteTexture(queue, &imageCopyTexture, data, 4 * width * height, &textureDataLayout, &writeSize);
|
||||
wgpuQueueSubmit(queue, 0, nullptr);
|
||||
} else {
|
||||
releaseTexture(texture);
|
||||
texture = createTexture(width, height, format);
|
||||
// update texture data
|
||||
const WGPUImageCopyTexture imageCopyTexture{ .texture = texture };
|
||||
const WGPUTextureDataLayout textureDataLayout{ .bytesPerRow = 4 * width, .rowsPerImage = height };
|
||||
const WGPUExtent3D writeSize{ .width = width, .height = height, .depthOrArrayLayers = 1 };
|
||||
wgpuQueueWriteTexture(queue, &imageCopyTexture, data, 4 * width * height, &textureDataLayout, &writeSize);
|
||||
wgpuQueueSubmit(queue, 0, nullptr);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
WGPUTexture WgContext::createTexture(uint32_t width, uint32_t height, WGPUTextureFormat format)
|
||||
{
|
||||
const WGPUTextureDescriptor textureDesc {
|
||||
|
|
|
@ -44,18 +44,21 @@ struct WgContext {
|
|||
WgPipelines* pipelines{};
|
||||
// shared webgpu assets
|
||||
WGPUBuffer bufferIndexFan{};
|
||||
WGPUSampler samplerNearest{};
|
||||
WGPUSampler samplerLinear{};
|
||||
WGPUSampler samplerNearestRepeat{};
|
||||
WGPUSampler samplerLinearRepeat{};
|
||||
WGPUSampler samplerLinearMirror{};
|
||||
WGPUSampler samplerLinearClamp{};
|
||||
|
||||
void initialize(WGPUInstance instance, WGPUSurface surface);
|
||||
void release();
|
||||
|
||||
// create common objects
|
||||
WGPUSampler createSampler(WGPUFilterMode filter, WGPUMipmapFilterMode mipmapFilter);
|
||||
WGPUSampler createSampler(WGPUFilterMode filter, WGPUMipmapFilterMode mipmapFilter, WGPUAddressMode addrMode);
|
||||
WGPUTexture createTexture(uint32_t width, uint32_t height, WGPUTextureFormat format);
|
||||
WGPUTexture createTexStorage(uint32_t width, uint32_t height, WGPUTextureFormat format, uint32_t sc = 1);
|
||||
WGPUTexture createTexStencil(uint32_t width, uint32_t height, WGPUTextureFormat format, uint32_t sc = 1);
|
||||
WGPUTextureView createTextureView(WGPUTexture texture);
|
||||
bool allocateTexture(WGPUTexture& texture, uint32_t width, uint32_t height, WGPUTextureFormat format, void* data);
|
||||
|
||||
// release common objects
|
||||
void releaseTextureView(WGPUTextureView& textureView);
|
||||
|
|
|
@ -371,10 +371,10 @@ void WgCompositor::drawShape(WgContext& context, WgRenderDataShape* renderData,
|
|||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupSolid, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->solid[blendTypeInd]);
|
||||
} else if (settings.fillType == WgRenderSettingsType::Linear) {
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupLinear, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupGradient, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->linear[blendTypeInd]);
|
||||
} else if (settings.fillType == WgRenderSettingsType::Radial) {
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupRadial, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupGradient, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->radial[blendTypeInd]);
|
||||
}
|
||||
// draw to color (second pass)
|
||||
|
@ -409,10 +409,10 @@ void WgCompositor::drawStrokes(WgContext& context, WgRenderDataShape* renderData
|
|||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupSolid, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->solid[blendTypeInd]);
|
||||
} else if (settings.fillType == WgRenderSettingsType::Linear) {
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupLinear, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupGradient, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->linear[blendTypeInd]);
|
||||
} else if (settings.fillType == WgRenderSettingsType::Radial) {
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupRadial, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupGradient, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->radial[blendTypeInd]);
|
||||
}
|
||||
// draw to color (second pass)
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
#include "tvgWgPipelines.h"
|
||||
#include "tvgWgShaderSrc.h"
|
||||
#include <cstring>
|
||||
|
||||
WGPUShaderModule WgPipelines::createShaderModule(WGPUDevice device, const char* label, const char* code)
|
||||
{
|
||||
|
@ -74,14 +75,15 @@ WGPURenderPipeline WgPipelines::createRenderPipeline(
|
|||
|
||||
WGPUComputePipeline WgPipelines::createComputePipeline(
|
||||
WGPUDevice device, const char* pipelineLabel,
|
||||
const WGPUShaderModule shaderModule, const WGPUPipelineLayout pipelineLayout)
|
||||
const WGPUShaderModule shaderModule, const char* entryPoint,
|
||||
const WGPUPipelineLayout pipelineLayout)
|
||||
{
|
||||
const WGPUComputePipelineDescriptor computePipelineDesc{
|
||||
.label = pipelineLabel,
|
||||
.layout = pipelineLayout,
|
||||
.compute = {
|
||||
.module = shaderModule,
|
||||
.entryPoint = "cs_main"
|
||||
.entryPoint = entryPoint
|
||||
}
|
||||
};
|
||||
return wgpuDeviceCreateComputePipeline(device, &computePipelineDesc);
|
||||
|
@ -165,11 +167,16 @@ void WgPipelines::initialize(WgContext& context)
|
|||
layouts.layoutBuffer1Un,
|
||||
layouts.layoutBuffer2Un
|
||||
};
|
||||
const WGPUBindGroupLayout bindGroupLayoutsFill[] = {
|
||||
const WGPUBindGroupLayout bindGroupLayoutsSolid[] = {
|
||||
layouts.layoutBuffer1Un,
|
||||
layouts.layoutBuffer2Un,
|
||||
layouts.layoutBuffer1Un
|
||||
};
|
||||
const WGPUBindGroupLayout bindGroupLayoutsGradient[] = {
|
||||
layouts.layoutBuffer1Un,
|
||||
layouts.layoutBuffer2Un,
|
||||
layouts.layoutTexSampledBuff1Un
|
||||
};
|
||||
const WGPUBindGroupLayout bindGroupLayoutsImage[] = {
|
||||
layouts.layoutBuffer1Un,
|
||||
layouts.layoutBuffer2Un,
|
||||
|
@ -199,7 +206,8 @@ void WgPipelines::initialize(WgContext& context)
|
|||
|
||||
// pipeline layouts
|
||||
layoutStencil = createPipelineLayout(context.device, bindGroupLayoutsStencil, 2);
|
||||
layoutFill = createPipelineLayout(context.device, bindGroupLayoutsFill, 3);
|
||||
layoutSolid = createPipelineLayout(context.device, bindGroupLayoutsSolid, 3);
|
||||
layoutGradient = createPipelineLayout(context.device, bindGroupLayoutsGradient, 3);
|
||||
layoutImage = createPipelineLayout(context.device, bindGroupLayoutsImage, 3);
|
||||
layoutBlend = createPipelineLayout(context.device, bindGroupLayoutsBlend, 4);
|
||||
layoutCompose = createPipelineLayout(context.device, bindGroupLayoutsCompose, 4);
|
||||
|
@ -257,7 +265,7 @@ void WgPipelines::initialize(WgContext& context)
|
|||
for (uint32_t i = 0; i < 3; i++) {
|
||||
solid[i] = createRenderPipeline(
|
||||
context.device, "The render pipeline solid",
|
||||
shaderSolid, layoutFill,
|
||||
shaderSolid, layoutSolid,
|
||||
vertexBufferLayoutsShape, 1,
|
||||
WGPUColorWriteMask_All,
|
||||
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
|
||||
|
@ -269,7 +277,7 @@ void WgPipelines::initialize(WgContext& context)
|
|||
for (uint32_t i = 0; i < 3; i++) {
|
||||
radial[i] = createRenderPipeline(
|
||||
context.device, "The render pipeline radial",
|
||||
shaderRadial, layoutFill,
|
||||
shaderRadial, layoutGradient,
|
||||
vertexBufferLayoutsShape, 1,
|
||||
WGPUColorWriteMask_All,
|
||||
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
|
||||
|
@ -281,7 +289,7 @@ void WgPipelines::initialize(WgContext& context)
|
|||
for (uint32_t i = 0; i < 3; i++) {
|
||||
linear[i] = createRenderPipeline(
|
||||
context.device, "The render pipeline linear",
|
||||
shaderLinear, layoutFill,
|
||||
shaderLinear, layoutGradient,
|
||||
vertexBufferLayoutsShape, 1,
|
||||
WGPUColorWriteMask_All,
|
||||
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
|
||||
|
@ -302,26 +310,68 @@ void WgPipelines::initialize(WgContext& context)
|
|||
}
|
||||
|
||||
// compute pipelines
|
||||
mergeMasks = createComputePipeline(context.device, "The pipeline merge masks", shaderMergeMasks, layoutMergeMasks);
|
||||
copy = createComputePipeline(context.device, "The pipeline copy", shaderCopy, layoutCopy);
|
||||
// compute pipelines blend
|
||||
const size_t shaderBlendCnt = sizeof(cShaderSrc_Blend_Solid)/sizeof(cShaderSrc_Blend_Solid[0]);
|
||||
for (uint32_t i = 0; i < shaderBlendCnt; i++) {
|
||||
// blend shaders
|
||||
shaderBlendSolid[i] = createShaderModule(context.device, "The shader blend solid", cShaderSrc_Blend_Solid[i]);
|
||||
shaderBlendGradient[i] = createShaderModule(context.device, "The shader blend gradient", cShaderSrc_Blend_Gradient[i]);
|
||||
shaderBlendImage[i] = createShaderModule(context.device, "The shader blend image", cShaderSrc_Blend_Image[i]);
|
||||
// blend pipelines
|
||||
blendSolid[i] = createComputePipeline(context.device, "The pipeline blend solid", shaderBlendSolid[i], layoutBlend);
|
||||
blendGradient[i] = createComputePipeline(context.device, "The pipeline blend gradient", shaderBlendGradient[i], layoutBlend);
|
||||
blendImage[i] = createComputePipeline(context.device, "The pipeline blend image", shaderBlendImage[i], layoutBlend);
|
||||
}
|
||||
// compute pipelines compose
|
||||
const size_t shaderComposeCnt = sizeof(cShaderSrc_Compose)/sizeof(cShaderSrc_Compose[0]);
|
||||
for (uint32_t i = 0; i < shaderComposeCnt; i++) {
|
||||
shaderCompose[i] = createShaderModule(context.device, "The shader compose", cShaderSrc_Compose[i]);
|
||||
compose[i] = createComputePipeline(context.device, "The pipeline compose", shaderCompose[i], layoutCompose);
|
||||
mergeMasks = createComputePipeline(context.device, "The pipeline merge masks", shaderMergeMasks, "cs_main", layoutMergeMasks);
|
||||
copy = createComputePipeline(context.device, "The pipeline copy", shaderCopy, "cs_main", layoutCopy);
|
||||
|
||||
// compute shader blend names
|
||||
const char* shaderBlendNames[] {
|
||||
"cs_main_Normal",
|
||||
"cs_main_Add",
|
||||
"cs_main_Screen",
|
||||
"cs_main_Multiply",
|
||||
"cs_main_Overlay",
|
||||
"cs_main_Difference",
|
||||
"cs_main_Exclusion",
|
||||
"cs_main_SrcOver",
|
||||
"cs_main_Darken",
|
||||
"cs_main_Lighten",
|
||||
"cs_main_ColorDodge",
|
||||
"cs_main_ColorBurn",
|
||||
"cs_main_HardLight",
|
||||
"cs_main_SoftLight"
|
||||
};
|
||||
|
||||
// create blend shaders
|
||||
char shaderSourceBuff[16384];
|
||||
shaderBlendSolid = createShaderModule(context.device, "The shader blend solid", strcat(strcpy(shaderSourceBuff, cShaderSrc_BlendHeader_Solid), cShaderSrc_Blend_Funcs));
|
||||
shaderBlendGradient = createShaderModule(context.device, "The shader blend gradient", strcat(strcpy(shaderSourceBuff, cShaderSrc_BlendHeader_Gradient), cShaderSrc_Blend_Funcs));
|
||||
shaderBlendImage = createShaderModule(context.device, "The shader blend image", strcat(strcpy(shaderSourceBuff, cShaderSrc_BlendHeader_Image), cShaderSrc_Blend_Funcs));
|
||||
|
||||
// create blend pipelines
|
||||
const size_t shaderBlendNamesCnt = sizeof(shaderBlendNames) / sizeof(shaderBlendNames[0]);
|
||||
const size_t pipesBlendCnt = sizeof(blendSolid) / sizeof(blendSolid[0]);
|
||||
assert(shaderBlendNamesCnt == pipesBlendCnt);
|
||||
for (uint32_t i = 0; i < pipesBlendCnt; i++) {
|
||||
blendSolid[i] = createComputePipeline(context.device, "The pipeline blend solid", shaderBlendSolid, shaderBlendNames[i], layoutBlend);
|
||||
blendGradient[i] = createComputePipeline(context.device, "The pipeline blend gradient", shaderBlendGradient, shaderBlendNames[i], layoutBlend);
|
||||
blendImage[i] = createComputePipeline(context.device, "The pipeline blend image", shaderBlendImage, shaderBlendNames[i], layoutBlend);
|
||||
}
|
||||
|
||||
// compute shader compose names
|
||||
const char* shaderComposeNames[] {
|
||||
"cs_main_None",
|
||||
"cs_main_ClipPath",
|
||||
"cs_main_AlphaMask",
|
||||
"cs_main_InvAlphaMask",
|
||||
"cs_main_LumaMask",
|
||||
"cs_main_InvLumaMask",
|
||||
"cs_main_AddMask",
|
||||
"cs_main_SubtractMask",
|
||||
"cs_main_IntersectMask",
|
||||
"cs_main_DifferenceMask",
|
||||
"cs_main_LightenMask",
|
||||
"cs_main_DarkenMask"
|
||||
};
|
||||
|
||||
// create compose shaders
|
||||
shaderCompose = createShaderModule(context.device, "The shader compose", cShaderSrc_Compose);
|
||||
|
||||
// create compose pipelines
|
||||
const size_t shaderComposeNamesCnt = sizeof(shaderComposeNames) / sizeof(shaderComposeNames[0]);
|
||||
const size_t pipesComposeCnt = sizeof(compose) / sizeof(compose[0]);
|
||||
assert(shaderComposeNamesCnt == pipesComposeCnt);
|
||||
for (uint32_t i = 0; i < pipesComposeCnt; i++)
|
||||
compose[i] = createComputePipeline(context.device, "The pipeline compose", shaderCompose, shaderComposeNames[i], layoutCompose);
|
||||
}
|
||||
|
||||
void WgPipelines::releaseGraphicHandles(WgContext& context)
|
||||
|
@ -337,7 +387,8 @@ void WgPipelines::releaseGraphicHandles(WgContext& context)
|
|||
releaseRenderPipeline(evenodd);
|
||||
releaseRenderPipeline(winding);
|
||||
releasePipelineLayout(layoutImage);
|
||||
releasePipelineLayout(layoutFill);
|
||||
releasePipelineLayout(layoutGradient);
|
||||
releasePipelineLayout(layoutSolid);
|
||||
releasePipelineLayout(layoutStencil);
|
||||
releaseShaderModule(shaderImage);
|
||||
releaseShaderModule(shaderLinear);
|
||||
|
@ -349,19 +400,14 @@ void WgPipelines::releaseGraphicHandles(WgContext& context)
|
|||
|
||||
void WgPipelines::releaseComputeHandles(WgContext& context)
|
||||
{
|
||||
const size_t shaderComposeCnt = sizeof(shaderCompose)/sizeof(shaderCompose[0]);
|
||||
for (uint32_t i = 0; i < shaderComposeCnt; i++) {
|
||||
size_t pipesComposeCnt = sizeof(compose) / sizeof(compose[0]);
|
||||
for (uint32_t i = 0; i < pipesComposeCnt; i++)
|
||||
releaseComputePipeline(compose[i]);
|
||||
releaseShaderModule(shaderCompose[i]);
|
||||
}
|
||||
const size_t shaderBlendImageCnt = sizeof(shaderBlendImage)/sizeof(shaderBlendImage[0]);
|
||||
for (uint32_t i = 0; i < shaderBlendImageCnt; i++) {
|
||||
const size_t pipesBlendCnt = sizeof(blendSolid)/sizeof(blendSolid[0]);
|
||||
for (uint32_t i = 0; i < pipesBlendCnt; i++) {
|
||||
releaseComputePipeline(blendImage[i]);
|
||||
releaseComputePipeline(blendSolid[i]);
|
||||
releaseComputePipeline(blendGradient[i]);
|
||||
releaseShaderModule(shaderBlendImage[i]);
|
||||
releaseShaderModule(shaderBlendGradient[i]);
|
||||
releaseShaderModule(shaderBlendSolid[i]);
|
||||
}
|
||||
releaseComputePipeline(copy);
|
||||
releaseComputePipeline(mergeMasks);
|
||||
|
@ -369,6 +415,10 @@ void WgPipelines::releaseComputeHandles(WgContext& context)
|
|||
releasePipelineLayout(layoutBlend);
|
||||
releasePipelineLayout(layoutMergeMasks);
|
||||
releasePipelineLayout(layoutCopy);
|
||||
releaseShaderModule(shaderCompose);
|
||||
releaseShaderModule(shaderBlendImage);
|
||||
releaseShaderModule(shaderBlendGradient);
|
||||
releaseShaderModule(shaderBlendSolid);
|
||||
releaseShaderModule(shaderMergeMasks);
|
||||
releaseShaderModule(shaderCopy);
|
||||
}
|
||||
|
|
|
@ -37,15 +37,16 @@ private:
|
|||
WGPUShaderModule shaderImage{};
|
||||
// compute pipeline shaders
|
||||
WGPUShaderModule shaderMergeMasks;
|
||||
WGPUShaderModule shaderBlendSolid[14];
|
||||
WGPUShaderModule shaderBlendGradient[14];
|
||||
WGPUShaderModule shaderBlendImage[14];
|
||||
WGPUShaderModule shaderCompose[12];
|
||||
WGPUShaderModule shaderBlendSolid;
|
||||
WGPUShaderModule shaderBlendGradient;
|
||||
WGPUShaderModule shaderBlendImage;
|
||||
WGPUShaderModule shaderCompose;
|
||||
WGPUShaderModule shaderCopy;
|
||||
private:
|
||||
// graphics pipeline layouts
|
||||
WGPUPipelineLayout layoutStencil{};
|
||||
WGPUPipelineLayout layoutFill{};
|
||||
WGPUPipelineLayout layoutSolid{};
|
||||
WGPUPipelineLayout layoutGradient{};
|
||||
WGPUPipelineLayout layoutImage{};
|
||||
// compute pipeline layouts
|
||||
WGPUPipelineLayout layoutMergeMasks{};
|
||||
|
@ -86,7 +87,8 @@ private:
|
|||
const WGPUPrimitiveState primitiveState, const WGPUMultisampleState multisampleState, const WGPUBlendState blendState);
|
||||
WGPUComputePipeline createComputePipeline(
|
||||
WGPUDevice device, const char* pipelineLabel,
|
||||
const WGPUShaderModule shaderModule, const WGPUPipelineLayout pipelineLayout);
|
||||
const WGPUShaderModule shaderModule, const char* entryPoint,
|
||||
const WGPUPipelineLayout pipelineLayout);
|
||||
void releaseComputePipeline(WGPUComputePipeline& computePipeline);
|
||||
void releaseRenderPipeline(WGPURenderPipeline& renderPipeline);
|
||||
void releasePipelineLayout(WGPUPipelineLayout& pipelineLayout);
|
||||
|
|
|
@ -212,22 +212,30 @@ void WgRenderSettings::update(WgContext& context, const Fill* fill, const uint8_
|
|||
// setup fill properties
|
||||
if ((flags & (RenderUpdateFlag::Gradient)) && fill) {
|
||||
rasterType = WgRenderRasterType::Gradient;
|
||||
// setup linear fill properties
|
||||
WgShaderTypeGradient gradient;
|
||||
if (fill->type() == Type::LinearGradient) {
|
||||
WgShaderTypeLinearGradient linearGradient((LinearGradient*)fill);
|
||||
if (context.allocateBufferUniform(bufferGroupLinear, &linearGradient, sizeof(linearGradient))) {
|
||||
context.pipelines->layouts.releaseBindGroup(bindGroupLinear);
|
||||
bindGroupLinear = context.pipelines->layouts.createBindGroupBuffer1Un(bufferGroupLinear);
|
||||
}
|
||||
gradient.update((LinearGradient*)fill);
|
||||
fillType = WgRenderSettingsType::Linear;
|
||||
} else if (fill->type() == Type::RadialGradient) {
|
||||
WgShaderTypeRadialGradient radialGradient((RadialGradient*)fill);
|
||||
if (context.allocateBufferUniform(bufferGroupRadial, &radialGradient, sizeof(radialGradient))) {
|
||||
context.pipelines->layouts.releaseBindGroup(bindGroupRadial);
|
||||
bindGroupRadial = context.pipelines->layouts.createBindGroupBuffer1Un(bufferGroupRadial);
|
||||
}
|
||||
gradient.update((RadialGradient*)fill);
|
||||
fillType = WgRenderSettingsType::Radial;
|
||||
}
|
||||
// update gpu assets
|
||||
bool bufferGradientSettingsChanged = context.allocateBufferUniform(bufferGroupGradient, &gradient.settings, sizeof(gradient.settings));
|
||||
bool textureGradientChanged = context.allocateTexture(texGradient, WG_TEXTURE_GRADIENT_SIZE, 1, WGPUTextureFormat_RGBA8Unorm, gradient.texData);
|
||||
if (bufferGradientSettingsChanged || textureGradientChanged) {
|
||||
// update texture view
|
||||
context.releaseTextureView(texViewGradient);
|
||||
texViewGradient = context.createTextureView(texGradient);
|
||||
// get sampler by spread type
|
||||
WGPUSampler sampler = context.samplerLinearClamp;
|
||||
if (fill->spread() == FillSpread::Reflect) sampler = context.samplerLinearMirror;
|
||||
if (fill->spread() == FillSpread::Repeat) sampler = context.samplerLinearRepeat;
|
||||
// update bind group
|
||||
context.pipelines->layouts.releaseBindGroup(bindGroupGradient);
|
||||
bindGroupGradient = context.pipelines->layouts.createBindGroupTexSampledBuff1Un(
|
||||
sampler, texViewGradient, bufferGroupGradient);
|
||||
}
|
||||
skip = false;
|
||||
} else if ((flags & (RenderUpdateFlag::Color)) && !fill) {
|
||||
rasterType = WgRenderRasterType::Solid;
|
||||
|
@ -245,12 +253,11 @@ void WgRenderSettings::update(WgContext& context, const Fill* fill, const uint8_
|
|||
void WgRenderSettings::release(WgContext& context)
|
||||
{
|
||||
context.pipelines->layouts.releaseBindGroup(bindGroupSolid);
|
||||
context.pipelines->layouts.releaseBindGroup(bindGroupLinear);
|
||||
context.pipelines->layouts.releaseBindGroup(bindGroupRadial);
|
||||
context.pipelines->layouts.releaseBindGroup(bindGroupGradient);
|
||||
context.releaseBuffer(bufferGroupSolid);
|
||||
context.releaseBuffer(bufferGroupLinear);
|
||||
context.releaseBuffer(bufferGroupRadial);
|
||||
|
||||
context.releaseBuffer(bufferGroupGradient);
|
||||
context.releaseTexture(texGradient);
|
||||
context.releaseTextureView(texViewGradient);
|
||||
};
|
||||
|
||||
//***********************************************************************
|
||||
|
|
|
@ -78,11 +78,11 @@ enum class WgRenderRasterType { Solid = 0, Gradient, Image };
|
|||
struct WgRenderSettings
|
||||
{
|
||||
WGPUBuffer bufferGroupSolid{};
|
||||
WGPUBuffer bufferGroupLinear{};
|
||||
WGPUBuffer bufferGroupRadial{};
|
||||
WGPUBindGroup bindGroupSolid{};
|
||||
WGPUBindGroup bindGroupLinear{};
|
||||
WGPUBindGroup bindGroupRadial{};
|
||||
WGPUTexture texGradient{};
|
||||
WGPUTextureView texViewGradient{};
|
||||
WGPUBuffer bufferGroupGradient{};
|
||||
WGPUBindGroup bindGroupGradient{};
|
||||
WgRenderSettingsType fillType{};
|
||||
WgRenderRasterType rasterType{};
|
||||
bool skip{};
|
||||
|
|
|
@ -30,7 +30,7 @@ void WgRenderStorage::initialize(WgContext& context, uint32_t width, uint32_t he
|
|||
texView = context.createTextureView(texture);
|
||||
bindGroupRead = context.pipelines->layouts.createBindGroupStrorage1RO(texView);
|
||||
bindGroupWrite = context.pipelines->layouts.createBindGroupStrorage1WO(texView);
|
||||
bindGroupTexure = context.pipelines->layouts.createBindGroupTexSampled(context.samplerNearest, texView);
|
||||
bindGroupTexure = context.pipelines->layouts.createBindGroupTexSampled(context.samplerNearestRepeat, texView);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
*/
|
||||
|
||||
#include "tvgWgRenderer.h"
|
||||
#include <iostream>
|
||||
|
||||
WgRenderer::WgRenderer()
|
||||
{
|
||||
|
@ -135,7 +134,7 @@ RenderData WgRenderer::prepare(Surface* surface, const RenderMesh* mesh, RenderD
|
|||
renderDataPicture->meshData.update(mContext, &geometryData);
|
||||
renderDataPicture->imageData.update(mContext, surface);
|
||||
renderDataPicture->bindGroupPicture = mContext.pipelines->layouts.createBindGroupTexSampled(
|
||||
mContext.samplerLinear, renderDataPicture->imageData.textureView
|
||||
mContext.samplerLinearRepeat, renderDataPicture->imageData.textureView
|
||||
);
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -32,11 +32,11 @@ extern const char* cShaderSrc_Image;
|
|||
|
||||
// compute shader sources: blend, compose and merge path
|
||||
extern const char* cShaderSrc_MergeMasks;
|
||||
extern const char* cShaderSrc_Blend_Solid[14];
|
||||
extern const char* cShaderSrc_Blend_Solid[14];
|
||||
extern const char* cShaderSrc_Blend_Gradient[14];
|
||||
extern const char* cShaderSrc_Blend_Image[14];
|
||||
extern const char* cShaderSrc_Compose[12];
|
||||
extern const char* cShaderSrc_BlendHeader_Solid;
|
||||
extern const char* cShaderSrc_BlendHeader_Gradient;
|
||||
extern const char* cShaderSrc_BlendHeader_Image;
|
||||
extern const char* cShaderSrc_Blend_Funcs;
|
||||
extern const char* cShaderSrc_Compose;
|
||||
extern const char* cShaderSrc_Copy;
|
||||
|
||||
#endif // _TVG_WG_SHEDER_SRC_H_
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
*/
|
||||
|
||||
#include "tvgWgShaderTypes.h"
|
||||
#include <cassert>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// shader types
|
||||
|
@ -92,10 +93,8 @@ WgShaderTypeBlendSettings::WgShaderTypeBlendSettings(const ColorSpace colorSpace
|
|||
|
||||
void WgShaderTypeBlendSettings::update(const ColorSpace colorSpace, uint8_t o)
|
||||
{
|
||||
format = (uint32_t)colorSpace;
|
||||
dummy0 = 0.0f;
|
||||
dummy1 = 0.0f;
|
||||
opacity = o / 255.0f;
|
||||
settings[0] = (uint32_t)colorSpace;
|
||||
settings[3] = o / 255.0f;
|
||||
}
|
||||
|
||||
|
||||
|
@ -114,53 +113,59 @@ void WgShaderTypeSolidColor::update(const uint8_t* c)
|
|||
}
|
||||
|
||||
|
||||
WgShaderTypeLinearGradient::WgShaderTypeLinearGradient(const LinearGradient* linearGradient)
|
||||
{
|
||||
update(linearGradient);
|
||||
}
|
||||
|
||||
|
||||
void WgShaderTypeLinearGradient::update(const LinearGradient* linearGradient)
|
||||
void WgShaderTypeGradient::update(const LinearGradient* linearGradient)
|
||||
{
|
||||
// update gradient data
|
||||
const Fill::ColorStop* stops = nullptr;
|
||||
auto stopCnt = linearGradient->colorStops(&stops);
|
||||
|
||||
nStops = stopCnt;
|
||||
spread = uint32_t(linearGradient->spread());
|
||||
|
||||
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]);
|
||||
}
|
||||
updateTexData(stops, stopCnt);
|
||||
// update base points
|
||||
linearGradient->linear(&settings[0], &settings[1], &settings[2], &settings[3]);
|
||||
};
|
||||
|
||||
|
||||
WgShaderTypeRadialGradient::WgShaderTypeRadialGradient(const RadialGradient* radialGradient)
|
||||
{
|
||||
update(radialGradient);
|
||||
}
|
||||
|
||||
|
||||
void WgShaderTypeRadialGradient::update(const RadialGradient* radialGradient)
|
||||
void WgShaderTypeGradient::update(const RadialGradient* radialGradient)
|
||||
{
|
||||
// update gradient data
|
||||
const Fill::ColorStop* stops = nullptr;
|
||||
auto stopCnt = radialGradient->colorStops(&stops);
|
||||
updateTexData(stops, stopCnt);
|
||||
// update base points
|
||||
radialGradient->radial(&settings[2], &settings[3], &settings[0]);
|
||||
};
|
||||
|
||||
nStops = stopCnt;
|
||||
spread = uint32_t(radialGradient->spread());
|
||||
|
||||
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;
|
||||
void WgShaderTypeGradient::updateTexData(const Fill::ColorStop* stops, uint32_t stopCnt)
|
||||
{
|
||||
assert(stops);
|
||||
// head
|
||||
uint32_t range_s = 0;
|
||||
uint32_t range_e = uint32_t(stops[0].offset * (WG_TEXTURE_GRADIENT_SIZE-1));
|
||||
for (uint32_t ti = range_s; (ti < range_e) && (ti < WG_TEXTURE_GRADIENT_SIZE); ti++) {
|
||||
texData[ti * 4 + 0] = stops[0].r;
|
||||
texData[ti * 4 + 1] = stops[0].g;
|
||||
texData[ti * 4 + 2] = stops[0].b;
|
||||
texData[ti * 4 + 3] = stops[0].a;
|
||||
}
|
||||
// body
|
||||
for (uint32_t di = 1; di < stopCnt; di++) {
|
||||
range_s = uint32_t(stops[di-1].offset * (WG_TEXTURE_GRADIENT_SIZE-1));
|
||||
range_e = uint32_t(stops[di-0].offset * (WG_TEXTURE_GRADIENT_SIZE-1));
|
||||
for (uint32_t ti = range_s; (ti < range_e) && (ti < WG_TEXTURE_GRADIENT_SIZE); ti++) {
|
||||
float t = float(ti - range_s) / (range_e - range_s);
|
||||
texData[ti * 4 + 0] = uint8_t((1.0f - t) * stops[di-1].r + t * stops[di].r);
|
||||
texData[ti * 4 + 1] = uint8_t((1.0f - t) * stops[di-1].g + t * stops[di].g);
|
||||
texData[ti * 4 + 2] = uint8_t((1.0f - t) * stops[di-1].b + t * stops[di].b);
|
||||
texData[ti * 4 + 3] = uint8_t((1.0f - t) * stops[di-1].a + t * stops[di].a);
|
||||
}
|
||||
}
|
||||
// tail
|
||||
range_s = uint32_t(stops[stopCnt-1].offset * (WG_TEXTURE_GRADIENT_SIZE-1));
|
||||
range_e = WG_TEXTURE_GRADIENT_SIZE;
|
||||
for (uint32_t ti = range_s; ti < range_e; ti++) {
|
||||
texData[ti * 4 + 0] = stops[stopCnt-1].r;
|
||||
texData[ti * 4 + 1] = stops[stopCnt-1].g;
|
||||
texData[ti * 4 + 2] = stops[stopCnt-1].b;
|
||||
texData[ti * 4 + 3] = stops[stopCnt-1].a;
|
||||
}
|
||||
|
||||
radialGradient->radial(¢erPos[0], ¢erPos[1], &radius[0]);
|
||||
}
|
||||
|
|
|
@ -42,27 +42,17 @@ struct WgShaderTypeMat4x4f
|
|||
void update(size_t w, size_t h);
|
||||
};
|
||||
|
||||
// struct BlendSettings {
|
||||
// format : u32, // ColorSpace
|
||||
// dummy0 : f32,
|
||||
// dummy1 : f32,
|
||||
// opacity : f32
|
||||
// };
|
||||
// vec4f
|
||||
struct WgShaderTypeBlendSettings
|
||||
{
|
||||
uint32_t format{}; // ColorSpace
|
||||
float dummy0{};
|
||||
float dummy1{};
|
||||
float opacity{};
|
||||
float settings[4]{};
|
||||
|
||||
WgShaderTypeBlendSettings() {};
|
||||
WgShaderTypeBlendSettings(const ColorSpace colorSpace, uint8_t o);
|
||||
void update(const ColorSpace colorSpace, uint8_t o);
|
||||
};
|
||||
|
||||
// struct SolidColor {
|
||||
// color: vec4f
|
||||
// };
|
||||
// vec4f
|
||||
struct WgShaderTypeSolidColor
|
||||
{
|
||||
float color[4]{};
|
||||
|
@ -71,58 +61,16 @@ struct WgShaderTypeSolidColor
|
|||
void update(const uint8_t* c);
|
||||
};
|
||||
|
||||
// const MAX_LINEAR_GRADIENT_STOPS = 4;
|
||||
// struct LinearGradient {
|
||||
// nStops : u32,
|
||||
// spread : u32,
|
||||
// dummy0 : u32,
|
||||
// dummy1 : u32,
|
||||
// gradStartPos : vec2f,
|
||||
// gradEndPos : vec2f,
|
||||
// stopPoints : vec4f,
|
||||
// stopColors : array<vec4f, MAX_LINEAR_GRADIENT_STOPS>
|
||||
// };
|
||||
#define MAX_LINEAR_GRADIENT_STOPS 32
|
||||
struct WgShaderTypeLinearGradient
|
||||
// sampler, texture, vec4f
|
||||
#define WG_TEXTURE_GRADIENT_SIZE 512
|
||||
struct WgShaderTypeGradient
|
||||
{
|
||||
uint32_t nStops{};
|
||||
uint32_t spread{};
|
||||
uint32_t dummy0{}; // align with WGSL struct
|
||||
uint32_t dummy1{}; // align with WGSL struct
|
||||
float startPos[2]{};
|
||||
float endPos[2]{};
|
||||
float stopPoints[MAX_LINEAR_GRADIENT_STOPS]{};
|
||||
float stopColors[4 * MAX_LINEAR_GRADIENT_STOPS]{};
|
||||
float settings[4]{};
|
||||
uint8_t texData[WG_TEXTURE_GRADIENT_SIZE * 4];
|
||||
|
||||
WgShaderTypeLinearGradient(const LinearGradient* linearGradient);
|
||||
void update(const LinearGradient* linearGradient);
|
||||
};
|
||||
|
||||
// const MAX_RADIAL_GRADIENT_STOPS = 4;
|
||||
// struct RadialGradient {
|
||||
// nStops : u32,
|
||||
// spread : u32,
|
||||
// dummy0 : u32,
|
||||
// dummy1 : u32,
|
||||
// centerPos : vec2f,
|
||||
// radius : vec2f,
|
||||
// stopPoints : vec4f,
|
||||
// stopColors : array<vec4f, MAX_RADIAL_GRADIENT_STOPS>
|
||||
// };
|
||||
#define MAX_RADIAL_GRADIENT_STOPS 32
|
||||
struct WgShaderTypeRadialGradient
|
||||
{
|
||||
uint32_t nStops{};
|
||||
uint32_t spread{};
|
||||
uint32_t dummy0{}; // align with WGSL struct
|
||||
uint32_t dummy1{}; // align with WGSL struct
|
||||
float centerPos[2]{};
|
||||
float radius[2]{};
|
||||
float stopPoints[MAX_RADIAL_GRADIENT_STOPS]{};
|
||||
float stopColors[4 * MAX_RADIAL_GRADIENT_STOPS]{};
|
||||
|
||||
WgShaderTypeRadialGradient(const RadialGradient* radialGradient);
|
||||
void update(const RadialGradient* radialGradient);
|
||||
void updateTexData(const Fill::ColorStop* stops, uint32_t stopCnt);
|
||||
};
|
||||
|
||||
#endif // _TVG_WG_SHADER_TYPES_H_
|
||||
|
|
Loading…
Add table
Reference in a new issue