1/*
2 * Copyright 2021 Google LLC.
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#ifndef AtlasInstancedHelper_DEFINED
9#define AtlasInstancedHelper_DEFINED
10
11#include "src/core/SkIPoint16.h"
12#include "src/gpu/GrGeometryProcessor.h"
13#include "src/gpu/GrSurfaceProxyView.h"
14#include "src/gpu/glsl/GrGLSLUniformHandler.h"
15
16namespace skgpu::v1 {
17
18// This class encapsulates all the necessary steps for an instanced GrGeometryProcessor to clip
19// against a path mask from an atlas.
20class AtlasInstancedHelper {
21public:
22    enum class ShaderFlags {
23        kNone = 0,
24        kInvertCoverage = 1 << 0,
25        kCheckBounds = 1 << 1
26    };
27
28    GR_DECL_BITFIELD_CLASS_OPS_FRIENDS(ShaderFlags);
29
30    constexpr static int kNumShaderFlags = 2;
31
32    AtlasInstancedHelper(GrSurfaceProxyView atlasView, ShaderFlags shaderFlags)
33            : fAtlasProxy(atlasView.detachProxy())
34            , fAtlasSwizzle(atlasView.swizzle())
35            , fShaderFlags(shaderFlags) {
36        // Bottom left origin is not supported.
37        SkASSERT(atlasView.origin() == kTopLeft_GrSurfaceOrigin);
38    }
39
40    GrSurfaceProxy* proxy() const { return fAtlasProxy.get(); }
41    const GrSwizzle& atlasSwizzle() const { return fAtlasSwizzle; }
42
43    // Returns whether the two helpers can be batched together in a single draw.
44    bool isCompatible(const AtlasInstancedHelper& helper) {
45        // TODO: We may want to consider two helpers compatible if they only differ in the
46        // kCheckBounds flag -- we can always promote one to checking its bounds.
47        SkASSERT(fAtlasProxy != helper.fAtlasProxy || fAtlasSwizzle == helper.fAtlasSwizzle);
48        return fAtlasProxy == helper.fAtlasProxy && fShaderFlags == helper.fShaderFlags;
49    }
50
51    // Adds bits to the shader key that uniquely identify this specific helper's shader code.
52    void getKeyBits(GrProcessorKeyBuilder* b) const {
53        b->addBits(kNumShaderFlags, (int)fShaderFlags, "atlasFlags");
54    }
55
56    // Appends the instanced input attribs to the back of the array that we will need in order to
57    // locate our path in the atlas.
58    void appendInstanceAttribs(SkTArray<GrGeometryProcessor::Attribute>* instanceAttribs) const;
59
60    struct Instance {
61        Instance(SkIPoint16 locationInAtlas, const SkIRect& pathDevIBounds, bool transposedInAtlas)
62                : fLocationInAtlas(locationInAtlas)
63                , fPathDevIBounds(pathDevIBounds)
64                , fTransposedInAtlas(transposedInAtlas) {
65            SkASSERT(fLocationInAtlas.x() >= 0);
66            SkASSERT(fLocationInAtlas.y() >= 0);
67        }
68        SkIPoint16 fLocationInAtlas;
69        SkIRect fPathDevIBounds;
70        bool fTransposedInAtlas;
71    };
72
73    // Writes out the given instance data, formatted for the specific attribs that we added during
74    // appendInstanceAttribs().
75    void writeInstanceData(VertexWriter* instanceWriter, const Instance*) const;
76
77    // Injects vertex code, fragment code, varyings, and uniforms to ultimately multiply
78    // "args.fOutputCoverage" in the fragment shader by the atlas coverage.
79    //
80    // The caller is responsible to store "atlasAdjustUniformHandle" and pass it to
81    // setUniformData().
82    void injectShaderCode(const GrGeometryProcessor::ProgramImpl::EmitArgs&,
83                          const GrShaderVar& devCoord,
84                          GrGLSLUniformHandler::UniformHandle* atlasAdjustUniformHandle) const;
85
86    // The atlas clip requires one uniform value -- "atlasAdjustUniform". The caller should have
87    // stored this handle after its call to injectShaderCode(). This method sets its value prior to
88    // drawing.
89    void setUniformData(const GrGLSLProgramDataManager&,
90                        const GrGLSLUniformHandler::UniformHandle& atlasAdjustUniformHandle) const;
91
92private:
93    const sk_sp<GrSurfaceProxy> fAtlasProxy;
94    const GrSwizzle fAtlasSwizzle;
95    const ShaderFlags fShaderFlags;
96};
97
98GR_MAKE_BITFIELD_CLASS_OPS(AtlasInstancedHelper::ShaderFlags);
99
100} // namespace skgpu::v1
101
102#endif // AtlasInstancedHelper_DEFINED
103