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