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 "include/core/SkTypes.h"
11 #include "tests/Test.h"
12
13 #include "include/core/SkString.h"
14 #include "include/gpu/GrContext.h"
15 #include "src/core/SkPointPriv.h"
16 #include "src/gpu/GrContextPriv.h"
17 #include "src/gpu/GrGeometryProcessor.h"
18 #include "src/gpu/GrGpu.h"
19 #include "src/gpu/GrMemoryPool.h"
20 #include "src/gpu/GrOpFlushState.h"
21 #include "src/gpu/GrRenderTargetContext.h"
22 #include "src/gpu/GrRenderTargetContextPriv.h"
23 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
24 #include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
25 #include "src/gpu/glsl/GrGLSLVarying.h"
26 #include "src/gpu/ops/GrMeshDrawOp.h"
27
28 namespace {
29 class Op : public GrMeshDrawOp {
30 public:
31 DEFINE_OP_CLASS_ID
32
name() const33 const char* name() const override { return "Dummy Op"; }
34
Make(GrContext * context,int numAttribs)35 static std::unique_ptr<GrDrawOp> Make(GrContext* context, int numAttribs) {
36 GrOpMemoryPool* pool = context->priv().opMemoryPool();
37
38 return pool->allocate<Op>(numAttribs);
39 }
40
fixedFunctionFlags() const41 FixedFunctionFlags fixedFunctionFlags() const override {
42 return FixedFunctionFlags::kNone;
43 }
44
finalize(const GrCaps &,const GrAppliedClip *,bool hasMixedSampledCoverage,GrClampType)45 GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*,
46 bool hasMixedSampledCoverage, GrClampType) override {
47 return GrProcessorSet::EmptySetAnalysis();
48 }
49
50 private:
51 friend class ::GrOpMemoryPool;
52
Op(int numAttribs)53 Op(int numAttribs) : INHERITED(ClassID()), fNumAttribs(numAttribs) {
54 this->setBounds(SkRect::MakeWH(1.f, 1.f), HasAABloat::kNo, IsZeroArea::kNo);
55 }
56
onPrepareDraws(Target * target)57 void onPrepareDraws(Target* target) override {
58 class GP : public GrGeometryProcessor {
59 public:
60 GP(int numAttribs) : INHERITED(kGP_ClassID), fNumAttribs(numAttribs) {
61 SkASSERT(numAttribs > 1);
62 fAttribNames.reset(new SkString[numAttribs]);
63 fAttributes.reset(new Attribute[numAttribs]);
64 for (auto i = 0; i < numAttribs; ++i) {
65 fAttribNames[i].printf("attr%d", i);
66 // This gives us more of a mix of attribute types, and allows the
67 // component count to fit within the limits for iOS Metal.
68 if (i & 0x1) {
69 fAttributes[i] = {fAttribNames[i].c_str(), kFloat_GrVertexAttribType,
70 kFloat_GrSLType};
71 } else {
72 fAttributes[i] = {fAttribNames[i].c_str(), kFloat2_GrVertexAttribType,
73 kFloat2_GrSLType};
74 }
75 }
76 this->setVertexAttributes(fAttributes.get(), numAttribs);
77 }
78 const char* name() const override { return "Dummy GP"; }
79
80 GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override {
81 class GLSLGP : public GrGLSLGeometryProcessor {
82 public:
83 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
84 const GP& gp = args.fGP.cast<GP>();
85 args.fVaryingHandler->emitAttributes(gp);
86 this->writeOutputPosition(args.fVertBuilder, gpArgs,
87 gp.fAttributes[0].name());
88 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
89 fragBuilder->codeAppendf("%s = half4(1);", args.fOutputColor);
90 fragBuilder->codeAppendf("%s = half4(1);", args.fOutputCoverage);
91 }
92 void setData(const GrGLSLProgramDataManager& pdman,
93 const GrPrimitiveProcessor& primProc,
94 FPCoordTransformIter&&) override {}
95 };
96 return new GLSLGP();
97 }
98 void getGLSLProcessorKey(const GrShaderCaps&,
99 GrProcessorKeyBuilder* builder) const override {
100 builder->add32(fNumAttribs);
101 }
102
103 private:
104 int fNumAttribs;
105 std::unique_ptr<SkString[]> fAttribNames;
106 std::unique_ptr<Attribute[]> fAttributes;
107
108 typedef GrGeometryProcessor INHERITED;
109 };
110 sk_sp<GrGeometryProcessor> gp(new GP(fNumAttribs));
111 size_t vertexStride = gp->vertexStride();
112 QuadHelper helper(target, vertexStride, 1);
113 SkPoint* vertices = reinterpret_cast<SkPoint*>(helper.vertices());
114 SkPointPriv::SetRectTriStrip(vertices, 0.f, 0.f, 1.f, 1.f, vertexStride);
115 helper.recordDraw(target, std::move(gp));
116 }
117
onExecute(GrOpFlushState * flushState,const SkRect & chainBounds)118 void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
119 flushState->executeDrawsAndUploadsForMeshDrawOp(
120 this, chainBounds, GrProcessorSet::MakeEmptySet());
121 }
122
123 int fNumAttribs;
124
125 typedef GrMeshDrawOp INHERITED;
126 };
127 }
128
DEF_GPUTEST_FOR_ALL_CONTEXTS(VertexAttributeCount,reporter,ctxInfo)129 DEF_GPUTEST_FOR_ALL_CONTEXTS(VertexAttributeCount, reporter, ctxInfo) {
130 GrContext* context = ctxInfo.grContext();
131 #if GR_GPU_STATS
132 GrGpu* gpu = context->priv().getGpu();
133 #endif
134
135 sk_sp<GrRenderTargetContext> renderTargetContext(
136 context->priv().makeDeferredRenderTargetContext(SkBackingFit::kApprox, 1, 1,
137 GrColorType::kRGBA_8888, nullptr));
138 if (!renderTargetContext) {
139 ERRORF(reporter, "Could not create render target context.");
140 return;
141 }
142 int attribCnt = context->priv().caps()->maxVertexAttributes();
143 if (!attribCnt) {
144 ERRORF(reporter, "No attributes allowed?!");
145 return;
146 }
147 context->flush();
148 context->priv().resetGpuStats();
149 #if GR_GPU_STATS
150 REPORTER_ASSERT(reporter, gpu->stats()->numDraws() == 0);
151 REPORTER_ASSERT(reporter, gpu->stats()->numFailedDraws() == 0);
152 #endif
153 // Adding discard to appease vulkan validation warning about loading uninitialized data on draw
154 renderTargetContext->discard();
155
156 GrPaint grPaint;
157 // This one should succeed.
158 renderTargetContext->priv().testingOnly_addDrawOp(Op::Make(context, attribCnt));
159 context->flush();
160 #if GR_GPU_STATS
161 REPORTER_ASSERT(reporter, gpu->stats()->numDraws() == 1);
162 REPORTER_ASSERT(reporter, gpu->stats()->numFailedDraws() == 0);
163 #endif
164 context->priv().resetGpuStats();
165 renderTargetContext->priv().testingOnly_addDrawOp(Op::Make(context, attribCnt + 1));
166 context->flush();
167 #if GR_GPU_STATS
168 REPORTER_ASSERT(reporter, gpu->stats()->numDraws() == 0);
169 REPORTER_ASSERT(reporter, gpu->stats()->numFailedDraws() == 1);
170 #endif
171 }
172