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 */
21static 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
43static 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 */
65static 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
89bool 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