incorporate r,g,b,a into shaderHash

Today's shader hash changes if the unordered set of {r,g,b,a} values we
produce changes, but is not sensitive to simple order changes like
sampling RGBA vs BGRA.

Folding in a hash of each value's ID in order will fix this.

This has been difficult to track down (thread-local caches),
so I've added a GM that reliably reproduces the bug.

Live demo: https://fiddle.skia.org/c/30f2e5b731c2e53a6f092424c585ca41

Bug: skia:9819
Change-Id: Iceb09d89eb036735028ae97dc79c576787199ac5
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/267119
Reviewed-by: Mike Klein <mtklein@google.com>
Commit-Queue: Mike Klein <mtklein@google.com>
This commit is contained in:
Mike Klein 2020-01-28 13:12:50 -06:00 committed by Skia Commit-Bot
parent 162e04b9a9
commit d352529216
3 changed files with 71 additions and 0 deletions

64
gm/skbug_9819.cpp Normal file
View File

@ -0,0 +1,64 @@
/*
* Copyright 2020 Google Inc.
*
* 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"
// This GM should draw two yellow boxes; the bug drew one in cyan.
DEF_SIMPLE_GM(skbug_9819, c, 256, 256) {
auto info = SkImageInfo::Make(1,1, kUnknown_SkColorType, kPremul_SkAlphaType);
SkBitmap rgba,
bgra;
rgba.allocPixels(info.makeColorType(kRGBA_8888_SkColorType));
bgra.allocPixels(info.makeColorType(kBGRA_8888_SkColorType));
SkColor yellow = 0xffffff00;
rgba.eraseColor(yellow);
bgra.eraseColor(yellow);
c->save();
c->scale(128,128);
c->drawBitmap(rgba, 0,0);
c->drawBitmap(bgra, 0,1);
c->restore();
auto grade = [&](int x, int y){
SkBitmap bm;
bm.allocPixels(SkImageInfo::Make(1,1,
kBGRA_8888_SkColorType,
kUnpremul_SkAlphaType,
SkColorSpace::MakeSRGB()));
if (!c->readPixels(bm, x,y)) {
// Picture-backed canvases, that sort of thing. Just assume they're good.
MarkGMGood(c, x+128, y);
return;
}
SkColor pixel;
memcpy(&pixel, bm.getAddr(0,0), sizeof(pixel));
auto close = [](int x, int y) {
return x-y < 2
&& y-x < 2;
};
if (close(SkColorGetR(pixel), SkColorGetR(yellow)) &&
close(SkColorGetG(pixel), SkColorGetG(yellow)) &&
close(SkColorGetB(pixel), SkColorGetB(yellow)) &&
close(SkColorGetA(pixel), SkColorGetA(yellow))) {
MarkGMGood(c, x+128,y);
} else {
MarkGMBad(c, x+128,y);
}
};
grade(64, 64);
grade(64, 192);
}

View File

@ -327,6 +327,7 @@ gm_sources = [
"$_gm/skbug_8664.cpp",
"$_gm/skbug_8955.cpp",
"$_gm/skbug_9319.cpp",
"$_gm/skbug_9819.cpp",
"$_gm/skinning.cpp",
"$_gm/smallarc.cpp",
"$_gm/smallpaths.cpp",

View File

@ -13,6 +13,7 @@
#include "src/core/SkColorSpaceXformSteps.h"
#include "src/core/SkCoreBlitters.h"
#include "src/core/SkLRUCache.h"
#include "src/core/SkOpts.h"
#include "src/core/SkVM.h"
#include "src/core/SkVMBlitter.h"
#include "src/shaders/SkColorFilterShader.h"
@ -132,6 +133,11 @@ namespace {
uniforms,alloc,
x,y, &r,&g,&b,&a)) {
shaderHash = p.hash();
// p.hash() folds in all instructions to produce r,g,b,a but does not know
// precisely which value we'll treat as which channel. Imagine the shader
// called std::swap(*r,*b)... it draws differently, but p.hash() is unchanged.
const int outputs[] = { r.id, g.id, b.id, a.id };
shaderHash ^= SkOpts::hash(outputs, sizeof(outputs));
} else {
*ok = false;
}