• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
16 namespace 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.
20 class AtlasInstancedHelper {
21 public:
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 
AtlasInstancedHelper(GrSurfaceProxyView atlasView,ShaderFlags shaderFlags)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 
proxy()40     GrSurfaceProxy* proxy() const { return fAtlasProxy.get(); }
atlasSwizzle()41     const GrSwizzle& atlasSwizzle() const { return fAtlasSwizzle; }
42 
43     // Returns whether the two helpers can be batched together in a single draw.
isCompatible(const AtlasInstancedHelper & helper)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.
getKeyBits(GrProcessorKeyBuilder * b)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 {
InstanceInstance61         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 
92 private:
93     const sk_sp<GrSurfaceProxy> fAtlasProxy;
94     const GrSwizzle fAtlasSwizzle;
95     const ShaderFlags fShaderFlags;
96 };
97 
98 GR_MAKE_BITFIELD_CLASS_OPS(AtlasInstancedHelper::ShaderFlags);
99 
100 } // namespace skgpu::v1
101 
102 #endif // AtlasInstancedHelper_DEFINED
103