4008acdc7c
The FP factory would apply optimizations based on the mode, and return one of the passed-in FPs. We use 'nullptr' as the 'src' FP when constructing the blender's FP in make_effect_fp. This means that we get back 'nullptr' from a src-mode blender. Later, we interpret that as src-over (the default for an unset blender). Oops. The new test variant would previously fail, before the fix to the FP. The tweak to the FP technically eliminates an optimization, but it's one that only applies to blending happening in the shader (eg, compose shader, or runtime effects using a blender), and only when the blender is one of the trivial modes. The resulting shader will still optimize down, it just involves a bit of extra work before that happens. This shouldn't have any long-term performance impact, particularly on important scenarios. Change-Id: Id5c6a6ca8a263b35c2dca3c41171748cffd41adb Reviewed-on: https://skia-review.googlesource.com/c/skia/+/556599 Reviewed-by: John Stiles <johnstiles@google.com> Commit-Queue: Brian Osman <brianosman@google.com>
104 lines
4.5 KiB
C++
104 lines
4.5 KiB
C++
/*
|
|
* Copyright 2021 Google LLC
|
|
*
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
|
|
#include "gm/gm.h"
|
|
#include "include/core/SkBitmap.h"
|
|
#include "include/core/SkCanvas.h"
|
|
#include "include/core/SkPaint.h"
|
|
#include "include/core/SkSize.h"
|
|
#include "include/core/SkSurface.h"
|
|
#include "include/effects/SkRuntimeEffect.h"
|
|
#include "src/gpu/ganesh/GrCaps.h"
|
|
#include "src/gpu/ganesh/GrDirectContextPriv.h"
|
|
#include "tests/Test.h"
|
|
#include "tools/Resources.h"
|
|
#include "tools/RuntimeBlendUtils.h"
|
|
#include "tools/ToolUtils.h"
|
|
|
|
static bool nearly_equal(const SkColor& x, const SkColor& y) {
|
|
const int kTolerance = 1;
|
|
return abs((int)SkColorGetA(x) - (int)SkColorGetA(y)) <= kTolerance &&
|
|
abs((int)SkColorGetR(x) - (int)SkColorGetR(y)) <= kTolerance &&
|
|
abs((int)SkColorGetG(x) - (int)SkColorGetG(y)) <= kTolerance &&
|
|
abs((int)SkColorGetB(x) - (int)SkColorGetB(y)) <= kTolerance;
|
|
}
|
|
|
|
static void test_blend(skiatest::Reporter* r, SkSurface* surface) {
|
|
SkBitmap bitmap;
|
|
REPORTER_ASSERT(r, bitmap.tryAllocPixels(surface->imageInfo()));
|
|
|
|
for (int m = 0; m < kSkBlendModeCount; ++m) {
|
|
SkBlendMode mode = (SkBlendMode)m;
|
|
for (int alpha : {0x80, 0xFF}) {
|
|
for (bool useShader : {false, true}) {
|
|
std::vector<SkColor> colors;
|
|
for (bool useRuntimeBlend : {false, true}) {
|
|
// Draw a solid red pixel.
|
|
SkPaint paint;
|
|
paint.setColor(SK_ColorRED);
|
|
paint.setBlendMode(SkBlendMode::kSrc);
|
|
surface->getCanvas()->drawRect(SkRect::MakeWH(1, 1), paint);
|
|
|
|
// Draw a blue pixel on top of it, using the passed-in blend mode.
|
|
if (useShader) {
|
|
// Install a different color in the paint, to ensure we're using the shader
|
|
paint.setColor(SK_ColorGREEN);
|
|
paint.setShader(SkShaders::Color(SkColorSetARGB(alpha, 0x00, 0x00, 0xFF)));
|
|
} else {
|
|
paint.setColor(SkColorSetARGB(alpha, 0x00, 0x00, 0xFF));
|
|
}
|
|
if (useRuntimeBlend) {
|
|
paint.setBlender(GetRuntimeBlendForBlendMode(mode));
|
|
} else {
|
|
paint.setBlendMode(mode);
|
|
}
|
|
surface->getCanvas()->drawRect(SkRect::MakeWH(1, 1), paint);
|
|
|
|
// Read back the red/blue blended pixel.
|
|
REPORTER_ASSERT(r,
|
|
surface->readPixels(bitmap.info(),
|
|
bitmap.getPixels(),
|
|
bitmap.rowBytes(),
|
|
/*srcX=*/0,
|
|
/*srcY=*/0));
|
|
colors.push_back(bitmap.getColor(/*x=*/0, /*y=*/0));
|
|
}
|
|
|
|
REPORTER_ASSERT(r,
|
|
nearly_equal(colors[0], colors[1]),
|
|
"Expected: %s %s %s blend matches. Actual: Built-in "
|
|
"A=%02X R=%02X G=%02X B=%02X, Runtime A=%02X R=%02X G=%02X B=%02X",
|
|
SkBlendMode_Name(mode),
|
|
(alpha == 0xFF) ? "solid" : "transparent",
|
|
useShader ? "shader" : "paint",
|
|
SkColorGetA(colors[0]),
|
|
SkColorGetR(colors[0]),
|
|
SkColorGetG(colors[0]),
|
|
SkColorGetB(colors[0]),
|
|
SkColorGetA(colors[1]),
|
|
SkColorGetR(colors[1]),
|
|
SkColorGetG(colors[1]),
|
|
SkColorGetB(colors[1]));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
DEF_TEST(SkRuntimeBlender_CPU, r) {
|
|
const SkImageInfo info = SkImageInfo::MakeN32Premul(/*width=*/1, /*height=*/1);
|
|
sk_sp<SkSurface> surface(SkSurface::MakeRaster(info));
|
|
|
|
test_blend(r, surface.get());
|
|
}
|
|
|
|
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRuntimeBlender_GPU, r, ctxInfo) {
|
|
const SkImageInfo info = SkImageInfo::MakeN32Premul(/*width=*/1, /*height=*/1);
|
|
sk_sp<SkSurface> surface(SkSurface::MakeRenderTarget(ctxInfo.directContext(),
|
|
SkBudgeted::kNo, info));
|
|
test_blend(r, surface.get());
|
|
}
|