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