blob: 02f0920c5667b4c320b9e16ebe084e8d5db3ea3c [file] [log] [blame]
Brian Osman387eaff2018-07-20 14:50:44 -04001/*
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 "Benchmark.h"
9
10#include "GrContext.h"
11#include "GrContextPriv.h"
12#include "GrGeometryProcessor.h"
13#include "GrMemoryPool.h"
14#include "GrRenderTargetContext.h"
15#include "GrRenderTargetContextPriv.h"
Mike Kleine28a6b52018-07-25 13:05:17 -040016#include "SkColorSpacePriv.h"
Brian Osman387eaff2018-07-20 14:50:44 -040017#include "SkGr.h"
Brian Osman499bf1a2018-09-17 11:32:42 -040018#include "SkHalf.h"
Brian Osman387eaff2018-07-20 14:50:44 -040019#include "SkString.h"
20#include "glsl/GrGLSLColorSpaceXformHelper.h"
21#include "glsl/GrGLSLFragmentShaderBuilder.h"
22#include "glsl/GrGLSLGeometryProcessor.h"
23#include "glsl/GrGLSLVarying.h"
24#include "glsl/GrGLSLVertexGeoBuilder.h"
25#include "ops/GrMeshDrawOp.h"
26
27namespace {
28
29enum Mode {
30 kBaseline_Mode, // Do the wrong thing, but quickly.
31 kFloat_Mode, // Transform colors on CPU, use float4 attributes.
Brian Osman499bf1a2018-09-17 11:32:42 -040032 kHalf_Mode, // Transform colors on CPU, use half4 attributes.
Brian Osman387eaff2018-07-20 14:50:44 -040033 kShader_Mode, // Use ubyte4 attributes, transform colors on GPU (vertex shader).
Brian Osmana5c578f2018-09-19 14:19:02 -040034 kShort_Mode, // Transform on CPU, use short4 (4.12) attributes with a bit of shader math.
Brian Osman387eaff2018-07-20 14:50:44 -040035};
36
37class GP : public GrGeometryProcessor {
38public:
39 GP(Mode mode, sk_sp<GrColorSpaceXform> colorSpaceXform)
40 : INHERITED(kVertexColorSpaceBenchGP_ClassID)
41 , fMode(mode)
42 , fColorSpaceXform(std::move(colorSpaceXform)) {
Brian Osmand4c29702018-09-14 16:16:55 -040043 fInPosition = {"inPosition", kFloat2_GrVertexAttribType, kFloat2_GrSLType};
Brian Osman499bf1a2018-09-17 11:32:42 -040044 switch (fMode) {
45 case kBaseline_Mode:
46 case kShader_Mode:
47 fInColor = {"inColor", kUByte4_norm_GrVertexAttribType, kHalf4_GrSLType};
48 break;
49 case kFloat_Mode:
50 fInColor = {"inColor", kFloat4_GrVertexAttribType, kHalf4_GrSLType};
51 break;
52 case kHalf_Mode:
53 fInColor = {"inColor", kHalf4_GrVertexAttribType, kHalf4_GrSLType};
54 break;
Brian Osmana5c578f2018-09-19 14:19:02 -040055 case kShort_Mode:
56 fInColor = {"inColor", kShort4_GrVertexAttribType, kFloat4_GrSLType};
57 break;
Brian Osman387eaff2018-07-20 14:50:44 -040058 }
59 this->setVertexAttributeCnt(2);
60 }
61 const char* name() const override { return "VertexColorXformGP"; }
62
63 GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override {
64 class GLSLGP : public GrGLSLGeometryProcessor {
65 public:
66 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
67 const GP& gp = args.fGP.cast<GP>();
68 GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
69 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
70 GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
71 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
72
73 varyingHandler->emitAttributes(gp);
74
75 // Setup color
76 GrGLSLVarying varying(kHalf4_GrSLType);
77 varyingHandler->addVarying("color", &varying);
78 vertBuilder->codeAppendf("half4 color = %s;", gp.fInColor.name());
79
80 if (kShader_Mode == gp.fMode) {
81 fColorSpaceHelper.emitCode(uniformHandler, gp.fColorSpaceXform.get(),
82 kVertex_GrShaderFlag);
83 SkString xformedColor;
84 vertBuilder->appendColorGamutXform(&xformedColor, "color", &fColorSpaceHelper);
85 vertBuilder->codeAppendf("color = %s;", xformedColor.c_str());
86 vertBuilder->codeAppend("color = half4(color.rgb * color.a, color.a);");
Brian Osmana5c578f2018-09-19 14:19:02 -040087 } else if (kShort_Mode == gp.fMode) {
88 vertBuilder->codeAppend("color = color * (1 / 4096.0);");
Brian Osman387eaff2018-07-20 14:50:44 -040089 }
90
91 vertBuilder->codeAppendf("%s = color;", varying.vsOut());
92 fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, varying.fsIn());
93
94 // Position
95 this->writeOutputPosition(args.fVertBuilder, gpArgs, gp.fInPosition.name());
96
97 // Coverage
98 fragBuilder->codeAppendf("%s = half4(1);", args.fOutputCoverage);
99 }
100 void setData(const GrGLSLProgramDataManager& pdman,
101 const GrPrimitiveProcessor& primProc,
102 FPCoordTransformIter&&) override {
103 const GP& gp = primProc.cast<GP>();
104 fColorSpaceHelper.setData(pdman, gp.fColorSpaceXform.get());
105 }
106
107 GrGLSLColorSpaceXformHelper fColorSpaceHelper;
108 };
109 return new GLSLGP();
110 }
111
112 void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override {
113 b->add32(fMode);
114 b->add32(GrColorSpaceXform::XformKey(fColorSpaceXform.get()));
115 }
116
117private:
118 const GrPrimitiveProcessor::Attribute& onVertexAttribute(int i) const override {
119 return IthAttribute(i, fInPosition, fInColor);
120 }
121
122 Mode fMode;
123 sk_sp<GrColorSpaceXform> fColorSpaceXform;
124
125 Attribute fInPosition;
126 Attribute fInColor;
127
128 typedef GrGeometryProcessor INHERITED;
129};
130
131class Op : public GrMeshDrawOp {
132public:
133 DEFINE_OP_CLASS_ID
134
135 const char* name() const override { return "VertColorXformOp"; }
136
137 Op(GrColor color)
138 : INHERITED(ClassID())
139 , fMode(kBaseline_Mode)
140 , fColor(color) {
141 this->setBounds(SkRect::MakeWH(100.f, 100.f), HasAABloat::kNo, IsZeroArea::kNo);
142 }
143
Brian Osman499bf1a2018-09-17 11:32:42 -0400144 Op(GrColor4f color4f, Mode mode)
Brian Osman387eaff2018-07-20 14:50:44 -0400145 : INHERITED(ClassID())
Brian Osman499bf1a2018-09-17 11:32:42 -0400146 , fMode(mode)
Brian Osman387eaff2018-07-20 14:50:44 -0400147 , fColor4f(color4f) {
Brian Osmana5c578f2018-09-19 14:19:02 -0400148 SkASSERT(kFloat_Mode == fMode || kHalf_Mode == mode || kShort_Mode == mode);
Brian Osman387eaff2018-07-20 14:50:44 -0400149 this->setBounds(SkRect::MakeWH(100.f, 100.f), HasAABloat::kNo, IsZeroArea::kNo);
150 }
151
152 Op(GrColor color, sk_sp<GrColorSpaceXform> colorSpaceXform)
153 : INHERITED(ClassID())
154 , fMode(kShader_Mode)
155 , fColor(color)
156 , fColorSpaceXform(std::move(colorSpaceXform)) {
157 this->setBounds(SkRect::MakeWH(100.f, 100.f), HasAABloat::kNo, IsZeroArea::kNo);
158 }
159
160 FixedFunctionFlags fixedFunctionFlags() const override {
161 return FixedFunctionFlags::kNone;
162 }
163
164 RequiresDstTexture finalize(const GrCaps&, const GrAppliedClip*) override {
165 return RequiresDstTexture::kNo;
166 }
167
168private:
169 friend class ::GrOpMemoryPool;
170
Brian Osman387eaff2018-07-20 14:50:44 -0400171 void onPrepareDraws(Target* target) override {
172 sk_sp<GrGeometryProcessor> gp(new GP(fMode, fColorSpaceXform));
173
Brian Osman499bf1a2018-09-17 11:32:42 -0400174 size_t vertexStride = sizeof(SkPoint);
175 switch (fMode) {
176 case kFloat_Mode:
177 vertexStride += sizeof(GrColor4f);
178 break;
179 case kHalf_Mode:
Brian Osmana5c578f2018-09-19 14:19:02 -0400180 case kShort_Mode:
Brian Osman499bf1a2018-09-17 11:32:42 -0400181 vertexStride += sizeof(uint64_t);
182 break;
183 default:
184 vertexStride += sizeof(uint32_t);
185 }
Brian Osman387eaff2018-07-20 14:50:44 -0400186 SkASSERT(vertexStride == gp->debugOnly_vertexStride());
187
188 const int kVertexCount = 1024;
189 const GrBuffer* vertexBuffer = nullptr;
190 int firstVertex = 0;
191 void* verts = target->makeVertexSpace(vertexStride, kVertexCount, &vertexBuffer,
192 &firstVertex);
193 if (!verts) {
194 return;
195 }
196
197 const float dx = 100.0f / kVertexCount;
198 if (kFloat_Mode == fMode) {
199 struct V {
200 SkPoint fPos;
201 GrColor4f fColor;
202 };
203 SkASSERT(sizeof(V) == vertexStride);
204 V* v = (V*)verts;
205 for (int i = 0; i < kVertexCount; i += 2) {
206 v[i + 0].fPos.set(dx * i, 0.0f);
207 v[i + 0].fColor = fColor4f;
208 v[i + 1].fPos.set(dx * i, 100.0f);
209 v[i + 1].fColor = fColor4f;
210 }
Brian Osman499bf1a2018-09-17 11:32:42 -0400211 } else if (kHalf_Mode == fMode) {
212 struct V {
213 SkPoint fPos;
214 uint64_t fColor;
215 };
216 SkASSERT(sizeof(V) == vertexStride);
217 uint64_t color;
Brian Osmana5c578f2018-09-19 14:19:02 -0400218 Sk4h halfColor = SkFloatToHalf_finite_ftz(Sk4f::Load(&fColor4f));
Brian Osman499bf1a2018-09-17 11:32:42 -0400219 color = (uint64_t)halfColor[0] << 48 |
220 (uint64_t)halfColor[1] << 32 |
221 (uint64_t)halfColor[2] << 16 |
222 (uint64_t)halfColor[3] << 0;
223 V* v = (V*)verts;
224 for (int i = 0; i < kVertexCount; i += 2) {
225 v[i + 0].fPos.set(dx * i, 0.0f);
226 v[i + 0].fColor = color;
227 v[i + 1].fPos.set(dx * i, 100.0f);
228 v[i + 1].fColor = color;
229 }
Brian Osmana5c578f2018-09-19 14:19:02 -0400230 } else if (kShort_Mode == fMode) {
231 struct ShortColor { int16_t fRGBA[4]; };
232 struct V {
233 SkPoint fPos;
234 ShortColor fColor;
235 };
236 SkASSERT(sizeof(V) == vertexStride);
237 Sk4i c = Sk4f_round(Sk4f::Load(&fColor4f) * 4096.0f);
238 c = Sk4i::Max(-32768, Sk4i::Min(c, 32767));
239 ShortColor color;
240 for (int i = 0; i < 4; ++i) {
241 color.fRGBA[i] = c[i];
242 }
243 V* v = (V*)verts;
244 for (int i = 0; i < kVertexCount; i += 2) {
245 v[i + 0].fPos.set(dx * i, 0.0f);
246 v[i + 0].fColor = color;
247 v[i + 1].fPos.set(dx * i, 100.0f);
248 v[i + 1].fColor = color;
249 }
Brian Osman387eaff2018-07-20 14:50:44 -0400250 } else {
251 struct V {
252 SkPoint fPos;
253 GrColor fColor;
254 };
255 SkASSERT(sizeof(V) == vertexStride);
256 V* v = (V*)verts;
257 for (int i = 0; i < kVertexCount; i += 2) {
258 v[i + 0].fPos.set(dx * i, 0.0f);
259 v[i + 0].fColor = fColor;
260 v[i + 1].fPos.set(dx * i, 100.0f);
261 v[i + 1].fColor = fColor;
262 }
263 }
264
Brian Salomon7eae3e02018-08-07 14:02:38 +0000265 GrMesh* mesh = target->allocMesh(GrPrimitiveType::kTriangleStrip);
266 mesh->setNonIndexedNonInstanced(kVertexCount);
267 mesh->setVertexData(vertexBuffer, firstVertex);
Brian Osman387eaff2018-07-20 14:50:44 -0400268 auto pipe = target->makePipeline(0, GrProcessorSet::MakeEmptySet(),
269 target->detachAppliedClip());
Brian Salomon7eae3e02018-08-07 14:02:38 +0000270 target->draw(gp, pipe.fPipeline, pipe.fFixedDynamicState, mesh);
Brian Osman387eaff2018-07-20 14:50:44 -0400271 }
272
273 Mode fMode;
274 GrColor fColor;
275 GrColor4f fColor4f;
276 sk_sp<GrColorSpaceXform> fColorSpaceXform;
277
278 typedef GrMeshDrawOp INHERITED;
279};
280}
281
282class VertexColorSpaceBench : public Benchmark {
283public:
284 VertexColorSpaceBench(Mode mode, const char* name) : fMode(mode) {
285 fName = "vertexcolorspace";
286 fName.appendf("_%s", name);
287 }
288
289 bool isSuitableFor(Backend backend) override { return kGPU_Backend == backend; }
290 const char* onGetName() override { return fName.c_str(); }
291
292 void onDraw(int loops, SkCanvas* canvas) override {
293 GrContext* context = canvas->getGrContext();
Brian Osman499bf1a2018-09-17 11:32:42 -0400294 SkASSERT(context);
295
296 if (kHalf_Mode == fMode &&
297 !context->contextPriv().caps()->halfFloatVertexAttributeSupport()) {
298 return;
299 }
300
Brian Osman387eaff2018-07-20 14:50:44 -0400301 GrOpMemoryPool* pool = context->contextPriv().opMemoryPool();
302
Brian Osman387eaff2018-07-20 14:50:44 -0400303 auto p3 = SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma,
304 SkColorSpace::kDCIP3_D65_Gamut);
Mike Kleine03a1762018-08-22 11:52:16 -0400305 auto xform = GrColorSpaceXform::Make(sk_srgb_singleton(), kUnpremul_SkAlphaType,
306 p3.get(), kUnpremul_SkAlphaType);
Brian Osman387eaff2018-07-20 14:50:44 -0400307
308 SkRandom r;
309 const int kDrawsPerLoop = 32;
310
311 for (int i = 0; i < loops; ++i) {
312 sk_sp<GrRenderTargetContext> rtc(
313 context->contextPriv().makeDeferredRenderTargetContext(SkBackingFit::kApprox,
314 100, 100, kRGBA_8888_GrPixelConfig, p3));
315 SkASSERT(rtc);
316
317 for (int j = 0; j < kDrawsPerLoop; ++j) {
318 SkColor c = r.nextU();
319 std::unique_ptr<GrDrawOp> op = nullptr;
320
321 switch (fMode) {
322 case kBaseline_Mode:
323 op = pool->allocate<Op>(SkColorToPremulGrColor(c));
324 break;
325 case kShader_Mode:
326 op = pool->allocate<Op>(SkColorToUnpremulGrColor(c), xform);
327 break;
Brian Osman499bf1a2018-09-17 11:32:42 -0400328 case kHalf_Mode:
Brian Osmana5c578f2018-09-19 14:19:02 -0400329 case kShort_Mode:
Brian Osman387eaff2018-07-20 14:50:44 -0400330 case kFloat_Mode: {
331 GrColor4f c4f = GrColor4f::FromGrColor(SkColorToUnpremulGrColor(c));
332 c4f = xform->apply(c4f);
Brian Osman499bf1a2018-09-17 11:32:42 -0400333 op = pool->allocate<Op>(c4f, fMode);
Brian Osman387eaff2018-07-20 14:50:44 -0400334 }
335 }
336 rtc->priv().testingOnly_addDrawOp(std::move(op));
337 }
338
339 context->flush();
340 }
341 }
342
343private:
344 SkString fName;
345 Mode fMode;
346
347 typedef Benchmark INHERITED;
348};
349
350DEF_BENCH(return new VertexColorSpaceBench(kBaseline_Mode, "baseline"));
351DEF_BENCH(return new VertexColorSpaceBench(kFloat_Mode, "float"));
Brian Osman499bf1a2018-09-17 11:32:42 -0400352DEF_BENCH(return new VertexColorSpaceBench(kHalf_Mode, "half"));
Brian Osmana5c578f2018-09-19 14:19:02 -0400353DEF_BENCH(return new VertexColorSpaceBench(kShort_Mode, "short"));
Brian Osman387eaff2018-07-20 14:50:44 -0400354DEF_BENCH(return new VertexColorSpaceBench(kShader_Mode, "shader"));