blob: 4f0011803c7d67d527386d5e39674614a605b89b [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.com798c8c42013-03-27 19:50:27 +000017void GrGLProgramDesc::Build(const GrDrawState& drawState,
18 bool isPoints,
19 GrDrawState::BlendOptFlags blendOpts,
20 GrBlendCoeff srcCoeff,
21 GrBlendCoeff dstCoeff,
22 const GrGpuGL* gpu,
bsalomon@google.com26e18b52013-03-29 19:22:36 +000023 const GrDeviceCoordTexture* dstCopy,
bsalomon@google.com2c84aa32013-06-06 20:28:57 +000024 SkTArray<const GrEffectStage*, true>* colorStages,
25 SkTArray<const GrEffectStage*, true>* coverageStages,
bsalomon@google.com798c8c42013-03-27 19:50:27 +000026 GrGLProgramDesc* desc) {
bsalomon@google.com2c84aa32013-06-06 20:28:57 +000027 colorStages->reset();
28 coverageStages->reset();
29
bsalomon@google.com798c8c42013-03-27 19:50:27 +000030 // This should already have been caught
31 GrAssert(!(GrDrawState::kSkipDraw_BlendOptFlag & blendOpts));
32
33 bool skipCoverage = SkToBool(blendOpts & GrDrawState::kEmitTransBlack_BlendOptFlag);
34
35 bool skipColor = SkToBool(blendOpts & (GrDrawState::kEmitTransBlack_BlendOptFlag |
36 GrDrawState::kEmitCoverage_BlendOptFlag));
37
38 // The descriptor is used as a cache key. Thus when a field of the
39 // descriptor will not affect program generation (because of the attribute
40 // bindings in use or other descriptor field settings) it should be set
41 // to a canonical value to avoid duplicate programs with different keys.
42
jvanverth@google.com054ae992013-04-01 20:06:51 +000043 bool requiresColorAttrib = !skipColor && drawState.hasColorVertexAttribute();
44 bool requiresCoverageAttrib = !skipCoverage && drawState.hasCoverageVertexAttribute();
45 // we only need the local coords if we're actually going to generate effect code
46 bool requiresLocalCoordAttrib = !(skipCoverage && skipColor) &&
47 drawState.hasLocalCoordAttribute();
bsalomon@google.com798c8c42013-03-27 19:50:27 +000048
bsalomon@google.com798c8c42013-03-27 19:50:27 +000049 bool colorIsTransBlack = SkToBool(blendOpts & GrDrawState::kEmitTransBlack_BlendOptFlag);
50 bool colorIsSolidWhite = (blendOpts & GrDrawState::kEmitCoverage_BlendOptFlag) ||
jvanverth@google.com054ae992013-04-01 20:06:51 +000051 (!requiresColorAttrib && 0xffffffff == drawState.getColor());
bsalomon@google.com2db3ded2013-05-22 14:34:04 +000052
53 // Do an initial loop over the stages to count them. We count the color and coverage effects
54 // separately here. Later we may decide the distinction doesn't matter and will count all
55 // effects as color in desc. Two things will allow simplication of this mess: GrDrawState will
56 // have tight lists of color and coverage stages rather than a fixed size array with NULLS and
57 // the xfermode-color filter will be removed.
bsalomon@google.com2db3ded2013-05-22 14:34:04 +000058 if (!skipColor) {
59 for (int s = 0; s < drawState.getFirstCoverageStage(); ++s) {
60 if (drawState.isStageEnabled(s)) {
bsalomon@google.com2c84aa32013-06-06 20:28:57 +000061 colorStages->push_back(&drawState.getStage(s));
bsalomon@google.com2db3ded2013-05-22 14:34:04 +000062 }
63 }
64 }
65 if (!skipCoverage) {
66 for (int s = drawState.getFirstCoverageStage(); s < GrDrawState::kNumStages; ++s) {
67 if (drawState.isStageEnabled(s)) {
bsalomon@google.com2c84aa32013-06-06 20:28:57 +000068 coverageStages->push_back(&drawState.getStage(s));
bsalomon@google.com2db3ded2013-05-22 14:34:04 +000069 }
70 }
bsalomon@google.com798c8c42013-03-27 19:50:27 +000071 }
72
bsalomon@google.com2c84aa32013-06-06 20:28:57 +000073 size_t newKeyLength = KeyLength(colorStages->count() + coverageStages->count());
bsalomon@google.com2db3ded2013-05-22 14:34:04 +000074 bool allocChanged;
75 desc->fKey.reset(newKeyLength, SkAutoMalloc::kAlloc_OnShrink, &allocChanged);
76 if (allocChanged || !desc->fInitialized) {
77 // make sure any padding in the header is zero if we we haven't used this allocation before.
78 memset(desc->header(), 0, kHeaderSize);
bsalomon@google.com798c8c42013-03-27 19:50:27 +000079 }
bsalomon@google.com2db3ded2013-05-22 14:34:04 +000080 // write the key length
81 *desc->atOffset<uint32_t, kLengthOffset>() = newKeyLength;
bsalomon@google.com798c8c42013-03-27 19:50:27 +000082
bsalomon@google.com2db3ded2013-05-22 14:34:04 +000083 KeyHeader* header = desc->header();
84 EffectKey* effectKeys = desc->effectKeys();
85
86 int currEffectKey = 0;
bsalomon@google.com26e18b52013-03-29 19:22:36 +000087 bool readsDst = false;
bsalomon@google.comb5158812013-05-13 18:50:25 +000088 bool readFragPosition = false;
bsalomon@google.com798c8c42013-03-27 19:50:27 +000089 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com798c8c42013-03-27 19:50:27 +000090 bool skip = s < drawState.getFirstCoverageStage() ? skipColor : skipCoverage;
91 if (!skip && drawState.isStageEnabled(s)) {
bsalomon@google.com798c8c42013-03-27 19:50:27 +000092 const GrEffectRef& effect = *drawState.getStage(s).getEffect();
93 const GrBackendEffectFactory& factory = effect->getFactory();
jvanverth@google.com054ae992013-04-01 20:06:51 +000094 GrDrawEffect drawEffect(drawState.getStage(s), requiresLocalCoordAttrib);
bsalomon@google.com2db3ded2013-05-22 14:34:04 +000095 effectKeys[currEffectKey] = factory.glEffectKey(drawEffect, gpu->glCaps());
96 ++currEffectKey;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +000097 if (effect->willReadDstColor()) {
bsalomon@google.com26e18b52013-03-29 19:22:36 +000098 readsDst = true;
99 }
bsalomon@google.comb5158812013-05-13 18:50:25 +0000100 if (effect->willReadFragmentPosition()) {
101 readFragPosition = true;
102 }
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000103 }
104 }
105
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000106 header->fEmitsPointSize = isPoints;
107 header->fColorFilterXfermode = skipColor ? SkXfermode::kDst_Mode : drawState.getColorFilterMode();
108
109 // Currently the experimental GS will only work with triangle prims (and it doesn't do anything
110 // other than pass through values from the VS to the FS anyway).
111#if GR_GL_EXPERIMENTAL_GS
112#if 0
113 header->fExperimentalGS = gpu->caps().geometryShaderSupport();
114#else
115 header->fExperimentalGS = false;
116#endif
117#endif
118 if (colorIsTransBlack) {
119 header->fColorInput = kTransBlack_ColorInput;
120 } else if (colorIsSolidWhite) {
121 header->fColorInput = kSolidWhite_ColorInput;
122 } else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresColorAttrib) {
123 header->fColorInput = kUniform_ColorInput;
124 } else {
125 header->fColorInput = kAttribute_ColorInput;
126 }
127
128 bool covIsSolidWhite = !requiresCoverageAttrib && 0xffffffff == drawState.getCoverage();
129
130 if (skipCoverage) {
131 header->fCoverageInput = kTransBlack_ColorInput;
132 } else if (covIsSolidWhite) {
133 header->fCoverageInput = kSolidWhite_ColorInput;
134 } else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresCoverageAttrib) {
135 header->fCoverageInput = kUniform_ColorInput;
136 } else {
137 header->fCoverageInput = kAttribute_ColorInput;
138 }
139
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000140 if (readsDst) {
bsalomon@google.com6b0cf022013-05-03 13:35:14 +0000141 GrAssert(NULL != dstCopy || gpu->caps()->dstReadInShaderSupport());
142 const GrTexture* dstCopyTexture = NULL;
143 if (NULL != dstCopy) {
144 dstCopyTexture = dstCopy->texture();
145 }
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000146 header->fDstReadKey = GrGLShaderBuilder::KeyForDstRead(dstCopyTexture, gpu->glCaps());
147 GrAssert(0 != header->fDstReadKey);
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000148 } else {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000149 header->fDstReadKey = 0;
bsalomon@google.comb5158812013-05-13 18:50:25 +0000150 }
151
152 if (readFragPosition) {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000153 header->fFragPosKey = GrGLShaderBuilder::KeyForFragmentPosition(drawState.getRenderTarget(),
bsalomon@google.comb5158812013-05-13 18:50:25 +0000154 gpu->glCaps());
155 } else {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000156 header->fFragPosKey = 0;
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000157 }
158
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000159 // Record attribute indices
160 header->fPositionAttributeIndex = drawState.positionAttributeIndex();
161 header->fLocalCoordAttributeIndex = drawState.localCoordAttributeIndex();
skia.committer@gmail.com2d816ad2013-05-23 07:01:22 +0000162
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000163 // For constant color and coverage we need an attribute with an index beyond those already set
164 int availableAttributeIndex = drawState.getVertexAttribCount();
165 if (requiresColorAttrib) {
166 header->fColorAttributeIndex = drawState.colorVertexAttributeIndex();
167 } else if (GrGLProgramDesc::kAttribute_ColorInput == header->fColorInput) {
168 GrAssert(availableAttributeIndex < GrDrawState::kMaxVertexAttribCnt);
169 header->fColorAttributeIndex = availableAttributeIndex;
170 availableAttributeIndex++;
171 } else {
172 header->fColorAttributeIndex = -1;
173 }
skia.committer@gmail.com2d816ad2013-05-23 07:01:22 +0000174
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000175 if (requiresCoverageAttrib) {
176 header->fCoverageAttributeIndex = drawState.coverageVertexAttributeIndex();
177 } else if (GrGLProgramDesc::kAttribute_ColorInput == header->fCoverageInput) {
178 GrAssert(availableAttributeIndex < GrDrawState::kMaxVertexAttribCnt);
179 header->fCoverageAttributeIndex = availableAttributeIndex;
180 } else {
181 header->fCoverageAttributeIndex = -1;
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000182 }
183
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000184 // Here we deal with whether/how we handle color and coverage separately.
skia.committer@gmail.com2d816ad2013-05-23 07:01:22 +0000185
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000186 // Set these defaults and then possibly change our mind if there is coverage.
187 header->fDiscardIfZeroCoverage = false;
188 header->fCoverageOutput = kModulate_CoverageOutput;
189
190 // If we do have coverage determine whether it matters.
191 bool separateCoverageFromColor = false;
bsalomon@google.com2c84aa32013-06-06 20:28:57 +0000192 if (!drawState.isCoverageDrawing() && (coverageStages->count() > 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.com2db3ded2013-05-22 14:34:04 +0000227 if (separateCoverageFromColor) {
bsalomon@google.com2c84aa32013-06-06 20:28:57 +0000228 header->fColorEffectCnt = colorStages->count();
229 header->fCoverageEffectCnt = coverageStages->count();
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000230 } else {
bsalomon@google.com2c84aa32013-06-06 20:28:57 +0000231 header->fColorEffectCnt = colorStages->count() + coverageStages->count();
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000232 header->fCoverageEffectCnt = 0;
bsalomon@google.com2c84aa32013-06-06 20:28:57 +0000233 colorStages->push_back_n(coverageStages->count(), coverageStages->begin());
234 coverageStages->reset();
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000235 }
236
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000237 *desc->checksum() = 0;
238 *desc->checksum() = SkChecksum::Compute(reinterpret_cast<uint32_t*>(desc->fKey.get()),
239 newKeyLength);
240 desc->fInitialized = true;
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000241}
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000242
243GrGLProgramDesc& GrGLProgramDesc::operator= (const GrGLProgramDesc& other) {
244 fInitialized = other.fInitialized;
245 if (fInitialized) {
246 size_t keyLength = other.keyLength();
247 fKey.reset(keyLength);
248 memcpy(fKey.get(), other.fKey.get(), keyLength);
249 }
250 return *this;
251}