1 /* 2 * Copyright 2011 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "SkBitmapProcShader.h" 9 10 #include "SkArenaAlloc.h" 11 #include "SkBitmapProcState.h" 12 #include "SkBitmapProvider.h" 13 #include "SkPM4fPriv.h" 14 #include "SkXfermodePriv.h" 15 16 static bool only_scale_and_translate(const SkMatrix& matrix) { 17 unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask; 18 return (matrix.getType() & ~mask) == 0; 19 } 20 21 class BitmapProcInfoContext : public SkShaderBase::Context { 22 public: 23 // The info has been allocated elsewhere, but we are responsible for calling its destructor. 24 BitmapProcInfoContext(const SkShaderBase& shader, const SkShaderBase::ContextRec& rec, 25 SkBitmapProcInfo* info) 26 : INHERITED(shader, rec) 27 , fInfo(info) 28 { 29 fFlags = 0; 30 if (fInfo->fPixmap.isOpaque() && (255 == this->getPaintAlpha())) { 31 fFlags |= SkShaderBase::kOpaqueAlpha_Flag; 32 } 33 34 if (1 == fInfo->fPixmap.height() && only_scale_and_translate(this->getTotalInverse())) { 35 fFlags |= SkShaderBase::kConstInY32_Flag; 36 } 37 } 38 39 uint32_t getFlags() const override { return fFlags; } 40 41 private: 42 SkBitmapProcInfo* fInfo; 43 uint32_t fFlags; 44 45 typedef SkShaderBase::Context INHERITED; 46 }; 47 48 /////////////////////////////////////////////////////////////////////////////////////////////////// 49 50 class BitmapProcShaderContext : public BitmapProcInfoContext { 51 public: 52 BitmapProcShaderContext(const SkShaderBase& shader, const SkShaderBase::ContextRec& rec, 53 SkBitmapProcState* state) 54 : INHERITED(shader, rec, state) 55 , fState(state) 56 {} 57 58 void shadeSpan(int x, int y, SkPMColor dstC[], int count) override { 59 const SkBitmapProcState& state = *fState; 60 if (state.getShaderProc32()) { 61 state.getShaderProc32()(&state, x, y, dstC, count); 62 return; 63 } 64 65 const int BUF_MAX = 128; 66 uint32_t buffer[BUF_MAX]; 67 SkBitmapProcState::MatrixProc mproc = state.getMatrixProc(); 68 SkBitmapProcState::SampleProc32 sproc = state.getSampleProc32(); 69 const int max = state.maxCountForBufferSize(sizeof(buffer[0]) * BUF_MAX); 70 71 SkASSERT(state.fPixmap.addr()); 72 73 for (;;) { 74 int n = SkTMin(count, max); 75 SkASSERT(n > 0 && n < BUF_MAX*2); 76 mproc(state, buffer, n, x, y); 77 sproc(state, buffer, n, dstC); 78 79 if ((count -= n) == 0) { 80 break; 81 } 82 SkASSERT(count > 0); 83 x += n; 84 dstC += n; 85 } 86 } 87 88 ShadeProc asAShadeProc(void** ctx) override { 89 if (fState->getShaderProc32()) { 90 *ctx = fState; 91 return (ShadeProc)fState->getShaderProc32(); 92 } 93 return nullptr; 94 } 95 96 private: 97 SkBitmapProcState* fState; 98 99 typedef BitmapProcInfoContext INHERITED; 100 }; 101 102 /////////////////////////////////////////////////////////////////////////////////////////////////// 103 #include "SkLinearBitmapPipeline.h" 104 #include "SkPM4f.h" 105 106 class LinearPipelineContext : public BitmapProcInfoContext { 107 public: 108 LinearPipelineContext(const SkShaderBase& shader, const SkShaderBase::ContextRec& rec, 109 SkBitmapProcInfo* info, SkArenaAlloc* alloc) 110 : INHERITED(shader, rec, info), fAllocator{alloc} 111 { 112 // Save things off in case we need to build a blitter pipeline. 113 fSrcPixmap = info->fPixmap; 114 fAlpha = SkColorGetA(info->fPaintColor) / 255.0f; 115 fFilterQuality = info->fFilterQuality; 116 fMatrixTypeMask = info->fRealInvMatrix.getType(); 117 118 fShaderPipeline = alloc->make<SkLinearBitmapPipeline>( 119 info->fRealInvMatrix, info->fFilterQuality, 120 info->fTileModeX, info->fTileModeY, 121 info->fPaintColor, 122 info->fPixmap, 123 fAllocator); 124 } 125 126 void shadeSpan4f(int x, int y, SkPM4f dstC[], int count) override { 127 fShaderPipeline->shadeSpan4f(x, y, dstC, count); 128 } 129 130 void shadeSpan(int x, int y, SkPMColor dstC[], int count) override { 131 const int N = 128; 132 SkPM4f tmp[N]; 133 134 while (count > 0) { 135 const int n = SkTMin(count, N); 136 fShaderPipeline->shadeSpan4f(x, y, tmp, n); 137 // now convert to SkPMColor 138 for (int i = 0; i < n; ++i) { 139 dstC[i] = Sk4f_toL32(tmp[i].to4f_pmorder()); 140 } 141 dstC += n; 142 x += n; 143 count -= n; 144 } 145 } 146 147 private: 148 // Store the allocator from the context creation incase we are asked to build a blitter. 149 SkArenaAlloc* fAllocator; 150 SkLinearBitmapPipeline* fShaderPipeline; 151 SkPixmap fSrcPixmap; 152 float fAlpha; 153 SkMatrix::TypeMask fMatrixTypeMask; 154 SkFilterQuality fFilterQuality; 155 156 typedef BitmapProcInfoContext INHERITED; 157 }; 158 159 /////////////////////////////////////////////////////////////////////////////////////////////////// 160 161 static bool choose_linear_pipeline(const SkShaderBase::ContextRec& rec, const SkImageInfo& srcInfo) { 162 // If we get here, we can reasonably use either context, respect the caller's preference 163 // 164 bool needsPremul = srcInfo.alphaType() == kUnpremul_SkAlphaType; 165 bool needsSwizzle = srcInfo.bytesPerPixel() == 4 && srcInfo.colorType() != kN32_SkColorType; 166 return SkShaderBase::ContextRec::kPM4f_DstType == rec.fPreferredDstType 167 || needsPremul || needsSwizzle; 168 } 169 170 size_t SkBitmapProcLegacyShader::ContextSize(const ContextRec& rec, const SkImageInfo& srcInfo) { 171 size_t size0 = sizeof(BitmapProcShaderContext) + sizeof(SkBitmapProcState); 172 size_t size1 = sizeof(LinearPipelineContext) + sizeof(SkBitmapProcInfo); 173 size_t s = SkTMax(size0, size1); 174 return s; 175 } 176 177 SkShaderBase::Context* SkBitmapProcLegacyShader::MakeContext( 178 const SkShaderBase& shader, TileMode tmx, TileMode tmy, 179 const SkBitmapProvider& provider, const ContextRec& rec, SkArenaAlloc* alloc) 180 { 181 SkMatrix totalInverse; 182 // Do this first, so we know the matrix can be inverted. 183 if (!shader.computeTotalInverse(*rec.fMatrix, rec.fLocalMatrix, &totalInverse)) { 184 return nullptr; 185 } 186 187 // Decide if we can/want to use the new linear pipeline 188 bool useLinearPipeline = choose_linear_pipeline(rec, provider.info()); 189 190 if (useLinearPipeline) { 191 SkBitmapProcInfo* info = alloc->make<SkBitmapProcInfo>(provider, tmx, tmy); 192 if (!info->init(totalInverse, *rec.fPaint)) { 193 return nullptr; 194 } 195 196 return alloc->make<LinearPipelineContext>(shader, rec, info, alloc); 197 } else { 198 SkBitmapProcState* state = alloc->make<SkBitmapProcState>(provider, tmx, tmy); 199 if (!state->setup(totalInverse, *rec.fPaint)) { 200 return nullptr; 201 } 202 return alloc->make<BitmapProcShaderContext>(shader, rec, state); 203 } 204 } 205