1 /* 2 * Copyright 2006 The Android Open Source Project 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 "SkArenaAlloc.h" 9 #include "SkColorSpace.h" 10 #include "SkCoreBlitters.h" 11 #include "SkOpts.h" 12 #include "SkPM4fPriv.h" 13 #include "SkRasterPipeline.h" 14 #include "SkSpriteBlitter.h" 15 #include "../jumper/SkJumper.h" 16 17 SkSpriteBlitter::SkSpriteBlitter(const SkPixmap& source) 18 : fSource(source) {} 19 20 void SkSpriteBlitter::setup(const SkPixmap& dst, int left, int top, const SkPaint& paint) { 21 fDst = dst; 22 fLeft = left; 23 fTop = top; 24 fPaint = &paint; 25 } 26 27 void SkSpriteBlitter::blitH(int x, int y, int width) { 28 SkDEBUGFAIL("how did we get here?"); 29 30 // Fallback to blitRect. 31 this->blitRect(x, y, width, 1); 32 } 33 34 void SkSpriteBlitter::blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) { 35 SkDEBUGFAIL("how did we get here?"); 36 37 // No fallback strategy. 38 } 39 40 void SkSpriteBlitter::blitV(int x, int y, int height, SkAlpha alpha) { 41 SkDEBUGFAIL("how did we get here?"); 42 43 // Fall back to superclass if the code gets here in release mode. 44 INHERITED::blitV(x, y, height, alpha); 45 } 46 47 void SkSpriteBlitter::blitMask(const SkMask& mask, const SkIRect& clip) { 48 SkDEBUGFAIL("how did we get here?"); 49 50 // Fall back to superclass if the code gets here in release mode. 51 INHERITED::blitMask(mask, clip); 52 } 53 54 /////////////////////////////////////////////////////////////////////////////// 55 56 class SkSpriteBlitter_Memcpy final : public SkSpriteBlitter { 57 public: 58 static bool Supports(const SkPixmap& dst, const SkPixmap& src, const SkPaint& paint) { 59 if (dst.colorType() != src.colorType()) { 60 return false; 61 } 62 if (!SkColorSpace::Equals(dst.colorSpace(), src.colorSpace())) { 63 return false; 64 } 65 if (paint.getMaskFilter() || paint.getColorFilter() || paint.getImageFilter()) { 66 return false; 67 } 68 if (0xFF != paint.getAlpha()) { 69 return false; 70 } 71 SkBlendMode mode = paint.getBlendMode(); 72 return SkBlendMode::kSrc == mode || (SkBlendMode::kSrcOver == mode && src.isOpaque()); 73 } 74 75 SkSpriteBlitter_Memcpy(const SkPixmap& src) 76 : INHERITED(src) {} 77 78 void blitRect(int x, int y, int width, int height) override { 79 SkASSERT(fDst.colorType() == fSource.colorType()); 80 SkASSERT(width > 0 && height > 0); 81 82 char* dst = (char*)fDst.writable_addr(x, y); 83 const char* src = (const char*)fSource.addr(x - fLeft, y - fTop); 84 const size_t dstRB = fDst.rowBytes(); 85 const size_t srcRB = fSource.rowBytes(); 86 const size_t bytesToCopy = width << fSource.shiftPerPixel(); 87 88 while (height --> 0) { 89 memcpy(dst, src, bytesToCopy); 90 dst += dstRB; 91 src += srcRB; 92 } 93 } 94 95 private: 96 typedef SkSpriteBlitter INHERITED; 97 }; 98 99 class SkRasterPipelineSpriteBlitter : public SkSpriteBlitter { 100 public: 101 SkRasterPipelineSpriteBlitter(const SkPixmap& src, SkArenaAlloc* alloc) 102 : INHERITED(src) 103 , fAlloc(alloc) 104 , fBlitter(nullptr) 105 , fSrcPtr{nullptr, 0} 106 {} 107 108 void setup(const SkPixmap& dst, int left, int top, const SkPaint& paint) override { 109 fDst = dst; 110 fLeft = left; 111 fTop = top; 112 113 fPaintColor = SkColor4f_from_SkColor(paint.getColor(), fDst.colorSpace()); 114 115 SkRasterPipeline p(fAlloc); 116 void* ctx = &fSrcPtr; 117 switch (fSource.colorType()) { 118 case kAlpha_8_SkColorType: p.append(SkRasterPipeline::load_a8, ctx); break; 119 case kGray_8_SkColorType: p.append(SkRasterPipeline::load_g8, ctx); break; 120 case kRGB_565_SkColorType: p.append(SkRasterPipeline::load_565, ctx); break; 121 case kARGB_4444_SkColorType: p.append(SkRasterPipeline::load_4444, ctx); break; 122 case kBGRA_8888_SkColorType: p.append(SkRasterPipeline::load_bgra, ctx); break; 123 case kRGBA_8888_SkColorType: p.append(SkRasterPipeline::load_8888, ctx); break; 124 case kRGBA_1010102_SkColorType: p.append(SkRasterPipeline::load_1010102, ctx); break; 125 case kRGBA_F16_SkColorType: p.append(SkRasterPipeline::load_f16, ctx); break; 126 127 case kRGB_888x_SkColorType: p.append(SkRasterPipeline::load_8888, ctx); 128 p.append(SkRasterPipeline::force_opaque ); break; 129 case kRGB_101010x_SkColorType: p.append(SkRasterPipeline::load_1010102, ctx); 130 p.append(SkRasterPipeline::force_opaque ); break; 131 default: SkASSERT(false); 132 } 133 if (fDst.colorSpace() && 134 (!fSource.colorSpace() || fSource.colorSpace()->gammaCloseToSRGB())) { 135 p.append(SkRasterPipeline::from_srgb); 136 } 137 if (fSource.colorType() == kAlpha_8_SkColorType) { 138 p.append(SkRasterPipeline::set_rgb, &fPaintColor); 139 p.append(SkRasterPipeline::premul); 140 } 141 append_gamut_transform(&p, fAlloc, 142 fSource.colorSpace(), fDst.colorSpace(), kPremul_SkAlphaType); 143 if (fPaintColor.fA != 1.0f) { 144 p.append(SkRasterPipeline::scale_1_float, &fPaintColor.fA); 145 } 146 147 bool is_opaque = fSource.isOpaque() && fPaintColor.fA == 1.0f; 148 fBlitter = SkCreateRasterPipelineBlitter(fDst, paint, p, is_opaque, fAlloc); 149 } 150 151 void blitRect(int x, int y, int width, int height) override { 152 fSrcPtr.stride = fSource.rowBytesAsPixels(); 153 154 // We really want fSrcPtr.pixels = fSource.addr(-fLeft, -fTop) here, but that asserts. 155 // Instead we ask for addr(-fLeft+x, -fTop+y), then back up (x,y) manually. 156 // Representing bpp as a size_t keeps all this math in size_t instead of int, 157 // which could wrap around with large enough fSrcPtr.stride and y. 158 size_t bpp = fSource.info().bytesPerPixel(); 159 fSrcPtr.pixels = (char*)fSource.addr(-fLeft+x, -fTop+y) - bpp * x 160 - bpp * y * fSrcPtr.stride; 161 162 fBlitter->blitRect(x,y,width,height); 163 } 164 165 private: 166 SkArenaAlloc* fAlloc; 167 SkBlitter* fBlitter; 168 SkJumper_MemoryCtx fSrcPtr; 169 SkColor4f fPaintColor; 170 171 typedef SkSpriteBlitter INHERITED; 172 }; 173 174 // returning null means the caller will call SkBlitter::Choose() and 175 // have wrapped the source bitmap inside a shader 176 SkBlitter* SkBlitter::ChooseSprite(const SkPixmap& dst, const SkPaint& paint, 177 const SkPixmap& source, int left, int top, SkArenaAlloc* allocator) { 178 /* We currently ignore antialiasing and filtertype, meaning we will take our 179 special blitters regardless of these settings. Ignoring filtertype seems fine 180 since by definition there is no scale in the matrix. Ignoring antialiasing is 181 a bit of a hack, since we "could" pass in the fractional left/top for the bitmap, 182 and respect that by blending the edges of the bitmap against the device. To support 183 this we could either add more special blitters here, or detect antialiasing in the 184 paint and return null if it is set, forcing the client to take the slow shader case 185 (which does respect soft edges). 186 */ 187 SkASSERT(allocator != nullptr); 188 189 if (source.alphaType() == kUnpremul_SkAlphaType) { 190 return nullptr; 191 } 192 193 SkSpriteBlitter* blitter = nullptr; 194 195 if (!blitter && SkSpriteBlitter_Memcpy::Supports(dst, source, paint)) { 196 blitter = allocator->make<SkSpriteBlitter_Memcpy>(source); 197 } 198 if (!blitter && !dst.colorSpace()) { 199 switch (dst.colorType()) { 200 case kN32_SkColorType: 201 blitter = SkSpriteBlitter::ChooseL32(source, paint, allocator); 202 break; 203 case kRGB_565_SkColorType: 204 blitter = SkSpriteBlitter::ChooseL565(source, paint, allocator); 205 break; 206 case kAlpha_8_SkColorType: 207 blitter = SkSpriteBlitter::ChooseLA8(source, paint, allocator); 208 break; 209 default: 210 break; 211 } 212 } 213 if (!blitter && !paint.getMaskFilter()) { 214 blitter = allocator->make<SkRasterPipelineSpriteBlitter>(source, allocator); 215 } 216 217 if (blitter) { 218 blitter->setup(dst, left, top, paint); 219 } 220 return blitter; 221 } 222