diff --git a/gm/SkLinearBitmapPipelineGM.cpp b/gm/SkLinearBitmapPipelineGM.cpp index d3a143c5c1..6b354df947 100644 --- a/gm/SkLinearBitmapPipelineGM.cpp +++ b/gm/SkLinearBitmapPipelineGM.cpp @@ -60,7 +60,7 @@ static void draw_rect_orig(SkCanvas* canvas, const SkRect& r, SkColor c, const S SkAutoTUnref image{SkImage::NewRasterCopy( info, pmsrc.addr32(), pmsrc.rowBytes())}; SkPaint paint; - int32_t storage[300]; + int32_t storage[200]; SkShader* shader = image->newShader(SkShader::kClamp_TileMode, SkShader::kClamp_TileMode); if (useBilerp) { paint.setFilterQuality(SkFilterQuality::kLow_SkFilterQuality); diff --git a/src/core/SkBitmapProcShader.cpp b/src/core/SkBitmapProcShader.cpp index 38f46d18b4..895922c6b8 100644 --- a/src/core/SkBitmapProcShader.cpp +++ b/src/core/SkBitmapProcShader.cpp @@ -27,7 +27,8 @@ static bool only_scale_and_translate(const SkMatrix& matrix) { class BitmapProcInfoContext : public SkShader::Context { public: - // The info has been allocated elsewhere, but we are responsible for calling its destructor. + // The context takes ownership of the info. It will call its destructor + // but will NOT free the memory. BitmapProcInfoContext(const SkShader& shader, const SkShader::ContextRec& rec, SkBitmapProcInfo* info) : INHERITED(shader, rec) @@ -44,6 +45,8 @@ public: } ~BitmapProcInfoContext() override { + // The bitmap proc state has been created outside of the context on memory that will be freed + // elsewhere. Only call the destructor but leave the freeing of the memory to the caller. fInfo->~SkBitmapProcInfo(); } @@ -60,6 +63,8 @@ private: class BitmapProcShaderContext : public BitmapProcInfoContext { public: + // The context takes ownership of the state. It will call its destructor + // but will NOT free the memory. BitmapProcShaderContext(const SkShader& shader, const SkShader::ContextRec& rec, SkBitmapProcState* state) : INHERITED(shader, rec, state) @@ -111,80 +116,11 @@ private: }; /////////////////////////////////////////////////////////////////////////////////////////////////// -#include "SkLinearBitmapPipeline.h" -#include "SkPM4f.h" -#include "SkXfermode.h" -class LinearPipelineContext : public BitmapProcInfoContext { -public: - LinearPipelineContext(const SkShader& shader, const SkShader::ContextRec& rec, - SkBitmapProcInfo* info) - : INHERITED(shader, rec, info) - , fPipeline(info->fInvMatrix, info->fFilterQuality, info->fTileModeX, info->fTileModeY, - info->fPixmap) - { - // To implement the old shadeSpan entry-point, we need to efficiently convert our native - // floats into SkPMColor. The SkXfermode::D32Procs do exactly that. - // - sk_sp xfer(SkXfermode::Create(SkXfermode::kSrc_Mode)); - fXferProc = SkXfermode::GetD32Proc(xfer.get(), 0); - } - - void shadeSpan4f(int x, int y, SkPM4f dstC[], int count) override { - fPipeline.shadeSpan4f(x, y, dstC, count); - } - - void shadeSpan(int x, int y, SkPMColor dstC[], int count) override { - const int N = 128; - SkPM4f tmp[N]; - - while (count > 0) { - const int n = SkTMin(count, N); - fPipeline.shadeSpan4f(x, y, tmp, n); - fXferProc(nullptr, dstC, tmp, n, nullptr); - dstC += n; - x += n; - count -= n; - } - } - -private: - SkLinearBitmapPipeline fPipeline; - SkXfermode::D32Proc fXferProc; - - typedef BitmapProcInfoContext INHERITED; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -static bool choose_linear_pipeline(const SkShader::ContextRec& rec, const SkImageInfo& srcInfo) { - // These src attributes are not supported in the new 4f context (yet) - // - if (srcInfo.bytesPerPixel() < 4 || - kRGBA_F16_SkColorType == srcInfo.colorType()) { - return false; - } - -#if 0 // later we may opt-in to the new code even if the client hasn't requested it... - // These src attributes are only supported in the new 4f context - // - if (srcInfo.isSRGB() || - kUnpremul_SkAlphaType == srcInfo.alphaType() || - (4 == srcInfo.bytesPerPixel() && kN32_SkColorType != srcInfo.colorType())) - { - return true; - } -#endif - - // If we get here, we can reasonably use either context, respect the caller's preference - // - return SkShader::ContextRec::kPM4f_DstType == rec.fPreferredDstType; -} - -size_t SkBitmapProcShader::ContextSize(const ContextRec& rec, const SkImageInfo& srcInfo) { - size_t size0 = sizeof(BitmapProcShaderContext) + sizeof(SkBitmapProcState); - size_t size1 = sizeof(LinearPipelineContext) + sizeof(SkBitmapProcInfo); - return SkTMax(size0, size1); +size_t SkBitmapProcShader::ContextSize(const ContextRec& rec) { + // The SkBitmapProcState is stored outside of the context object, with the context holding + // a pointer to it. + return sizeof(BitmapProcShaderContext) + sizeof(SkBitmapProcState); } SkShader::Context* SkBitmapProcShader::MakeContext(const SkShader& shader, @@ -197,32 +133,16 @@ SkShader::Context* SkBitmapProcShader::MakeContext(const SkShader& shader, return nullptr; } - // Decide if we can/want to use the new linear pipeine - bool useLinearPipeline = choose_linear_pipeline(rec, provider.info()); - if (SkShader::kMirror_TileMode == tmx || SkShader::kMirror_TileMode == tmy) { - useLinearPipeline = false; - } - if (totalInverse.hasPerspective()) { - useLinearPipeline = false; + void* stateStorage = (char*)storage + sizeof(BitmapProcShaderContext); + SkBitmapProcState* state = new (stateStorage) SkBitmapProcState(provider, tmx, tmy); + + SkASSERT(state); + if (!state->setup(totalInverse, *rec.fPaint)) { + state->~SkBitmapProcState(); + return nullptr; } - if (useLinearPipeline) { - void* infoStorage = (char*)storage + sizeof(LinearPipelineContext); - SkBitmapProcInfo* info = new (infoStorage) SkBitmapProcInfo(provider, tmx, tmy); - if (!info->init(totalInverse, *rec.fPaint)) { - info->~SkBitmapProcInfo(); - return nullptr; - } - return new (storage) LinearPipelineContext(shader, rec, info); - } else { - void* stateStorage = (char*)storage + sizeof(BitmapProcShaderContext); - SkBitmapProcState* state = new (stateStorage) SkBitmapProcState(provider, tmx, tmy); - if (!state->setup(totalInverse, *rec.fPaint)) { - state->~SkBitmapProcState(); - return nullptr; - } - return new (storage) BitmapProcShaderContext(shader, rec, state); - } + return new (storage) BitmapProcShaderContext(shader, rec, state); } SkShader::Context* SkBitmapProcShader::onCreateContext(const ContextRec& rec, void* storage) const { diff --git a/src/core/SkBitmapProcShader.h b/src/core/SkBitmapProcShader.h index a83fda7628..9f4c16202c 100644 --- a/src/core/SkBitmapProcShader.h +++ b/src/core/SkBitmapProcShader.h @@ -21,9 +21,7 @@ public: bool isOpaque() const override; - size_t contextSize(const ContextRec& rec) const override { - return ContextSize(rec, fRawBitmap.info()); - } + size_t contextSize(const ContextRec& rec) const override { return ContextSize(rec); } SK_TO_STRING_OVERRIDE() SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkBitmapProcShader) @@ -38,13 +36,13 @@ protected: Context* onCreateContext(const ContextRec&, void* storage) const override; bool onIsABitmap(SkBitmap*, SkMatrix*, TileMode*) const override; - SkBitmap fRawBitmap; + SkBitmap fRawBitmap; // experimental for RLE encoding uint8_t fTileModeX, fTileModeY; private: friend class SkImageShader; - static size_t ContextSize(const ContextRec&, const SkImageInfo& srcInfo); + static size_t ContextSize(const ContextRec&); static Context* MakeContext(const SkShader&, TileMode tmx, TileMode tmy, const SkBitmapProvider&, const ContextRec&, void* storage); @@ -56,7 +54,7 @@ private: // an Sk3DBlitter in SkDraw.cpp // Note that some contexts may contain other contexts (e.g. for compose shaders), but we've not // yet found a situation where the size below isn't big enough. -typedef SkSmallAllocator<3, 2100> SkTBlitterAllocator; +typedef SkSmallAllocator<3, 1500> SkTBlitterAllocator; // If alloc is non-nullptr, it will be used to allocate the returned SkShader, and MUST outlive // the SkShader. diff --git a/src/core/SkComposeShader.cpp b/src/core/SkComposeShader.cpp index 57f0989e2d..46ff4019fc 100644 --- a/src/core/SkComposeShader.cpp +++ b/src/core/SkComposeShader.cpp @@ -31,9 +31,9 @@ SkComposeShader::~SkComposeShader() { } size_t SkComposeShader::contextSize(const ContextRec& rec) const { - return SkAlign16(sizeof(ComposeShaderContext)) - + SkAlign16(fShaderA->contextSize(rec)) - + SkAlign16(fShaderB->contextSize(rec)); + return sizeof(ComposeShaderContext) + + fShaderA->contextSize(rec) + + fShaderB->contextSize(rec); } class SkAutoAlphaRestore { @@ -76,8 +76,8 @@ template void safe_call_destructor(T* obj) { } SkShader::Context* SkComposeShader::onCreateContext(const ContextRec& rec, void* storage) const { - char* aStorage = (char*) storage + SkAlign16(sizeof(ComposeShaderContext)); - char* bStorage = aStorage + SkAlign16(fShaderA->contextSize(rec)); + char* aStorage = (char*) storage + sizeof(ComposeShaderContext); + char* bStorage = aStorage + fShaderA->contextSize(rec); // we preconcat our localMatrix (if any) with the device matrix // before calling our sub-shaders diff --git a/src/core/SkShader.cpp b/src/core/SkShader.cpp index 5fb441a5c3..e36df5b5af 100644 --- a/src/core/SkShader.cpp +++ b/src/core/SkShader.cpp @@ -86,9 +86,6 @@ bool SkShader::asLuminanceColor(SkColor* colorPtr) const { } SkShader::Context* SkShader::createContext(const ContextRec& rec, void* storage) const { - // We currently require 16byte alignment for some of our subclasses, so assert that here. - SkASSERT(SkIsAlign16((intptr_t)storage)); - if (!this->computeTotalInverse(rec, nullptr)) { return nullptr; } diff --git a/src/image/SkImageShader.cpp b/src/image/SkImageShader.cpp index e8c16b8096..a07603c671 100644 --- a/src/image/SkImageShader.cpp +++ b/src/image/SkImageShader.cpp @@ -43,7 +43,7 @@ bool SkImageShader::isOpaque() const { } size_t SkImageShader::contextSize(const ContextRec& rec) const { - return SkBitmapProcShader::ContextSize(rec, SkBitmapProvider(fImage).info()); + return SkBitmapProcShader::ContextSize(rec); } SkShader::Context* SkImageShader::onCreateContext(const ContextRec& rec, void* storage) const { diff --git a/tests/SkColor4fTest.cpp b/tests/SkColor4fTest.cpp index ea99c4b934..c9656b9b2a 100644 --- a/tests/SkColor4fTest.cpp +++ b/tests/SkColor4fTest.cpp @@ -149,7 +149,7 @@ DEF_TEST(Color4f_shader, reporter) { SkPaint paint; for (const auto& rec : recs) { - uint32_t storage[300]; + uint32_t storage[200]; paint.setShader(rec.fFact())->unref(); // Encourage 4f context selection. At some point we may need // to instantiate two separate contexts for optimal 4b/4f selection.