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:
Sergii Liebodkin 2024-08-11 21:24:46 +00:00 committed by Hermet Park
parent a25366b283
commit 9efab30b00
15 changed files with 633 additions and 715 deletions

View file

@ -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) { WGPUBindGroup WgBindGroupLayouts::createBindGroupScreen1WO(WGPUTextureView texView) {
const WGPUBindGroupEntry bindGroupEntrys[] = { const WGPUBindGroupEntry bindGroupEntrys[] = {
{ .binding = 0, .textureView = texView } { .binding = 0, .textureView = texView }
@ -151,6 +163,17 @@ void WgBindGroupLayouts::initialize(WgContext& context)
assert(layoutTexSampled); 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 { // bind group layout tex screen 1 RO
const WGPUBindGroupLayoutEntry bindGroupLayoutEntries[] { const WGPUBindGroupLayoutEntry bindGroupLayoutEntries[] {
{ .binding = 0, .visibility = visibility_frag, .storageTexture = storageScreenWO } { .binding = 0, .visibility = visibility_frag, .storageTexture = storageScreenWO }
@ -241,6 +264,7 @@ void WgBindGroupLayouts::release(WgContext& context)
wgpuBindGroupLayoutRelease(layoutTexStrorage2RO); wgpuBindGroupLayoutRelease(layoutTexStrorage2RO);
wgpuBindGroupLayoutRelease(layoutTexStrorage1RO); wgpuBindGroupLayoutRelease(layoutTexStrorage1RO);
wgpuBindGroupLayoutRelease(layoutTexStrorage1WO); wgpuBindGroupLayoutRelease(layoutTexStrorage1WO);
wgpuBindGroupLayoutRelease(layoutTexSampledBuff1Un);
wgpuBindGroupLayoutRelease(layoutTexSampled); wgpuBindGroupLayoutRelease(layoutTexSampled);
device = nullptr; device = nullptr;
} }

View file

@ -30,6 +30,7 @@ private:
WGPUDevice device{}; WGPUDevice device{};
public: public:
WGPUBindGroupLayout layoutTexSampled{}; WGPUBindGroupLayout layoutTexSampled{};
WGPUBindGroupLayout layoutTexSampledBuff1Un{};
WGPUBindGroupLayout layoutTexScreen1WO{}; WGPUBindGroupLayout layoutTexScreen1WO{};
WGPUBindGroupLayout layoutTexStrorage1WO{}; WGPUBindGroupLayout layoutTexStrorage1WO{};
WGPUBindGroupLayout layoutTexStrorage1RO{}; WGPUBindGroupLayout layoutTexStrorage1RO{};
@ -40,6 +41,7 @@ public:
WGPUBindGroupLayout layoutBuffer3Un{}; WGPUBindGroupLayout layoutBuffer3Un{};
public: public:
WGPUBindGroup createBindGroupTexSampled(WGPUSampler sampler, WGPUTextureView texView); WGPUBindGroup createBindGroupTexSampled(WGPUSampler sampler, WGPUTextureView texView);
WGPUBindGroup createBindGroupTexSampledBuff1Un(WGPUSampler sampler, WGPUTextureView texView, WGPUBuffer buff);
WGPUBindGroup createBindGroupScreen1WO(WGPUTextureView texView); WGPUBindGroup createBindGroupScreen1WO(WGPUTextureView texView);
WGPUBindGroup createBindGroupStrorage1WO(WGPUTextureView texView); WGPUBindGroup createBindGroupStrorage1WO(WGPUTextureView texView);
WGPUBindGroup createBindGroupStrorage1RO(WGPUTextureView texView); WGPUBindGroup createBindGroupStrorage1RO(WGPUTextureView texView);

View file

@ -69,26 +69,33 @@ void WgContext::initialize(WGPUInstance instance, WGPUSurface surface)
// create shared webgpu assets // create shared webgpu assets
allocateBufferIndexFan(32768); allocateBufferIndexFan(32768);
samplerNearest = createSampler(WGPUFilterMode_Nearest, WGPUMipmapFilterMode_Nearest); samplerNearestRepeat = createSampler(WGPUFilterMode_Nearest, WGPUMipmapFilterMode_Nearest, WGPUAddressMode_Repeat);
samplerLinear = createSampler(WGPUFilterMode_Linear, WGPUMipmapFilterMode_Linear); samplerLinearRepeat = createSampler(WGPUFilterMode_Linear, WGPUMipmapFilterMode_Linear, WGPUAddressMode_Repeat);
assert(samplerNearest); samplerLinearMirror = createSampler(WGPUFilterMode_Linear, WGPUMipmapFilterMode_Linear, WGPUAddressMode_MirrorRepeat);
assert(samplerLinear); samplerLinearClamp = createSampler(WGPUFilterMode_Linear, WGPUMipmapFilterMode_Linear, WGPUAddressMode_ClampToEdge);
assert(samplerNearestRepeat);
assert(samplerLinearRepeat);
assert(samplerLinearMirror);
assert(samplerLinearClamp);
} }
void WgContext::release() void WgContext::release()
{ {
releaseSampler(samplerNearest); releaseSampler(samplerLinearClamp);
releaseSampler(samplerLinear); releaseSampler(samplerLinearMirror);
releaseSampler(samplerLinearRepeat);
releaseSampler(samplerNearestRepeat);
releaseBuffer(bufferIndexFan); releaseBuffer(bufferIndexFan);
wgpuDeviceRelease(device); wgpuDeviceRelease(device);
wgpuAdapterRelease(adapter); wgpuAdapterRelease(adapter);
} }
WGPUSampler WgContext::createSampler(WGPUFilterMode filter, WGPUMipmapFilterMode mipmapFilter) WGPUSampler WgContext::createSampler(WGPUFilterMode filter, WGPUMipmapFilterMode mipmapFilter, WGPUAddressMode addrMode)
{ {
const WGPUSamplerDescriptor samplerDesc { const WGPUSamplerDescriptor samplerDesc {
.addressModeU = addrMode, .addressModeV = addrMode, .addressModeW = addrMode,
.magFilter = filter, .minFilter = filter, .mipmapFilter = mipmapFilter, .magFilter = filter, .minFilter = filter, .mipmapFilter = mipmapFilter,
.lodMinClamp = 0.0f, .lodMaxClamp = 32.0f, .maxAnisotropy = 1 .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) WGPUTexture WgContext::createTexture(uint32_t width, uint32_t height, WGPUTextureFormat format)
{ {
const WGPUTextureDescriptor textureDesc { const WGPUTextureDescriptor textureDesc {

View file

@ -44,18 +44,21 @@ struct WgContext {
WgPipelines* pipelines{}; WgPipelines* pipelines{};
// shared webgpu assets // shared webgpu assets
WGPUBuffer bufferIndexFan{}; WGPUBuffer bufferIndexFan{};
WGPUSampler samplerNearest{}; WGPUSampler samplerNearestRepeat{};
WGPUSampler samplerLinear{}; WGPUSampler samplerLinearRepeat{};
WGPUSampler samplerLinearMirror{};
WGPUSampler samplerLinearClamp{};
void initialize(WGPUInstance instance, WGPUSurface surface); void initialize(WGPUInstance instance, WGPUSurface surface);
void release(); void release();
// create common objects // 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 createTexture(uint32_t width, uint32_t height, WGPUTextureFormat format);
WGPUTexture createTexStorage(uint32_t width, uint32_t height, WGPUTextureFormat format, uint32_t sc = 1); 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); WGPUTexture createTexStencil(uint32_t width, uint32_t height, WGPUTextureFormat format, uint32_t sc = 1);
WGPUTextureView createTextureView(WGPUTexture texture); WGPUTextureView createTextureView(WGPUTexture texture);
bool allocateTexture(WGPUTexture& texture, uint32_t width, uint32_t height, WGPUTextureFormat format, void* data);
// release common objects // release common objects
void releaseTextureView(WGPUTextureView& textureView); void releaseTextureView(WGPUTextureView& textureView);

View file

@ -371,10 +371,10 @@ void WgCompositor::drawShape(WgContext& context, WgRenderDataShape* renderData,
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupSolid, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupSolid, 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->solid[blendTypeInd]); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->solid[blendTypeInd]);
} else if (settings.fillType == WgRenderSettingsType::Linear) { } 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]); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->linear[blendTypeInd]);
} else if (settings.fillType == WgRenderSettingsType::Radial) { } 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]); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->radial[blendTypeInd]);
} }
// draw to color (second pass) // draw to color (second pass)
@ -409,10 +409,10 @@ void WgCompositor::drawStrokes(WgContext& context, WgRenderDataShape* renderData
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupSolid, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupSolid, 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->solid[blendTypeInd]); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->solid[blendTypeInd]);
} else if (settings.fillType == WgRenderSettingsType::Linear) { } 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]); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->linear[blendTypeInd]);
} else if (settings.fillType == WgRenderSettingsType::Radial) { } 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]); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->radial[blendTypeInd]);
} }
// draw to color (second pass) // draw to color (second pass)

