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// This is a GPU-backend specific test. It relies on static intializers to work 9 10#include "SkTypes.h" 11#include "Test.h" 12 13#if SK_SUPPORT_GPU 14#include "GrContext.h" 15#include "GrGeometryProcessor.h" 16#include "GrGpu.h" 17#include "GrOpFlushState.h" 18#include "GrRenderTargetContext.h" 19#include "GrRenderTargetContextPriv.h" 20#include "SkPointPriv.h" 21#include "SkString.h" 22#include "glsl/GrGLSLFragmentShaderBuilder.h" 23#include "glsl/GrGLSLGeometryProcessor.h" 24#include "glsl/GrGLSLVarying.h" 25#include "ops/GrMeshDrawOp.h" 26 27namespace { 28class Op : public GrMeshDrawOp { 29public: 30 DEFINE_OP_CLASS_ID 31 32 const char* name() const override { return "Dummy Op"; } 33 34 static std::unique_ptr<GrDrawOp> Make(int numAttribs) { 35 return std::unique_ptr<GrDrawOp>(new Op(numAttribs)); 36 } 37 38 FixedFunctionFlags fixedFunctionFlags() const override { 39 return FixedFunctionFlags::kNone; 40 } 41 42 RequiresDstTexture finalize(const GrCaps&, const GrAppliedClip*,\ 43 GrPixelConfigIsClamped) override { 44 return RequiresDstTexture::kNo; 45 } 46 47private: 48 Op(int numAttribs) : INHERITED(ClassID()), fNumAttribs(numAttribs) { 49 this->setBounds(SkRect::MakeWH(1.f, 1.f), HasAABloat::kNo, IsZeroArea::kNo); 50 } 51 52 bool onCombineIfPossible(GrOp*, const GrCaps&) override { return false; } 53 54 void onPrepareDraws(Target* target) override { 55 class GP : public GrGeometryProcessor { 56 public: 57 GP(int numAttribs) 58 : INHERITED(kGP_ClassID) { 59 SkASSERT(numAttribs > 1); 60 for (auto i = 0; i < numAttribs; ++i) { 61 fAttribNames.push_back().printf("attr%d", i); 62 } 63 for (auto i = 0; i < numAttribs; ++i) { 64 this->addVertexAttrib(fAttribNames[i].c_str(), kFloat2_GrVertexAttribType); 65 } 66 } 67 const char* name() const override { return "Dummy GP"; } 68 69 GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override { 70 class GLSLGP : public GrGLSLGeometryProcessor { 71 public: 72 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override { 73 const GP& gp = args.fGP.cast<GP>(); 74 args.fVaryingHandler->emitAttributes(gp); 75 this->writeOutputPosition(args.fVertBuilder, gpArgs, gp.getAttrib(0).fName); 76 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; 77 fragBuilder->codeAppendf("%s = half4(1);", args.fOutputColor); 78 fragBuilder->codeAppendf("%s = half4(1);", args.fOutputCoverage); 79 } 80 void setData(const GrGLSLProgramDataManager& pdman, 81 const GrPrimitiveProcessor& primProc, 82 FPCoordTransformIter&&) override {} 83 }; 84 return new GLSLGP(); 85 } 86 void getGLSLProcessorKey(const GrShaderCaps&, 87 GrProcessorKeyBuilder* builder) const override { 88 builder->add32(this->numAttribs()); 89 } 90 91 private: 92 SkTArray<SkString> fAttribNames; 93 94 typedef GrGeometryProcessor INHERITED; 95 }; 96 sk_sp<GrGeometryProcessor> gp(new GP(fNumAttribs)); 97 QuadHelper helper; 98 size_t vertexStride = gp->getVertexStride(); 99 SkPoint* vertices = reinterpret_cast<SkPoint*>(helper.init(target, vertexStride, 1)); 100 SkPointPriv::SetRectTriStrip(vertices, 0.f, 0.f, 1.f, 1.f, vertexStride); 101 helper.recordDraw(target, gp.get(), 102 target->makePipeline(0, GrProcessorSet::MakeEmptySet(), 103 target->detachAppliedClip())); 104 } 105 106 int fNumAttribs; 107 108 typedef GrMeshDrawOp INHERITED; 109}; 110} 111 112DEF_GPUTEST_FOR_ALL_CONTEXTS(VertexAttributeCount, reporter, ctxInfo) { 113 GrContext* context = ctxInfo.grContext(); 114#if GR_GPU_STATS 115 GrGpu* gpu = context->contextPriv().getGpu(); 116#endif 117 118 sk_sp<GrRenderTargetContext> renderTargetContext(context->makeDeferredRenderTargetContext( 119 SkBackingFit::kApprox, 120 1, 1, kRGBA_8888_GrPixelConfig, 121 nullptr)); 122 if (!renderTargetContext) { 123 ERRORF(reporter, "Could not create render target context."); 124 return; 125 } 126 int attribCnt = context->caps()->maxVertexAttributes(); 127 if (!attribCnt) { 128 ERRORF(reporter, "No attributes allowed?!"); 129 return; 130 } 131 context->flush(); 132 context->resetGpuStats(); 133#if GR_GPU_STATS 134 REPORTER_ASSERT(reporter, gpu->stats()->numDraws() == 0); 135 REPORTER_ASSERT(reporter, gpu->stats()->numFailedDraws() == 0); 136#endif 137 // Adding discard to appease vulkan validation warning about loading uninitialized data on draw 138 renderTargetContext->discard(); 139 140 GrPaint grPaint; 141 // This one should succeed. 142 renderTargetContext->priv().testingOnly_addDrawOp(Op::Make(attribCnt)); 143 context->flush(); 144#if GR_GPU_STATS 145 REPORTER_ASSERT(reporter, gpu->stats()->numDraws() == 1); 146 REPORTER_ASSERT(reporter, gpu->stats()->numFailedDraws() == 0); 147#endif 148 context->resetGpuStats(); 149 renderTargetContext->priv().testingOnly_addDrawOp(Op::Make(attribCnt + 1)); 150 context->flush(); 151#if GR_GPU_STATS 152 REPORTER_ASSERT(reporter, gpu->stats()->numDraws() == 0); 153 REPORTER_ASSERT(reporter, gpu->stats()->numFailedDraws() == 1); 154#endif 155} 156#endif 157