blob: 0e56fc48100f947548686ab24bae91b8966bb787 [file] [log] [blame]
mtklein281b33f2016-07-12 15:01:26 -07001/*
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 "SkRasterPipeline.h"
Mike Reedc91e3872017-07-05 14:12:37 -04009#include "SkPM4f.h"
Mike Klein1a2e3e12017-08-03 11:24:13 -040010#include "SkPM4fPriv.h"
11#include "../jumper/SkJumper.h"
mtklein281b33f2016-07-12 15:01:26 -070012
Mike Kleinb24704d2017-05-24 07:53:00 -040013SkRasterPipeline::SkRasterPipeline(SkArenaAlloc* alloc) : fAlloc(alloc) {
14 this->reset();
Mike Klein1859f692017-05-22 08:28:45 -040015}
Mike Kleinb24704d2017-05-24 07:53:00 -040016void SkRasterPipeline::reset() {
17 fStages = nullptr;
Mike Klein9fff1112017-05-24 11:37:52 -040018 fNumStages = 0;
Mike Kleinb24704d2017-05-24 07:53:00 -040019 fSlotsNeeded = 1; // We always need one extra slot for just_return().
Mike Klein159db0a2017-07-25 12:02:13 -040020 fClamped = true;
Mike Klein1859f692017-05-22 08:28:45 -040021}
mtklein281b33f2016-07-12 15:01:26 -070022
Mike Klein26bea5d2016-10-05 10:36:38 -040023void SkRasterPipeline::append(StockStage stage, void* ctx) {
Mike Klein16776df2017-08-03 10:22:42 -040024 SkASSERT(stage != from_srgb); // Please use append_from_srgb().
25 SkASSERT(stage != uniform_color); // Please use append_constant_color().
Mike Kleinb24704d2017-05-24 07:53:00 -040026 this->unchecked_append(stage, ctx);
27}
28void SkRasterPipeline::unchecked_append(StockStage stage, void* ctx) {
29 fStages = fAlloc->make<StageList>( StageList{fStages, stage, ctx} );
Mike Klein9fff1112017-05-24 11:37:52 -040030 fNumStages += 1;
Mike Kleinb24704d2017-05-24 07:53:00 -040031 fSlotsNeeded += ctx ? 2 : 1;
Mike Kleinfa9f2412016-09-29 13:40:01 -040032}
33
mtklein9a5c47f2016-07-22 11:05:04 -070034void SkRasterPipeline::extend(const SkRasterPipeline& src) {
Mike Klein9fff1112017-05-24 11:37:52 -040035 if (src.empty()) {
Mike Kleinb24704d2017-05-24 07:53:00 -040036 return;
37 }
Mike Klein9fff1112017-05-24 11:37:52 -040038 auto stages = fAlloc->makeArrayDefault<StageList>(src.fNumStages);
39
40 int n = src.fNumStages;
41 const StageList* st = src.fStages;
42 while (n --> 1) {
43 stages[n] = *st;
44 stages[n].prev = &stages[n-1];
45 st = st->prev;
46 }
47 stages[0] = *st;
48 stages[0].prev = fStages;
49
50 fStages = &stages[src.fNumStages - 1];
51 fNumStages += src.fNumStages;
52 fSlotsNeeded += src.fSlotsNeeded - 1; // Don't double count just_returns().
Mike Klein159db0a2017-07-25 12:02:13 -040053 fClamped = fClamped && src.fClamped;
mtklein9a5c47f2016-07-22 11:05:04 -070054}
55
Mike Klein3928c6b2016-11-15 16:18:38 -050056void SkRasterPipeline::dump() const {
Mike Klein9fff1112017-05-24 11:37:52 -040057 SkDebugf("SkRasterPipeline, %d stages (in reverse)\n", fNumStages);
Mike Kleinb24704d2017-05-24 07:53:00 -040058 for (auto st = fStages; st; st = st->prev) {
Mike Klein3928c6b2016-11-15 16:18:38 -050059 const char* name = "";
Mike Kleinb24704d2017-05-24 07:53:00 -040060 switch (st->stage) {
Mike Klein3928c6b2016-11-15 16:18:38 -050061 #define M(x) case x: name = #x; break;
62 SK_RASTER_PIPELINE_STAGES(M)
63 #undef M
64 }
Mike Kleinbf49d612016-11-30 20:54:37 +000065 SkDebugf("\t%s\n", name);
Mike Klein3928c6b2016-11-15 16:18:38 -050066 }
67 SkDebugf("\n");
68}
Mike Kleind37d5d92016-12-14 13:38:24 +000069
Mike Reedc91e3872017-07-05 14:12:37 -040070//#define TRACK_COLOR_HISTOGRAM
71#ifdef TRACK_COLOR_HISTOGRAM
72 static int gBlack;
73 static int gWhite;
74 static int gColor;
75 #define INC_BLACK gBlack++
76 #define INC_WHITE gWhite++
77 #define INC_COLOR gColor++
78#else
79 #define INC_BLACK
80 #define INC_WHITE
81 #define INC_COLOR
82#endif
83
Mike Klein16776df2017-08-03 10:22:42 -040084void SkRasterPipeline::append_constant_color(SkArenaAlloc* alloc, const float rgba[4]) {
Mike Kleinf757ae62017-09-15 14:57:02 -040085 SkASSERT(0 <= rgba[0] && rgba[0] <= 1);
86 SkASSERT(0 <= rgba[1] && rgba[1] <= 1);
87 SkASSERT(0 <= rgba[2] && rgba[2] <= 1);
88 SkASSERT(0 <= rgba[3] && rgba[3] <= 1);
89
Mike Klein16776df2017-08-03 10:22:42 -040090 if (rgba[0] == 0 && rgba[1] == 0 && rgba[2] == 0 && rgba[3] == 1) {
Mike Reedc91e3872017-07-05 14:12:37 -040091 this->append(black_color);
92 INC_BLACK;
Mike Klein16776df2017-08-03 10:22:42 -040093 } else if (rgba[0] == 1 && rgba[1] == 1 && rgba[2] == 1 && rgba[3] == 1) {
Mike Reedc91e3872017-07-05 14:12:37 -040094 this->append(white_color);
95 INC_WHITE;
96 } else {
Mike Klein1a2e3e12017-08-03 11:24:13 -040097 auto ctx = alloc->make<SkJumper_UniformColorCtx>();
98 Sk4f color = Sk4f::Load(rgba);
99 color.store(&ctx->r);
Mike Kleinf757ae62017-09-15 14:57:02 -0400100
101 // To make loads more direct, we store 8-bit values in 16-bit slots.
102 color = color * 255.0f + 0.5f;
103 ctx->rgba[0] = (uint16_t)color[0];
104 ctx->rgba[1] = (uint16_t)color[1];
105 ctx->rgba[2] = (uint16_t)color[2];
106 ctx->rgba[3] = (uint16_t)color[3];
Mike Klein1a2e3e12017-08-03 11:24:13 -0400107
108 this->unchecked_append(uniform_color, ctx);
Mike Reedc91e3872017-07-05 14:12:37 -0400109 INC_COLOR;
110 }
111
112#ifdef TRACK_COLOR_HISTOGRAM
113 SkDebugf("B=%d W=%d C=%d\n", gBlack, gWhite, gColor);
114#endif
115}
116
117#undef INC_BLACK
118#undef INC_WHITE
119#undef INC_COLOR
120
Mike Kleind37d5d92016-12-14 13:38:24 +0000121// It's pretty easy to start with sound premultiplied linear floats, pack those
122// to sRGB encoded bytes, then read them back to linear floats and find them not
123// quite premultiplied, with a color channel just a smidge greater than the alpha
124// channel. This can happen basically any time we have different transfer
125// functions for alpha and colors... sRGB being the only one we draw into.
126
127// This is an annoying problem with no known good solution. So apply the clamp hammer.
128
129void SkRasterPipeline::append_from_srgb(SkAlphaType at) {
Mike Kleinb24704d2017-05-24 07:53:00 -0400130 this->unchecked_append(from_srgb, nullptr);
Mike Kleind37d5d92016-12-14 13:38:24 +0000131 if (at == kPremul_SkAlphaType) {
132 this->append(SkRasterPipeline::clamp_a);
133 }
134}
Mike Reed279091e2017-06-27 16:58:00 -0400135
136void SkRasterPipeline::append_from_srgb_dst(SkAlphaType at) {
137 this->unchecked_append(from_srgb_dst, nullptr);
138 if (at == kPremul_SkAlphaType) {
139 this->append(SkRasterPipeline::clamp_a_dst);
140 }
141}
Mike Reed6b59bf42017-07-03 21:26:44 -0400142
Mike Reed7aad8cc2017-07-05 12:33:06 -0400143//static int gCounts[5] = { 0, 0, 0, 0, 0 };
144
Mike Reed6b59bf42017-07-03 21:26:44 -0400145void SkRasterPipeline::append_matrix(SkArenaAlloc* alloc, const SkMatrix& matrix) {
Mike Reed7aad8cc2017-07-05 12:33:06 -0400146 SkMatrix::TypeMask mt = matrix.getType();
147#if 0
148 if (mt > 4) mt = 4;
149 gCounts[mt] += 1;
150 SkDebugf("matrices: %d %d %d %d %d\n",
151 gCounts[0], gCounts[1], gCounts[2], gCounts[3], gCounts[4]);
152#endif
153
154 // Based on a histogram of skps, we determined the following special cases were common, more
155 // or fewer can be used if client behaviors change.
156
157 if (mt == SkMatrix::kIdentity_Mask) {
158 return;
159 }
160 if (mt == SkMatrix::kTranslate_Mask) {
161 float* trans = alloc->makeArrayDefault<float>(2);
162 trans[0] = matrix.getTranslateX();
163 trans[1] = matrix.getTranslateY();
164 this->append(SkRasterPipeline::matrix_translate, trans);
165 } else if ((mt | (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)) ==
166 (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)) {
167 float* scaleTrans = alloc->makeArrayDefault<float>(4);
168 scaleTrans[0] = matrix.getTranslateX();
169 scaleTrans[1] = matrix.getTranslateY();
170 scaleTrans[2] = matrix.getScaleX();
171 scaleTrans[3] = matrix.getScaleY();
172 this->append(SkRasterPipeline::matrix_scale_translate, scaleTrans);
Mike Reed6b59bf42017-07-03 21:26:44 -0400173 } else {
Mike Reed7aad8cc2017-07-05 12:33:06 -0400174 float* storage = alloc->makeArrayDefault<float>(9);
175 if (matrix.asAffine(storage)) {
176 // note: asAffine and the 2x3 stage really only need 6 entries
177 this->append(SkRasterPipeline::matrix_2x3, storage);
178 } else {
179 matrix.get9(storage);
180 this->append(SkRasterPipeline::matrix_perspective, storage);
181 }
Mike Reed6b59bf42017-07-03 21:26:44 -0400182 }
183}
Mike Klein159db0a2017-07-25 12:02:13 -0400184
185void SkRasterPipeline::clamp_if_unclamped(SkAlphaType alphaType) {
186 if (!fClamped) {
187 this->append(SkRasterPipeline::clamp_0);
188 this->append(alphaType == kPremul_SkAlphaType ? SkRasterPipeline::clamp_a
189 : SkRasterPipeline::clamp_1);
190 fClamped = true;
191 }
192}