1 /*
2  * Copyright 2013 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 #include "GrGLProgramDesc.h"
8 
9 #include "GrGLProcessor.h"
10 #include "GrProcessor.h"
11 #include "GrGLGpu.h"
12 #include "GrPipeline.h"
13 #include "SkChecksum.h"
14 #include "gl/builders/GrGLFragmentShaderBuilder.h"
15 
16 /**
17  * Do we need to either map r,g,b->a or a->r. configComponentMask indicates which channels are
18  * present in the texture's config. swizzleComponentMask indicates the channels present in the
19  * shader swizzle.
20  */
swizzle_requires_alpha_remapping(const GrGLCaps & caps,uint32_t configComponentMask,uint32_t swizzleComponentMask)21 static bool swizzle_requires_alpha_remapping(const GrGLCaps& caps,
22                                              uint32_t configComponentMask,
23                                              uint32_t swizzleComponentMask) {
24     if (caps.textureSwizzleSupport()) {
25         // Any remapping is handled using texture swizzling not shader modifications.
26         return false;
27     }
28     // check if the texture is alpha-only
29     if (kA_GrColorComponentFlag == configComponentMask) {
30         if (caps.textureRedSupport() && (kA_GrColorComponentFlag & swizzleComponentMask)) {
31             // we must map the swizzle 'a's to 'r'.
32             return true;
33         }
34         if (kRGB_GrColorComponentFlags & swizzleComponentMask) {
35             // The 'r', 'g', and/or 'b's must be mapped to 'a' according to our semantics that
36             // alpha-only textures smear alpha across all four channels when read.
37             return true;
38         }
39     }
40     return false;
41 }
42 
gen_texture_key(const GrProcessor & proc,const GrGLCaps & caps)43 static uint32_t gen_texture_key(const GrProcessor& proc, const GrGLCaps& caps) {
44     uint32_t key = 0;
45     int numTextures = proc.numTextures();
46     for (int t = 0; t < numTextures; ++t) {
47         const GrTextureAccess& access = proc.textureAccess(t);
48         uint32_t configComponentMask = GrPixelConfigComponentMask(access.getTexture()->config());
49         if (swizzle_requires_alpha_remapping(caps, configComponentMask, access.swizzleMask())) {
50             key |= 1 << t;
51         }
52     }
53     return key;
54 }
55 
56 /**
57  * A function which emits a meta key into the key builder.  This is required because shader code may
58  * be dependent on properties of the effect that the effect itself doesn't use
59  * in its key (e.g. the pixel format of textures used). So we create a meta-key for
60  * every effect using this function. It is also responsible for inserting the effect's class ID
61  * which must be different for every GrProcessor subclass. It can fail if an effect uses too many
62  * textures, transforms, etc, for the space allotted in the meta-key.  NOTE, both FPs and GPs share
63  * this function because it is hairy, though FPs do not have attribs, and GPs do not have transforms
64  */
get_meta_key(const GrProcessor & proc,const GrGLCaps & caps,uint32_t transformKey,GrProcessorKeyBuilder * b)65 static bool get_meta_key(const GrProcessor& proc,
66                          const GrGLCaps& caps,
67                          uint32_t transformKey,
68                          GrProcessorKeyBuilder* b) {
69     size_t processorKeySize = b->size();
70     uint32_t textureKey = gen_texture_key(proc, caps);
71     uint32_t classID = proc.classID();
72 
73     // Currently we allow 16 bits for each of the above portions of the meta-key. Fail if they
74     // don't fit.
75     static const uint32_t kMetaKeyInvalidMask = ~((uint32_t) SK_MaxU16);
76     if ((textureKey | transformKey | classID) & kMetaKeyInvalidMask) {
77         return false;
78     }
79     if (processorKeySize > SK_MaxU16) {
80         return false;
81     }
82 
83     uint32_t* key = b->add32n(2);
84     key[0] = (textureKey << 16 | transformKey);
85     key[1] = (classID << 16 | SkToU16(processorKeySize));
86     return true;
87 }
88 
Build(GrProgramDesc * desc,const GrPrimitiveProcessor & primProc,const GrPipeline & pipeline,const GrGLGpu * gpu,const GrBatchTracker & batchTracker)89 bool GrGLProgramDescBuilder::Build(GrProgramDesc* desc,
90                                    const GrPrimitiveProcessor& primProc,
91                                    const GrPipeline& pipeline,
92                                    const GrGLGpu* gpu,
93                                    const GrBatchTracker& batchTracker) {
94     // The descriptor is used as a cache key. Thus when a field of the
95     // descriptor will not affect program generation (because of the attribute
96     // bindings in use or other descriptor field settings) it should be set
97     // to a canonical value to avoid duplicate programs with different keys.
98 
99     GrGLProgramDesc* glDesc = (GrGLProgramDesc*) desc;
100 
101     GR_STATIC_ASSERT(0 == kProcessorKeysOffset % sizeof(uint32_t));
102     // Make room for everything up to the effect keys.
103     glDesc->key().reset();
104     glDesc->key().push_back_n(kProcessorKeysOffset);
105 
106     GrProcessorKeyBuilder b(&glDesc->key());
107 
108     primProc.getGLProcessorKey(batchTracker, *gpu->glCaps().glslCaps(), &b);
109     //**** use glslCaps here?
110     if (!get_meta_key(primProc, gpu->glCaps(), 0, &b)) {
111         glDesc->key().reset();
112         return false;
113     }
114 
115     for (int s = 0; s < pipeline.numFragmentStages(); ++s) {
116         const GrPendingFragmentStage& fps = pipeline.getFragmentStage(s);
117         const GrFragmentProcessor& fp = *fps.processor();
118         fp.getGLProcessorKey(*gpu->glCaps().glslCaps(), &b);
119         //**** use glslCaps here?
120         if (!get_meta_key(fp, gpu->glCaps(), primProc.getTransformKey(fp.coordTransforms()), &b)) {
121             glDesc->key().reset();
122             return false;
123         }
124     }
125 
126     const GrXferProcessor& xp = *pipeline.getXferProcessor();
127     xp.getGLProcessorKey(*gpu->glCaps().glslCaps(), &b);
128     //**** use glslCaps here?
129     if (!get_meta_key(xp, gpu->glCaps(), 0, &b)) {
130         glDesc->key().reset();
131         return false;
132     }
133 
134     // --------DO NOT MOVE HEADER ABOVE THIS LINE--------------------------------------------------
135     // Because header is a pointer into the dynamic array, we can't push any new data into the key
136     // below here.
137     KeyHeader* header = glDesc->atOffset<KeyHeader, kHeaderOffset>();
138 
139     // make sure any padding in the header is zeroed.
140     memset(header, 0, kHeaderSize);
141 
142     if (pipeline.readsFragPosition()) {
143         header->fFragPosKey =
144                 GrGLFragmentShaderBuilder::KeyForFragmentPosition(pipeline.getRenderTarget(),
145                                                                   gpu->glCaps());
146     } else {
147         header->fFragPosKey = 0;
148     }
149     header->fSnapVerticesToPixelCenters = pipeline.snapVerticesToPixelCenters();
150     header->fColorEffectCnt = pipeline.numColorFragmentStages();
151     header->fCoverageEffectCnt = pipeline.numCoverageFragmentStages();
152     glDesc->finalize();
153     return true;
154 }
155