1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2017 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "include/core/SkTypes.h"
9cb93a386Sopenharmony_ci#include "tests/Test.h"
10cb93a386Sopenharmony_ci
11cb93a386Sopenharmony_ci#include "include/gpu/GrDirectContext.h"
12cb93a386Sopenharmony_ci#include "include/gpu/GrRecordingContext.h"
13cb93a386Sopenharmony_ci#include "src/gpu/GrColor.h"
14cb93a386Sopenharmony_ci#include "src/gpu/GrDirectContextPriv.h"
15cb93a386Sopenharmony_ci#include "src/gpu/GrGeometryProcessor.h"
16cb93a386Sopenharmony_ci#include "src/gpu/GrImageInfo.h"
17cb93a386Sopenharmony_ci#include "src/gpu/GrMemoryPool.h"
18cb93a386Sopenharmony_ci#include "src/gpu/GrOpFlushState.h"
19cb93a386Sopenharmony_ci#include "src/gpu/GrOpsRenderPass.h"
20cb93a386Sopenharmony_ci#include "src/gpu/GrProgramInfo.h"
21cb93a386Sopenharmony_ci#include "src/gpu/GrRecordingContextPriv.h"
22cb93a386Sopenharmony_ci#include "src/gpu/GrResourceProvider.h"
23cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
24cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLVarying.h"
25cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
26cb93a386Sopenharmony_ci#include "src/gpu/ops/GrDrawOp.h"
27cb93a386Sopenharmony_ci#include "src/gpu/v1/SurfaceDrawContext_v1.h"
28cb93a386Sopenharmony_ci
29cb93a386Sopenharmony_ci/**
30cb93a386Sopenharmony_ci * This is a GPU-backend specific test for dynamic pipeline state. It draws boxes using dynamic
31cb93a386Sopenharmony_ci * scissor rectangles then reads back the result to verify a successful test.
32cb93a386Sopenharmony_ci */
33cb93a386Sopenharmony_ci
34cb93a386Sopenharmony_cistatic constexpr int kScreenSize = 6;
35cb93a386Sopenharmony_cistatic constexpr int kNumMeshes = 4;
36cb93a386Sopenharmony_cistatic constexpr int kScreenSplitX = kScreenSize/2;
37cb93a386Sopenharmony_cistatic constexpr int kScreenSplitY = kScreenSize/2;
38cb93a386Sopenharmony_ci
39cb93a386Sopenharmony_cistatic const SkIRect kDynamicScissors[kNumMeshes] = {
40cb93a386Sopenharmony_ci    SkIRect::MakeLTRB(0,              0,              kScreenSplitX,  kScreenSplitY),
41cb93a386Sopenharmony_ci    SkIRect::MakeLTRB(0,              kScreenSplitY,  kScreenSplitX,  kScreenSize),
42cb93a386Sopenharmony_ci    SkIRect::MakeLTRB(kScreenSplitX,  0,              kScreenSize,    kScreenSplitY),
43cb93a386Sopenharmony_ci    SkIRect::MakeLTRB(kScreenSplitX,  kScreenSplitY,  kScreenSize,    kScreenSize),
44cb93a386Sopenharmony_ci};
45cb93a386Sopenharmony_ci
46cb93a386Sopenharmony_cistatic const GrColor kMeshColors[kNumMeshes] {
47cb93a386Sopenharmony_ci    GrColorPackRGBA(255, 0, 0, 255),
48cb93a386Sopenharmony_ci    GrColorPackRGBA(0, 255, 0, 255),
49cb93a386Sopenharmony_ci    GrColorPackRGBA(0, 0, 255, 255),
50cb93a386Sopenharmony_ci    GrColorPackRGBA(0, 0, 0, 255)
51cb93a386Sopenharmony_ci};
52cb93a386Sopenharmony_ci
53cb93a386Sopenharmony_cistruct Vertex {
54cb93a386Sopenharmony_ci    float     fX;
55cb93a386Sopenharmony_ci    float     fY;
56cb93a386Sopenharmony_ci    GrColor   fColor;
57cb93a386Sopenharmony_ci};
58cb93a386Sopenharmony_ci
59cb93a386Sopenharmony_cinamespace {
60cb93a386Sopenharmony_ciclass PipelineDynamicStateTestProcessor : public GrGeometryProcessor {
61cb93a386Sopenharmony_cipublic:
62cb93a386Sopenharmony_ci    static GrGeometryProcessor* Make(SkArenaAlloc* arena) {
63cb93a386Sopenharmony_ci        return arena->make(
64cb93a386Sopenharmony_ci                [&](void* ptr) { return new (ptr) PipelineDynamicStateTestProcessor(); });
65cb93a386Sopenharmony_ci    }
66cb93a386Sopenharmony_ci
67cb93a386Sopenharmony_ci    const char* name() const override { return "GrPipelineDynamicStateTest Processor"; }
68cb93a386Sopenharmony_ci
69cb93a386Sopenharmony_ci    void addToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const final {}
70cb93a386Sopenharmony_ci
71cb93a386Sopenharmony_ci    std::unique_ptr<ProgramImpl> makeProgramImpl(const GrShaderCaps&) const final;
72cb93a386Sopenharmony_ci
73cb93a386Sopenharmony_ciprivate:
74cb93a386Sopenharmony_ci    PipelineDynamicStateTestProcessor() : INHERITED(kGrPipelineDynamicStateTestProcessor_ClassID) {
75cb93a386Sopenharmony_ci        this->setVertexAttributes(kAttributes, SK_ARRAY_COUNT(kAttributes));
76cb93a386Sopenharmony_ci    }
77cb93a386Sopenharmony_ci
78cb93a386Sopenharmony_ci    const Attribute& inVertex() const { return kAttributes[0]; }
79cb93a386Sopenharmony_ci    const Attribute& inColor() const { return kAttributes[1]; }
80cb93a386Sopenharmony_ci
81cb93a386Sopenharmony_ci    inline static constexpr Attribute kAttributes[] = {
82cb93a386Sopenharmony_ci            {"vertex", kFloat2_GrVertexAttribType, kHalf2_GrSLType},
83cb93a386Sopenharmony_ci            {"color", kUByte4_norm_GrVertexAttribType, kHalf4_GrSLType},
84cb93a386Sopenharmony_ci    };
85cb93a386Sopenharmony_ci
86cb93a386Sopenharmony_ci    friend class GLSLPipelineDynamicStateTestProcessor;
87cb93a386Sopenharmony_ci    using INHERITED = GrGeometryProcessor;
88cb93a386Sopenharmony_ci};
89cb93a386Sopenharmony_ci}  // anonymous namespace
90cb93a386Sopenharmony_ci
91cb93a386Sopenharmony_cistd::unique_ptr<GrGeometryProcessor::ProgramImpl>
92cb93a386Sopenharmony_ciPipelineDynamicStateTestProcessor::makeProgramImpl(const GrShaderCaps&) const {
93cb93a386Sopenharmony_ci    class Impl : public GrGeometryProcessor::ProgramImpl {
94cb93a386Sopenharmony_ci    public:
95cb93a386Sopenharmony_ci        void setData(const GrGLSLProgramDataManager&,
96cb93a386Sopenharmony_ci                     const GrShaderCaps&,
97cb93a386Sopenharmony_ci                     const GrGeometryProcessor&) final {}
98cb93a386Sopenharmony_ci
99cb93a386Sopenharmony_ci        void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) final {
100cb93a386Sopenharmony_ci            const PipelineDynamicStateTestProcessor& mp =
101cb93a386Sopenharmony_ci                    args.fGeomProc.cast<PipelineDynamicStateTestProcessor>();
102cb93a386Sopenharmony_ci            GrGLSLVertexBuilder* v = args.fVertBuilder;
103cb93a386Sopenharmony_ci            GrGLSLFPFragmentBuilder* f = args.fFragBuilder;
104cb93a386Sopenharmony_ci
105cb93a386Sopenharmony_ci            GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
106cb93a386Sopenharmony_ci            varyingHandler->emitAttributes(mp);
107cb93a386Sopenharmony_ci            f->codeAppendf("half4 %s;", args.fOutputColor);
108cb93a386Sopenharmony_ci            varyingHandler->addPassThroughAttribute(mp.inColor().asShaderVar(), args.fOutputColor);
109cb93a386Sopenharmony_ci
110cb93a386Sopenharmony_ci            v->codeAppendf("float2 vertex = %s;", mp.inVertex().name());
111cb93a386Sopenharmony_ci            gpArgs->fPositionVar.set(kFloat2_GrSLType, "vertex");
112cb93a386Sopenharmony_ci            f->codeAppendf("const half4 %s = half4(1);", args.fOutputCoverage);
113cb93a386Sopenharmony_ci        }
114cb93a386Sopenharmony_ci    };
115cb93a386Sopenharmony_ci    return std::make_unique<Impl>();
116cb93a386Sopenharmony_ci}
117cb93a386Sopenharmony_ci
118cb93a386Sopenharmony_cinamespace {
119cb93a386Sopenharmony_ciclass GrPipelineDynamicStateTestOp : public GrDrawOp {
120cb93a386Sopenharmony_cipublic:
121cb93a386Sopenharmony_ci    DEFINE_OP_CLASS_ID
122cb93a386Sopenharmony_ci
123cb93a386Sopenharmony_ci    static GrOp::Owner Make(GrRecordingContext* context,
124cb93a386Sopenharmony_ci                            GrScissorTest scissorTest,
125cb93a386Sopenharmony_ci                            sk_sp<const GrBuffer> vbuff) {
126cb93a386Sopenharmony_ci        return GrOp::Make<GrPipelineDynamicStateTestOp>(context, scissorTest, std::move(vbuff));
127cb93a386Sopenharmony_ci    }
128cb93a386Sopenharmony_ci
129cb93a386Sopenharmony_ciprivate:
130cb93a386Sopenharmony_ci    friend class GrOp;
131cb93a386Sopenharmony_ci
132cb93a386Sopenharmony_ci    GrPipelineDynamicStateTestOp(GrScissorTest scissorTest, sk_sp<const GrBuffer> vbuff)
133cb93a386Sopenharmony_ci        : INHERITED(ClassID())
134cb93a386Sopenharmony_ci        , fScissorTest(scissorTest)
135cb93a386Sopenharmony_ci        , fVertexBuffer(std::move(vbuff)) {
136cb93a386Sopenharmony_ci        this->setBounds(SkRect::MakeIWH(kScreenSize, kScreenSize),
137cb93a386Sopenharmony_ci                        HasAABloat::kNo, IsHairline::kNo);
138cb93a386Sopenharmony_ci    }
139cb93a386Sopenharmony_ci
140cb93a386Sopenharmony_ci    const char* name() const override { return "GrPipelineDynamicStateTestOp"; }
141cb93a386Sopenharmony_ci    FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
142cb93a386Sopenharmony_ci    GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*, GrClampType) override {
143cb93a386Sopenharmony_ci        return GrProcessorSet::EmptySetAnalysis();
144cb93a386Sopenharmony_ci    }
145cb93a386Sopenharmony_ci    void onPrePrepare(GrRecordingContext*,
146cb93a386Sopenharmony_ci                      const GrSurfaceProxyView& writeView,
147cb93a386Sopenharmony_ci                      GrAppliedClip*,
148cb93a386Sopenharmony_ci                      const GrDstProxyView&,
149cb93a386Sopenharmony_ci                      GrXferBarrierFlags renderPassXferBarriers,
150cb93a386Sopenharmony_ci                      GrLoadOp colorLoadOp) override {}
151cb93a386Sopenharmony_ci    void onPrepare(GrOpFlushState*) override {}
152cb93a386Sopenharmony_ci    void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
153cb93a386Sopenharmony_ci        GrPipeline pipeline(fScissorTest, SkBlendMode::kSrc,
154cb93a386Sopenharmony_ci                            flushState->drawOpArgs().writeView().swizzle());
155cb93a386Sopenharmony_ci        SkSTArray<kNumMeshes, GrSimpleMesh> meshes;
156cb93a386Sopenharmony_ci        for (int i = 0; i < kNumMeshes; ++i) {
157cb93a386Sopenharmony_ci            GrSimpleMesh& mesh = meshes.push_back();
158cb93a386Sopenharmony_ci            mesh.set(fVertexBuffer, 4, 4 * i);
159cb93a386Sopenharmony_ci        }
160cb93a386Sopenharmony_ci
161cb93a386Sopenharmony_ci        auto geomProc = PipelineDynamicStateTestProcessor::Make(flushState->allocator());
162cb93a386Sopenharmony_ci
163cb93a386Sopenharmony_ci        GrProgramInfo programInfo(flushState->caps(),
164cb93a386Sopenharmony_ci                                  flushState->writeView(),
165cb93a386Sopenharmony_ci                                  flushState->usesMSAASurface(),
166cb93a386Sopenharmony_ci                                  &pipeline,
167cb93a386Sopenharmony_ci                                  &GrUserStencilSettings::kUnused,
168cb93a386Sopenharmony_ci                                  geomProc,
169cb93a386Sopenharmony_ci                                  GrPrimitiveType::kTriangleStrip, 0,
170cb93a386Sopenharmony_ci                                  flushState->renderPassBarriers(),
171cb93a386Sopenharmony_ci                                  flushState->colorLoadOp());
172cb93a386Sopenharmony_ci
173cb93a386Sopenharmony_ci        flushState->bindPipeline(programInfo, SkRect::MakeIWH(kScreenSize, kScreenSize));
174cb93a386Sopenharmony_ci        for (int i = 0; i < 4; ++i) {
175cb93a386Sopenharmony_ci            if (fScissorTest == GrScissorTest::kEnabled) {
176cb93a386Sopenharmony_ci                flushState->setScissorRect(kDynamicScissors[i]);
177cb93a386Sopenharmony_ci            }
178cb93a386Sopenharmony_ci            flushState->drawMesh(meshes[i]);
179cb93a386Sopenharmony_ci        }
180cb93a386Sopenharmony_ci    }
181cb93a386Sopenharmony_ci
182cb93a386Sopenharmony_ci    GrScissorTest               fScissorTest;
183cb93a386Sopenharmony_ci    const sk_sp<const GrBuffer> fVertexBuffer;
184cb93a386Sopenharmony_ci
185cb93a386Sopenharmony_ci    using INHERITED = GrDrawOp;
186cb93a386Sopenharmony_ci};
187cb93a386Sopenharmony_ci}  // anonymous namespace
188cb93a386Sopenharmony_ci
189cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrPipelineDynamicStateTest, reporter, ctxInfo) {
190cb93a386Sopenharmony_ci    auto dContext = ctxInfo.directContext();
191cb93a386Sopenharmony_ci    GrResourceProvider* rp = dContext->priv().resourceProvider();
192cb93a386Sopenharmony_ci
193cb93a386Sopenharmony_ci    auto sdc = skgpu::v1::SurfaceDrawContext::Make(
194cb93a386Sopenharmony_ci            dContext, GrColorType::kRGBA_8888, nullptr, SkBackingFit::kExact,
195cb93a386Sopenharmony_ci            {kScreenSize, kScreenSize}, SkSurfaceProps());
196cb93a386Sopenharmony_ci    if (!sdc) {
197cb93a386Sopenharmony_ci        ERRORF(reporter, "could not create render target context.");
198cb93a386Sopenharmony_ci        return;
199cb93a386Sopenharmony_ci    }
200cb93a386Sopenharmony_ci
201cb93a386Sopenharmony_ci    constexpr float d = (float) kScreenSize;
202cb93a386Sopenharmony_ci    Vertex vdata[kNumMeshes * 4] = {
203cb93a386Sopenharmony_ci        {0, 0, kMeshColors[0]},
204cb93a386Sopenharmony_ci        {0, d, kMeshColors[0]},
205cb93a386Sopenharmony_ci        {d, 0, kMeshColors[0]},
206cb93a386Sopenharmony_ci        {d, d, kMeshColors[0]},
207cb93a386Sopenharmony_ci
208cb93a386Sopenharmony_ci        {0, 0, kMeshColors[1]},
209cb93a386Sopenharmony_ci        {0, d, kMeshColors[1]},
210cb93a386Sopenharmony_ci        {d, 0, kMeshColors[1]},
211cb93a386Sopenharmony_ci        {d, d, kMeshColors[1]},
212cb93a386Sopenharmony_ci
213cb93a386Sopenharmony_ci        {0, 0, kMeshColors[2]},
214cb93a386Sopenharmony_ci        {0, d, kMeshColors[2]},
215cb93a386Sopenharmony_ci        {d, 0, kMeshColors[2]},
216cb93a386Sopenharmony_ci        {d, d, kMeshColors[2]},
217cb93a386Sopenharmony_ci
218cb93a386Sopenharmony_ci        {0, 0, kMeshColors[3]},
219cb93a386Sopenharmony_ci        {0, d, kMeshColors[3]},
220cb93a386Sopenharmony_ci        {d, 0, kMeshColors[3]},
221cb93a386Sopenharmony_ci        {d, d, kMeshColors[3]}
222cb93a386Sopenharmony_ci    };
223cb93a386Sopenharmony_ci
224cb93a386Sopenharmony_ci    sk_sp<const GrBuffer> vbuff(rp->createBuffer(sizeof(vdata), GrGpuBufferType::kVertex,
225cb93a386Sopenharmony_ci                                                 kDynamic_GrAccessPattern, vdata));
226cb93a386Sopenharmony_ci    if (!vbuff) {
227cb93a386Sopenharmony_ci        ERRORF(reporter, "vbuff is null.");
228cb93a386Sopenharmony_ci        return;
229cb93a386Sopenharmony_ci    }
230cb93a386Sopenharmony_ci
231cb93a386Sopenharmony_ci    uint32_t resultPx[kScreenSize * kScreenSize];
232cb93a386Sopenharmony_ci
233cb93a386Sopenharmony_ci    for (GrScissorTest scissorTest : {GrScissorTest::kEnabled, GrScissorTest::kDisabled}) {
234cb93a386Sopenharmony_ci        sdc->clear(SkPMColor4f::FromBytes_RGBA(0xbaaaaaad));
235cb93a386Sopenharmony_ci        sdc->addDrawOp(GrPipelineDynamicStateTestOp::Make(dContext, scissorTest, vbuff));
236cb93a386Sopenharmony_ci        auto ii = SkImageInfo::Make(kScreenSize, kScreenSize,
237cb93a386Sopenharmony_ci                                    kRGBA_8888_SkColorType, kPremul_SkAlphaType);
238cb93a386Sopenharmony_ci        GrPixmap resultPM(ii, resultPx, kScreenSize*sizeof(uint32_t));
239cb93a386Sopenharmony_ci        sdc->readPixels(dContext, resultPM, {0, 0});
240cb93a386Sopenharmony_ci        for (int y = 0; y < kScreenSize; ++y) {
241cb93a386Sopenharmony_ci            for (int x = 0; x < kScreenSize; ++x) {
242cb93a386Sopenharmony_ci                int expectedColorIdx;
243cb93a386Sopenharmony_ci                if (GrScissorTest::kEnabled == scissorTest) {
244cb93a386Sopenharmony_ci                    expectedColorIdx = (x < kScreenSplitX ? 0 : 2) + (y < kScreenSplitY ? 0 : 1);
245cb93a386Sopenharmony_ci                } else {
246cb93a386Sopenharmony_ci                    expectedColorIdx = kNumMeshes - 1;
247cb93a386Sopenharmony_ci                }
248cb93a386Sopenharmony_ci                uint32_t expected = kMeshColors[expectedColorIdx];
249cb93a386Sopenharmony_ci                uint32_t actual = resultPx[y * kScreenSize + x];
250cb93a386Sopenharmony_ci                if (expected != actual) {
251cb93a386Sopenharmony_ci                    ERRORF(reporter, "[scissor=%s] pixel (%i,%i): got 0x%x expected 0x%x",
252cb93a386Sopenharmony_ci                           GrScissorTest::kEnabled == scissorTest ? "enabled" : "disabled", x, y,
253cb93a386Sopenharmony_ci                           actual, expected);
254cb93a386Sopenharmony_ci                    return;
255cb93a386Sopenharmony_ci                }
256cb93a386Sopenharmony_ci            }
257cb93a386Sopenharmony_ci        }
258cb93a386Sopenharmony_ci    }
259cb93a386Sopenharmony_ci}
260