View file

@ -22,6 +22,7 @@
#include "tvgWgPipelines.h" #include "tvgWgPipelines.h"
#include "tvgWgShaderSrc.h" #include "tvgWgShaderSrc.h"
#include <cstring>
WGPUShaderModule WgPipelines::createShaderModule(WGPUDevice device, const char* label, const char* code) WGPUShaderModule WgPipelines::createShaderModule(WGPUDevice device, const char* label, const char* code)
{ {
@ -74,14 +75,15 @@ WGPURenderPipeline WgPipelines::createRenderPipeline(
WGPUComputePipeline WgPipelines::createComputePipeline( WGPUComputePipeline WgPipelines::createComputePipeline(
WGPUDevice device, const char* pipelineLabel, WGPUDevice device, const char* pipelineLabel,
const WGPUShaderModule shaderModule, const WGPUPipelineLayout pipelineLayout) const WGPUShaderModule shaderModule, const char* entryPoint,
const WGPUPipelineLayout pipelineLayout)
{ {
const WGPUComputePipelineDescriptor computePipelineDesc{ const WGPUComputePipelineDescriptor computePipelineDesc{
.label = pipelineLabel, .label = pipelineLabel,
.layout = pipelineLayout, .layout = pipelineLayout,
.compute = { .compute = {
.module = shaderModule, .module = shaderModule,
.entryPoint = "cs_main" .entryPoint = entryPoint
} }
}; };
return wgpuDeviceCreateComputePipeline(device, &computePipelineDesc); return wgpuDeviceCreateComputePipeline(device, &computePipelineDesc);
@ -165,11 +167,16 @@ void WgPipelines::initialize(WgContext& context)
layouts.layoutBuffer1Un, layouts.layoutBuffer1Un,
layouts.layoutBuffer2Un layouts.layoutBuffer2Un
}; };
const WGPUBindGroupLayout bindGroupLayoutsFill[] = { const WGPUBindGroupLayout bindGroupLayoutsSolid[] = {
layouts.layoutBuffer1Un, layouts.layoutBuffer1Un,
layouts.layoutBuffer2Un, layouts.layoutBuffer2Un,
layouts.layoutBuffer1Un layouts.layoutBuffer1Un
}; };
const WGPUBindGroupLayout bindGroupLayoutsGradient[] = {
layouts.layoutBuffer1Un,
layouts.layoutBuffer2Un,
layouts.layoutTexSampledBuff1Un
};
const WGPUBindGroupLayout bindGroupLayoutsImage[] = { const WGPUBindGroupLayout bindGroupLayoutsImage[] = {
layouts.layoutBuffer1Un, layouts.layoutBuffer1Un,
layouts.layoutBuffer2Un, layouts.layoutBuffer2Un,
@ -199,7 +206,8 @@ void WgPipelines::initialize(WgContext& context)
// pipeline layouts // pipeline layouts
layoutStencil = createPipelineLayout(context.device, bindGroupLayoutsStencil, 2); 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); layoutImage = createPipelineLayout(context.device, bindGroupLayoutsImage, 3);
layoutBlend = createPipelineLayout(context.device, bindGroupLayoutsBlend, 4); layoutBlend = createPipelineLayout(context.device, bindGroupLayoutsBlend, 4);
layoutCompose = createPipelineLayout(context.device, bindGroupLayoutsCompose, 4); layoutCompose = createPipelineLayout(context.device, bindGroupLayoutsCompose, 4);
@ -257,7 +265,7 @@ void WgPipelines::initialize(WgContext& context)
for (uint32_t i = 0; i < 3; i++) { for (uint32_t i = 0; i < 3; i++) {
solid[i] = createRenderPipeline( solid[i] = createRenderPipeline(
context.device, "The render pipeline solid", context.device, "The render pipeline solid",
shaderSolid, layoutFill, shaderSolid, layoutSolid,
vertexBufferLayoutsShape, 1, vertexBufferLayoutsShape, 1,
WGPUColorWriteMask_All, WGPUColorWriteMask_All,
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero, WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
@ -269,7 +277,7 @@ void WgPipelines::initialize(WgContext& context)
for (uint32_t i = 0; i < 3; i++) { for (uint32_t i = 0; i < 3; i++) {
radial[i] = createRenderPipeline( radial[i] = createRenderPipeline(
context.device, "The render pipeline radial", context.device, "The render pipeline radial",
shaderRadial, layoutFill, shaderRadial, layoutGradient,
vertexBufferLayoutsShape, 1, vertexBufferLayoutsShape, 1,
WGPUColorWriteMask_All, WGPUColorWriteMask_All,
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero, WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
@ -281,7 +289,7 @@ void WgPipelines::initialize(WgContext& context)
for (uint32_t i = 0; i < 3; i++) { for (uint32_t i = 0; i < 3; i++) {
linear[i] = createRenderPipeline( linear[i] = createRenderPipeline(
context.device, "The render pipeline linear", context.device, "The render pipeline linear",
shaderLinear, layoutFill, shaderLinear, layoutGradient,
vertexBufferLayoutsShape, 1, vertexBufferLayoutsShape, 1,
WGPUColorWriteMask_All, WGPUColorWriteMask_All,
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero, WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
@ -302,26 +310,68 @@ void WgPipelines::initialize(WgContext& context)
} }
// compute pipelines // compute pipelines
mergeMasks = createComputePipeline(context.device, "The pipeline merge masks", shaderMergeMasks, layoutMergeMasks); mergeMasks = createComputePipeline(context.device, "The pipeline merge masks", shaderMergeMasks, "cs_main", layoutMergeMasks);
copy = createComputePipeline(context.device, "The pipeline copy", shaderCopy, layoutCopy); copy = createComputePipeline(context.device, "The pipeline copy", shaderCopy, "cs_main", layoutCopy);
// compute pipelines blend
const size_t shaderBlendCnt = sizeof(cShaderSrc_Blend_Solid)/sizeof(cShaderSrc_Blend_Solid[0]); // compute shader blend names
for (uint32_t i = 0; i < shaderBlendCnt; i++) { const char* shaderBlendNames[] {
// blend shaders "cs_main_Normal",
shaderBlendSolid[i] = createShaderModule(context.device, "The shader blend solid", cShaderSrc_Blend_Solid[i]); "cs_main_Add",
shaderBlendGradient[i] = createShaderModule(context.device, "The shader blend gradient", cShaderSrc_Blend_Gradient[i]); "cs_main_Screen",
shaderBlendImage[i] = createShaderModule(context.device, "The shader blend image", cShaderSrc_Blend_Image[i]); "cs_main_Multiply",
// blend pipelines "cs_main_Overlay",
blendSolid[i] = createComputePipeline(context.device, "The pipeline blend solid", shaderBlendSolid[i], layoutBlend); "cs_main_Difference",
blendGradient[i] = createComputePipeline(context.device, "The pipeline blend gradient", shaderBlendGradient[i], layoutBlend); "cs_main_Exclusion",
blendImage[i] = createComputePipeline(context.device, "The pipeline blend image", shaderBlendImage[i], layoutBlend); "cs_main_SrcOver",
} "cs_main_Darken",
// compute pipelines compose "cs_main_Lighten",
const size_t shaderComposeCnt = sizeof(cShaderSrc_Compose)/sizeof(cShaderSrc_Compose[0]); "cs_main_ColorDodge",
for (uint32_t i = 0; i < shaderComposeCnt; i++) { "cs_main_ColorBurn",
shaderCompose[i] = createShaderModule(context.device, "The shader compose", cShaderSrc_Compose[i]); "cs_main_HardLight",
compose[i] = createComputePipeline(context.device, "The pipeline compose", shaderCompose[i], layoutCompose); "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) void WgPipelines::releaseGraphicHandles(WgContext& context)
@ -337,7 +387,8 @@ void WgPipelines::releaseGraphicHandles(WgContext& context)
releaseRenderPipeline(evenodd); releaseRenderPipeline(evenodd);
releaseRenderPipeline(winding); releaseRenderPipeline(winding);
releasePipelineLayout(layoutImage); releasePipelineLayout(layoutImage);
releasePipelineLayout(layoutFill); releasePipelineLayout(layoutGradient);
releasePipelineLayout(layoutSolid);
releasePipelineLayout(layoutStencil); releasePipelineLayout(layoutStencil);
releaseShaderModule(shaderImage); releaseShaderModule(shaderImage);
releaseShaderModule(shaderLinear); releaseShaderModule(shaderLinear);
@ -349,19 +400,14 @@ void WgPipelines::releaseGraphicHandles(WgContext& context)
void WgPipelines::releaseComputeHandles(WgContext& context) void WgPipelines::releaseComputeHandles(WgContext& context)
{ {
const size_t shaderComposeCnt = sizeof(shaderCompose)/sizeof(shaderCompose[0]); size_t pipesComposeCnt = sizeof(compose) / sizeof(compose[0]);
for (uint32_t i = 0; i < shaderComposeCnt; i++) { for (uint32_t i = 0; i < pipesComposeCnt; i++)
releaseComputePipeline(compose[i]); releaseComputePipeline(compose[i]);
releaseShaderModule(shaderCompose[i]); const size_t pipesBlendCnt = sizeof(blendSolid)/sizeof(blendSolid[0]);
} for (uint32_t i = 0; i < pipesBlendCnt; i++) {
const size_t shaderBlendImageCnt = sizeof(shaderBlendImage)/sizeof(shaderBlendImage[0]);
for (uint32_t i = 0; i < shaderBlendImageCnt; i++) {
releaseComputePipeline(blendImage[i]); releaseComputePipeline(blendImage[i]);
releaseComputePipeline(blendSolid[i]); releaseComputePipeline(blendSolid[i]);
releaseComputePipeline(blendGradient[i]); releaseComputePipeline(blendGradient[i]);
releaseShaderModule(shaderBlendImage[i]);
releaseShaderModule(shaderBlendGradient[i]);
releaseShaderModule(shaderBlendSolid[i]);
} }
releaseComputePipeline(copy); releaseComputePipeline(copy);
releaseComputePipeline(mergeMasks); releaseComputePipeline(mergeMasks);
@ -369,6 +415,10 @@ void WgPipelines::releaseComputeHandles(WgContext& context)
releasePipelineLayout(layoutBlend); releasePipelineLayout(layoutBlend);
releasePipelineLayout(layoutMergeMasks); releasePipelineLayout(layoutMergeMasks);
releasePipelineLayout(layoutCopy); releasePipelineLayout(layoutCopy);
releaseShaderModule(shaderCompose);
releaseShaderModule(shaderBlendImage);
releaseShaderModule(shaderBlendGradient);
releaseShaderModule(shaderBlendSolid);
releaseShaderModule(shaderMergeMasks); releaseShaderModule(shaderMergeMasks);
releaseShaderModule(shaderCopy); releaseShaderModule(shaderCopy);
} }

View file

@ -37,15 +37,16 @@ private:
WGPUShaderModule shaderImage{}; WGPUShaderModule shaderImage{};
// compute pipeline shaders // compute pipeline shaders
WGPUShaderModule shaderMergeMasks; WGPUShaderModule shaderMergeMasks;
WGPUShaderModule shaderBlendSolid[14]; WGPUShaderModule shaderBlendSolid;
WGPUShaderModule shaderBlendGradient[14]; WGPUShaderModule shaderBlendGradient;
WGPUShaderModule shaderBlendImage[14]; WGPUShaderModule shaderBlendImage;
WGPUShaderModule shaderCompose[12]; WGPUShaderModule shaderCompose;
WGPUShaderModule shaderCopy; WGPUShaderModule shaderCopy;
private: private:
// graphics pipeline layouts // graphics pipeline layouts
WGPUPipelineLayout layoutStencil{}; WGPUPipelineLayout layoutStencil{};
WGPUPipelineLayout layoutFill{}; WGPUPipelineLayout layoutSolid{};
WGPUPipelineLayout layoutGradient{};
WGPUPipelineLayout layoutImage{}; WGPUPipelineLayout layoutImage{};
// compute pipeline layouts // compute pipeline layouts
WGPUPipelineLayout layoutMergeMasks{}; WGPUPipelineLayout layoutMergeMasks{};
@ -86,7 +87,8 @@ private:
const WGPUPrimitiveState primitiveState, const WGPUMultisampleState multisampleState, const WGPUBlendState blendState); const WGPUPrimitiveState primitiveState, const WGPUMultisampleState multisampleState, const WGPUBlendState blendState);
WGPUComputePipeline createComputePipeline( WGPUComputePipeline createComputePipeline(
WGPUDevice device, const char* pipelineLabel, 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 releaseComputePipeline(WGPUComputePipeline& computePipeline);
void releaseRenderPipeline(WGPURenderPipeline& renderPipeline); void releaseRenderPipeline(WGPURenderPipeline& renderPipeline);
void releasePipelineLayout(WGPUPipelineLayout& pipelineLayout); void releasePipelineLayout(WGPUPipelineLayout& pipelineLayout);

View file

@ -212,22 +212,30 @@ void WgRenderSettings::update(WgContext& context, const Fill* fill, const uint8_
// setup fill properties // setup fill properties
if ((flags & (RenderUpdateFlag::Gradient)) && fill) { if ((flags & (RenderUpdateFlag::Gradient)) && fill) {
rasterType = WgRenderRasterType::Gradient; rasterType = WgRenderRasterType::Gradient;
// setup linear fill properties WgShaderTypeGradient gradient;
if (fill->type() == Type::LinearGradient) { if (fill->type() == Type::LinearGradient) {
WgShaderTypeLinearGradient linearGradient((LinearGradient*)fill); gradient.update((LinearGradient*)fill);
if (context.allocateBufferUniform(bufferGroupLinear, &linearGradient, sizeof(linearGradient))) {
context.pipelines->layouts.releaseBindGroup(bindGroupLinear);
bindGroupLinear = context.pipelines->layouts.createBindGroupBuffer1Un(bufferGroupLinear);
}
fillType = WgRenderSettingsType::Linear; fillType = WgRenderSettingsType::Linear;
} else if (fill->type() == Type::RadialGradient) { } else if (fill->type() == Type::RadialGradient) {
WgShaderTypeRadialGradient radialGradient((RadialGradient*)fill); gradient.update((RadialGradient*)fill);
if (context.allocateBufferUniform(bufferGroupRadial, &radialGradient, sizeof(radialGradient))) {
context.pipelines->layouts.releaseBindGroup(bindGroupRadial);
bindGroupRadial = context.pipelines->layouts.createBindGroupBuffer1Un(bufferGroupRadial);
}
fillType = WgRenderSettingsType::Radial; 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; skip = false;
} else if ((flags & (RenderUpdateFlag::Color)) && !fill) { } else if ((flags & (RenderUpdateFlag::Color)) && !fill) {
rasterType = WgRenderRasterType::Solid; rasterType = WgRenderRasterType::Solid;
@ -245,12 +253,11 @@ void WgRenderSettings::update(WgContext& context, const Fill* fill, const uint8_
void WgRenderSettings::release(WgContext& context) void WgRenderSettings::release(WgContext& context)
{ {
context.pipelines->layouts.releaseBindGroup(bindGroupSolid); context.pipelines->layouts.releaseBindGroup(bindGroupSolid);
context.pipelines->layouts.releaseBindGroup(bindGroupLinear); context.pipelines->layouts.releaseBindGroup(bindGroupGradient);
context.pipelines->layouts.releaseBindGroup(bindGroupRadial);
context.releaseBuffer(bufferGroupSolid); context.releaseBuffer(bufferGroupSolid);
context.releaseBuffer(bufferGroupLinear); context.releaseBuffer(bufferGroupGradient);
context.releaseBuffer(bufferGroupRadial); context.releaseTexture(texGradient);
context.releaseTextureView(texViewGradient);
}; };
//*********************************************************************** //***********************************************************************

View file

@ -78,11 +78,11 @@ enum class WgRenderRasterType { Solid = 0, Gradient, Image };
struct WgRenderSettings struct WgRenderSettings
{ {
WGPUBuffer bufferGroupSolid{}; WGPUBuffer bufferGroupSolid{};
WGPUBuffer bufferGroupLinear{};
WGPUBuffer bufferGroupRadial{};
WGPUBindGroup bindGroupSolid{}; WGPUBindGroup bindGroupSolid{};
WGPUBindGroup bindGroupLinear{}; WGPUTexture texGradient{};
WGPUBindGroup bindGroupRadial{}; WGPUTextureView texViewGradient{};
WGPUBuffer bufferGroupGradient{};
WGPUBindGroup bindGroupGradient{};
WgRenderSettingsType fillType{}; WgRenderSettingsType fillType{};
WgRenderRasterType rasterType{}; WgRenderRasterType rasterType{};
bool skip{}; bool skip{};

View file

@ -30,7 +30,7 @@ void WgRenderStorage::initialize(WgContext& context, uint32_t width, uint32_t he
texView = context.createTextureView(texture); texView = context.createTextureView(texture);
bindGroupRead = context.pipelines->layouts.createBindGroupStrorage1RO(texView); bindGroupRead = context.pipelines->layouts.createBindGroupStrorage1RO(texView);
bindGroupWrite = context.pipelines->layouts.createBindGroupStrorage1WO(texView); bindGroupWrite = context.pipelines->layouts.createBindGroupStrorage1WO(texView);
bindGroupTexure = context.pipelines->layouts.createBindGroupTexSampled(context.samplerNearest, texView); bindGroupTexure = context.pipelines->layouts.createBindGroupTexSampled(context.samplerNearestRepeat, texView);
} }

View file

@ -21,7 +21,6 @@
*/ */
#include "tvgWgRenderer.h" #include "tvgWgRenderer.h"
#include <iostream>
WgRenderer::WgRenderer() WgRenderer::WgRenderer()
{ {
@ -135,7 +134,7 @@ RenderData WgRenderer::prepare(Surface* surface, const RenderMesh* mesh, RenderD
renderDataPicture->meshData.update(mContext, &geometryData); renderDataPicture->meshData.update(mContext, &geometryData);
renderDataPicture->imageData.update(mContext, surface); renderDataPicture->imageData.update(mContext, surface);
renderDataPicture->bindGroupPicture = mContext.pipelines->layouts.createBindGroupTexSampled( 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

View file

@ -32,11 +32,11 @@ extern const char* cShaderSrc_Image;
// compute shader sources: blend, compose and merge path // compute shader sources: blend, compose and merge path
extern const char* cShaderSrc_MergeMasks; extern const char* cShaderSrc_MergeMasks;
extern const char* cShaderSrc_Blend_Solid[14]; extern const char* cShaderSrc_BlendHeader_Solid;
extern const char* cShaderSrc_Blend_Solid[14]; extern const char* cShaderSrc_BlendHeader_Gradient;
extern const char* cShaderSrc_Blend_Gradient[14]; extern const char* cShaderSrc_BlendHeader_Image;
extern const char* cShaderSrc_Blend_Image[14]; extern const char* cShaderSrc_Blend_Funcs;
extern const char* cShaderSrc_Compose[12]; extern const char* cShaderSrc_Compose;
extern const char* cShaderSrc_Copy; extern const char* cShaderSrc_Copy;
#endif // _TVG_WG_SHEDER_SRC_H_ #endif // _TVG_WG_SHEDER_SRC_H_

View file

@ -21,6 +21,7 @@
*/ */
#include "tvgWgShaderTypes.h" #include "tvgWgShaderTypes.h"
#include <cassert>
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// shader types // shader types
@ -92,10 +93,8 @@ WgShaderTypeBlendSettings::WgShaderTypeBlendSettings(const ColorSpace colorSpace
void WgShaderTypeBlendSettings::update(const ColorSpace colorSpace, uint8_t o) void WgShaderTypeBlendSettings::update(const ColorSpace colorSpace, uint8_t o)
{ {
format = (uint32_t)colorSpace; settings[0] = (uint32_t)colorSpace;
dummy0 = 0.0f; settings[3] = o / 255.0f;
dummy1 = 0.0f;
opacity = o / 255.0f;
} }
@ -114,53 +113,59 @@ void WgShaderTypeSolidColor::update(const uint8_t* c)
} }
WgShaderTypeLinearGradient::WgShaderTypeLinearGradient(const LinearGradient* linearGradient) void WgShaderTypeGradient::update(const LinearGradient* linearGradient)
{
update(linearGradient);
}
void WgShaderTypeLinearGradient::update(const LinearGradient* linearGradient)
{ {
// update gradient data
const Fill::ColorStop* stops = nullptr; const Fill::ColorStop* stops = nullptr;
auto stopCnt = linearGradient->colorStops(&stops); auto stopCnt = linearGradient->colorStops(&stops);
updateTexData(stops, stopCnt);
nStops = stopCnt; // update base points
spread = uint32_t(linearGradient->spread()); linearGradient->linear(&settings[0], &settings[1], &settings[2], &settings[3]);
};
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) void WgShaderTypeGradient::update(const RadialGradient* radialGradient)
{
update(radialGradient);
}
void WgShaderTypeRadialGradient::update(const RadialGradient* radialGradient)
{ {
// update gradient data
const Fill::ColorStop* stops = nullptr; const Fill::ColorStop* stops = nullptr;
auto stopCnt = radialGradient->colorStops(&stops); 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) { void WgShaderTypeGradient::updateTexData(const Fill::ColorStop* stops, uint32_t stopCnt)
stopPoints[i] = stops[i].offset; {
stopColors[i * 4 + 0] = stops[i].r / 255.f; assert(stops);
stopColors[i * 4 + 1] = stops[i].g / 255.f; // head
stopColors[i * 4 + 2] = stops[i].b / 255.f; uint32_t range_s = 0;
stopColors[i * 4 + 3] = stops[i].a / 255.f; 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(&centerPos[0], &centerPos[1], &radius[0]);
} }

View file

@ -42,27 +42,17 @@ struct WgShaderTypeMat4x4f
void update(size_t w, size_t h); void update(size_t w, size_t h);
}; };
// struct BlendSettings { // vec4f
// format : u32, // ColorSpace
// dummy0 : f32,
// dummy1 : f32,
// opacity : f32
// };
struct WgShaderTypeBlendSettings struct WgShaderTypeBlendSettings
{ {
uint32_t format{}; // ColorSpace float settings[4]{};
float dummy0{};
float dummy1{};
float opacity{};
WgShaderTypeBlendSettings() {}; WgShaderTypeBlendSettings() {};
WgShaderTypeBlendSettings(const ColorSpace colorSpace, uint8_t o); WgShaderTypeBlendSettings(const ColorSpace colorSpace, uint8_t o);
void update(const ColorSpace colorSpace, uint8_t o); void update(const ColorSpace colorSpace, uint8_t o);
}; };
// struct SolidColor { // vec4f
// color: vec4f
// };
struct WgShaderTypeSolidColor struct WgShaderTypeSolidColor
{ {
float color[4]{}; float color[4]{};
@ -71,58 +61,16 @@ struct WgShaderTypeSolidColor
void update(const uint8_t* c); void update(const uint8_t* c);
}; };
// const MAX_LINEAR_GRADIENT_STOPS = 4; // sampler, texture, vec4f
// struct LinearGradient { #define WG_TEXTURE_GRADIENT_SIZE 512
// nStops : u32, struct WgShaderTypeGradient
// 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
{ {
uint32_t nStops{}; float settings[4]{};
uint32_t spread{}; uint8_t texData[WG_TEXTURE_GRADIENT_SIZE * 4];
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]{};
WgShaderTypeLinearGradient(const LinearGradient* linearGradient);
void update(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 update(const RadialGradient* radialGradient);
void updateTexData(const Fill::ColorStop* stops, uint32_t stopCnt);
}; };
#endif // _TVG_WG_SHADER_TYPES_H_ #endif // _TVG_WG_SHADER_TYPES_H_