SkBlitter_RGB565.cpp revision fe17456d5e528078ce69b5f15cf7adf1fab963f9
1/*
2 * Copyright 2017 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 "SkCoreBlitters.h"
9#include "SkColorData.h"
10#include "SkShader.h"
11#include "SkUtils.h"
12#include "SkXfermodePriv.h"
13#include "SkBlitMask.h"
14#include "SkColorData.h"
15
16#include "SkNx.h"
17
18static void D16_S32X_src(uint16_t dst[], const SkPMColor src[], int count, uint8_t coverage) {
19    SkASSERT(coverage == 0xFF);
20    for (int i = 0; i < count; ++i) {
21        dst[i] = SkPixel32ToPixel16(src[i]);
22    }
23}
24
25static void D16_S32X_src_coverage(uint16_t dst[], const SkPMColor src[], int count,
26                                  uint8_t coverage) {
27    switch (coverage) {
28        case 0: break;
29        case 0xFF:
30            for (int i = 0; i < count; ++i) {
31                dst[i] = SkPixel32ToPixel16(src[i]);
32            }
33            break;
34        default:
35            unsigned scale = coverage + (coverage >> 7);
36            for (int i = 0; i < count; ++i) {
37                dst[i] = SkSrcOver32To16(SkAlphaMulQ(src[i], scale), dst[i]);
38            }
39            break;
40    }
41}
42
43static void D16_S32A_srcover(uint16_t dst[], const SkPMColor src[], int count, uint8_t coverage) {
44    SkASSERT(coverage == 0xFF);
45    for (int i = 0; i < count; ++i) {
46        dst[i] = SkSrcOver32To16(src[i], dst[i]);
47    }
48}
49
50static void D16_S32A_srcover_coverage(uint16_t dst[], const SkPMColor src[], int count,
51                                      uint8_t coverage) {
52    switch (coverage) {
53        case 0: break;
54        case 0xFF:
55            for (int i = 0; i < count; ++i) {
56                dst[i] = SkSrcOver32To16(src[i], dst[i]);
57            }
58            break;
59        default:
60            unsigned scale = coverage + (coverage >> 7);
61            for (int i = 0; i < count; ++i) {
62                dst[i] = SkSrcOver32To16(SkAlphaMulQ(src[i], scale), dst[i]);
63            }
64            break;
65    }
66}
67
68bool SkRGB565_Shader_Blitter::Supports(const SkPixmap& device, const SkPaint& paint) {
69    if (device.colorType() != kRGB_565_SkColorType) {
70        return false;
71    }
72    if (device.colorSpace()) {
73        return false;
74    }
75    if (paint.getBlendMode() != SkBlendMode::kSrcOver &&
76        paint.getBlendMode() != SkBlendMode::kSrc) {
77        return false;
78    }
79    if (paint.isLCDRenderText()) {
80        return false;
81    }
82    if (paint.isDither()) {
83        return false;
84    }
85    return true;
86}
87
88SkRGB565_Shader_Blitter::SkRGB565_Shader_Blitter(const SkPixmap& device,
89        const SkPaint& paint, SkShaderBase::Context* shaderContext)
90    : INHERITED(device, paint, shaderContext)
91{
92    SkASSERT(shaderContext);
93    SkASSERT(Supports(device, paint));
94
95    fBuffer = (SkPMColor*)sk_malloc_throw(device.width() * (sizeof(SkPMColor)));
96
97    bool isOpaque = SkToBool(shaderContext->getFlags() & SkShaderBase::kOpaqueAlpha_Flag);
98
99    if (paint.getBlendMode() == SkBlendMode::kSrc || isOpaque) {
100        fBlend = D16_S32X_src;
101        fBlendCoverage = D16_S32X_src_coverage;
102    } else {    // srcover
103        fBlend = isOpaque ? D16_S32X_src : D16_S32A_srcover;
104        fBlendCoverage = isOpaque ? D16_S32X_src_coverage : D16_S32A_srcover_coverage;
105    }
106}
107
108SkRGB565_Shader_Blitter::~SkRGB565_Shader_Blitter() {
109    sk_free(fBuffer);
110}
111
112void SkRGB565_Shader_Blitter::blitH(int x, int y, int width) {
113    SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width());
114
115    uint16_t* device = fDevice.writable_addr16(x, y);
116
117    SkPMColor*  span = fBuffer;
118    fShaderContext->shadeSpan(x, y, span, width);
119    fBlend(device, span, width, 0xFF);
120}
121
122void SkRGB565_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha coverage[],
123                                        const int16_t runs[]) {
124    SkPMColor* span = fBuffer;
125    uint16_t*  device = fDevice.writable_addr16(x, y);
126    auto*      shaderContext = fShaderContext;
127
128    for (;;) {
129        int count = *runs;
130        if (count <= 0) {
131            break;
132        }
133        int aa = *coverage;
134        if (aa) {
135            shaderContext->shadeSpan(x, y, span, count);
136            fBlendCoverage(device, span, count, aa);
137        }
138        device += count;
139        runs += count;
140        coverage += count;
141        x += count;
142    }
143}
144