• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "bench/Benchmark.h"
9 
10 #include "include/core/SkString.h"
11 #include "include/gpu/GrDirectContext.h"
12 #include "include/private/SkHalf.h"
13 #include "src/core/SkColorSpacePriv.h"
14 #include "src/gpu/GrDirectContextPriv.h"
15 #include "src/gpu/GrGeometryProcessor.h"
16 #include "src/gpu/GrMemoryPool.h"
17 #include "src/gpu/GrProgramInfo.h"
18 #include "src/gpu/KeyBuilder.h"
19 #include "src/gpu/SkGr.h"
20 #include "src/gpu/glsl/GrGLSLColorSpaceXformHelper.h"
21 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
22 #include "src/gpu/glsl/GrGLSLVarying.h"
23 #include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
24 #include "src/gpu/ops/GrMeshDrawOp.h"
25 #include "src/gpu/ops/GrSimpleMeshDrawOpHelper.h"
26 #include "src/gpu/v1/SurfaceDrawContext_v1.h"
27 
28 namespace {
29 
30 enum Mode {
31     kBaseline_Mode,  // Do the wrong thing, but quickly.
32     kFloat_Mode,     // Transform colors on CPU, use float4 attributes.
33     kHalf_Mode,      // Transform colors on CPU, use half4 attributes.
34     kShader_Mode,    // Use ubyte4 attributes, transform colors on GPU (vertex shader).
35 };
36 
37 class GP : public GrGeometryProcessor {
38 public:
Make(SkArenaAlloc * arena,Mode mode,sk_sp<GrColorSpaceXform> colorSpaceXform)39     static GrGeometryProcessor* Make(SkArenaAlloc* arena, Mode mode,
40                                      sk_sp<GrColorSpaceXform> colorSpaceXform) {
41         return arena->make([&](void* ptr) {
42             return new (ptr) GP(mode, std::move(colorSpaceXform));
43         });
44     }
45 
name() const46     const char* name() const override { return "VertexColorXformGP"; }
47 
makeProgramImpl(const GrShaderCaps &) const48     std::unique_ptr<ProgramImpl> makeProgramImpl(const GrShaderCaps&) const override {
49         class Impl : public ProgramImpl {
50         public:
51             void setData(const GrGLSLProgramDataManager& pdman,
52                          const GrShaderCaps&,
53                          const GrGeometryProcessor& geomProc) override {
54                 const GP& gp = geomProc.cast<GP>();
55                 fColorSpaceHelper.setData(pdman, gp.fColorSpaceXform.get());
56             }
57 
58         private:
59             void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
60                 const GP& gp = args.fGeomProc.cast<GP>();
61                 GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
62                 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
63                 GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
64                 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
65 
66                 varyingHandler->emitAttributes(gp);
67 
68                 // Setup color
69                 GrGLSLVarying varying(SkSLType::kHalf4);
70                 varyingHandler->addVarying("color", &varying);
71                 vertBuilder->codeAppendf("half4 color = %s;", gp.fInColor.name());
72 
73                 if (kShader_Mode == gp.fMode) {
74                     fColorSpaceHelper.emitCode(uniformHandler, gp.fColorSpaceXform.get(),
75                                                kVertex_GrShaderFlag);
76                     SkString xformedColor;
77                     vertBuilder->appendColorGamutXform(&xformedColor, "color", &fColorSpaceHelper);
78                     vertBuilder->codeAppendf("color = %s;", xformedColor.c_str());
79                     vertBuilder->codeAppend("color = half4(color.rgb * color.a, color.a);");
80                 }
81 
82                 vertBuilder->codeAppendf("%s = color;", varying.vsOut());
83                 fragBuilder->codeAppendf("half4 %s = %s;", args.fOutputColor, varying.fsIn());
84 
85                 // Position
86                 WriteOutputPosition(args.fVertBuilder, gpArgs, gp.fInPosition.name());
87 
88                 // Coverage
89                 fragBuilder->codeAppendf("const half4 %s = half4(1);", args.fOutputCoverage);
90             }
91 
92             GrGLSLColorSpaceXformHelper fColorSpaceHelper;
93         };
94 
95         return std::make_unique<Impl>();
96     }
97 
addToKey(const GrShaderCaps &,skgpu::KeyBuilder * b) const98     void addToKey(const GrShaderCaps&, skgpu::KeyBuilder* b) const override {
99         b->add32(fMode);
100         b->add32(GrColorSpaceXform::XformKey(fColorSpaceXform.get()));
101     }
102 
103 private:
GP(Mode mode,sk_sp<GrColorSpaceXform> colorSpaceXform)104     GP(Mode mode, sk_sp<GrColorSpaceXform> colorSpaceXform)
105             : INHERITED(kVertexColorSpaceBenchGP_ClassID)
106             , fMode(mode)
107             , fColorSpaceXform(std::move(colorSpaceXform)) {
108         fInPosition = {"inPosition", kFloat2_GrVertexAttribType, SkSLType::kFloat2};
109         switch (fMode) {
110             case kBaseline_Mode:
111             case kShader_Mode:
112                 fInColor = {"inColor", kUByte4_norm_GrVertexAttribType, SkSLType::kHalf4};
113                 break;
114             case kFloat_Mode:
115                 fInColor = {"inColor", kFloat4_GrVertexAttribType, SkSLType::kHalf4};
116                 break;
117             case kHalf_Mode:
118                 fInColor = {"inColor", kHalf4_GrVertexAttribType, SkSLType::kHalf4};
119                 break;
120         }
121         this->setVertexAttributesWithImplicitOffsets(&fInPosition, 2);
122     }
123 
124     Mode fMode;
125     sk_sp<GrColorSpaceXform> fColorSpaceXform;
126 
127     Attribute fInPosition;
128     Attribute fInColor;
129 
130     using INHERITED = GrGeometryProcessor;
131 };
132 
133 class Op : public GrMeshDrawOp {
134 public:
135     DEFINE_OP_CLASS_ID
136 
name() const137     const char* name() const override { return "VertColorXformOp"; }
138 
Op(GrColor color)139     Op(GrColor color)
140             : INHERITED(ClassID())
141             , fMode(kBaseline_Mode)
142             , fColor(color) {
143         this->setBounds(SkRect::MakeWH(100.f, 100.f), HasAABloat::kNo, IsHairline::kNo);
144     }
145 
Op(const SkColor4f & color4f,Mode mode)146     Op(const SkColor4f& color4f, Mode mode)
147             : INHERITED(ClassID())
148             , fMode(mode)
149             , fColor4f(color4f) {
150         SkASSERT(kFloat_Mode == fMode || kHalf_Mode == mode);
151         this->setBounds(SkRect::MakeWH(100.f, 100.f), HasAABloat::kNo, IsHairline::kNo);
152     }
153 
Op(GrColor color,sk_sp<GrColorSpaceXform> colorSpaceXform)154     Op(GrColor color, sk_sp<GrColorSpaceXform> colorSpaceXform)
155             : INHERITED(ClassID())
156             , fMode(kShader_Mode)
157             , fColor(color)
158             , fColorSpaceXform(std::move(colorSpaceXform)) {
159         this->setBounds(SkRect::MakeWH(100.f, 100.f), HasAABloat::kNo, IsHairline::kNo);
160     }
161 
fixedFunctionFlags() const162     FixedFunctionFlags fixedFunctionFlags() const override {
163         return FixedFunctionFlags::kNone;
164     }
165 
finalize(const GrCaps &,const GrAppliedClip *,GrClampType)166     GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*, GrClampType) override {
167         return GrProcessorSet::EmptySetAnalysis();
168     }
169 
170 private:
171     friend class ::GrMemoryPool;
172 
programInfo()173     GrProgramInfo* programInfo() override { return fProgramInfo; }
174 
onCreateProgramInfo(const GrCaps * caps,SkArenaAlloc * arena,const GrSurfaceProxyView & writeView,bool usesMSAASurface,GrAppliedClip && appliedClip,const GrDstProxyView & dstProxyView,GrXferBarrierFlags renderPassXferBarriers,GrLoadOp colorLoadOp)175     void onCreateProgramInfo(const GrCaps* caps,
176                              SkArenaAlloc* arena,
177                              const GrSurfaceProxyView& writeView,
178                              bool usesMSAASurface,
179                              GrAppliedClip&& appliedClip,
180                              const GrDstProxyView& dstProxyView,
181                              GrXferBarrierFlags renderPassXferBarriers,
182                              GrLoadOp colorLoadOp) override {
183         GrGeometryProcessor* gp = GP::Make(arena, fMode, fColorSpaceXform);
184 
185         fProgramInfo = GrSimpleMeshDrawOpHelper::CreateProgramInfo(caps,
186                                                                    arena,
187                                                                    writeView,
188                                                                    usesMSAASurface,
189                                                                    std::move(appliedClip),
190                                                                    dstProxyView,
191                                                                    gp,
192                                                                    GrProcessorSet::MakeEmptySet(),
193                                                                    GrPrimitiveType::kTriangleStrip,
194                                                                    renderPassXferBarriers,
195                                                                    colorLoadOp,
196                                                                    GrPipeline::InputFlags::kNone);
197     }
198 
onPrepareDraws(GrMeshDrawTarget * target)199     void onPrepareDraws(GrMeshDrawTarget* target) override {
200         if (!fProgramInfo) {
201             this->createProgramInfo(target);
202         }
203 
204         size_t vertexStride = fProgramInfo->geomProc().vertexStride();
205         const int kVertexCount = 1024;
206         sk_sp<const GrBuffer> vertexBuffer;
207         int firstVertex = 0;
208         void* verts = target->makeVertexSpace(vertexStride, kVertexCount, &vertexBuffer,
209                                               &firstVertex);
210         if (!verts) {
211             return;
212         }
213 
214         const float dx = 100.0f / kVertexCount;
215         if (kFloat_Mode == fMode) {
216             struct V {
217                 SkPoint fPos;
218                 SkColor4f fColor;
219             };
220             SkASSERT(sizeof(V) == vertexStride);
221             V* v = (V*)verts;
222             for (int i = 0; i < kVertexCount; i += 2) {
223                 v[i + 0].fPos.set(dx * i, 0.0f);
224                 v[i + 0].fColor = fColor4f;
225                 v[i + 1].fPos.set(dx * i, 100.0f);
226                 v[i + 1].fColor = fColor4f;
227             }
228         } else if (kHalf_Mode == fMode) {
229             struct V {
230                 SkPoint fPos;
231                 uint64_t fColor;
232             };
233             SkASSERT(sizeof(V) == vertexStride);
234             uint64_t color;
235             Sk4h halfColor = SkFloatToHalf_finite_ftz(Sk4f::Load(&fColor4f));
236             color = (uint64_t)halfColor[0] << 48 |
237                     (uint64_t)halfColor[1] << 32 |
238                     (uint64_t)halfColor[2] << 16 |
239                     (uint64_t)halfColor[3] << 0;
240             V* v = (V*)verts;
241             for (int i = 0; i < kVertexCount; i += 2) {
242                 v[i + 0].fPos.set(dx * i, 0.0f);
243                 v[i + 0].fColor = color;
244                 v[i + 1].fPos.set(dx * i, 100.0f);
245                 v[i + 1].fColor = color;
246             }
247         } else {
248             struct V {
249                 SkPoint fPos;
250                 GrColor fColor;
251             };
252             SkASSERT(sizeof(V) == vertexStride);
253             V* v = (V*)verts;
254             for (int i = 0; i < kVertexCount; i += 2) {
255                 v[i + 0].fPos.set(dx * i, 0.0f);
256                 v[i + 0].fColor = fColor;
257                 v[i + 1].fPos.set(dx * i, 100.0f);
258                 v[i + 1].fColor = fColor;
259             }
260         }
261 
262         fMesh = target->allocMesh();
263         fMesh->set(std::move(vertexBuffer), kVertexCount, firstVertex);
264     }
265 
onExecute(GrOpFlushState * flushState,const SkRect & chainBounds)266     void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
267         if (!fProgramInfo || !fMesh) {
268             return;
269         }
270 
271         flushState->bindPipelineAndScissorClip(*fProgramInfo, chainBounds);
272         flushState->bindTextures(fProgramInfo->geomProc(), nullptr, fProgramInfo->pipeline());
273         flushState->drawMesh(*fMesh);
274     }
275 
276     Mode fMode;
277     GrColor fColor;
278     SkColor4f fColor4f;
279     sk_sp<GrColorSpaceXform> fColorSpaceXform;
280 
281     GrSimpleMesh*  fMesh = nullptr;
282     GrProgramInfo* fProgramInfo = nullptr;
283 
284     using INHERITED = GrMeshDrawOp;
285 };
286 }  // namespace
287 
288 class VertexColorSpaceBench : public Benchmark {
289 public:
VertexColorSpaceBench(Mode mode,const char * name)290     VertexColorSpaceBench(Mode mode, const char* name) : fMode(mode) {
291         fName = "vertexcolorspace";
292         fName.appendf("_%s", name);
293     }
294 
isSuitableFor(Backend backend)295     bool isSuitableFor(Backend backend) override { return kGPU_Backend == backend; }
onGetName()296     const char* onGetName() override { return fName.c_str(); }
297 
onDraw(int loops,SkCanvas * canvas)298     void onDraw(int loops, SkCanvas* canvas) override {
299         auto context = canvas->recordingContext()->asDirectContext();
300         SkASSERT(context);
301 
302         if (kHalf_Mode == fMode &&
303             !context->priv().caps()->halfFloatVertexAttributeSupport()) {
304             return;
305         }
306 
307         auto p3 = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB,
308                                         SkNamedGamut::kDisplayP3);
309         auto xform = GrColorSpaceXform::Make(sk_srgb_singleton(), kUnpremul_SkAlphaType,
310                                              p3.get(),            kUnpremul_SkAlphaType);
311 
312         SkRandom r;
313         const int kDrawsPerLoop = 32;
314 
315         for (int i = 0; i < loops; ++i) {
316             auto sdc = skgpu::v1::SurfaceDrawContext::Make(context, GrColorType::kRGBA_8888, p3,
317                                                            SkBackingFit::kApprox, {100, 100},
318                                                            SkSurfaceProps());
319             SkASSERT(sdc);
320 
321             for (int j = 0; j < kDrawsPerLoop; ++j) {
322                 SkColor c = r.nextU();
323                 GrOp::Owner op = nullptr;
324                 GrRecordingContext* rContext = canvas->recordingContext();
325                 switch (fMode) {
326                     case kBaseline_Mode:
327                         op = GrOp::Make<Op>(rContext, SkColorToPremulGrColor(c));
328                         break;
329                     case kShader_Mode:
330                         op = GrOp::Make<Op>(rContext, SkColorToUnpremulGrColor(c), xform);
331                         break;
332                     case kHalf_Mode:
333                     case kFloat_Mode: {
334                         SkColor4f c4f = SkColor4f::FromColor(c);
335                         c4f = xform->apply(c4f);
336                         op = GrOp::Make<Op>(rContext, c4f, fMode);
337                     }
338                 }
339                 sdc->addDrawOp(std::move(op));
340             }
341 
342             context->flushAndSubmit();
343         }
344     }
345 
346 private:
347     SkString fName;
348     Mode fMode;
349 
350     using INHERITED = Benchmark;
351 };
352 
353 DEF_BENCH(return new VertexColorSpaceBench(kBaseline_Mode, "baseline"));
354 DEF_BENCH(return new VertexColorSpaceBench(kFloat_Mode,    "float"));
355 DEF_BENCH(return new VertexColorSpaceBench(kHalf_Mode,     "half"));
356 DEF_BENCH(return new VertexColorSpaceBench(kShader_Mode,   "shader"));
357