blob: 8b731fbc2c71244e80a6f6dc87262280e31e214a [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,
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +000022 bool* setTrueIfReadsPos,
23 bool* setTrueIfHasVertexCode) {
bsalomon@google.comeb6879f2013-06-13 19:34:18 +000024 const GrEffectRef& effect = *stage.getEffect();
25 const GrBackendEffectFactory& factory = effect->getFactory();
26 GrDrawEffect drawEffect(stage, useExplicitLocalCoords);
27 if (effect->willReadDstColor()) {
28 *setTrueIfReadsDst = true;
29 }
30 if (effect->willReadFragmentPosition()) {
31 *setTrueIfReadsPos = true;
32 }
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +000033 if (effect->hasVertexCode()) {
34 *setTrueIfHasVertexCode = true;
35 }
bsalomon@google.comeb6879f2013-06-13 19:34:18 +000036 return factory.glEffectKey(drawEffect, caps);
37}
38}
bsalomon@google.com798c8c42013-03-27 19:50:27 +000039void GrGLProgramDesc::Build(const GrDrawState& drawState,
40 bool isPoints,
41 GrDrawState::BlendOptFlags blendOpts,
42 GrBlendCoeff srcCoeff,
43 GrBlendCoeff dstCoeff,
44 const GrGpuGL* gpu,
bsalomon@google.com26e18b52013-03-29 19:22:36 +000045 const GrDeviceCoordTexture* dstCopy,
bsalomon@google.com2c84aa32013-06-06 20:28:57 +000046 SkTArray<const GrEffectStage*, true>* colorStages,
47 SkTArray<const GrEffectStage*, true>* coverageStages,
bsalomon@google.com798c8c42013-03-27 19:50:27 +000048 GrGLProgramDesc* desc) {
bsalomon@google.com2c84aa32013-06-06 20:28:57 +000049 colorStages->reset();
50 coverageStages->reset();
51
bsalomon@google.com798c8c42013-03-27 19:50:27 +000052 // This should already have been caught
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +000053 SkASSERT(!(GrDrawState::kSkipDraw_BlendOptFlag & blendOpts));
bsalomon@google.com798c8c42013-03-27 19:50:27 +000054
55 bool skipCoverage = SkToBool(blendOpts & GrDrawState::kEmitTransBlack_BlendOptFlag);
56
57 bool skipColor = SkToBool(blendOpts & (GrDrawState::kEmitTransBlack_BlendOptFlag |
58 GrDrawState::kEmitCoverage_BlendOptFlag));
59
60 // The descriptor is used as a cache key. Thus when a field of the
61 // descriptor will not affect program generation (because of the attribute
62 // bindings in use or other descriptor field settings) it should be set
63 // to a canonical value to avoid duplicate programs with different keys.
64
jvanverth@google.com054ae992013-04-01 20:06:51 +000065 bool requiresColorAttrib = !skipColor && drawState.hasColorVertexAttribute();
66 bool requiresCoverageAttrib = !skipCoverage && drawState.hasCoverageVertexAttribute();
67 // we only need the local coords if we're actually going to generate effect code
68 bool requiresLocalCoordAttrib = !(skipCoverage && skipColor) &&
69 drawState.hasLocalCoordAttribute();
bsalomon@google.com798c8c42013-03-27 19:50:27 +000070
bsalomon@google.com798c8c42013-03-27 19:50:27 +000071 bool colorIsTransBlack = SkToBool(blendOpts & GrDrawState::kEmitTransBlack_BlendOptFlag);
72 bool colorIsSolidWhite = (blendOpts & GrDrawState::kEmitCoverage_BlendOptFlag) ||
jvanverth@google.com054ae992013-04-01 20:06:51 +000073 (!requiresColorAttrib && 0xffffffff == drawState.getColor());
bsalomon@google.com2db3ded2013-05-22 14:34:04 +000074
bsalomon@google.comeb6879f2013-06-13 19:34:18 +000075 int numEffects = (skipColor ? 0 : drawState.numColorStages()) +
76 (skipCoverage ? 0 : drawState.numCoverageStages());
bsalomon@google.com798c8c42013-03-27 19:50:27 +000077
bsalomon@google.comeb6879f2013-06-13 19:34:18 +000078 size_t newKeyLength = KeyLength(numEffects);
bsalomon@google.com2db3ded2013-05-22 14:34:04 +000079 bool allocChanged;
80 desc->fKey.reset(newKeyLength, SkAutoMalloc::kAlloc_OnShrink, &allocChanged);
81 if (allocChanged || !desc->fInitialized) {
82 // make sure any padding in the header is zero if we we haven't used this allocation before.
83 memset(desc->header(), 0, kHeaderSize);
bsalomon@google.com798c8c42013-03-27 19:50:27 +000084 }
bsalomon@google.com2db3ded2013-05-22 14:34:04 +000085 // write the key length
86 *desc->atOffset<uint32_t, kLengthOffset>() = newKeyLength;
bsalomon@google.com798c8c42013-03-27 19:50:27 +000087
bsalomon@google.com2db3ded2013-05-22 14:34:04 +000088 KeyHeader* header = desc->header();
89 EffectKey* effectKeys = desc->effectKeys();
90
91 int currEffectKey = 0;
bsalomon@google.com26e18b52013-03-29 19:22:36 +000092 bool readsDst = false;
bsalomon@google.comb5158812013-05-13 18:50:25 +000093 bool readFragPosition = false;
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +000094 bool hasVertexCode = false;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +000095 if (!skipColor) {
96 for (int s = 0; s < drawState.numColorStages(); ++s) {
skia.committer@gmail.com5c493d52013-06-14 07:00:49 +000097 effectKeys[currEffectKey++] =
bsalomon@google.comeb6879f2013-06-13 19:34:18 +000098 get_key_and_update_stats(drawState.getColorStage(s), gpu->glCaps(),
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +000099 requiresLocalCoordAttrib, &readsDst, &readFragPosition,
100 &hasVertexCode);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000101 }
102 }
103 if (!skipCoverage) {
104 for (int s = 0; s < drawState.numCoverageStages(); ++s) {
skia.committer@gmail.com5c493d52013-06-14 07:00:49 +0000105 effectKeys[currEffectKey++] =
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000106 get_key_and_update_stats(drawState.getCoverageStage(s), gpu->glCaps(),
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000107 requiresLocalCoordAttrib, &readsDst, &readFragPosition,
108 &hasVertexCode);
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000109 }
110 }
111
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000112 header->fHasVertexCode = hasVertexCode || requiresLocalCoordAttrib;
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000113 header->fEmitsPointSize = isPoints;
114 header->fColorFilterXfermode = skipColor ? SkXfermode::kDst_Mode : drawState.getColorFilterMode();
115
116 // Currently the experimental GS will only work with triangle prims (and it doesn't do anything
117 // other than pass through values from the VS to the FS anyway).
118#if GR_GL_EXPERIMENTAL_GS
119#if 0
120 header->fExperimentalGS = gpu->caps().geometryShaderSupport();
121#else
122 header->fExperimentalGS = false;
123#endif
124#endif
125 if (colorIsTransBlack) {
126 header->fColorInput = kTransBlack_ColorInput;
127 } else if (colorIsSolidWhite) {
128 header->fColorInput = kSolidWhite_ColorInput;
129 } else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresColorAttrib) {
130 header->fColorInput = kUniform_ColorInput;
131 } else {
132 header->fColorInput = kAttribute_ColorInput;
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000133 header->fHasVertexCode = true;
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000134 }
135
136 bool covIsSolidWhite = !requiresCoverageAttrib && 0xffffffff == drawState.getCoverage();
137
138 if (skipCoverage) {
139 header->fCoverageInput = kTransBlack_ColorInput;
140 } else if (covIsSolidWhite) {
141 header->fCoverageInput = kSolidWhite_ColorInput;
142 } else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresCoverageAttrib) {
143 header->fCoverageInput = kUniform_ColorInput;
144 } else {
145 header->fCoverageInput = kAttribute_ColorInput;
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000146 header->fHasVertexCode = true;
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000147 }
148
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000149 if (readsDst) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000150 SkASSERT(NULL != dstCopy || gpu->caps()->dstReadInShaderSupport());
bsalomon@google.com6b0cf022013-05-03 13:35:14 +0000151 const GrTexture* dstCopyTexture = NULL;
152 if (NULL != dstCopy) {
153 dstCopyTexture = dstCopy->texture();
154 }
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000155 header->fDstReadKey = GrGLShaderBuilder::KeyForDstRead(dstCopyTexture, gpu->glCaps());
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000156 SkASSERT(0 != header->fDstReadKey);
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000157 } else {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000158 header->fDstReadKey = 0;
bsalomon@google.comb5158812013-05-13 18:50:25 +0000159 }
160
161 if (readFragPosition) {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000162 header->fFragPosKey = GrGLShaderBuilder::KeyForFragmentPosition(drawState.getRenderTarget(),
bsalomon@google.comb5158812013-05-13 18:50:25 +0000163 gpu->glCaps());
164 } else {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000165 header->fFragPosKey = 0;
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000166 }
167
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000168 // Record attribute indices
169 header->fPositionAttributeIndex = drawState.positionAttributeIndex();
170 header->fLocalCoordAttributeIndex = drawState.localCoordAttributeIndex();
skia.committer@gmail.com2d816ad2013-05-23 07:01:22 +0000171
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000172 // For constant color and coverage we need an attribute with an index beyond those already set
173 int availableAttributeIndex = drawState.getVertexAttribCount();
174 if (requiresColorAttrib) {
175 header->fColorAttributeIndex = drawState.colorVertexAttributeIndex();
176 } else if (GrGLProgramDesc::kAttribute_ColorInput == header->fColorInput) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000177 SkASSERT(availableAttributeIndex < GrDrawState::kMaxVertexAttribCnt);
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000178 header->fColorAttributeIndex = availableAttributeIndex;
179 availableAttributeIndex++;
180 } else {
181 header->fColorAttributeIndex = -1;
182 }
skia.committer@gmail.com2d816ad2013-05-23 07:01:22 +0000183
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000184 if (requiresCoverageAttrib) {
185 header->fCoverageAttributeIndex = drawState.coverageVertexAttributeIndex();
186 } else if (GrGLProgramDesc::kAttribute_ColorInput == header->fCoverageInput) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000187 SkASSERT(availableAttributeIndex < GrDrawState::kMaxVertexAttribCnt);
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000188 header->fCoverageAttributeIndex = availableAttributeIndex;
189 } else {
190 header->fCoverageAttributeIndex = -1;
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000191 }
192
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000193 // Here we deal with whether/how we handle color and coverage separately.
skia.committer@gmail.com2d816ad2013-05-23 07:01:22 +0000194
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000195 // Set these defaults and then possibly change our mind if there is coverage.
196 header->fDiscardIfZeroCoverage = false;
197 header->fCoverageOutput = kModulate_CoverageOutput;
198
199 // If we do have coverage determine whether it matters.
200 bool separateCoverageFromColor = false;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000201 if (!drawState.isCoverageDrawing() && !skipCoverage &&
202 (drawState.numCoverageStages() > 0 || requiresCoverageAttrib)) {
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000203 // color filter is applied between color/coverage computation
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000204 if (SkXfermode::kDst_Mode != header->fColorFilterXfermode) {
205 separateCoverageFromColor = true;
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000206 }
207
208 // If we're stenciling then we want to discard samples that have zero coverage
209 if (drawState.getStencil().doesWrite()) {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000210 header->fDiscardIfZeroCoverage = true;
211 separateCoverageFromColor = true;
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000212 }
213
214 if (gpu->caps()->dualSourceBlendingSupport() &&
215 !(blendOpts & (GrDrawState::kEmitCoverage_BlendOptFlag |
216 GrDrawState::kCoverageAsAlpha_BlendOptFlag))) {
217 if (kZero_GrBlendCoeff == dstCoeff) {
218 // write the coverage value to second color
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000219 header->fCoverageOutput = kSecondaryCoverage_CoverageOutput;
220 separateCoverageFromColor = true;
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000221 } else if (kSA_GrBlendCoeff == dstCoeff) {
222 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000223 header->fCoverageOutput = kSecondaryCoverageISA_CoverageOutput;
224 separateCoverageFromColor = true;
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000225 } else if (kSC_GrBlendCoeff == dstCoeff) {
226 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000227 header->fCoverageOutput = kSecondaryCoverageISC_CoverageOutput;
228 separateCoverageFromColor = true;
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000229 }
bsalomon@google.com5920ac22013-04-19 13:14:45 +0000230 } else if (readsDst &&
bsalomon@google.com0c89db22013-05-15 17:53:04 +0000231 kOne_GrBlendCoeff == srcCoeff &&
232 kZero_GrBlendCoeff == dstCoeff) {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000233 header->fCoverageOutput = kCombineWithDst_CoverageOutput;
234 separateCoverageFromColor = true;
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000235 }
236 }
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000237 if (!skipColor) {
238 for (int s = 0; s < drawState.numColorStages(); ++s) {
239 colorStages->push_back(&drawState.getColorStage(s));
240 }
241 header->fColorEffectCnt = drawState.numColorStages();
242 }
243 if (!skipCoverage) {
244 SkTArray<const GrEffectStage*, true>* array;
245 if (separateCoverageFromColor) {
246 array = coverageStages;
247 header->fCoverageEffectCnt = drawState.numCoverageStages();
248 } else {
249 array = colorStages;
250 header->fColorEffectCnt += drawState.numCoverageStages();
251 }
252 for (int s = 0; s < drawState.numCoverageStages(); ++s) {
253 array->push_back(&drawState.getCoverageStage(s));
254 }
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000255 }
256
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000257 *desc->checksum() = 0;
258 *desc->checksum() = SkChecksum::Compute(reinterpret_cast<uint32_t*>(desc->fKey.get()),
259 newKeyLength);
260 desc->fInitialized = true;
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000261}
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000262
263GrGLProgramDesc& GrGLProgramDesc::operator= (const GrGLProgramDesc& other) {
264 fInitialized = other.fInitialized;
265 if (fInitialized) {
266 size_t keyLength = other.keyLength();
267 fKey.reset(keyLength);
268 memcpy(fKey.get(), other.fKey.get(), keyLength);
269 }
270 return *this;
271}