Chromium Code Reviews| Index: src/core/SkBitmapProcShader.cpp |
| diff --git a/src/core/SkBitmapProcShader.cpp b/src/core/SkBitmapProcShader.cpp |
| index 895922c6b873a388210e0887d768f08dc05646c5..55b7f884be4f71d5cce944d3318b9cc62318d966 100644 |
| --- a/src/core/SkBitmapProcShader.cpp |
| +++ b/src/core/SkBitmapProcShader.cpp |
| @@ -67,8 +67,8 @@ public: |
| // but will NOT free the memory. |
| BitmapProcShaderContext(const SkShader& shader, const SkShader::ContextRec& rec, |
| SkBitmapProcState* state) |
| - : INHERITED(shader, rec, state) |
| - , fState(state) |
| + : INHERITED(shader, rec, state) |
| + , fState(state) |
| {} |
| void shadeSpan(int x, int y, SkPMColor dstC[], int count) override { |
| @@ -116,11 +116,76 @@ 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: |
| + // The context takes ownership of the state. It will call its destructor |
|
mtklein
2016/03/03 01:30:37
Having read this code, or at least in a while, it'
reed1
2016/03/03 14:05:25
Done.
|
| + // but will NOT free the memory. |
| + 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) |
| + {} |
| + |
| + 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 { |
| + // we're not necessarily opaque, but we want the proc to treat us as if we are, so we |
| + // get memcpy performance/semantics |
|
mtklein
2016/03/03 01:30:37
remind me (or the reader) why this is okay?
reed1
2016/03/03 14:05:25
Done.
|
| + auto proc = SkXfermode::GetD32Proc(nullptr, SkXfermode::kSrcIsOpaque_D32Flag); |
| + const int N = 128; |
| + SkPM4f tmp[N]; |
| + |
| + while (count > 0) { |
| + const int n = SkTMin(count, N); |
| + fPipeline.shadeSpan4f(x, y, tmp, n); |
| + proc(nullptr, dstC, tmp, n, nullptr); |
| + dstC += n; |
| + x += n; |
| + count -= n; |
| + } |
| + } |
| + |
| +private: |
| + SkLinearBitmapPipeline fPipeline; |
| + |
| + 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; |
| + } |
| + |
| + // 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; |
| + } |
| + |
| + // 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 +198,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 { |