sw_engine: code chores & fix gradient filling bugs.

renaming internal methods for integrating with upcoming blending features.
this also fixes minor wrong gradient filling blending equations.
This commit is contained in:
Hermet Park 2023-06-15 12:38:03 +09:00 committed by Hermet Park
parent b60a291edc
commit eea54f5fea
3 changed files with 66 additions and 47 deletions

View file

@ -239,6 +239,7 @@ struct SwImage
bool scaled = false; //draw scaled image
};
typedef uint32_t(*SwBlender)(uint32_t s, uint32_t d, uint8_t sa); //src, dst, alpha
typedef uint32_t(*SwJoin)(uint8_t r, uint8_t g, uint8_t b, uint8_t a); //color channel join
typedef uint8_t(*SwAlpha)(uint8_t*); //blending alpha
@ -314,48 +315,66 @@ static inline uint8_t IALPHA(uint32_t c)
return (~c >> 24);
}
static inline uint32_t opBlendInterp(uint32_t s, uint32_t d, uint8_t a)
{
return INTERPOLATE(s, d, a);
}
typedef uint32_t(*SwBlendOp)(uint32_t s, uint32_t d, uint8_t a); //src, dst, alpha
static inline uint32_t opAlphaBlend(uint32_t s, uint32_t d, uint8_t a)
static inline uint32_t opBlendNormal(uint32_t s, uint32_t d, uint8_t a)
{
auto t = ALPHA_BLEND(s, a);
return t + ALPHA_BLEND(d, IALPHA(t));
}
static inline uint32_t opBlend(uint32_t s, uint32_t d, TVG_UNUSED uint8_t a)
static inline uint32_t opBlendPreNormal(uint32_t s, uint32_t d, TVG_UNUSED uint8_t a)
{
return s + ALPHA_BLEND(d, IALPHA(s));
}
static inline uint32_t opDirect(uint32_t s, TVG_UNUSED uint32_t d, TVG_UNUSED uint8_t a)
static inline uint32_t opBlendSrcOver(uint32_t s, TVG_UNUSED uint32_t d, TVG_UNUSED uint8_t a)
{
return s;
}
static inline uint32_t opAddMask(uint32_t s, uint32_t d, TVG_UNUSED uint8_t a)
static inline uint32_t opMaskAdd(uint32_t s, uint32_t d, uint8_t a)
{
return opBlend(s, d, a);
return opBlendNormal(s, d, a);
}
static inline uint32_t opSubMask(uint32_t s, uint32_t d, TVG_UNUSED uint8_t a)
static inline uint32_t opMaskSubtract(uint32_t s, uint32_t d, uint8_t a)
{
return ALPHA_BLEND(d, MULTIPLY(IALPHA(s), a));
}
static inline uint32_t opMaskDifference(uint32_t s, uint32_t d, uint8_t a)
{
auto t = ALPHA_BLEND(s, a);
return ALPHA_BLEND(t, IALPHA(d)) + ALPHA_BLEND(d, IALPHA(t));
}
static inline uint32_t opMaskIntersect(uint32_t s, uint32_t d, uint8_t a)
{
return ALPHA_BLEND(d, MULTIPLY(IALPHA(s), a));
}
static inline uint32_t opMaskPreAdd(uint32_t s, uint32_t d, TVG_UNUSED uint8_t a)
{
return opBlendPreNormal(s, d, a);
}
static inline uint32_t opMaskPreSubtract(uint32_t s, uint32_t d, TVG_UNUSED uint8_t a)
{
return ALPHA_BLEND(d, IALPHA(s));
}
static inline uint32_t opIntMask(TVG_UNUSED uint32_t s, uint32_t d, uint8_t a)
{
return ALPHA_BLEND(d, a);
}
static inline uint32_t opDifMask(uint32_t s, uint32_t d, TVG_UNUSED uint8_t a)
static inline uint32_t opMaskPreDifference(uint32_t s, uint32_t d, TVG_UNUSED uint8_t a)
{
return ALPHA_BLEND(s, IALPHA(d)) + ALPHA_BLEND(d, IALPHA(s));
}
static inline uint32_t opInterpolate(uint32_t s, uint32_t d, uint8_t a)
static inline uint32_t opMaskPreIntersect(uint32_t s, uint32_t d, TVG_UNUSED uint8_t a)
{
return INTERPOLATE(s, d, a);
return ALPHA_BLEND(d, MULTIPLY(a, IALPHA(s)));
}
@ -407,9 +426,9 @@ bool fillGenColorTable(SwFill* fill, const Fill* fdata, const Matrix* transform,
void fillReset(SwFill* fill);
void fillFree(SwFill* fill);
//OPTIMIZE_ME: Skip the function pointer access
void fillLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlendOp op, uint8_t a); //blending ver.
void fillLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlender op, uint8_t a); //blending ver.
void fillLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, uint8_t* cmp, SwAlpha alpha, uint8_t csize, uint8_t opacity); //masking ver.
void fillRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlendOp op, uint8_t a); //blending ver.
void fillRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlender op, uint8_t a); //blending ver.
void fillRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, uint8_t* cmp, SwAlpha alpha, uint8_t csize, uint8_t opacity); //masking ver.
SwRleData* rleRender(SwRleData* rle, const SwOutline* outline, const SwBBox& renderRegion, bool antiAlias);

