blob: 6b3008b7bdf999475042daa1792911c3d447d1c4 [file] [log] [blame]
bsalomon@google.com798c8c42013-03-27 19:50:27 +00001/*
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
8#include "GrGLProgramDesc.h"
9#include "GrBackendEffectFactory.h"
10#include "GrDrawEffect.h"
11#include "GrEffect.h"
bsalomon@google.com26e18b52013-03-29 19:22:36 +000012#include "GrGLShaderBuilder.h"
bsalomon@google.com798c8c42013-03-27 19:50:27 +000013#include "GrGpuGL.h"
14
bsalomon@google.com2db3ded2013-05-22 14:34:04 +000015#include "SkChecksum.h"
16
bsalomon@google.comeb6879f2013-06-13 19:34:18 +000017namespace {
18inline GrGLEffect::EffectKey get_key_and_update_stats(const GrEffectStage& stage,
19 const GrGLCaps& caps,
20 bool useExplicitLocalCoords,
21 bool* setTrueIfReadsDst,
22 bool* setTrueIfReadsPos) {
23 const GrEffectRef& effect = *stage.getEffect();
24 const GrBackendEffectFactory& factory = effect->getFactory();
25 GrDrawEffect drawEffect(stage, useExplicitLocalCoords);
26 if (effect->willReadDstColor()) {
27 *setTrueIfReadsDst = true;
28 }
29 if (effect->willReadFragmentPosition()) {
30 *setTrueIfReadsPos = true;
31 }
32 return factory.glEffectKey(drawEffect, caps);
33}
34}
bsalomon@google.com798c8c42013-03-27 19:50:27 +000035void GrGLProgramDesc::Build(const GrDrawState& drawState,
36 bool isPoints,
37 GrDrawState::BlendOptFlags blendOpts,
38 GrBlendCoeff srcCoeff,
39 GrBlendCoeff dstCoeff,
40 const GrGpuGL* gpu,
bsalomon@google.com26e18b52013-03-29 19:22:36 +000041 const GrDeviceCoordTexture* dstCopy,
bsalomon@google.com2c84aa32013-06-06 20:28:57 +000042 SkTArray<const GrEffectStage*, true>* colorStages,
43 SkTArray<const GrEffectStage*, true>* coverageStages,
bsalomon@google.com798c8c42013-03-27 19:50:27 +000044 GrGLProgramDesc* desc) {
bsalomon@google.com2c84aa32013-06-06 20:28:57 +000045 colorStages->reset();
46 coverageStages->reset();
47
bsalomon@google.com798c8c42013-03-27 19:50:27 +000048 // This should already have been caught
49 GrAssert(!(GrDrawState::kSkipDraw_BlendOptFlag & blendOpts));
50
51 bool skipCoverage = SkToBool(blendOpts & GrDrawState::kEmitTransBlack_BlendOptFlag);
52
53 bool skipColor = SkToBool(blendOpts & (GrDrawState::kEmitTransBlack_BlendOptFlag |
54 GrDrawState::kEmitCoverage_BlendOptFlag));
55
56 // The descriptor is used as a cache key. Thus when a field of the
57 // descriptor will not affect program generation (because of the attribute
58 // bindings in use or other descriptor field settings) it should be set
59 // to a canonical value to avoid duplicate programs with different keys.
60
jvanverth@google.com054ae992013-04-01 20:06:51 +000061 bool requiresColorAttrib = !skipColor && drawState.hasColorVertexAttribute();
62 bool requiresCoverageAttrib = !skipCoverage && drawState.hasCoverageVertexAttribute();
63 // we only need the local coords if we're actually going to generate effect code
64 bool requiresLocalCoordAttrib = !(skipCoverage && skipColor) &&
65 drawState.hasLocalCoordAttribute();
bsalomon@google.com798c8c42013-03-27 19:50:27 +000066
bsalomon@google.com798c8c42013-03-27 19:50:27 +000067 bool colorIsTransBlack = SkToBool(blendOpts & GrDrawState::kEmitTransBlack_BlendOptFlag);
68 bool colorIsSolidWhite = (blendOpts & GrDrawState::kEmitCoverage_BlendOptFlag) ||
jvanverth@google.com054ae992013-04-01 20:06:51 +000069 (!requiresColorAttrib && 0xffffffff == drawState.getColor());
bsalomon@google.com2db3ded2013-05-22 14:34:04 +000070
bsalomon@google.comeb6879f2013-06-13 19:34:18 +000071 int numEffects = (skipColor ? 0 : drawState.numColorStages()) +
72 (skipCoverage ? 0 : drawState.numCoverageStages());
bsalomon@google.com798c8c42013-03-27 19:50:27 +000073
bsalomon@google.comeb6879f2013-06-13 19:34:18 +000074 size_t newKeyLength = KeyLength(numEffects);
bsalomon@google.com2db3ded2013-05-22 14:34:04 +000075 bool allocChanged;
76 desc->fKey.reset(newKeyLength, SkAutoMalloc::kAlloc_OnShrink, &allocChanged);
77 if (allocChanged || !desc->fInitialized) {
78 // make sure any padding in the header is zero if we we haven't used this allocation before.
79 memset(desc->header(), 0, kHeaderSize);
bsalomon@google.com798c8c42013-03-27 19:50:27 +000080 }
bsalomon@google.com2db3ded2013-05-22 14:34:04 +000081 // write the key length
82 *desc->atOffset<uint32_t, kLengthOffset>() = newKeyLength;
bsalomon@google.com798c8c42013-03-27 19:50:27 +000083
bsalomon@google.com2db3ded2013-05-22 14:34:04 +000084 KeyHeader* header = desc->header();
85 EffectKey* effectKeys = desc->effectKeys();
86
87 int currEffectKey = 0;
bsalomon@google.com26e18b52013-03-29 19:22:36 +000088 bool readsDst = false;
bsalomon@google.comb5158812013-05-13 18:50:25 +000089 bool readFragPosition = false;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +000090 if (!skipColor) {
91 for (int s = 0; s < drawState.numColorStages(); ++s) {
92 effectKeys[currEffectKey++] =
93 get_key_and_update_stats(drawState.getColorStage(s), gpu->glCaps(),
94 requiresLocalCoordAttrib, &readsDst, &readFragPosition);
95 }
96 }
97 if (!skipCoverage) {
98 for (int s = 0; s < drawState.numCoverageStages(); ++s) {
99 effectKeys[currEffectKey++] =
100 get_key_and_update_stats(drawState.getCoverageStage(s), gpu->glCaps(),
101 requiresLocalCoordAttrib, &readsDst, &readFragPosition);
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000102 }
103 }
104
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000105 header->fEmitsPointSize = isPoints;
106 header->fColorFilterXfermode = skipColor ? SkXfermode::kDst_Mode : drawState.getColorFilterMode();
107
108 // Currently the experimental GS will only work with triangle prims (and it doesn't do anything
109 // other than pass through values from the VS to the FS anyway).
110#if GR_GL_EXPERIMENTAL_GS
111#if 0
112 header->fExperimentalGS = gpu->caps().geometryShaderSupport();
113#else
114 header->fExperimentalGS = false;
115#endif
116#endif
117 if (colorIsTransBlack) {
118 header->fColorInput = kTransBlack_ColorInput;
119 } else if (colorIsSolidWhite) {
120 header->fColorInput = kSolidWhite_ColorInput;
121 } else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresColorAttrib) {
122 header->fColorInput = kUniform_ColorInput;
123 } else {
124 header->fColorInput = kAttribute_ColorInput;
125 }
126
127 bool covIsSolidWhite = !requiresCoverageAttrib && 0xffffffff == drawState.getCoverage();
128
129 if (skipCoverage) {
130 header->fCoverageInput = kTransBlack_ColorInput;
131 } else if (covIsSolidWhite) {
132 header->fCoverageInput = kSolidWhite_ColorInput;
133 } else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresCoverageAttrib) {
134 header->fCoverageInput = kUniform_ColorInput;
135 } else {
136 header->fCoverageInput = kAttribute_ColorInput;
137 }
138
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000139 if (readsDst) {
bsalomon@google.com6b0cf022013-05-03 13:35:14 +0000140 GrAssert(NULL != dstCopy || gpu->caps()->dstReadInShaderSupport());
141 const GrTexture* dstCopyTexture = NULL;
142 if (NULL != dstCopy) {
143 dstCopyTexture = dstCopy->texture();
144 }
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000145 header->fDstReadKey = GrGLShaderBuilder::KeyForDstRead(dstCopyTexture, gpu->glCaps());
146 GrAssert(0 != header->fDstReadKey);
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000147 } else {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000148 header->fDstReadKey = 0;
bsalomon@google.comb5158812013-05-13 18:50:25 +0000149 }
150
151 if (readFragPosition) {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000152 header->fFragPosKey = GrGLShaderBuilder::KeyForFragmentPosition(drawState.getRenderTarget(),
bsalomon@google.comb5158812013-05-13 18:50:25 +0000153 gpu->glCaps());
154 } else {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000155 header->fFragPosKey = 0;
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000156 }
157
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000158 // Record attribute indices
159 header->fPositionAttributeIndex = drawState.positionAttributeIndex();
160 header->fLocalCoordAttributeIndex = drawState.localCoordAttributeIndex();
skia.committer@gmail.com2d816ad2013-05-23 07:01:22 +0000161
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000162 // For constant color and coverage we need an attribute with an index beyond those already set
163 int availableAttributeIndex = drawState.getVertexAttribCount();
164 if (requiresColorAttrib) {
165 header->fColorAttributeIndex = drawState.colorVertexAttributeIndex();
166 } else if (GrGLProgramDesc::kAttribute_ColorInput == header->fColorInput) {
167 GrAssert(availableAttributeIndex < GrDrawState::kMaxVertexAttribCnt);
168 header->fColorAttributeIndex = availableAttributeIndex;
169 availableAttributeIndex++;
170 } else {
171 header->fColorAttributeIndex = -1;
172 }
skia.committer@gmail.com2d816ad2013-05-23 07:01:22 +0000173
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000174 if (requiresCoverageAttrib) {
175 header->fCoverageAttributeIndex = drawState.coverageVertexAttributeIndex();
176 } else if (GrGLProgramDesc::kAttribute_ColorInput == header->fCoverageInput) {
177 GrAssert(availableAttributeIndex < GrDrawState::kMaxVertexAttribCnt);
178 header->fCoverageAttributeIndex = availableAttributeIndex;
179 } else {
180 header->fCoverageAttributeIndex = -1;
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000181 }
182
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000183 // Here we deal with whether/how we handle color and coverage separately.
skia.committer@gmail.com2d816ad2013-05-23 07:01:22 +0000184
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000185 // Set these defaults and then possibly change our mind if there is coverage.
186 header->fDiscardIfZeroCoverage = false;
187 header->fCoverageOutput = kModulate_CoverageOutput;
188
189 // If we do have coverage determine whether it matters.
190 bool separateCoverageFromColor = false;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000191 if (!drawState.isCoverageDrawing() && !skipCoverage &&
192 (drawState.numCoverageStages() > 0 || requiresCoverageAttrib)) {
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000193 // color filter is applied between color/coverage computation
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000194 if (SkXfermode::kDst_Mode != header->fColorFilterXfermode) {
195 separateCoverageFromColor = true;
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000196 }
197
198 // If we're stenciling then we want to discard samples that have zero coverage
199 if (drawState.getStencil().doesWrite()) {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000200 header->fDiscardIfZeroCoverage = true;
201 separateCoverageFromColor = true;
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000202 }
203
204 if (gpu->caps()->dualSourceBlendingSupport() &&
205 !(blendOpts & (GrDrawState::kEmitCoverage_BlendOptFlag |
206 GrDrawState::kCoverageAsAlpha_BlendOptFlag))) {
207 if (kZero_GrBlendCoeff == dstCoeff) {
208 // write the coverage value to second color
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000209 header->fCoverageOutput = kSecondaryCoverage_CoverageOutput;
210 separateCoverageFromColor = true;
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000211 } else if (kSA_GrBlendCoeff == dstCoeff) {
212 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000213 header->fCoverageOutput = kSecondaryCoverageISA_CoverageOutput;
214 separateCoverageFromColor = true;
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000215 } else if (kSC_GrBlendCoeff == dstCoeff) {
216 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000217 header->fCoverageOutput = kSecondaryCoverageISC_CoverageOutput;
218 separateCoverageFromColor = true;
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000219 }
bsalomon@google.com5920ac22013-04-19 13:14:45 +0000220 } else if (readsDst &&
bsalomon@google.com0c89db22013-05-15 17:53:04 +0000221 kOne_GrBlendCoeff == srcCoeff &&
222 kZero_GrBlendCoeff == dstCoeff) {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000223 header->fCoverageOutput = kCombineWithDst_CoverageOutput;
224 separateCoverageFromColor = true;
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000225 }
226 }
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000227 if (!skipColor) {
228 for (int s = 0; s < drawState.numColorStages(); ++s) {
229 colorStages->push_back(&drawState.getColorStage(s));
230 }
231 header->fColorEffectCnt = drawState.numColorStages();
232 }
233 if (!skipCoverage) {
234 SkTArray<const GrEffectStage*, true>* array;
235 if (separateCoverageFromColor) {
236 array = coverageStages;
237 header->fCoverageEffectCnt = drawState.numCoverageStages();
238 } else {
239 array = colorStages;
240 header->fColorEffectCnt += drawState.numCoverageStages();
241 }
242 for (int s = 0; s < drawState.numCoverageStages(); ++s) {
243 array->push_back(&drawState.getCoverageStage(s));
244 }
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000245 }
246
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000247 *desc->checksum() = 0;
248 *desc->checksum() = SkChecksum::Compute(reinterpret_cast<uint32_t*>(desc->fKey.get()),
249 newKeyLength);
250 desc->fInitialized = true;
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000251}
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000252
253GrGLProgramDesc& GrGLProgramDesc::operator= (const GrGLProgramDesc& other) {
254 fInitialized = other.fInitialized;
255 if (fInitialized) {
256 size_t keyLength = other.keyLength();
257 fKey.reset(keyLength);
258 memcpy(fKey.get(), other.fKey.get(), keyLength);
259 }
260 return *this;
261}