aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar reed <reed@google.com>2016-03-03 09:16:22 -0800
committerGravatar Commit bot <commit-bot@chromium.org>2016-03-03 09:16:22 -0800
commit19cef56344b5a5f26f802d7be34c44af36b7e797 (patch)
tree4d8510a489ace60f36b9348585cc10cb5fde99a4
parent1610835624a9658cc60940b80038b84f297e836f (diff)
add support for new bitmapshader context
-rw-r--r--gm/SkLinearBitmapPipelineGM.cpp2
-rw-r--r--src/core/SkBitmapProcShader.cpp116
-rw-r--r--src/core/SkBitmapProcShader.h10
-rw-r--r--src/core/SkComposeShader.cpp10
-rw-r--r--src/core/SkShader.cpp3
-rw-r--r--src/image/SkImageShader.cpp2
-rw-r--r--tests/SkColor4fTest.cpp2
7 files changed, 115 insertions, 30 deletions
diff --git a/gm/SkLinearBitmapPipelineGM.cpp b/gm/SkLinearBitmapPipelineGM.cpp
index 6b354df947..d3a143c5c1 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<SkImage> image{SkImage::NewRasterCopy(
info, pmsrc.addr32(), pmsrc.rowBytes())};
SkPaint paint;
- int32_t storage[200];
+ int32_t storage[300];
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 895922c6b8..38f46d18b4 100644
--- a/src/core/SkBitmapProcShader.cpp
+++ b/src/core/SkBitmapProcShader.cpp
@@ -27,8 +27,7 @@ static bool only_scale_and_translate(const SkMatrix& matrix) {
class BitmapProcInfoContext : public SkShader::Context {
public:
- // The context takes ownership of the info. It will call its destructor
- // but will NOT free the memory.
+ // The info has been allocated elsewhere, but we are responsible for calling its destructor.
BitmapProcInfoContext(const SkShader& shader, const SkShader::ContextRec& rec,
SkBitmapProcInfo* info)
: INHERITED(shader, rec)
@@ -45,8 +44,6 @@ 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();
}
@@ -63,8 +60,6 @@ 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)
@@ -116,11 +111,80 @@ private:
};
///////////////////////////////////////////////////////////////////////////////////////////////////
+#include "SkLinearBitmapPipeline.h"
+#include "SkPM4f.h"
+#include "SkXfermode.h"
-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);
+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<SkXfermode> 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);
}
SkShader::Context* SkBitmapProcShader::MakeContext(const SkShader& shader,
@@ -133,16 +197,32 @@ SkShader::Context* SkBitmapProcShader::MakeContext(const SkShader& shader,
return nullptr;
}
- 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;
+ // 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;
}
- return new (storage) BitmapProcShaderContext(shader, rec, state);
+ 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);
+ }
}
SkShader::Context* SkBitmapProcShader::onCreateContext(const ContextRec& rec, void* storage) const {
diff --git a/src/core/SkBitmapProcShader.h b/src/core/SkBitmapProcShader.h
index 9f4c16202c..a83fda7628 100644
--- a/src/core/SkBitmapProcShader.h
+++ b/src/core/SkBitmapProcShader.h
@@ -21,7 +21,9 @@ public:
bool isOpaque() const override;
- size_t contextSize(const ContextRec& rec) const override { return ContextSize(rec); }
+ size_t contextSize(const ContextRec& rec) const override {
+ return ContextSize(rec, fRawBitmap.info());
+ }
SK_TO_STRING_OVERRIDE()
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkBitmapProcShader)
@@ -36,13 +38,13 @@ protected:
Context* onCreateContext(const ContextRec&, void* storage) const override;
bool onIsABitmap(SkBitmap*, SkMatrix*, TileMode*) const override;
- SkBitmap fRawBitmap; // experimental for RLE encoding
+ SkBitmap fRawBitmap;
uint8_t fTileModeX, fTileModeY;
private:
friend class SkImageShader;
- static size_t ContextSize(const ContextRec&);
+ static size_t ContextSize(const ContextRec&, const SkImageInfo& srcInfo);
static Context* MakeContext(const SkShader&, TileMode tmx, TileMode tmy,
const SkBitmapProvider&, const ContextRec&, void* storage);
@@ -54,7 +56,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, 1500> SkTBlitterAllocator;
+typedef SkSmallAllocator<3, 2100> 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 46ff4019fc..57f0989e2d 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 sizeof(ComposeShaderContext)
- + fShaderA->contextSize(rec)
- + fShaderB->contextSize(rec);
+ return SkAlign16(sizeof(ComposeShaderContext))
+ + SkAlign16(fShaderA->contextSize(rec))
+ + SkAlign16(fShaderB->contextSize(rec));
}
class SkAutoAlphaRestore {
@@ -76,8 +76,8 @@ template <typename T> void safe_call_destructor(T* obj) {
}
SkShader::Context* SkComposeShader::onCreateContext(const ContextRec& rec, void* storage) const {
- char* aStorage = (char*) storage + sizeof(ComposeShaderContext);
- char* bStorage = aStorage + fShaderA->contextSize(rec);
+ char* aStorage = (char*) storage + SkAlign16(sizeof(ComposeShaderContext));
+ char* bStorage = aStorage + SkAlign16(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 e36df5b5af..5fb441a5c3 100644
--- a/src/core/SkShader.cpp
+++ b/src/core/SkShader.cpp
@@ -86,6 +86,9 @@ 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 a07603c671..e8c16b8096 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);
+ return SkBitmapProcShader::ContextSize(rec, SkBitmapProvider(fImage).info());
}
SkShader::Context* SkImageShader::onCreateContext(const ContextRec& rec, void* storage) const {
diff --git a/tests/SkColor4fTest.cpp b/tests/SkColor4fTest.cpp
index c9656b9b2a..ea99c4b934 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[200];
+ uint32_t storage[300];
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.