mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-14 12:04:29 +00:00
renderer: blending refactoring++
- reordered the blending types to align with lottie spec. - removed source over.
This commit is contained in:
parent
a7aac95b03
commit
371139e220
11 changed files with 49 additions and 91 deletions
|
@ -108,13 +108,6 @@ struct UserExample : tvgexam::Example
|
|||
shape7->fill(0, 0, 255);
|
||||
canvas->push(std::move(shape7));
|
||||
|
||||
//SrcOver
|
||||
auto shape8 = tvg::Shape::gen();
|
||||
shape8->appendRect(550, 600, 150, 150);
|
||||
shape8->blend(tvg::BlendMethod::SrcOver);
|
||||
shape8->fill(10, 255, 155, 50);
|
||||
canvas->push(std::move(shape8));
|
||||
|
||||
//Darken
|
||||
auto shape9 = tvg::Shape::gen();
|
||||
shape9->appendRect(600, 650, 350, 250);
|
||||
|
|
16
inc/thorvg.h
16
inc/thorvg.h
|
@ -183,19 +183,23 @@ enum class CompositeMethod
|
|||
enum class BlendMethod : uint8_t
|
||||
{
|
||||
Normal = 0, ///< Perform the alpha blending(default). S if (Sa == 255), otherwise (Sa * S) + (255 - Sa) * D
|
||||
Add, ///< Simply adds pixel values of one layer with the other. (S + D)
|
||||
Screen, ///< The values of the pixels in the two layers are inverted, multiplied, and then inverted again. (S + D) - (S * D)
|
||||
Multiply, ///< Takes the RGB channel values from 0 to 255 of each pixel in the top layer and multiples them with the values for the corresponding pixel from the bottom layer. (S * D)
|
||||
Screen, ///< The values of the pixels in the two layers are inverted, multiplied, and then inverted again. (S + D) - (S * D)
|
||||
Overlay, ///< Combines Multiply and Screen blend modes. (2 * S * D) if (2 * D < Da), otherwise (Sa * Da) - 2 * (Da - S) * (Sa - D)
|
||||
Difference, ///< Subtracts the bottom layer from the top layer or the other way around, to always get a non-negative value. (S - D) if (S > D), otherwise (D - S)
|
||||
Exclusion, ///< The result is twice the product of the top and bottom layers, subtracted from their sum. s + d - (2 * s * d)
|
||||
SrcOver, ///< Replace the bottom layer with the top layer.
|
||||
Darken, ///< Creates a pixel that retains the smallest components of the top and bottom layer pixels. min(S, D)
|
||||
Lighten, ///< Only has the opposite action of Darken Only. max(S, D)
|
||||
ColorDodge, ///< Divides the bottom layer by the inverted top layer. D / (255 - S)
|
||||
ColorBurn, ///< Divides the inverted bottom layer by the top layer, and then inverts the result. 255 - (255 - D) / S
|
||||
HardLight, ///< The same as Overlay but with the color roles reversed. (2 * S * D) if (S < Sa), otherwise (Sa * Da) - 2 * (Da - S) * (Sa - D)
|
||||
SoftLight ///< The same as Overlay but with applying pure black or white does not result in pure black or white. (1 - 2 * S) * (D ^ 2) + (2 * S * D)
|
||||
SoftLight, ///< The same as Overlay but with applying pure black or white does not result in pure black or white. (1 - 2 * S) * (D ^ 2) + (2 * S * D)
|
||||
Difference, ///< Subtracts the bottom layer from the top layer or the other way around, to always get a non-negative value. (S - D) if (S > D), otherwise (D - S)
|
||||
Exclusion, ///< The result is twice the product of the top and bottom layers, subtracted from their sum. s + d - (2 * s * d)
|
||||
Hue, ///< Reserved. Not supported.
|
||||
Saturation, ///< Reserved. Not supported.
|
||||
Color, ///< Reserved. Not supported.
|
||||
Luminosity, ///< Reserved. Not supported.
|
||||
Add, ///< Simply adds pixel values of one layer with the other. (S + D)
|
||||
HardMix ///< Reserved. Not supported.
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -77,35 +77,6 @@ CompositeMethod LottieParser::getMaskMethod(bool inversed)
|
|||
}
|
||||
|
||||
|
||||
BlendMethod LottieParser::getBlendMethod()
|
||||
{
|
||||
switch (getInt()) {
|
||||
case 0: return BlendMethod::Normal;
|
||||
case 1: return BlendMethod::Multiply;
|
||||
case 2: return BlendMethod::Screen;
|
||||
case 3: return BlendMethod::Overlay;
|
||||
case 4: return BlendMethod::Darken;
|
||||
case 5: return BlendMethod::Lighten;
|
||||
case 6: return BlendMethod::ColorDodge;
|
||||
case 7: return BlendMethod::ColorBurn;
|
||||
case 8: return BlendMethod::HardLight;
|
||||
case 9: return BlendMethod::SoftLight;
|
||||
case 10: return BlendMethod::Difference;
|
||||
case 11: return BlendMethod::Exclusion;
|
||||
//case 12: return BlendMethod::Hue:
|
||||
//case 13: return BlendMethod::Saturation:
|
||||
//case 14: return BlendMethod::Color:
|
||||
//case 15: return BlendMethod::Luminosity:
|
||||
case 16: return BlendMethod::Add;
|
||||
//case 17: return BlendMethod::HardMix:
|
||||
default: {
|
||||
TVGERR("LOTTIE", "Non-Supported Blend Mode");
|
||||
return BlendMethod::Normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
RGB24 LottieParser::getColor(const char *str)
|
||||
{
|
||||
RGB24 color = {0, 0, 0};
|
||||
|
@ -1293,7 +1264,7 @@ LottieLayer* LottieParser::parseLayer(LottieLayer* precomp)
|
|||
else if (KEY_AS("ip")) layer->inFrame = getFloat();
|
||||
else if (KEY_AS("op")) layer->outFrame = getFloat();
|
||||
else if (KEY_AS("st")) layer->startFrame = getFloat();
|
||||
else if (KEY_AS("bm")) layer->blendMethod = getBlendMethod();
|
||||
else if (KEY_AS("bm")) layer->blendMethod = (BlendMethod) getInt();
|
||||
else if (KEY_AS("parent")) layer->pidx = getInt();
|
||||
else if (KEY_AS("tm")) parseTimeRemap(layer);
|
||||
else if (KEY_AS("w") || KEY_AS("sw")) getLayerSize(layer->w);
|
||||
|
|
|
@ -43,7 +43,6 @@ public:
|
|||
const char* dirName = nullptr; //base resource directory
|
||||
|
||||
private:
|
||||
BlendMethod getBlendMethod();
|
||||
RGB24 getColor(const char *str);
|
||||
CompositeMethod getMatteType();
|
||||
FillRule getFillRule();
|
||||
|
|
|
@ -452,27 +452,18 @@ bool SwRenderer::blend(BlendMethod method)
|
|||
surface->blendMethod = method;
|
||||
|
||||
switch (method) {
|
||||
case BlendMethod::Add:
|
||||
surface->blender = opBlendAdd;
|
||||
break;
|
||||
case BlendMethod::Screen:
|
||||
surface->blender = opBlendScreen;
|
||||
case BlendMethod::Normal:
|
||||
surface->blender = nullptr;
|
||||
break;
|
||||
case BlendMethod::Multiply:
|
||||
surface->blender = opBlendMultiply;
|
||||
break;
|
||||
case BlendMethod::Screen:
|
||||
surface->blender = opBlendScreen;
|
||||
break;
|
||||
case BlendMethod::Overlay:
|
||||
surface->blender = opBlendOverlay;
|
||||
break;
|
||||
case BlendMethod::Difference:
|
||||
surface->blender = opBlendDifference;
|
||||
break;
|
||||
case BlendMethod::Exclusion:
|
||||
surface->blender = opBlendExclusion;
|
||||
break;
|
||||
case BlendMethod::SrcOver:
|
||||
surface->blender = opBlendSrcOver;
|
||||
break;
|
||||
case BlendMethod::Darken:
|
||||
surface->blender = opBlendDarken;
|
||||
break;
|
||||
|
@ -491,7 +482,17 @@ bool SwRenderer::blend(BlendMethod method)
|
|||
case BlendMethod::SoftLight:
|
||||
surface->blender = opBlendSoftLight;
|
||||
break;
|
||||
case BlendMethod::Difference:
|
||||
surface->blender = opBlendDifference;
|
||||
break;
|
||||
case BlendMethod::Exclusion:
|
||||
surface->blender = opBlendExclusion;
|
||||
break;
|
||||
case BlendMethod::Add:
|
||||
surface->blender = opBlendAdd;
|
||||
break;
|
||||
default:
|
||||
TVGLOG("SW_ENGINE", "Non supported blending option = %d", (int) method);
|
||||
surface->blender = nullptr;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -82,7 +82,6 @@ void WgCompositor::release(WgContext& context)
|
|||
WgPipelineBlendType WgCompositor::blendMethodToBlendType(BlendMethod blendMethod)
|
||||
{
|
||||
if (blendMethod == BlendMethod::Normal) return WgPipelineBlendType::Normal;
|
||||
if (blendMethod == BlendMethod::SrcOver) return WgPipelineBlendType::SrcOver;
|
||||
return WgPipelineBlendType::Custom;
|
||||
}
|
||||
|
||||
|
|
|
@ -159,7 +159,6 @@ void WgPipelines::initialize(WgContext& context)
|
|||
.alpha = { .operation = WGPUBlendOperation_Add, .srcFactor = WGPUBlendFactor_One, .dstFactor = WGPUBlendFactor_OneMinusSrcAlpha }
|
||||
};
|
||||
const WGPUBlendState blendStates[] {
|
||||
blendStateSrc, // WgPipelineBlendType::SrcOver
|
||||
blendStateNrm, // WgPipelineBlendType::Normal
|
||||
blendStateSrc // WgPipelineBlendType::Custom (same as SrcOver)
|
||||
};
|
||||
|
@ -268,7 +267,7 @@ void WgPipelines::initialize(WgContext& context)
|
|||
primitiveState, multisampleState, blendStateSrc);
|
||||
|
||||
// render pipeline solid
|
||||
for (uint32_t i = 0; i < 3; i++) {
|
||||
for (uint32_t i = 0; i < 2; i++) {
|
||||
solid[i] = createRenderPipeline(
|
||||
context.device, "The render pipeline solid",
|
||||
shaderSolid, "vs_main", "fs_main", layoutSolid,
|
||||
|
@ -280,7 +279,7 @@ void WgPipelines::initialize(WgContext& context)
|
|||
}
|
||||
|
||||
// render pipeline radial
|
||||
for (uint32_t i = 0; i < 3; i++) {
|
||||
for (uint32_t i = 0; i < 2; i++) {
|
||||
radial[i] = createRenderPipeline(
|
||||
context.device, "The render pipeline radial",
|
||||
shaderRadial, "vs_main", "fs_main", layoutGradient,
|
||||
|
@ -292,7 +291,7 @@ void WgPipelines::initialize(WgContext& context)
|
|||
}
|
||||
|
||||
// render pipeline linear
|
||||
for (uint32_t i = 0; i < 3; i++) {
|
||||
for (uint32_t i = 0; i < 2; i++) {
|
||||
linear[i] = createRenderPipeline(
|
||||
context.device, "The render pipeline linear",
|
||||
shaderLinear, "vs_main", "fs_main", layoutGradient,
|
||||
|
@ -304,7 +303,7 @@ void WgPipelines::initialize(WgContext& context)
|
|||
}
|
||||
|
||||
// render pipeline image
|
||||
for (uint32_t i = 0; i < 3; i++) {
|
||||
for (uint32_t i = 0; i < 2; i++) {
|
||||
image[i] = createRenderPipeline(
|
||||
context.device, "The render pipeline image",
|
||||
shaderImage, "vs_main", "fs_main", layoutImage,
|
||||
|
@ -389,19 +388,23 @@ void WgPipelines::initialize(WgContext& context)
|
|||
// compute shader blend names
|
||||
const char* shaderBlendNames[] {
|
||||
"cs_main_Normal",
|
||||
"cs_main_Add",
|
||||
"cs_main_Screen",
|
||||
"cs_main_Multiply",
|
||||
"cs_main_Screen",
|
||||
"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"
|
||||
"cs_main_SoftLight",
|
||||
"cs_main_Difference",
|
||||
"cs_main_Exclusion",
|
||||
"cs_main_Normal", //TODO: a padding for reserved Hue.
|
||||
"cs_main_Normal", //TODO: a padding for reserved Saturation.
|
||||
"cs_main_Normal", //TODO: a padding for reserved Color.
|
||||
"cs_main_Normal", //TODO: a padding for reserved Luminosity.
|
||||
"cs_main_Add",
|
||||
"cs_main_Normal" //TODO: a padding for reserved Hardmix.
|
||||
};
|
||||
|
||||
// create blend shaders
|
||||
|
@ -429,7 +432,7 @@ void WgPipelines::releaseGraphicHandles(WgContext& context)
|
|||
size_t pipesSceneCompCnt = sizeof(sceneComp) / sizeof(sceneComp[0]);
|
||||
for (uint32_t i = 0; i < pipesSceneCompCnt; i++)
|
||||
releaseRenderPipeline(sceneComp[i]);
|
||||
for (uint32_t i = 0; i < 3; i++) {
|
||||
for (uint32_t i = 0; i < 2; i++) {
|
||||
releaseRenderPipeline(image[i]);
|
||||
releaseRenderPipeline(linear[i]);
|
||||
releaseRenderPipeline(radial[i]);
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
|
||||
#include "tvgWgBindGroups.h"
|
||||
|
||||
enum class WgPipelineBlendType { SrcOver = 0, Normal, Custom };
|
||||
enum class WgPipelineBlendType { Normal, Custom };
|
||||
|
||||
class WgPipelines {
|
||||
private:
|
||||
|
@ -61,19 +61,19 @@ public:
|
|||
WGPURenderPipeline winding{};
|
||||
WGPURenderPipeline evenodd{};
|
||||
WGPURenderPipeline direct{};
|
||||
WGPURenderPipeline solid[3]{};
|
||||
WGPURenderPipeline radial[3]{};
|
||||
WGPURenderPipeline linear[3]{};
|
||||
WGPURenderPipeline image[3]{};
|
||||
WGPURenderPipeline solid[2]{};
|
||||
WGPURenderPipeline radial[2]{};
|
||||
WGPURenderPipeline linear[2]{};
|
||||
WGPURenderPipeline image[2]{};
|
||||
WGPURenderPipeline sceneComp[12];
|
||||
WGPURenderPipeline sceneBlend;
|
||||
WGPURenderPipeline blit{};
|
||||
WGPURenderPipeline clipPath{};
|
||||
// compute pipeline
|
||||
WGPUComputePipeline mergeMasks;
|
||||
WGPUComputePipeline blendSolid[14];
|
||||
WGPUComputePipeline blendGradient[14];
|
||||
WGPUComputePipeline blendImage[14];
|
||||
WGPUComputePipeline blendSolid[18];
|
||||
WGPUComputePipeline blendGradient[18];
|
||||
WGPUComputePipeline blendImage[18];
|
||||
private:
|
||||
void releaseGraphicHandles(WgContext& context);
|
||||
void releaseComputeHandles(WgContext& context);
|
||||
|
|
|
@ -505,13 +505,6 @@ fn cs_main_Exclusion(@builtin(global_invocation_id) id: vec3u) {
|
|||
textureStore(imageTgt, id.xy, postProcess(d, vec4f(Rc, 1.0)));
|
||||
};
|
||||
|
||||
@compute @workgroup_size(8, 8)
|
||||
fn cs_main_SrcOver(@builtin(global_invocation_id) id: vec3u) {
|
||||
let d: FragData = getFragData(id.xy);
|
||||
if (d.skip) { return; }
|
||||
textureStore(imageTgt, id.xy, postProcess(d, vec4f(d.Sc, d.Sa)));
|
||||
};
|
||||
|
||||
@compute @workgroup_size(8, 8)
|
||||
fn cs_main_Darken(@builtin(global_invocation_id) id: vec3u) {
|
||||
let d: FragData = getFragData(id.xy);
|
||||
|
|
|
@ -289,10 +289,6 @@ TEST_CASE("Blending", "[tvgPaint]")
|
|||
REQUIRE(shape->blend(BlendMethod::Exclusion) == Result::Success);
|
||||
REQUIRE(shape->blend() == BlendMethod::Exclusion);
|
||||
|
||||
//SrcOver
|
||||
REQUIRE(shape->blend(BlendMethod::SrcOver) == Result::Success);
|
||||
REQUIRE(shape->blend() == BlendMethod::SrcOver);
|
||||
|
||||
//Darken
|
||||
REQUIRE(shape->blend(BlendMethod::Darken) == Result::Success);
|
||||
REQUIRE(shape->blend() == BlendMethod::Darken);
|
||||
|
|
|
@ -1239,7 +1239,6 @@ TEST_CASE("Blending Shapes", "[tvgSwEngine]")
|
|||
BlendMethod::Overlay,
|
||||
BlendMethod::Difference,
|
||||
BlendMethod::Exclusion,
|
||||
BlendMethod::SrcOver,
|
||||
BlendMethod::Darken,
|
||||
BlendMethod::Lighten,
|
||||
BlendMethod::ColorDodge,
|
||||
|
|
Loading…
Add table
Reference in a new issue