View file

@ -246,13 +246,13 @@ void fillRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint3
if (opacity == 255) {
for (uint32_t i = 0 ; i < len ; ++i, ++dst, cmp += csize) {
*dst = opAlphaBlend(_pixel(fill, sqrtf(det)), *dst, alpha(cmp));
*dst = opBlendNormal(_pixel(fill, sqrtf(det)), *dst, alpha(cmp));
det += detFirstDerivative;
detFirstDerivative += detSecondDerivative;
}
} else {
for (uint32_t i = 0 ; i < len ; ++i, ++dst, cmp += csize) {
*dst = opAlphaBlend(_pixel(fill, sqrtf(det)), *dst, MULTIPLY(opacity, alpha(cmp)));
*dst = opBlendNormal(_pixel(fill, sqrtf(det)), *dst, MULTIPLY(opacity, alpha(cmp)));
det += detFirstDerivative;
detFirstDerivative += detSecondDerivative;
}
@ -260,7 +260,7 @@ void fillRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint3
}
void fillRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlendOp op, uint8_t a)
void fillRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlender op, uint8_t a)
{
auto rx = (x + 0.5f) * fill->radial.a11 + (y + 0.5f) * fill->radial.a12 + fill->radial.shiftX;
auto ry = (x + 0.5f) * fill->radial.a21 + (y + 0.5f) * fill->radial.a22 + fill->radial.shiftY;
@ -291,7 +291,7 @@ void fillLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint3
if (mathZero(inc)) {
auto color = _fixedPixel(fill, static_cast<int32_t>(t * FIXPT_SIZE));
for (uint32_t i = 0; i < len; ++i, ++dst, cmp += csize) {
*dst = opAlphaBlend(color, *dst, alpha(cmp));
*dst = opBlendNormal(color, *dst, alpha(cmp));
}
return;
}
@ -305,14 +305,14 @@ void fillLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint3
auto t2 = static_cast<int32_t>(t * FIXPT_SIZE);
auto inc2 = static_cast<int32_t>(inc * FIXPT_SIZE);
for (uint32_t j = 0; j < len; ++j, ++dst, cmp += csize) {
*dst = opAlphaBlend(_fixedPixel(fill, t2), *dst, alpha(cmp));
*dst = opBlendNormal(_fixedPixel(fill, t2), *dst, alpha(cmp));
t2 += inc2;
}
//we have to fallback to float math
} else {
uint32_t counter = 0;
while (counter++ < len) {
*dst = opAlphaBlend(_pixel(fill, t / GRADIENT_STOP_SIZE), *dst, alpha(cmp));
*dst = opBlendNormal(_pixel(fill, t / GRADIENT_STOP_SIZE), *dst, alpha(cmp));
++dst;
t += inc;
cmp += csize;
@ -322,7 +322,7 @@ void fillLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint3
if (mathZero(inc)) {
auto color = _fixedPixel(fill, static_cast<int32_t>(t * FIXPT_SIZE));
for (uint32_t i = 0; i < len; ++i, ++dst, cmp += csize) {
*dst = opAlphaBlend(color, *dst, MULTIPLY(alpha(cmp), opacity));
*dst = opBlendNormal(color, *dst, MULTIPLY(alpha(cmp), opacity));
}
return;
}
@ -336,14 +336,14 @@ void fillLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint3
auto t2 = static_cast<int32_t>(t * FIXPT_SIZE);
auto inc2 = static_cast<int32_t>(inc * FIXPT_SIZE);
for (uint32_t j = 0; j < len; ++j, ++dst, cmp += csize) {
*dst = opAlphaBlend(_fixedPixel(fill, t2), *dst, MULTIPLY(alpha(cmp), opacity));
*dst = opBlendNormal(_fixedPixel(fill, t2), *dst, MULTIPLY(alpha(cmp), opacity));
t2 += inc2;
}
//we have to fallback to float math
} else {
uint32_t counter = 0;
while (counter++ < len) {
*dst = opAlphaBlend(_pixel(fill, t / GRADIENT_STOP_SIZE), *dst, MULTIPLY(opacity, alpha(cmp)));
*dst = opBlendNormal(_pixel(fill, t / GRADIENT_STOP_SIZE), *dst, MULTIPLY(opacity, alpha(cmp)));
++dst;
t += inc;
cmp += csize;
@ -353,7 +353,7 @@ void fillLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint3
}
void fillLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlendOp op, uint8_t a)
void fillLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlender op, uint8_t a)
{
//Rotation
float rx = x + 0.5f;

View file

@ -39,7 +39,7 @@ constexpr auto DOWN_SCALE_TOLERANCE = 0.5f;
struct FillLinear
{
void operator()(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlendOp op, uint8_t a)
void operator()(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlender op, uint8_t a)
{
fillLinear(fill, dst, y, x, len, op, a);
}
@ -52,7 +52,7 @@ struct FillLinear
struct FillRadial
{
void operator()(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlendOp op, uint8_t a)
void operator()(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlender op, uint8_t a)
{
fillRadial(fill, dst, y, x, len, op, a);
}
@ -694,7 +694,7 @@ static bool _rasterScaledMaskedRleRGBAImage(SwSurface* surface, const SwImage* i
if (method == CompositeMethod::AddMask) _rasterScaledMaskedRleRGBAImageDup<AddMaskOp, AddMaskAOp>(surface, image, itransform, region, opacity, halfScale);
else if (method == CompositeMethod::SubtractMask) _rasterScaledMaskedRleRGBAImageDup<SubMaskOp, SubMaskAOp>(surface, image, itransform, region, opacity, halfScale);
else if (method == CompositeMethod::IntersectMask) _rasterScaledMaskedRleRGBAImageDup<DifMaskOp, DifMaskAOp>(surface, image, itransform, region, opacity, halfScale);
else if (method == CompositeMethod::DifferenceMask) _rasterScaledMaskedRleRGBAImageDup<DifMaskOp, DifMaskAOp>(surface, image, itransform, region, opacity, halfScale);
else if (method == CompositeMethod::IntersectMask) _rasterScaledMaskedRleRGBAImageInt(surface, image, itransform, region, opacity, halfScale);
else return false;
@ -1341,7 +1341,7 @@ static bool _rasterRGBAImage(SwSurface* surface, SwImage* image, const Matrix* t
/************************************************************************/
template<typename fillMethod>
static void _rasterGradientMaskedRectDup(SwSurface* surface, const SwBBox& region, const SwFill* fill, SwBlendOp maskOp)
static void _rasterGradientMaskedRectDup(SwSurface* surface, const SwBBox& region, const SwFill* fill, SwBlender maskOp)
{
auto h = static_cast<uint32_t>(region.max.y - region.min.y);
auto w = static_cast<uint32_t>(region.max.x - region.min.x);
@ -1370,7 +1370,7 @@ static void _rasterGradientMaskedRectInt(SwSurface* surface, const SwBBox& regio
auto x = surface->compositor->bbox.min.x;
while (x < surface->compositor->bbox.max.x) {
if (x == region.min.x) {
fillMethod()(fill, tmp, y2, x, w, opIntMask, 255);
fillMethod()(fill, tmp, y2, x, w, opMaskPreIntersect, 255);
x += w;
tmp += w;
} else {
@ -1397,9 +1397,9 @@ static bool _rasterGradientMaskedRect(SwSurface* surface, const SwBBox& region,
TVGLOG("SW_ENGINE", "Masked(%d) Gradient [Region: %lu %lu %lu %lu]", (int)surface->compositor->method, region.min.x, region.min.y, region.max.x - region.min.x, region.max.y - region.min.y);
if (method == CompositeMethod::AddMask) _rasterGradientMaskedRectDup<fillMethod>(surface, region, fill, opAddMask);
else if (method == CompositeMethod::SubtractMask) _rasterGradientMaskedRectDup<fillMethod>(surface, region, fill, opSubMask);
else if (method == CompositeMethod::DifferenceMask) _rasterGradientMaskedRectDup<fillMethod>(surface, region, fill, opDifMask);
if (method == CompositeMethod::AddMask) _rasterGradientMaskedRectDup<fillMethod>(surface, region, fill, opMaskPreAdd);
else if (method == CompositeMethod::SubtractMask) _rasterGradientMaskedRectDup<fillMethod>(surface, region, fill, opMaskPreSubtract);
else if (method == CompositeMethod::DifferenceMask) _rasterGradientMaskedRectDup<fillMethod>(surface, region, fill, opMaskPreDifference);
else if (method == CompositeMethod::IntersectMask) _rasterGradientMaskedRectInt<fillMethod>(surface, region, fill);
else return false;
@ -1437,7 +1437,7 @@ static bool _rasterTranslucentGradientRect(SwSurface* surface, const SwBBox& reg
auto w = static_cast<uint32_t>(region.max.x - region.min.x);
for (uint32_t y = 0; y < h; ++y) {
fillMethod()(fill, buffer, region.min.y + y, region.min.x, w, opBlend, 255);
fillMethod()(fill, buffer, region.min.y + y, region.min.x, w, opBlendPreNormal, 255);
buffer += surface->stride;
}
return true;
@ -1452,7 +1452,7 @@ static bool _rasterSolidGradientRect(SwSurface* surface, const SwBBox& region, c
auto h = static_cast<uint32_t>(region.max.y - region.min.y);
for (uint32_t y = 0; y < h; ++y) {
fillMethod()(fill, buffer + y * surface->stride, region.min.y + y, region.min.x, w, opDirect, 0);
fillMethod()(fill, buffer + y * surface->stride, region.min.y + y, region.min.x, w, opBlendSrcOver, 255);
}
return true;
}
@ -1494,7 +1494,7 @@ static bool _rasterRadialGradientRect(SwSurface* surface, const SwBBox& region,
/************************************************************************/
template<typename fillMethod>
static void _rasterGradientMaskedRleDup(SwSurface* surface, const SwRleData* rle, const SwFill* fill, SwBlendOp maskOp)
static void _rasterGradientMaskedRleDup(SwSurface* surface, const SwRleData* rle, const SwFill* fill, SwBlender maskOp)
{
auto span = rle->spans;
auto cstride = surface->compositor->image.stride;
@ -1519,7 +1519,7 @@ static void _rasterGradientMaskedRleInt(SwSurface* surface, const SwRleData* rle
uint32_t x = surface->compositor->bbox.min.x;
while (x < surface->compositor->bbox.max.x) {
if (y == span->y && x == span->x && x + span->len <= surface->compositor->bbox.max.x) {
fillMethod()(fill, cmp, span->y, span->x, span->len, opIntMask, span->coverage);
fillMethod()(fill, cmp, span->y, span->x, span->len, opMaskIntersect, span->coverage);
x += span->len;
++span;
} else {
@ -1538,9 +1538,9 @@ static bool _rasterGradientMaskedRle(SwSurface* surface, const SwRleData* rle, c
auto method = surface->compositor->method;
if (method == CompositeMethod::AddMask) _rasterGradientMaskedRleDup<fillMethod>(surface, rle, fill, opAddMask);
else if (method == CompositeMethod::SubtractMask) _rasterGradientMaskedRleDup<fillMethod>(surface, rle, fill, opSubMask);
else if (method == CompositeMethod::DifferenceMask) _rasterGradientMaskedRleDup<fillMethod>(surface, rle, fill, opDifMask);
if (method == CompositeMethod::AddMask) _rasterGradientMaskedRleDup<fillMethod>(surface, rle, fill, opMaskAdd);
else if (method == CompositeMethod::SubtractMask) _rasterGradientMaskedRleDup<fillMethod>(surface, rle, fill, opMaskSubtract);
else if (method == CompositeMethod::DifferenceMask) _rasterGradientMaskedRleDup<fillMethod>(surface, rle, fill, opMaskDifference);
else if (method == CompositeMethod::IntersectMask) _rasterGradientMaskedRleInt<fillMethod>(surface, rle, fill);
else return false;
@ -1575,8 +1575,8 @@ static bool _rasterTranslucentGradientRle(SwSurface* surface, const SwRleData* r
for (uint32_t i = 0; i < rle->size; ++i, ++span) {
auto dst = &surface->buf32[span->y * surface->stride + span->x];
if (span->coverage == 255) fillMethod()(fill, dst, span->y, span->x, span->len, opBlend, 255);
else fillMethod()(fill, dst, span->y, span->x, span->len, opAlphaBlend, span->coverage);
if (span->coverage == 255) fillMethod()(fill, dst, span->y, span->x, span->len, opBlendPreNormal, 255);
else fillMethod()(fill, dst, span->y, span->x, span->len, opBlendNormal, span->coverage);
}
return true;
}
@ -1589,8 +1589,8 @@ static bool _rasterSolidGradientRle(SwSurface* surface, const SwRleData* rle, co
for (uint32_t i = 0; i < rle->size; ++i, ++span) {
auto dst = &surface->buf32[span->y * surface->stride + span->x];
if (span->coverage == 255) fillMethod()(fill, dst, span->y, span->x, span->len, opDirect, 0);
else fillMethod()(fill, dst, span->y, span->x, span->len, opInterpolate, span->coverage);
if (span->coverage == 255) fillMethod()(fill, dst, span->y, span->x, span->len, opBlendSrcOver, 255);
else fillMethod()(fill, dst, span->y, span->x, span->len, opBlendInterp, span->coverage);
}
return true;
}