blob: ecd48e014810eb4158a452a256418bad0aaba159 [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) {
bsalomonf99f8842014-07-07 11:54:23 -070024 const GrEffect* effect = stage.getEffect();
bsalomon@google.comeb6879f2013-06-13 19:34:18 +000025 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,
commit-bot@chromium.org0a6fe712014-04-23 19:26:26 +000040 GrGpu::DrawType drawType,
bsalomon@google.com798c8c42013-03-27 19:50:27 +000041 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));
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +000059 int firstEffectiveColorStage = 0;
60 bool inputColorIsUsed = true;
61 if (!skipColor) {
62 firstEffectiveColorStage = drawState.numColorStages();
63 while (firstEffectiveColorStage > 0 && inputColorIsUsed) {
64 --firstEffectiveColorStage;
bsalomonf99f8842014-07-07 11:54:23 -070065 const GrEffect* effect = drawState.getColorStage(firstEffectiveColorStage).getEffect();
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +000066 inputColorIsUsed = effect->willUseInputColor();
67 }
68 }
69
70 int firstEffectiveCoverageStage = 0;
71 bool inputCoverageIsUsed = true;
72 if (!skipCoverage) {
73 firstEffectiveCoverageStage = drawState.numCoverageStages();
74 while (firstEffectiveCoverageStage > 0 && inputCoverageIsUsed) {
75 --firstEffectiveCoverageStage;
bsalomonf99f8842014-07-07 11:54:23 -070076 const GrEffect* effect = drawState.getCoverageStage(firstEffectiveCoverageStage).getEffect();
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +000077 inputCoverageIsUsed = effect->willUseInputColor();
78 }
79 }
bsalomon@google.com798c8c42013-03-27 19:50:27 +000080
81 // The descriptor is used as a cache key. Thus when a field of the
82 // descriptor will not affect program generation (because of the attribute
83 // bindings in use or other descriptor field settings) it should be set
84 // to a canonical value to avoid duplicate programs with different keys.
85
jvanverth@google.com054ae992013-04-01 20:06:51 +000086 bool requiresColorAttrib = !skipColor && drawState.hasColorVertexAttribute();
87 bool requiresCoverageAttrib = !skipCoverage && drawState.hasCoverageVertexAttribute();
88 // we only need the local coords if we're actually going to generate effect code
89 bool requiresLocalCoordAttrib = !(skipCoverage && skipColor) &&
90 drawState.hasLocalCoordAttribute();
bsalomon@google.com798c8c42013-03-27 19:50:27 +000091
bsalomon@google.com798c8c42013-03-27 19:50:27 +000092 bool colorIsTransBlack = SkToBool(blendOpts & GrDrawState::kEmitTransBlack_BlendOptFlag);
93 bool colorIsSolidWhite = (blendOpts & GrDrawState::kEmitCoverage_BlendOptFlag) ||
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +000094 (!requiresColorAttrib && 0xffffffff == drawState.getColor()) ||
95 (!inputColorIsUsed);
bsalomon@google.com2db3ded2013-05-22 14:34:04 +000096
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +000097 int numEffects = (skipColor ? 0 : (drawState.numColorStages() - firstEffectiveColorStage)) +
98 (skipCoverage ? 0 : (drawState.numCoverageStages() - firstEffectiveCoverageStage));
bsalomon@google.com798c8c42013-03-27 19:50:27 +000099
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000100 size_t newKeyLength = KeyLength(numEffects);
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000101 bool allocChanged;
102 desc->fKey.reset(newKeyLength, SkAutoMalloc::kAlloc_OnShrink, &allocChanged);
103 if (allocChanged || !desc->fInitialized) {
104 // make sure any padding in the header is zero if we we haven't used this allocation before.
105 memset(desc->header(), 0, kHeaderSize);
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000106 }
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000107 // write the key length
robertphillips@google.coma4662862013-11-21 14:24:16 +0000108 *desc->atOffset<uint32_t, kLengthOffset>() = SkToU32(newKeyLength);
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000109
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000110 KeyHeader* header = desc->header();
111 EffectKey* effectKeys = desc->effectKeys();
112
113 int currEffectKey = 0;
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000114 bool readsDst = false;
bsalomon@google.comb5158812013-05-13 18:50:25 +0000115 bool readFragPosition = false;
commit-bot@chromium.org0a6fe712014-04-23 19:26:26 +0000116 // We use vertexshader-less shader programs only when drawing paths.
117 bool hasVertexCode = !(GrGpu::kDrawPath_DrawType == drawType ||
118 GrGpu::kDrawPaths_DrawType == drawType);
119
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000120 if (!skipColor) {
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +0000121 for (int s = firstEffectiveColorStage; s < drawState.numColorStages(); ++s) {
skia.committer@gmail.com5c493d52013-06-14 07:00:49 +0000122 effectKeys[currEffectKey++] =
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000123 get_key_and_update_stats(drawState.getColorStage(s), gpu->glCaps(),
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000124 requiresLocalCoordAttrib, &readsDst, &readFragPosition,
125 &hasVertexCode);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000126 }
127 }
128 if (!skipCoverage) {
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +0000129 for (int s = firstEffectiveCoverageStage; s < drawState.numCoverageStages(); ++s) {
skia.committer@gmail.com5c493d52013-06-14 07:00:49 +0000130 effectKeys[currEffectKey++] =
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000131 get_key_and_update_stats(drawState.getCoverageStage(s), gpu->glCaps(),
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000132 requiresLocalCoordAttrib, &readsDst, &readFragPosition,
133 &hasVertexCode);
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000134 }
135 }
136
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000137 header->fHasVertexCode = hasVertexCode || requiresLocalCoordAttrib;
commit-bot@chromium.org0a6fe712014-04-23 19:26:26 +0000138 header->fEmitsPointSize = GrGpu::kDrawPoints_DrawType == drawType;
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000139
140 // Currently the experimental GS will only work with triangle prims (and it doesn't do anything
141 // other than pass through values from the VS to the FS anyway).
142#if GR_GL_EXPERIMENTAL_GS
143#if 0
144 header->fExperimentalGS = gpu->caps().geometryShaderSupport();
145#else
146 header->fExperimentalGS = false;
147#endif
148#endif
commit-bot@chromium.orgc4dc0ad2013-10-09 14:11:33 +0000149 bool defaultToUniformInputs = GR_GL_NO_CONSTANT_ATTRIBUTES || gpu->caps()->pathRenderingSupport();
150
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000151 if (colorIsTransBlack) {
152 header->fColorInput = kTransBlack_ColorInput;
153 } else if (colorIsSolidWhite) {
154 header->fColorInput = kSolidWhite_ColorInput;
commit-bot@chromium.orgc4dc0ad2013-10-09 14:11:33 +0000155 } else if (defaultToUniformInputs && !requiresColorAttrib) {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000156 header->fColorInput = kUniform_ColorInput;
157 } else {
158 header->fColorInput = kAttribute_ColorInput;
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000159 header->fHasVertexCode = true;
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000160 }
161
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000162 bool covIsSolidWhite = !requiresCoverageAttrib && 0xffffffff == drawState.getCoverageColor();
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000163
164 if (skipCoverage) {
165 header->fCoverageInput = kTransBlack_ColorInput;
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +0000166 } else if (covIsSolidWhite || !inputCoverageIsUsed) {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000167 header->fCoverageInput = kSolidWhite_ColorInput;
commit-bot@chromium.orgc4dc0ad2013-10-09 14:11:33 +0000168 } else if (defaultToUniformInputs && !requiresCoverageAttrib) {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000169 header->fCoverageInput = kUniform_ColorInput;
170 } else {
171 header->fCoverageInput = kAttribute_ColorInput;
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000172 header->fHasVertexCode = true;
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000173 }
174
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000175 if (readsDst) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000176 SkASSERT(NULL != dstCopy || gpu->caps()->dstReadInShaderSupport());
bsalomon@google.com6b0cf022013-05-03 13:35:14 +0000177 const GrTexture* dstCopyTexture = NULL;
178 if (NULL != dstCopy) {
179 dstCopyTexture = dstCopy->texture();
180 }
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000181 header->fDstReadKey = GrGLShaderBuilder::KeyForDstRead(dstCopyTexture, gpu->glCaps());
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000182 SkASSERT(0 != header->fDstReadKey);
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000183 } else {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000184 header->fDstReadKey = 0;
bsalomon@google.comb5158812013-05-13 18:50:25 +0000185 }
186
187 if (readFragPosition) {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000188 header->fFragPosKey = GrGLShaderBuilder::KeyForFragmentPosition(drawState.getRenderTarget(),
bsalomon@google.comb5158812013-05-13 18:50:25 +0000189 gpu->glCaps());
190 } else {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000191 header->fFragPosKey = 0;
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000192 }
193
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000194 // Record attribute indices
195 header->fPositionAttributeIndex = drawState.positionAttributeIndex();
196 header->fLocalCoordAttributeIndex = drawState.localCoordAttributeIndex();
skia.committer@gmail.com2d816ad2013-05-23 07:01:22 +0000197
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000198 // For constant color and coverage we need an attribute with an index beyond those already set
199 int availableAttributeIndex = drawState.getVertexAttribCount();
200 if (requiresColorAttrib) {
201 header->fColorAttributeIndex = drawState.colorVertexAttributeIndex();
202 } else if (GrGLProgramDesc::kAttribute_ColorInput == header->fColorInput) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000203 SkASSERT(availableAttributeIndex < GrDrawState::kMaxVertexAttribCnt);
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000204 header->fColorAttributeIndex = availableAttributeIndex;
205 availableAttributeIndex++;
206 } else {
207 header->fColorAttributeIndex = -1;
208 }
skia.committer@gmail.com2d816ad2013-05-23 07:01:22 +0000209
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000210 if (requiresCoverageAttrib) {
211 header->fCoverageAttributeIndex = drawState.coverageVertexAttributeIndex();
212 } else if (GrGLProgramDesc::kAttribute_ColorInput == header->fCoverageInput) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000213 SkASSERT(availableAttributeIndex < GrDrawState::kMaxVertexAttribCnt);
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000214 header->fCoverageAttributeIndex = availableAttributeIndex;
215 } else {
216 header->fCoverageAttributeIndex = -1;
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000217 }
218
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000219 // Here we deal with whether/how we handle color and coverage separately.
skia.committer@gmail.com2d816ad2013-05-23 07:01:22 +0000220
commit-bot@chromium.org8a135882014-02-05 16:29:12 +0000221 // Set this default and then possibly change our mind if there is coverage.
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000222 header->fCoverageOutput = kModulate_CoverageOutput;
223
224 // If we do have coverage determine whether it matters.
225 bool separateCoverageFromColor = false;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000226 if (!drawState.isCoverageDrawing() && !skipCoverage &&
227 (drawState.numCoverageStages() > 0 || requiresCoverageAttrib)) {
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000228
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000229 if (gpu->caps()->dualSourceBlendingSupport() &&
230 !(blendOpts & (GrDrawState::kEmitCoverage_BlendOptFlag |
231 GrDrawState::kCoverageAsAlpha_BlendOptFlag))) {
232 if (kZero_GrBlendCoeff == dstCoeff) {
233 // write the coverage value to second color
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000234 header->fCoverageOutput = kSecondaryCoverage_CoverageOutput;
235 separateCoverageFromColor = true;
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000236 } else if (kSA_GrBlendCoeff == dstCoeff) {
237 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000238 header->fCoverageOutput = kSecondaryCoverageISA_CoverageOutput;
239 separateCoverageFromColor = true;
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000240 } else if (kSC_GrBlendCoeff == dstCoeff) {
241 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000242 header->fCoverageOutput = kSecondaryCoverageISC_CoverageOutput;
243 separateCoverageFromColor = true;
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000244 }
bsalomon@google.com5920ac22013-04-19 13:14:45 +0000245 } else if (readsDst &&
bsalomon@google.com0c89db22013-05-15 17:53:04 +0000246 kOne_GrBlendCoeff == srcCoeff &&
247 kZero_GrBlendCoeff == dstCoeff) {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000248 header->fCoverageOutput = kCombineWithDst_CoverageOutput;
249 separateCoverageFromColor = true;
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000250 }
251 }
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000252 if (!skipColor) {
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +0000253 for (int s = firstEffectiveColorStage; s < drawState.numColorStages(); ++s) {
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000254 colorStages->push_back(&drawState.getColorStage(s));
255 }
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000256 }
257 if (!skipCoverage) {
258 SkTArray<const GrEffectStage*, true>* array;
259 if (separateCoverageFromColor) {
260 array = coverageStages;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000261 } else {
262 array = colorStages;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000263 }
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +0000264 for (int s = firstEffectiveCoverageStage; s < drawState.numCoverageStages(); ++s) {
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000265 array->push_back(&drawState.getCoverageStage(s));
266 }
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000267 }
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +0000268 header->fColorEffectCnt = colorStages->count();
269 header->fCoverageEffectCnt = coverageStages->count();
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000270
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000271 *desc->checksum() = 0;
272 *desc->checksum() = SkChecksum::Compute(reinterpret_cast<uint32_t*>(desc->fKey.get()),
273 newKeyLength);
274 desc->fInitialized = true;
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000275}
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000276
277GrGLProgramDesc& GrGLProgramDesc::operator= (const GrGLProgramDesc& other) {
278 fInitialized = other.fInitialized;
279 if (fInitialized) {
280 size_t keyLength = other.keyLength();
281 fKey.reset(keyLength);
282 memcpy(fKey.get(), other.fKey.get(), keyLength);
283 }
284 return *this;
285}