blob: cef4cfaa2f091f4bb8435541513ad925a2c99812 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
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
herba62038c2016-05-26 10:56:17 -07008#include "SkOpts.h"
commit-bot@chromium.orga5572e52014-03-07 03:24:41 +00009#include "SkSmallAllocator.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000010#include "SkSpriteBlitter.h"
11
herb7df9e4a2016-06-10 13:01:27 -070012SkSpriteBlitter::SkSpriteBlitter(const SkPixmap& source)
13 : fSource(source) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +000014
reedcb674142015-06-05 06:58:22 -070015void SkSpriteBlitter::setup(const SkPixmap& dst, int left, int top, const SkPaint& paint) {
16 fDst = dst;
reed@android.com8a1c16f2008-12-17 15:59:43 +000017 fLeft = left;
18 fTop = top;
19 fPaint = &paint;
20}
21
mike@reedtribe.orgebe5bcd2011-04-20 11:01:37 +000022void SkSpriteBlitter::blitH(int x, int y, int width) {
tomhudson@google.com0c00f212011-12-28 14:59:50 +000023 SkDEBUGFAIL("how did we get here?");
herb7df9e4a2016-06-10 13:01:27 -070024
25 // Fallback to blitRect.
26 this->blitRect(x, y, width, 1);
reed@android.com8a1c16f2008-12-17 15:59:43 +000027}
28
herb7df9e4a2016-06-10 13:01:27 -070029void SkSpriteBlitter::blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) {
tomhudson@google.com0c00f212011-12-28 14:59:50 +000030 SkDEBUGFAIL("how did we get here?");
herb7df9e4a2016-06-10 13:01:27 -070031
32 // No fallback strategy.
reed@android.com8a1c16f2008-12-17 15:59:43 +000033}
34
mike@reedtribe.orgebe5bcd2011-04-20 11:01:37 +000035void SkSpriteBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
tomhudson@google.com0c00f212011-12-28 14:59:50 +000036 SkDEBUGFAIL("how did we get here?");
herb7df9e4a2016-06-10 13:01:27 -070037
38 // Fall back to superclass if the code gets here in release mode.
39 INHERITED::blitV(x, y, height, alpha);
reed@android.com8a1c16f2008-12-17 15:59:43 +000040}
41
herb7df9e4a2016-06-10 13:01:27 -070042void SkSpriteBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {
tomhudson@google.com0c00f212011-12-28 14:59:50 +000043 SkDEBUGFAIL("how did we get here?");
herb7df9e4a2016-06-10 13:01:27 -070044
45 // Fall back to superclass if the code gets here in release mode.
46 INHERITED::blitMask(mask, clip);
reed@android.com8a1c16f2008-12-17 15:59:43 +000047}
reed@android.com8a1c16f2008-12-17 15:59:43 +000048
mike@reedtribe.orgebe5bcd2011-04-20 11:01:37 +000049///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +000050
reed8c3fd4f2016-04-15 06:59:38 -070051// Only valid if...
52// 1. src == dst format
53// 2. paint has no modifiers (i.e. alpha, colorfilter, etc.)
54// 3. xfermode needs no blending: e.g. kSrc_Mode or kSrcOver_Mode + opaque src
55//
herb7df9e4a2016-06-10 13:01:27 -070056class SkSpriteBlitter_Src_SrcOver final : public SkSpriteBlitter {
reed8c3fd4f2016-04-15 06:59:38 -070057public:
58 static bool Supports(const SkPixmap& dst, const SkPixmap& src, const SkPaint& paint) {
59 if (dst.colorType() != src.colorType()) {
60 return false;
61 }
reeddabe5d32016-06-21 10:28:14 -070062 if (dst.info().gammaCloseToSRGB() != src.info().gammaCloseToSRGB()) {
reed8c3fd4f2016-04-15 06:59:38 -070063 return false;
64 }
65 if (paint.getMaskFilter() || paint.getColorFilter() || paint.getImageFilter()) {
66 return false;
67 }
68 if (0xFF != paint.getAlpha()) {
69 return false;
70 }
reed374772b2016-10-05 17:33:02 -070071 SkBlendMode mode = paint.getBlendMode();
72 if (SkBlendMode::kSrc == mode) {
reed8c3fd4f2016-04-15 06:59:38 -070073 return true;
74 }
reed374772b2016-10-05 17:33:02 -070075 if (SkBlendMode::kSrcOver == mode && src.isOpaque()) {
reed8c3fd4f2016-04-15 06:59:38 -070076 return true;
77 }
herba62038c2016-05-26 10:56:17 -070078
79 // At this point memcpy can't be used. The following check for using SrcOver.
80
reeddabe5d32016-06-21 10:28:14 -070081 if (dst.colorType() != kN32_SkColorType || !dst.info().gammaCloseToSRGB()) {
herba62038c2016-05-26 10:56:17 -070082 return false;
83 }
84
reed374772b2016-10-05 17:33:02 -070085 return SkBlendMode::kSrcOver == mode;
reed8c3fd4f2016-04-15 06:59:38 -070086 }
87
herb7df9e4a2016-06-10 13:01:27 -070088 SkSpriteBlitter_Src_SrcOver(const SkPixmap& src)
89 : INHERITED(src) {}
reed8c3fd4f2016-04-15 06:59:38 -070090
91 void setup(const SkPixmap& dst, int left, int top, const SkPaint& paint) override {
92 SkASSERT(Supports(dst, fSource, paint));
93 this->INHERITED::setup(dst, left, top, paint);
reed374772b2016-10-05 17:33:02 -070094 SkBlendMode mode = paint.getBlendMode();
herba62038c2016-05-26 10:56:17 -070095
reed374772b2016-10-05 17:33:02 -070096 SkASSERT(mode == SkBlendMode::kSrcOver || mode == SkBlendMode::kSrc);
herba62038c2016-05-26 10:56:17 -070097
reed374772b2016-10-05 17:33:02 -070098 if (mode == SkBlendMode::kSrcOver && !fSource.isOpaque()) {
herba62038c2016-05-26 10:56:17 -070099 fUseMemcpy = false;
100 }
reed8c3fd4f2016-04-15 06:59:38 -0700101 }
102
103 void blitRect(int x, int y, int width, int height) override {
104 SkASSERT(fDst.colorType() == fSource.colorType());
reeddabe5d32016-06-21 10:28:14 -0700105 SkASSERT(fDst.info().gammaCloseToSRGB() == fSource.info().gammaCloseToSRGB());
reed8c3fd4f2016-04-15 06:59:38 -0700106 SkASSERT(width > 0 && height > 0);
107
herba62038c2016-05-26 10:56:17 -0700108 if (fUseMemcpy) {
109 char* dst = (char*)fDst.writable_addr(x, y);
110 const char* src = (const char*)fSource.addr(x - fLeft, y - fTop);
111 const size_t dstRB = fDst.rowBytes();
112 const size_t srcRB = fSource.rowBytes();
113 const size_t bytesToCopy = width << fSource.shiftPerPixel();
reed8c3fd4f2016-04-15 06:59:38 -0700114
herba62038c2016-05-26 10:56:17 -0700115 while (height --> 0) {
116 memcpy(dst, src, bytesToCopy);
117 dst += dstRB;
118 src += srcRB;
119 }
120 } else {
121 uint32_t* dst = fDst.writable_addr32(x, y);
122 const uint32_t* src = fSource.addr32(x - fLeft, y - fTop);
123 const int dstStride = fDst.rowBytesAsPixels();
124 const int srcStride = fSource.rowBytesAsPixels();
125
126 while (height --> 0) {
127 SkOpts::srcover_srgb_srgb(dst, src, width, width);
128 dst += dstStride;
129 src += srcStride;
130 }
reed8c3fd4f2016-04-15 06:59:38 -0700131 }
132 }
133
herba62038c2016-05-26 10:56:17 -0700134private:
reed8c3fd4f2016-04-15 06:59:38 -0700135 typedef SkSpriteBlitter INHERITED;
reed8c3fd4f2016-04-15 06:59:38 -0700136
herba62038c2016-05-26 10:56:17 -0700137 bool fUseMemcpy {true};
138};
reed8c3fd4f2016-04-15 06:59:38 -0700139
reed@android.com8a1c16f2008-12-17 15:59:43 +0000140// returning null means the caller will call SkBlitter::Choose() and
141// have wrapped the source bitmap inside a shader
reedcb674142015-06-05 06:58:22 -0700142SkBlitter* SkBlitter::ChooseSprite(const SkPixmap& dst, const SkPaint& paint,
reedc240e712015-05-23 12:26:41 -0700143 const SkPixmap& source, int left, int top, SkTBlitterAllocator* allocator) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000144 /* We currently ignore antialiasing and filtertype, meaning we will take our
145 special blitters regardless of these settings. Ignoring filtertype seems fine
146 since by definition there is no scale in the matrix. Ignoring antialiasing is
147 a bit of a hack, since we "could" pass in the fractional left/top for the bitmap,
148 and respect that by blending the edges of the bitmap against the device. To support
149 this we could either add more special blitters here, or detect antialiasing in the
150 paint and return null if it is set, forcing the client to take the slow shader case
151 (which does respect soft edges).
152 */
halcanary96fcdcc2015-08-27 07:41:13 -0700153 SkASSERT(allocator != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000154
herb58238462016-06-03 09:44:53 -0700155 // Defer to the general code if the pixels are unpremultipled. This case is not common,
156 // and this simplifies the code.
157 if (source.alphaType() == kUnpremul_SkAlphaType) {
158 return nullptr;
159 }
160
herba62038c2016-05-26 10:56:17 -0700161 SkSpriteBlitter* blitter = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000162
herba62038c2016-05-26 10:56:17 -0700163 if (SkSpriteBlitter_Src_SrcOver::Supports(dst, source, paint)) {
164 blitter = allocator->createT<SkSpriteBlitter_Src_SrcOver>(source);
reed8c3fd4f2016-04-15 06:59:38 -0700165 } else {
166 switch (dst.colorType()) {
167 case kRGB_565_SkColorType:
168 blitter = SkSpriteBlitter::ChooseD16(source, paint, allocator);
169 break;
170 case kN32_SkColorType:
reeddabe5d32016-06-21 10:28:14 -0700171 if (dst.info().gammaCloseToSRGB()) {
reed8c3fd4f2016-04-15 06:59:38 -0700172 blitter = SkSpriteBlitter::ChooseS32(source, paint, allocator);
173 } else {
174 blitter = SkSpriteBlitter::ChooseL32(source, paint, allocator);
175 }
176 break;
177 case kRGBA_F16_SkColorType:
178 blitter = SkSpriteBlitter::ChooseF16(source, paint, allocator);
179 break;
180 default:
reed8c3fd4f2016-04-15 06:59:38 -0700181 break;
182 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000183 }
184
mike@reedtribe.orgebe5bcd2011-04-20 11:01:37 +0000185 if (blitter) {
reedcb674142015-06-05 06:58:22 -0700186 blitter->setup(dst, left, top, paint);
mike@reedtribe.orgebe5bcd2011-04-20 11:01:37 +0000187 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000188 return blitter;
189}