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