Fix picture shader handling of outer local matrix
Instead of applying local matrices to the cached shader, pass them explicitly/composed to createContext/appendStages/asFragmentProcessor. Change-Id: I39aaf07ac883094c447c4e03e2ef9dcf8de13555 Reviewed-on: https://skia-review.googlesource.com/104580 Commit-Queue: Florin Malita <fmalita@chromium.org> Reviewed-by: Mike Reed <reed@google.com>
This commit is contained in:
parent
133bc33330
commit
18f7e0a19c
@ -25,10 +25,10 @@ static struct {
|
||||
|
||||
class PictureShaderGM : public skiagm::GM {
|
||||
public:
|
||||
PictureShaderGM(SkScalar tileSize, SkScalar sceneSize)
|
||||
PictureShaderGM(SkScalar tileSize, SkScalar sceneSize, bool useLocalMatrixWrapper = false)
|
||||
: fTileSize(tileSize)
|
||||
, fSceneSize(sceneSize) {
|
||||
}
|
||||
, fSceneSize(sceneSize)
|
||||
, fUseLocalMatrixWrapper(useLocalMatrixWrapper) {}
|
||||
|
||||
protected:
|
||||
void onOnceBeforeDraw() override {
|
||||
@ -47,7 +47,7 @@ public:
|
||||
|
||||
|
||||
SkString onShortName() override {
|
||||
return SkString("pictureshader");
|
||||
return SkStringPrintf("pictureshader%s", fUseLocalMatrixWrapper ? "_localwrapper" : "");
|
||||
}
|
||||
|
||||
SkISize onISize() override {
|
||||
@ -151,32 +151,43 @@ private:
|
||||
canvas->drawRect(SkRect::MakeWH(fSceneSize, fSceneSize), paint);
|
||||
canvas->drawRect(SkRect::MakeXYWH(fSceneSize * 1.1f, 0, fSceneSize, fSceneSize), paint);
|
||||
|
||||
paint.setShader(SkShader::MakePictureShader(fPicture, kTileConfigs[tileMode].tmx,
|
||||
kTileConfigs[tileMode].tmy, &localMatrix,
|
||||
nullptr));
|
||||
auto pictureShader = SkShader::MakePictureShader(fPicture, kTileConfigs[tileMode].tmx,
|
||||
kTileConfigs[tileMode].tmy,
|
||||
fUseLocalMatrixWrapper
|
||||
? nullptr : &localMatrix,
|
||||
nullptr);
|
||||
paint.setShader(fUseLocalMatrixWrapper
|
||||
? pictureShader->makeWithLocalMatrix(localMatrix)
|
||||
: pictureShader);
|
||||
canvas->drawRect(SkRect::MakeWH(fSceneSize, fSceneSize), paint);
|
||||
|
||||
canvas->translate(fSceneSize * 1.1f, 0);
|
||||
|
||||
paint.setShader(SkShader::MakeBitmapShader(fBitmap,
|
||||
kTileConfigs[tileMode].tmx,
|
||||
kTileConfigs[tileMode].tmy,
|
||||
&localMatrix));
|
||||
auto bitmapShader = SkShader::MakeBitmapShader(fBitmap,
|
||||
kTileConfigs[tileMode].tmx,
|
||||
kTileConfigs[tileMode].tmy,
|
||||
fUseLocalMatrixWrapper
|
||||
? nullptr : &localMatrix);
|
||||
paint.setShader(fUseLocalMatrixWrapper
|
||||
? bitmapShader->makeWithLocalMatrix(localMatrix)
|
||||
: bitmapShader);
|
||||
canvas->drawRect(SkRect::MakeWH(fSceneSize, fSceneSize), paint);
|
||||
|
||||
canvas->restore();
|
||||
}
|
||||
|
||||
SkScalar fTileSize;
|
||||
SkScalar fSceneSize;
|
||||
|
||||
sk_sp<SkPicture> fPicture;
|
||||
SkBitmap fBitmap;
|
||||
|
||||
SkScalar fTileSize;
|
||||
SkScalar fSceneSize;
|
||||
bool fUseLocalMatrixWrapper;
|
||||
|
||||
typedef GM INHERITED;
|
||||
};
|
||||
|
||||
DEF_GM(return new PictureShaderGM(50, 100);)
|
||||
DEF_GM(return new PictureShaderGM(50, 100, true);)
|
||||
|
||||
DEF_SIMPLE_GM(tiled_picture_shader, canvas, 400, 400) {
|
||||
// https://code.google.com/p/skia/issues/detail?id=3398
|
||||
|
@ -38,7 +38,6 @@ public:
|
||||
SkShader::TileMode tmx,
|
||||
SkShader::TileMode tmy,
|
||||
const SkSize& scale,
|
||||
const SkMatrix& localMatrix,
|
||||
SkTransferFunctionBehavior blendBehavior)
|
||||
: fColorSpace(std::move(colorSpace))
|
||||
, fTile(tile)
|
||||
@ -47,15 +46,10 @@ public:
|
||||
, fScale(scale)
|
||||
, fBlendBehavior(blendBehavior) {
|
||||
|
||||
for (int i = 0; i < 9; ++i) {
|
||||
fLocalMatrixStorage[i] = localMatrix[i];
|
||||
}
|
||||
|
||||
static const size_t keySize = sizeof(fColorSpace) +
|
||||
sizeof(fTile) +
|
||||
sizeof(fTmx) + sizeof(fTmy) +
|
||||
sizeof(fScale) +
|
||||
sizeof(fLocalMatrixStorage) +
|
||||
sizeof(fBlendBehavior);
|
||||
// This better be packed.
|
||||
SkASSERT(sizeof(uint32_t) * (&fEndOfStruct - (uint32_t*)&fColorSpace) == keySize);
|
||||
@ -79,7 +73,6 @@ private:
|
||||
SkRect fTile;
|
||||
SkShader::TileMode fTmx, fTmy;
|
||||
SkSize fScale;
|
||||
SkScalar fLocalMatrixStorage[9];
|
||||
SkTransferFunctionBehavior fBlendBehavior;
|
||||
|
||||
SkDEBUGCODE(uint32_t fEndOfStruct;)
|
||||
@ -179,16 +172,28 @@ void SkPictureShader::flatten(SkWriteBuffer& buffer) const {
|
||||
fPicture->flatten(buffer);
|
||||
}
|
||||
|
||||
sk_sp<SkShader> SkPictureShader::refBitmapShader(const SkMatrix& viewMatrix, const SkMatrix* localM,
|
||||
// This helper returns two artifacts:
|
||||
//
|
||||
// 1) a cached image shader, which wraps a single picture tile at the given CTM/local matrix
|
||||
//
|
||||
// 2) a "composite" local matrix, to be passed down when dispatching createContext(),
|
||||
// appendStages() and asFragmentProcessor() in callers
|
||||
//
|
||||
// The composite local matrix includes the actual local matrix, any inherited/outer local matrix
|
||||
// and a scale component (to mape the actual tile bitmap size -> fTile size).
|
||||
//
|
||||
sk_sp<SkShader> SkPictureShader::refBitmapShader(const SkMatrix& viewMatrix,
|
||||
const SkMatrix* outerLocalMatrix,
|
||||
SkColorSpace* dstColorSpace,
|
||||
SkMatrix* compositeLocalMatrix,
|
||||
const int maxTextureSize) const {
|
||||
SkASSERT(fPicture && !fPicture->cullRect().isEmpty());
|
||||
|
||||
SkMatrix m;
|
||||
m.setConcat(viewMatrix, this->getLocalMatrix());
|
||||
if (localM) {
|
||||
m.preConcat(*localM);
|
||||
*compositeLocalMatrix = this->getLocalMatrix();
|
||||
if (outerLocalMatrix) {
|
||||
compositeLocalMatrix->preConcat(*outerLocalMatrix);
|
||||
}
|
||||
const SkMatrix m = SkMatrix::Concat(viewMatrix, *compositeLocalMatrix);
|
||||
|
||||
// Use a rotation-invariant scale
|
||||
SkPoint scale;
|
||||
@ -246,7 +251,6 @@ sk_sp<SkShader> SkPictureShader::refBitmapShader(const SkMatrix& viewMatrix, con
|
||||
fTmx,
|
||||
fTmy,
|
||||
tileScale,
|
||||
this->getLocalMatrix(),
|
||||
blendBehavior);
|
||||
|
||||
if (!SkResourceCache::Find(key, BitmapShaderRec::Visitor, &tileShader)) {
|
||||
@ -265,14 +269,14 @@ sk_sp<SkShader> SkPictureShader::refBitmapShader(const SkMatrix& viewMatrix, con
|
||||
tileImage = tileImage->makeColorSpace(fColorSpace, SkTransferFunctionBehavior::kIgnore);
|
||||
}
|
||||
|
||||
SkMatrix shaderMatrix = this->getLocalMatrix();
|
||||
shaderMatrix.preScale(1 / tileScale.width(), 1 / tileScale.height());
|
||||
tileShader = tileImage->makeShader(fTmx, fTmy, &shaderMatrix);
|
||||
tileShader = tileImage->makeShader(fTmx, fTmy);
|
||||
|
||||
SkResourceCache::Add(new BitmapShaderRec(key, tileShader.get()));
|
||||
fAddedToCache.store(true);
|
||||
}
|
||||
|
||||
compositeLocalMatrix->preScale(1 / tileScale.width(), 1 / tileScale.height());
|
||||
|
||||
return tileShader;
|
||||
}
|
||||
|
||||
@ -284,21 +288,32 @@ bool SkPictureShader::onIsRasterPipelineOnly(const SkMatrix& ctm) const {
|
||||
bool SkPictureShader::onAppendStages(const StageRec& rec) const {
|
||||
// Keep bitmapShader alive by using alloc instead of stack memory
|
||||
auto& bitmapShader = *rec.fAlloc->make<sk_sp<SkShader>>();
|
||||
bitmapShader = this->refBitmapShader(rec.fCTM, rec.fLocalM, rec.fDstCS);
|
||||
return bitmapShader && as_SB(bitmapShader)->appendStages(rec);
|
||||
SkMatrix compositeLocalMatrix;
|
||||
bitmapShader = this->refBitmapShader(rec.fCTM, rec.fLocalM, rec.fDstCS, &compositeLocalMatrix);
|
||||
|
||||
StageRec localRec = rec;
|
||||
localRec.fLocalM = compositeLocalMatrix.isIdentity() ? nullptr : &compositeLocalMatrix;
|
||||
|
||||
return bitmapShader && as_SB(bitmapShader)->appendStages(localRec);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
SkShaderBase::Context* SkPictureShader::onMakeContext(const ContextRec& rec, SkArenaAlloc* alloc)
|
||||
const {
|
||||
sk_sp<SkShader> bitmapShader(this->refBitmapShader(*rec.fMatrix, rec.fLocalMatrix,
|
||||
rec.fDstColorSpace));
|
||||
SkMatrix compositeLocalMatrix;
|
||||
sk_sp<SkShader> bitmapShader = this->refBitmapShader(*rec.fMatrix,
|
||||
rec.fLocalMatrix,
|
||||
rec.fDstColorSpace,
|
||||
&compositeLocalMatrix);
|
||||
if (!bitmapShader) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ContextRec localRec = rec;
|
||||
localRec.fLocalMatrix = compositeLocalMatrix.isIdentity() ? nullptr : &compositeLocalMatrix;
|
||||
|
||||
PictureShaderContext* ctx =
|
||||
alloc->make<PictureShaderContext>(*this, rec, std::move(bitmapShader), alloc);
|
||||
alloc->make<PictureShaderContext>(*this, localRec, std::move(bitmapShader), alloc);
|
||||
if (nullptr == ctx->fBitmapShaderContext) {
|
||||
ctx = nullptr;
|
||||
}
|
||||
@ -362,14 +377,20 @@ std::unique_ptr<GrFragmentProcessor> SkPictureShader::asFragmentProcessor(
|
||||
if (args.fContext) {
|
||||
maxTextureSize = args.fContext->caps()->maxTextureSize();
|
||||
}
|
||||
SkMatrix compositeLocalMatrix;
|
||||
sk_sp<SkShader> bitmapShader(this->refBitmapShader(*args.fViewMatrix, args.fLocalMatrix,
|
||||
args.fDstColorSpaceInfo->colorSpace(),
|
||||
&compositeLocalMatrix,
|
||||
maxTextureSize));
|
||||
if (!bitmapShader) {
|
||||
return nullptr;
|
||||
}
|
||||
return as_SB(bitmapShader)
|
||||
->asFragmentProcessor(GrFPArgs(args.fContext, args.fViewMatrix,
|
||||
args.fFilterQuality, args.fDstColorSpaceInfo));
|
||||
|
||||
return as_SB(bitmapShader)->asFragmentProcessor(
|
||||
GrFPArgs(args.fContext,
|
||||
args.fViewMatrix,
|
||||
compositeLocalMatrix.isIdentity() ? nullptr : &compositeLocalMatrix,
|
||||
args.fFilterQuality,
|
||||
args.fDstColorSpaceInfo));
|
||||
}
|
||||
#endif
|
||||
|
@ -49,6 +49,7 @@ private:
|
||||
|
||||
sk_sp<SkShader> refBitmapShader(const SkMatrix&, const SkMatrix* localMatrix,
|
||||
SkColorSpace* dstColorSpace,
|
||||
SkMatrix* compositeLocalMatrix,
|
||||
const int maxTextureSize = 0) const;
|
||||
|
||||
class PictureShaderContext : public Context {
|
||||
|
Loading…
Reference in New Issue
Block a user