mtklein | 9a5c47f | 2016-07-22 11:05:04 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2016 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 "SkBlitter.h" |
| 9 | #include "SkColor.h" |
| 10 | #include "SkColorFilter.h" |
Mike Klein | baaf8ad | 2016-09-29 09:04:15 -0400 | [diff] [blame^] | 11 | #include "SkOpts.h" |
mtklein | 9a5c47f | 2016-07-22 11:05:04 -0700 | [diff] [blame] | 12 | #include "SkPM4f.h" |
mtklein | 9a5c47f | 2016-07-22 11:05:04 -0700 | [diff] [blame] | 13 | #include "SkRasterPipeline.h" |
| 14 | #include "SkShader.h" |
mtklein | 9a5c47f | 2016-07-22 11:05:04 -0700 | [diff] [blame] | 15 | #include "SkXfermode.h" |
| 16 | |
| 17 | |
| 18 | class SkRasterPipelineBlitter : public SkBlitter { |
| 19 | public: |
| 20 | static SkBlitter* Create(const SkPixmap&, const SkPaint&, SkTBlitterAllocator*); |
| 21 | |
| 22 | SkRasterPipelineBlitter(SkPixmap dst, |
| 23 | SkRasterPipeline shader, |
| 24 | SkRasterPipeline colorFilter, |
| 25 | SkRasterPipeline xfermode, |
| 26 | SkPM4f paintColor) |
| 27 | : fDst(dst) |
| 28 | , fShader(shader) |
| 29 | , fColorFilter(colorFilter) |
| 30 | , fXfermode(xfermode) |
| 31 | , fPaintColor(paintColor) |
| 32 | {} |
| 33 | |
| 34 | void blitH (int x, int y, int w) override; |
| 35 | void blitAntiH(int x, int y, const SkAlpha[], const int16_t[]) override; |
| 36 | void blitMask (const SkMask&, const SkIRect& clip) override; |
| 37 | |
| 38 | // TODO: The default implementations of the other blits look fine, |
| 39 | // but some of them like blitV could probably benefit from custom |
| 40 | // blits using something like a SkRasterPipeline::runFew() method. |
| 41 | |
| 42 | private: |
mtklein | 8e4373f | 2016-07-22 14:20:27 -0700 | [diff] [blame] | 43 | void append_load_d(SkRasterPipeline*, const void*) const; |
| 44 | void append_store (SkRasterPipeline*, void*) const; |
| 45 | |
mtklein | 9a5c47f | 2016-07-22 11:05:04 -0700 | [diff] [blame] | 46 | SkPixmap fDst; |
| 47 | SkRasterPipeline fShader, fColorFilter, fXfermode; |
| 48 | SkPM4f fPaintColor; |
| 49 | |
| 50 | typedef SkBlitter INHERITED; |
| 51 | }; |
| 52 | |
| 53 | SkBlitter* SkCreateRasterPipelineBlitter(const SkPixmap& dst, |
| 54 | const SkPaint& paint, |
| 55 | SkTBlitterAllocator* alloc) { |
| 56 | return SkRasterPipelineBlitter::Create(dst, paint, alloc); |
| 57 | } |
| 58 | |
mtklein | 8e4373f | 2016-07-22 14:20:27 -0700 | [diff] [blame] | 59 | static bool supported(const SkImageInfo& info) { |
mtklein | 8e4373f | 2016-07-22 14:20:27 -0700 | [diff] [blame] | 60 | switch (info.colorType()) { |
mtklein | 4e90e3e | 2016-07-25 14:35:31 -0700 | [diff] [blame] | 61 | case kN32_SkColorType: return info.gammaCloseToSRGB(); |
| 62 | case kRGBA_F16_SkColorType: return true; |
| 63 | case kRGB_565_SkColorType: return true; |
| 64 | default: return false; |
mtklein | 8e4373f | 2016-07-22 14:20:27 -0700 | [diff] [blame] | 65 | } |
| 66 | } |
mtklein | 9a5c47f | 2016-07-22 11:05:04 -0700 | [diff] [blame] | 67 | |
| 68 | template <typename Effect> |
| 69 | static bool append_effect_stages(const Effect* effect, SkRasterPipeline* pipeline) { |
| 70 | return !effect || effect->appendStages(pipeline); |
| 71 | } |
| 72 | |
| 73 | |
| 74 | SkBlitter* SkRasterPipelineBlitter::Create(const SkPixmap& dst, |
| 75 | const SkPaint& paint, |
| 76 | SkTBlitterAllocator* alloc) { |
mtklein | 8e4373f | 2016-07-22 14:20:27 -0700 | [diff] [blame] | 77 | if (!supported(dst.info())) { |
| 78 | return nullptr; |
mtklein | 9a5c47f | 2016-07-22 11:05:04 -0700 | [diff] [blame] | 79 | } |
| 80 | if (paint.getShader()) { |
| 81 | return nullptr; // TODO: need to work out how shaders and their contexts work |
| 82 | } |
| 83 | |
| 84 | SkRasterPipeline shader, colorFilter, xfermode; |
| 85 | if (!append_effect_stages(paint.getColorFilter(), &colorFilter) || |
| 86 | !append_effect_stages(paint.getXfermode(), &xfermode )) { |
| 87 | return nullptr; |
| 88 | } |
| 89 | |
mtklein | 8e4373f | 2016-07-22 14:20:27 -0700 | [diff] [blame] | 90 | uint32_t paintColor = paint.getColor(); |
| 91 | |
| 92 | SkColor4f color; |
mtklein | 4e90e3e | 2016-07-25 14:35:31 -0700 | [diff] [blame] | 93 | if (SkImageInfoIsGammaCorrect(dst.info())) { |
mtklein | 8e4373f | 2016-07-22 14:20:27 -0700 | [diff] [blame] | 94 | color = SkColor4f::FromColor(paintColor); |
| 95 | } else { |
| 96 | swizzle_rb(SkNx_cast<float>(Sk4b::Load(&paintColor)) * (1/255.0f)).store(&color); |
| 97 | } |
| 98 | |
mtklein | 9a5c47f | 2016-07-22 11:05:04 -0700 | [diff] [blame] | 99 | auto blitter = alloc->createT<SkRasterPipelineBlitter>( |
| 100 | dst, |
| 101 | shader, colorFilter, xfermode, |
mtklein | 8e4373f | 2016-07-22 14:20:27 -0700 | [diff] [blame] | 102 | color.premul()); |
mtklein | 9a5c47f | 2016-07-22 11:05:04 -0700 | [diff] [blame] | 103 | |
| 104 | if (!paint.getShader()) { |
Mike Klein | baaf8ad | 2016-09-29 09:04:15 -0400 | [diff] [blame^] | 105 | blitter->fShader.append(SkOpts::constant_color, &blitter->fPaintColor); |
mtklein | 9a5c47f | 2016-07-22 11:05:04 -0700 | [diff] [blame] | 106 | } |
| 107 | if (!paint.getXfermode()) { |
Mike Klein | baaf8ad | 2016-09-29 09:04:15 -0400 | [diff] [blame^] | 108 | blitter->fXfermode.append(SkOpts::srcover); |
mtklein | 9a5c47f | 2016-07-22 11:05:04 -0700 | [diff] [blame] | 109 | } |
| 110 | |
| 111 | return blitter; |
| 112 | } |
| 113 | |
mtklein | 8e4373f | 2016-07-22 14:20:27 -0700 | [diff] [blame] | 114 | void SkRasterPipelineBlitter::append_load_d(SkRasterPipeline* p, const void* dst) const { |
| 115 | SkASSERT(supported(fDst.info())); |
| 116 | |
| 117 | switch (fDst.info().colorType()) { |
| 118 | case kN32_SkColorType: |
| 119 | if (fDst.info().gammaCloseToSRGB()) { |
Mike Klein | baaf8ad | 2016-09-29 09:04:15 -0400 | [diff] [blame^] | 120 | p->append(SkOpts::load_d_srgb_body, SkOpts::load_d_srgb_tail, dst); |
mtklein | 8e4373f | 2016-07-22 14:20:27 -0700 | [diff] [blame] | 121 | } |
| 122 | break; |
mtklein | 4e90e3e | 2016-07-25 14:35:31 -0700 | [diff] [blame] | 123 | case kRGBA_F16_SkColorType: |
Mike Klein | baaf8ad | 2016-09-29 09:04:15 -0400 | [diff] [blame^] | 124 | p->append(SkOpts::load_d_f16_body, SkOpts::load_d_f16_tail, dst); |
mtklein | 4e90e3e | 2016-07-25 14:35:31 -0700 | [diff] [blame] | 125 | break; |
mtklein | 8e4373f | 2016-07-22 14:20:27 -0700 | [diff] [blame] | 126 | case kRGB_565_SkColorType: |
Mike Klein | baaf8ad | 2016-09-29 09:04:15 -0400 | [diff] [blame^] | 127 | p->append(SkOpts::load_d_565_body, SkOpts::load_d_565_tail, dst); |
mtklein | 8e4373f | 2016-07-22 14:20:27 -0700 | [diff] [blame] | 128 | break; |
| 129 | default: break; |
| 130 | } |
| 131 | } |
| 132 | |
| 133 | void SkRasterPipelineBlitter::append_store(SkRasterPipeline* p, void* dst) const { |
| 134 | SkASSERT(supported(fDst.info())); |
| 135 | |
| 136 | switch (fDst.info().colorType()) { |
| 137 | case kN32_SkColorType: |
| 138 | if (fDst.info().gammaCloseToSRGB()) { |
Mike Klein | baaf8ad | 2016-09-29 09:04:15 -0400 | [diff] [blame^] | 139 | p->append(SkOpts::store_srgb_body, SkOpts::store_srgb_tail, dst); |
mtklein | 8e4373f | 2016-07-22 14:20:27 -0700 | [diff] [blame] | 140 | } |
| 141 | break; |
mtklein | 4e90e3e | 2016-07-25 14:35:31 -0700 | [diff] [blame] | 142 | case kRGBA_F16_SkColorType: |
Mike Klein | baaf8ad | 2016-09-29 09:04:15 -0400 | [diff] [blame^] | 143 | p->append(SkOpts::store_f16_body, SkOpts::store_f16_tail, dst); |
mtklein | 4e90e3e | 2016-07-25 14:35:31 -0700 | [diff] [blame] | 144 | break; |
mtklein | 8e4373f | 2016-07-22 14:20:27 -0700 | [diff] [blame] | 145 | case kRGB_565_SkColorType: |
Mike Klein | baaf8ad | 2016-09-29 09:04:15 -0400 | [diff] [blame^] | 146 | p->append(SkOpts::store_565_body, SkOpts::store_565_tail, dst); |
mtklein | 8e4373f | 2016-07-22 14:20:27 -0700 | [diff] [blame] | 147 | break; |
| 148 | default: break; |
| 149 | } |
| 150 | } |
| 151 | |
mtklein | 9a5c47f | 2016-07-22 11:05:04 -0700 | [diff] [blame] | 152 | void SkRasterPipelineBlitter::blitH(int x, int y, int w) { |
| 153 | auto dst = fDst.writable_addr(0,y); |
| 154 | |
| 155 | SkRasterPipeline p; |
| 156 | p.extend(fShader); |
| 157 | p.extend(fColorFilter); |
mtklein | 8e4373f | 2016-07-22 14:20:27 -0700 | [diff] [blame] | 158 | this->append_load_d(&p, dst); |
mtklein | 9a5c47f | 2016-07-22 11:05:04 -0700 | [diff] [blame] | 159 | p.extend(fXfermode); |
mtklein | 8e4373f | 2016-07-22 14:20:27 -0700 | [diff] [blame] | 160 | this->append_store(&p, dst); |
mtklein | 9a5c47f | 2016-07-22 11:05:04 -0700 | [diff] [blame] | 161 | |
| 162 | p.run(x, w); |
| 163 | } |
| 164 | |
| 165 | void SkRasterPipelineBlitter::blitAntiH(int x, int y, const SkAlpha aa[], const int16_t runs[]) { |
| 166 | auto dst = fDst.writable_addr(0,y); |
| 167 | float coverage; |
| 168 | |
| 169 | SkRasterPipeline p; |
| 170 | p.extend(fShader); |
| 171 | p.extend(fColorFilter); |
mtklein | 8e4373f | 2016-07-22 14:20:27 -0700 | [diff] [blame] | 172 | this->append_load_d(&p, dst); |
mtklein | 9a5c47f | 2016-07-22 11:05:04 -0700 | [diff] [blame] | 173 | p.extend(fXfermode); |
Mike Klein | baaf8ad | 2016-09-29 09:04:15 -0400 | [diff] [blame^] | 174 | p.append(SkOpts::lerp_constant_float, &coverage); |
mtklein | 8e4373f | 2016-07-22 14:20:27 -0700 | [diff] [blame] | 175 | this->append_store(&p, dst); |
mtklein | 9a5c47f | 2016-07-22 11:05:04 -0700 | [diff] [blame] | 176 | |
| 177 | for (int16_t run = *runs; run > 0; run = *runs) { |
| 178 | coverage = *aa * (1/255.0f); |
| 179 | p.run(x, run); |
| 180 | |
| 181 | x += run; |
| 182 | runs += run; |
| 183 | aa += run; |
| 184 | } |
| 185 | } |
| 186 | |
| 187 | void SkRasterPipelineBlitter::blitMask(const SkMask& mask, const SkIRect& clip) { |
| 188 | if (mask.fFormat == SkMask::kBW_Format) { |
| 189 | // TODO: native BW masks? |
| 190 | return INHERITED::blitMask(mask, clip); |
| 191 | } |
| 192 | |
| 193 | int x = clip.left(); |
| 194 | for (int y = clip.top(); y < clip.bottom(); y++) { |
| 195 | auto dst = fDst.writable_addr(0,y); |
| 196 | |
| 197 | SkRasterPipeline p; |
| 198 | p.extend(fShader); |
| 199 | p.extend(fColorFilter); |
mtklein | 8e4373f | 2016-07-22 14:20:27 -0700 | [diff] [blame] | 200 | this->append_load_d(&p, dst); |
mtklein | 9a5c47f | 2016-07-22 11:05:04 -0700 | [diff] [blame] | 201 | p.extend(fXfermode); |
| 202 | switch (mask.fFormat) { |
| 203 | case SkMask::kA8_Format: |
Mike Klein | baaf8ad | 2016-09-29 09:04:15 -0400 | [diff] [blame^] | 204 | p.append(SkOpts::lerp_u8_body, SkOpts::lerp_u8_tail, mask.getAddr8(x,y)-x); |
mtklein | 9a5c47f | 2016-07-22 11:05:04 -0700 | [diff] [blame] | 205 | break; |
| 206 | case SkMask::kLCD16_Format: |
Mike Klein | baaf8ad | 2016-09-29 09:04:15 -0400 | [diff] [blame^] | 207 | p.append(SkOpts::lerp_565_body, SkOpts::lerp_565_tail, mask.getAddrLCD16(x,y)-x); |
mtklein | 9a5c47f | 2016-07-22 11:05:04 -0700 | [diff] [blame] | 208 | break; |
| 209 | default: break; |
| 210 | } |
mtklein | 8e4373f | 2016-07-22 14:20:27 -0700 | [diff] [blame] | 211 | this->append_store(&p, dst); |
mtklein | 9a5c47f | 2016-07-22 11:05:04 -0700 | [diff] [blame] | 212 | |
| 213 | p.run(x, clip.width()); |
| 214 | } |
| 215 | } |