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