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 "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" 16 #include "SkColorSpacePriv.h" 17 #include "SkGr.h" 18 #include "SkHalf.h" 19 #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 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: GP(Mode mode,sk_sp<GrColorSpaceXform> colorSpaceXform)38 GP(Mode mode, sk_sp<GrColorSpaceXform> colorSpaceXform) 39 : INHERITED(kVertexColorSpaceBenchGP_ClassID) 40 , fMode(mode) 41 , fColorSpaceXform(std::move(colorSpaceXform)) { 42 fInPosition = {"inPosition", kFloat2_GrVertexAttribType, kFloat2_GrSLType}; 43 switch (fMode) { 44 case kBaseline_Mode: 45 case kShader_Mode: 46 fInColor = {"inColor", kUByte4_norm_GrVertexAttribType, kHalf4_GrSLType}; 47 break; 48 case kFloat_Mode: 49 fInColor = {"inColor", kFloat4_GrVertexAttribType, kHalf4_GrSLType}; 50 break; 51 case kHalf_Mode: 52 fInColor = {"inColor", kHalf4_GrVertexAttribType, kHalf4_GrSLType}; 53 break; 54 } 55 this->setVertexAttributes(&fInPosition, 2); 56 } name() const57 const char* name() const override { return "VertexColorXformGP"; } 58 createGLSLInstance(const GrShaderCaps &) const59 GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override { 60 class GLSLGP : public GrGLSLGeometryProcessor { 61 public: 62 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override { 63 const GP& gp = args.fGP.cast<GP>(); 64 GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder; 65 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; 66 GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; 67 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; 68 69 varyingHandler->emitAttributes(gp); 70 71 // Setup color 72 GrGLSLVarying varying(kHalf4_GrSLType); 73 varyingHandler->addVarying("color", &varying); 74 vertBuilder->codeAppendf("half4 color = %s;", gp.fInColor.name()); 75 76 if (kShader_Mode == gp.fMode) { 77 fColorSpaceHelper.emitCode(uniformHandler, gp.fColorSpaceXform.get(), 78 kVertex_GrShaderFlag); 79 SkString xformedColor; 80 vertBuilder->appendColorGamutXform(&xformedColor, "color", &fColorSpaceHelper); 81 vertBuilder->codeAppendf("color = %s;", xformedColor.c_str()); 82 vertBuilder->codeAppend("color = half4(color.rgb * color.a, color.a);"); 83 } 84 85 vertBuilder->codeAppendf("%s = color;", varying.vsOut()); 86 fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, varying.fsIn()); 87 88 // Position 89 this->writeOutputPosition(args.fVertBuilder, gpArgs, gp.fInPosition.name()); 90 91 // Coverage 92 fragBuilder->codeAppendf("%s = half4(1);", args.fOutputCoverage); 93 } 94 void setData(const GrGLSLProgramDataManager& pdman, 95 const GrPrimitiveProcessor& primProc, 96 FPCoordTransformIter&&) override { 97 const GP& gp = primProc.cast<GP>(); 98 fColorSpaceHelper.setData(pdman, gp.fColorSpaceXform.get()); 99 } 100 101 GrGLSLColorSpaceXformHelper fColorSpaceHelper; 102 }; 103 return new GLSLGP(); 104 } 105 getGLSLProcessorKey(const GrShaderCaps &,GrProcessorKeyBuilder * b) const106 void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override { 107 b->add32(fMode); 108 b->add32(GrColorSpaceXform::XformKey(fColorSpaceXform.get())); 109 } 110 111 private: 112 Mode fMode; 113 sk_sp<GrColorSpaceXform> fColorSpaceXform; 114 115 Attribute fInPosition; 116 Attribute fInColor; 117 118 typedef GrGeometryProcessor INHERITED; 119 }; 120 121 class Op : public GrMeshDrawOp { 122 public: 123 DEFINE_OP_CLASS_ID 124 name() const125 const char* name() const override { return "VertColorXformOp"; } 126 Op(GrColor color)127 Op(GrColor color) 128 : INHERITED(ClassID()) 129 , fMode(kBaseline_Mode) 130 , fColor(color) { 131 this->setBounds(SkRect::MakeWH(100.f, 100.f), HasAABloat::kNo, IsZeroArea::kNo); 132 } 133 Op(const SkColor4f & color4f,Mode mode)134 Op(const SkColor4f& color4f, Mode mode) 135 : INHERITED(ClassID()) 136 , fMode(mode) 137 , fColor4f(color4f) { 138 SkASSERT(kFloat_Mode == fMode || kHalf_Mode == mode); 139 this->setBounds(SkRect::MakeWH(100.f, 100.f), HasAABloat::kNo, IsZeroArea::kNo); 140 } 141 Op(GrColor color,sk_sp<GrColorSpaceXform> colorSpaceXform)142 Op(GrColor color, sk_sp<GrColorSpaceXform> colorSpaceXform) 143 : INHERITED(ClassID()) 144 , fMode(kShader_Mode) 145 , fColor(color) 146 , fColorSpaceXform(std::move(colorSpaceXform)) { 147 this->setBounds(SkRect::MakeWH(100.f, 100.f), HasAABloat::kNo, IsZeroArea::kNo); 148 } 149 fixedFunctionFlags() const150 FixedFunctionFlags fixedFunctionFlags() const override { 151 return FixedFunctionFlags::kNone; 152 } 153 finalize(const GrCaps &,const GrAppliedClip *,GrFSAAType,GrClampType)154 GrProcessorSet::Analysis finalize( 155 const GrCaps&, const GrAppliedClip*, GrFSAAType, GrClampType) override { 156 return GrProcessorSet::EmptySetAnalysis(); 157 } 158 159 private: 160 friend class ::GrOpMemoryPool; 161 onPrepareDraws(Target * target)162 void onPrepareDraws(Target* target) override { 163 sk_sp<GrGeometryProcessor> gp(new GP(fMode, fColorSpaceXform)); 164 165 size_t vertexStride = gp->vertexStride(); 166 const int kVertexCount = 1024; 167 sk_sp<const GrBuffer> vertexBuffer; 168 int firstVertex = 0; 169 void* verts = target->makeVertexSpace(vertexStride, kVertexCount, &vertexBuffer, 170 &firstVertex); 171 if (!verts) { 172 return; 173 } 174 175 const float dx = 100.0f / kVertexCount; 176 if (kFloat_Mode == fMode) { 177 struct V { 178 SkPoint fPos; 179 SkColor4f fColor; 180 }; 181 SkASSERT(sizeof(V) == vertexStride); 182 V* v = (V*)verts; 183 for (int i = 0; i < kVertexCount; i += 2) { 184 v[i + 0].fPos.set(dx * i, 0.0f); 185 v[i + 0].fColor = fColor4f; 186 v[i + 1].fPos.set(dx * i, 100.0f); 187 v[i + 1].fColor = fColor4f; 188 } 189 } else if (kHalf_Mode == fMode) { 190 struct V { 191 SkPoint fPos; 192 uint64_t fColor; 193 }; 194 SkASSERT(sizeof(V) == vertexStride); 195 uint64_t color; 196 Sk4h halfColor = SkFloatToHalf_finite_ftz(Sk4f::Load(&fColor4f)); 197 color = (uint64_t)halfColor[0] << 48 | 198 (uint64_t)halfColor[1] << 32 | 199 (uint64_t)halfColor[2] << 16 | 200 (uint64_t)halfColor[3] << 0; 201 V* v = (V*)verts; 202 for (int i = 0; i < kVertexCount; i += 2) { 203 v[i + 0].fPos.set(dx * i, 0.0f); 204 v[i + 0].fColor = color; 205 v[i + 1].fPos.set(dx * i, 100.0f); 206 v[i + 1].fColor = color; 207 } 208 } else { 209 struct V { 210 SkPoint fPos; 211 GrColor fColor; 212 }; 213 SkASSERT(sizeof(V) == vertexStride); 214 V* v = (V*)verts; 215 for (int i = 0; i < kVertexCount; i += 2) { 216 v[i + 0].fPos.set(dx * i, 0.0f); 217 v[i + 0].fColor = fColor; 218 v[i + 1].fPos.set(dx * i, 100.0f); 219 v[i + 1].fColor = fColor; 220 } 221 } 222 223 GrMesh* mesh = target->allocMesh(GrPrimitiveType::kTriangleStrip); 224 mesh->setNonIndexedNonInstanced(kVertexCount); 225 mesh->setVertexData(std::move(vertexBuffer), firstVertex); 226 target->recordDraw(gp, mesh); 227 } 228 onExecute(GrOpFlushState * flushState,const SkRect & chainBounds)229 void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override { 230 flushState->executeDrawsAndUploadsForMeshDrawOp( 231 this, chainBounds, GrProcessorSet::MakeEmptySet()); 232 } 233 234 Mode fMode; 235 GrColor fColor; 236 SkColor4f fColor4f; 237 sk_sp<GrColorSpaceXform> fColorSpaceXform; 238 239 typedef GrMeshDrawOp INHERITED; 240 }; 241 } 242 243 class VertexColorSpaceBench : public Benchmark { 244 public: VertexColorSpaceBench(Mode mode,const char * name)245 VertexColorSpaceBench(Mode mode, const char* name) : fMode(mode) { 246 fName = "vertexcolorspace"; 247 fName.appendf("_%s", name); 248 } 249 isSuitableFor(Backend backend)250 bool isSuitableFor(Backend backend) override { return kGPU_Backend == backend; } onGetName()251 const char* onGetName() override { return fName.c_str(); } 252 onDraw(int loops,SkCanvas * canvas)253 void onDraw(int loops, SkCanvas* canvas) override { 254 GrContext* context = canvas->getGrContext(); 255 SkASSERT(context); 256 257 if (kHalf_Mode == fMode && 258 !context->priv().caps()->halfFloatVertexAttributeSupport()) { 259 return; 260 } 261 262 GrOpMemoryPool* pool = context->priv().opMemoryPool(); 263 264 auto p3 = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, 265 SkNamedGamut::kDCIP3); 266 auto xform = GrColorSpaceXform::Make(sk_srgb_singleton(), kUnpremul_SkAlphaType, 267 p3.get(), kUnpremul_SkAlphaType); 268 269 SkRandom r; 270 const int kDrawsPerLoop = 32; 271 272 const GrBackendFormat format = 273 context->priv().caps()->getBackendFormatFromColorType(kRGBA_8888_SkColorType); 274 for (int i = 0; i < loops; ++i) { 275 sk_sp<GrRenderTargetContext> rtc( 276 context->priv().makeDeferredRenderTargetContext( 277 format, SkBackingFit::kApprox, 100, 100, kRGBA_8888_GrPixelConfig, p3)); 278 SkASSERT(rtc); 279 280 for (int j = 0; j < kDrawsPerLoop; ++j) { 281 SkColor c = r.nextU(); 282 std::unique_ptr<GrDrawOp> op = nullptr; 283 284 switch (fMode) { 285 case kBaseline_Mode: 286 op = pool->allocate<Op>(SkColorToPremulGrColor(c)); 287 break; 288 case kShader_Mode: 289 op = pool->allocate<Op>(SkColorToUnpremulGrColor(c), xform); 290 break; 291 case kHalf_Mode: 292 case kFloat_Mode: { 293 SkColor4f c4f = SkColor4f::FromColor(c); 294 c4f = xform->apply(c4f); 295 op = pool->allocate<Op>(c4f, fMode); 296 } 297 } 298 rtc->priv().testingOnly_addDrawOp(std::move(op)); 299 } 300 301 context->flush(); 302 } 303 } 304 305 private: 306 SkString fName; 307 Mode fMode; 308 309 typedef Benchmark INHERITED; 310 }; 311 312 DEF_BENCH(return new VertexColorSpaceBench(kBaseline_Mode, "baseline")); 313 DEF_BENCH(return new VertexColorSpaceBench(kFloat_Mode, "float")); 314 DEF_BENCH(return new VertexColorSpaceBench(kHalf_Mode, "half")); 315 DEF_BENCH(return new VertexColorSpaceBench(kShader_Mode, "shader")); 316