• 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 // This is a GPU-backend specific test. It relies on static intializers to work
9 
10 #include <memory>
11 
12 #include "include/core/SkTypes.h"
13 #include "tests/Test.h"
14 
15 #include "include/core/SkString.h"
16 #include "include/gpu/GrDirectContext.h"
17 #include "src/core/SkPointPriv.h"
18 #include "src/gpu/GrDirectContextPriv.h"
19 #include "src/gpu/GrGeometryProcessor.h"
20 #include "src/gpu/GrGpu.h"
21 #include "src/gpu/GrMemoryPool.h"
22 #include "src/gpu/GrOpFlushState.h"
23 #include "src/gpu/GrProgramInfo.h"
24 #include "src/gpu/GrSurfaceDrawContext.h"
25 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
26 #include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
27 #include "src/gpu/glsl/GrGLSLVarying.h"
28 #include "src/gpu/ops/GrMeshDrawOp.h"
29 #include "src/gpu/ops/GrSimpleMeshDrawOpHelper.h"
30 
31 namespace {
32 class Op : public GrMeshDrawOp {
33 public:
34     DEFINE_OP_CLASS_ID
35 
name() const36     const char* name() const override { return "Dummy Op"; }
37 
Make(GrRecordingContext * rContext,int numAttribs)38     static GrOp::Owner Make(GrRecordingContext* rContext, int numAttribs) {
39         return GrOp::Make<Op>(rContext, numAttribs);
40     }
41 
fixedFunctionFlags() const42     FixedFunctionFlags fixedFunctionFlags() const override {
43         return FixedFunctionFlags::kNone;
44     }
45 
finalize(const GrCaps &,const GrAppliedClip *,GrClampType)46     GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*, GrClampType) override {
47         return GrProcessorSet::EmptySetAnalysis();
48     }
49 
50 private:
51     friend class ::GrOp;
52 
Op(int numAttribs)53     Op(int numAttribs) : INHERITED(ClassID()), fNumAttribs(numAttribs) {
54         this->setBounds(SkRect::MakeWH(1.f, 1.f), HasAABloat::kNo, IsHairline::kNo);
55     }
56 
programInfo()57     GrProgramInfo* programInfo() override { return fProgramInfo; }
58 
onCreateProgramInfo(const GrCaps * caps,SkArenaAlloc * arena,const GrSurfaceProxyView & writeView,GrAppliedClip && appliedClip,const GrXferProcessor::DstProxyView & dstProxyView,GrXferBarrierFlags renderPassXferBarriers,GrLoadOp colorLoadOp)59     void onCreateProgramInfo(const GrCaps* caps,
60                              SkArenaAlloc* arena,
61                              const GrSurfaceProxyView& writeView,
62                              GrAppliedClip&& appliedClip,
63                              const GrXferProcessor::DstProxyView& dstProxyView,
64                              GrXferBarrierFlags renderPassXferBarriers,
65                              GrLoadOp colorLoadOp) override {
66         class GP : public GrGeometryProcessor {
67         public:
68             static GrGeometryProcessor* Make(SkArenaAlloc* arena, int numAttribs) {
69                 return arena->make([&](void* ptr) {
70                     return new (ptr) GP(numAttribs);
71                 });
72             }
73 
74             const char* name() const override { return "Dummy GP"; }
75 
76             GrGLSLGeometryProcessor* createGLSLInstance(const GrShaderCaps&) const override {
77                 class GLSLGP : public GrGLSLGeometryProcessor {
78                 public:
79                     void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
80                         const GP& gp = args.fGeomProc.cast<GP>();
81                         args.fVaryingHandler->emitAttributes(gp);
82                         WriteOutputPosition(args.fVertBuilder, gpArgs, gp.fAttributes[0].name());
83                         GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
84                         fragBuilder->codeAppendf("const half4 %s = half4(1);", args.fOutputColor);
85                         fragBuilder->codeAppendf("const half4 %s = half4(1);",
86                                                  args.fOutputCoverage);
87                     }
88                     void setData(const GrGLSLProgramDataManager&,
89                                  const GrShaderCaps&,
90                                  const GrGeometryProcessor&) override {}
91                 };
92                 return new GLSLGP();
93             }
94             void getGLSLProcessorKey(const GrShaderCaps&,
95                                      GrProcessorKeyBuilder* builder) const override {
96                 builder->add32(fNumAttribs);
97             }
98 
99         private:
100             GP(int numAttribs) : INHERITED(kGP_ClassID), fNumAttribs(numAttribs) {
101                 SkASSERT(numAttribs > 1);
102                 fAttribNames = std::make_unique<SkString[]>(numAttribs);
103                 fAttributes = std::make_unique<Attribute[]>(numAttribs);
104                 for (auto i = 0; i < numAttribs; ++i) {
105                     fAttribNames[i].printf("attr%d", i);
106                     // This gives us more of a mix of attribute types, and allows the
107                     // component count to fit within the limits for iOS Metal.
108                     if (i & 0x1) {
109                         fAttributes[i] = {fAttribNames[i].c_str(), kFloat_GrVertexAttribType,
110                                                                    kFloat_GrSLType};
111                     } else {
112                         fAttributes[i] = {fAttribNames[i].c_str(), kFloat2_GrVertexAttribType,
113                                                                    kFloat2_GrSLType};
114                     }
115                 }
116                 this->setVertexAttributes(fAttributes.get(), numAttribs);
117             }
118 
119             int fNumAttribs;
120             std::unique_ptr<SkString[]> fAttribNames;
121             std::unique_ptr<Attribute[]> fAttributes;
122 
123             using INHERITED = GrGeometryProcessor;
124         };
125 
126         GrGeometryProcessor* gp = GP::Make(arena, fNumAttribs);
127 
128         fProgramInfo = GrSimpleMeshDrawOpHelper::CreateProgramInfo(caps,
129                                                                    arena,
130                                                                    writeView,
131                                                                    std::move(appliedClip),
132                                                                    dstProxyView,
133                                                                    gp,
134                                                                    GrProcessorSet::MakeEmptySet(),
135                                                                    GrPrimitiveType::kTriangles,
136                                                                    renderPassXferBarriers,
137                                                                    colorLoadOp,
138                                                                    GrPipeline::InputFlags::kNone);
139     }
140 
onPrepareDraws(Target * target)141     void onPrepareDraws(Target* target) override {
142         if (!fProgramInfo) {
143             this->createProgramInfo(target);
144         }
145 
146         size_t vertexStride = fProgramInfo->geomProc().vertexStride();
147         QuadHelper helper(target, vertexStride, 1);
148         SkPoint* vertices = reinterpret_cast<SkPoint*>(helper.vertices());
149         SkPointPriv::SetRectTriStrip(vertices, 0.f, 0.f, 1.f, 1.f, vertexStride);
150         fMesh = helper.mesh();
151     }
152 
onExecute(GrOpFlushState * flushState,const SkRect & chainBounds)153     void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
154         if (!fProgramInfo || !fMesh) {
155             return;
156         }
157 
158         flushState->bindPipelineAndScissorClip(*fProgramInfo, chainBounds);
159         flushState->bindTextures(fProgramInfo->geomProc(), nullptr, fProgramInfo->pipeline());
160         flushState->drawMesh(*fMesh);
161     }
162 
163     int            fNumAttribs;
164     GrSimpleMesh*  fMesh = nullptr;
165     GrProgramInfo* fProgramInfo = nullptr;
166 
167     using INHERITED = GrMeshDrawOp;
168 };
169 }  // namespace
170 
DEF_GPUTEST_FOR_ALL_CONTEXTS(VertexAttributeCount,reporter,ctxInfo)171 DEF_GPUTEST_FOR_ALL_CONTEXTS(VertexAttributeCount, reporter, ctxInfo) {
172     auto context = ctxInfo.directContext();
173 #if GR_GPU_STATS
174     GrGpu* gpu = context->priv().getGpu();
175 #endif
176 
177     auto surfaceDrawContext = GrSurfaceDrawContext::Make(context, GrColorType::kRGBA_8888, nullptr,
178                                                          SkBackingFit::kApprox, {1, 1},
179                                                          SkSurfaceProps());
180     if (!surfaceDrawContext) {
181         ERRORF(reporter, "Could not create render target context.");
182         return;
183     }
184     int attribCnt = context->priv().caps()->maxVertexAttributes();
185     if (!attribCnt) {
186         ERRORF(reporter, "No attributes allowed?!");
187         return;
188     }
189     context->flushAndSubmit();
190     context->priv().resetGpuStats();
191 #if GR_GPU_STATS
192     REPORTER_ASSERT(reporter, gpu->stats()->numDraws() == 0);
193     REPORTER_ASSERT(reporter, gpu->stats()->numFailedDraws() == 0);
194 #endif
195     // Adding discard to appease vulkan validation warning about loading uninitialized data on draw
196     surfaceDrawContext->discard();
197 
198     GrPaint grPaint;
199     // This one should succeed.
200     surfaceDrawContext->addDrawOp(Op::Make(context, attribCnt));
201     context->flushAndSubmit();
202 #if GR_GPU_STATS
203     REPORTER_ASSERT(reporter, gpu->stats()->numDraws() == 1);
204     REPORTER_ASSERT(reporter, gpu->stats()->numFailedDraws() == 0);
205 #endif
206     context->priv().resetGpuStats();
207     surfaceDrawContext->addDrawOp(Op::Make(context, attribCnt + 1));
208     context->flushAndSubmit();
209 #if GR_GPU_STATS
210     REPORTER_ASSERT(reporter, gpu->stats()->numDraws() == 0);
211     REPORTER_ASSERT(reporter, gpu->stats()->numFailedDraws() == 1);
212 #endif
213 }
214