blob: 2c260cda52b16e3808fc03534b76e6d640ef49fc [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
bsalomon848faf02014-07-11 10:01:02 -070017static inline bool get_key_and_update_stats(const GrEffectStage& stage,
18 const GrGLCaps& caps,
19 bool useExplicitLocalCoords,
20 GrEffectKeyBuilder* b,
21 bool* setTrueIfReadsDst,
22 bool* setTrueIfReadsPos,
23 bool* setTrueIfHasVertexCode) {
24 const GrBackendEffectFactory& factory = stage.getEffect()->getFactory();
bsalomon@google.comeb6879f2013-06-13 19:34:18 +000025 GrDrawEffect drawEffect(stage, useExplicitLocalCoords);
bsalomon848faf02014-07-11 10:01:02 -070026 if (stage.getEffect()->willReadDstColor()) {
bsalomon@google.comeb6879f2013-06-13 19:34:18 +000027 *setTrueIfReadsDst = true;
28 }
bsalomon848faf02014-07-11 10:01:02 -070029 if (stage.getEffect()->willReadFragmentPosition()) {
bsalomon@google.comeb6879f2013-06-13 19:34:18 +000030 *setTrueIfReadsPos = true;
31 }
bsalomon848faf02014-07-11 10:01:02 -070032 if (stage.getEffect()->hasVertexCode()) {
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +000033 *setTrueIfHasVertexCode = true;
34 }
bsalomon848faf02014-07-11 10:01:02 -070035 return factory.getGLEffectKey(drawEffect, caps, b);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +000036}
bsalomon848faf02014-07-11 10:01:02 -070037
38bool GrGLProgramDesc::Build(const GrDrawState& drawState,
commit-bot@chromium.org0a6fe712014-04-23 19:26:26 +000039 GrGpu::DrawType drawType,
bsalomon@google.com798c8c42013-03-27 19:50:27 +000040 GrDrawState::BlendOptFlags blendOpts,
41 GrBlendCoeff srcCoeff,
42 GrBlendCoeff dstCoeff,
43 const GrGpuGL* gpu,
bsalomon@google.com26e18b52013-03-29 19:22:36 +000044 const GrDeviceCoordTexture* dstCopy,
bsalomon@google.com2c84aa32013-06-06 20:28:57 +000045 SkTArray<const GrEffectStage*, true>* colorStages,
46 SkTArray<const GrEffectStage*, true>* coverageStages,
bsalomon@google.com798c8c42013-03-27 19:50:27 +000047 GrGLProgramDesc* desc) {
bsalomon@google.com2c84aa32013-06-06 20:28:57 +000048 colorStages->reset();
49 coverageStages->reset();
50
bsalomon@google.com798c8c42013-03-27 19:50:27 +000051 // This should already have been caught
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +000052 SkASSERT(!(GrDrawState::kSkipDraw_BlendOptFlag & blendOpts));
bsalomon@google.com798c8c42013-03-27 19:50:27 +000053
54 bool skipCoverage = SkToBool(blendOpts & GrDrawState::kEmitTransBlack_BlendOptFlag);
55
56 bool skipColor = SkToBool(blendOpts & (GrDrawState::kEmitTransBlack_BlendOptFlag |
57 GrDrawState::kEmitCoverage_BlendOptFlag));
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +000058 int firstEffectiveColorStage = 0;
59 bool inputColorIsUsed = true;
60 if (!skipColor) {
61 firstEffectiveColorStage = drawState.numColorStages();
62 while (firstEffectiveColorStage > 0 && inputColorIsUsed) {
63 --firstEffectiveColorStage;
bsalomonf99f8842014-07-07 11:54:23 -070064 const GrEffect* effect = drawState.getColorStage(firstEffectiveColorStage).getEffect();
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +000065 inputColorIsUsed = effect->willUseInputColor();
66 }
67 }
68
69 int firstEffectiveCoverageStage = 0;
70 bool inputCoverageIsUsed = true;
71 if (!skipCoverage) {
72 firstEffectiveCoverageStage = drawState.numCoverageStages();
73 while (firstEffectiveCoverageStage > 0 && inputCoverageIsUsed) {
74 --firstEffectiveCoverageStage;
bsalomonf99f8842014-07-07 11:54:23 -070075 const GrEffect* effect = drawState.getCoverageStage(firstEffectiveCoverageStage).getEffect();
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +000076 inputCoverageIsUsed = effect->willUseInputColor();
77 }
78 }
bsalomon@google.com798c8c42013-03-27 19:50:27 +000079
80 // The descriptor is used as a cache key. Thus when a field of the
81 // descriptor will not affect program generation (because of the attribute
82 // bindings in use or other descriptor field settings) it should be set
83 // to a canonical value to avoid duplicate programs with different keys.
84
jvanverth@google.com054ae992013-04-01 20:06:51 +000085 bool requiresColorAttrib = !skipColor && drawState.hasColorVertexAttribute();
86 bool requiresCoverageAttrib = !skipCoverage && drawState.hasCoverageVertexAttribute();
87 // we only need the local coords if we're actually going to generate effect code
88 bool requiresLocalCoordAttrib = !(skipCoverage && skipColor) &&
89 drawState.hasLocalCoordAttribute();
bsalomon@google.com798c8c42013-03-27 19:50:27 +000090
egdanielc855ca02014-07-11 09:13:37 -070091 bool colorIsTransBlack = SkToBool(blendOpts & GrDrawState::kEmitTransBlack_BlendOptFlag);
92 bool colorIsSolidWhite = (blendOpts & GrDrawState::kEmitCoverage_BlendOptFlag) ||
93 (!requiresColorAttrib && 0xffffffff == drawState.getColor()) ||
94 (!inputColorIsUsed);
95
bsalomon@google.com26e18b52013-03-29 19:22:36 +000096 bool readsDst = false;
bsalomon@google.comb5158812013-05-13 18:50:25 +000097 bool readFragPosition = false;
commit-bot@chromium.org0a6fe712014-04-23 19:26:26 +000098 // We use vertexshader-less shader programs only when drawing paths.
99 bool hasVertexCode = !(GrGpu::kDrawPath_DrawType == drawType ||
100 GrGpu::kDrawPaths_DrawType == drawType);
bsalomon848faf02014-07-11 10:01:02 -0700101 int numStages = 0;
102 if (!skipColor) {
103 numStages += drawState.numColorStages() - firstEffectiveColorStage;
104 }
105 if (!skipCoverage) {
106 numStages += drawState.numCoverageStages() - firstEffectiveCoverageStage;
107 }
108 GR_STATIC_ASSERT(0 == kEffectKeyLengthsOffset % sizeof(uint32_t));
109 // Make room for everything up to and including the array of offsets to effect keys.
110 desc->fKey.reset();
111 desc->fKey.push_back_n(kEffectKeyLengthsOffset + sizeof(uint32_t) * numStages);
commit-bot@chromium.org0a6fe712014-04-23 19:26:26 +0000112
bsalomon848faf02014-07-11 10:01:02 -0700113 size_t offset = desc->fKey.count();
114 int offsetIndex = 0;
115
116 bool effectKeySuccess = true;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000117 if (!skipColor) {
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +0000118 for (int s = firstEffectiveColorStage; s < drawState.numColorStages(); ++s) {
bsalomon848faf02014-07-11 10:01:02 -0700119 uint32_t* offsetLocation = reinterpret_cast<uint32_t*>(desc->fKey.begin() +
120 kEffectKeyLengthsOffset +
121 offsetIndex * sizeof(uint32_t));
122 *offsetLocation = offset;
123 ++offsetIndex;
124
125 GrEffectKeyBuilder b(&desc->fKey);
126 effectKeySuccess |= get_key_and_update_stats(drawState.getColorStage(s), gpu->glCaps(),
127 requiresLocalCoordAttrib, &b, &readsDst,
128 &readFragPosition, &hasVertexCode);
129 offset += b.size();
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000130 }
131 }
132 if (!skipCoverage) {
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +0000133 for (int s = firstEffectiveCoverageStage; s < drawState.numCoverageStages(); ++s) {
bsalomon848faf02014-07-11 10:01:02 -0700134 uint32_t* offsetLocation = reinterpret_cast<uint32_t*>(desc->fKey.begin() +
135 kEffectKeyLengthsOffset +
136 offsetIndex * sizeof(uint32_t));
137 *offsetLocation = offset;
138 ++offsetIndex;
139 GrEffectKeyBuilder b(&desc->fKey);
140 effectKeySuccess |= get_key_and_update_stats(drawState.getCoverageStage(s),
141 gpu->glCaps(), requiresLocalCoordAttrib,
142 &b, &readsDst, &readFragPosition,
143 &hasVertexCode);
144 offset += b.size();
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000145 }
146 }
bsalomon848faf02014-07-11 10:01:02 -0700147 if (!effectKeySuccess) {
148 desc->fKey.reset();
149 return false;
150 }
151
152 KeyHeader* header = desc->header();
153 // make sure any padding in the header is zeroed.
154 memset(desc->header(), 0, kHeaderSize);
155
156 // Because header is a pointer into the dynamic array, we can't push any new data into the key
157 // below here.
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000158
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000159 header->fHasVertexCode = hasVertexCode || requiresLocalCoordAttrib;
commit-bot@chromium.org0a6fe712014-04-23 19:26:26 +0000160 header->fEmitsPointSize = GrGpu::kDrawPoints_DrawType == drawType;
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000161
162 // Currently the experimental GS will only work with triangle prims (and it doesn't do anything
163 // other than pass through values from the VS to the FS anyway).
164#if GR_GL_EXPERIMENTAL_GS
165#if 0
166 header->fExperimentalGS = gpu->caps().geometryShaderSupport();
167#else
168 header->fExperimentalGS = false;
169#endif
170#endif
commit-bot@chromium.orgc4dc0ad2013-10-09 14:11:33 +0000171 bool defaultToUniformInputs = GR_GL_NO_CONSTANT_ATTRIBUTES || gpu->caps()->pathRenderingSupport();
172
egdanielc855ca02014-07-11 09:13:37 -0700173 if (colorIsTransBlack) {
174 header->fColorInput = kTransBlack_ColorInput;
175 } else if (colorIsSolidWhite) {
176 header->fColorInput = kSolidWhite_ColorInput;
177 } else if (defaultToUniformInputs && !requiresColorAttrib) {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000178 header->fColorInput = kUniform_ColorInput;
179 } else {
180 header->fColorInput = kAttribute_ColorInput;
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000181 header->fHasVertexCode = true;
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000182 }
183
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000184 bool covIsSolidWhite = !requiresCoverageAttrib && 0xffffffff == drawState.getCoverageColor();
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000185
egdanielc855ca02014-07-11 09:13:37 -0700186 if (skipCoverage) {
187 header->fCoverageInput = kTransBlack_ColorInput;
188 } else if (covIsSolidWhite || !inputCoverageIsUsed) {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000189 header->fCoverageInput = kSolidWhite_ColorInput;
commit-bot@chromium.orgc4dc0ad2013-10-09 14:11:33 +0000190 } else if (defaultToUniformInputs && !requiresCoverageAttrib) {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000191 header->fCoverageInput = kUniform_ColorInput;
192 } else {
193 header->fCoverageInput = kAttribute_ColorInput;
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000194 header->fHasVertexCode = true;
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000195 }
196
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000197 if (readsDst) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000198 SkASSERT(NULL != dstCopy || gpu->caps()->dstReadInShaderSupport());
bsalomon@google.com6b0cf022013-05-03 13:35:14 +0000199 const GrTexture* dstCopyTexture = NULL;
200 if (NULL != dstCopy) {
201 dstCopyTexture = dstCopy->texture();
202 }
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000203 header->fDstReadKey = GrGLShaderBuilder::KeyForDstRead(dstCopyTexture, gpu->glCaps());
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000204 SkASSERT(0 != header->fDstReadKey);
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000205 } else {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000206 header->fDstReadKey = 0;
bsalomon@google.comb5158812013-05-13 18:50:25 +0000207 }
208
209 if (readFragPosition) {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000210 header->fFragPosKey = GrGLShaderBuilder::KeyForFragmentPosition(drawState.getRenderTarget(),
bsalomon@google.comb5158812013-05-13 18:50:25 +0000211 gpu->glCaps());
212 } else {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000213 header->fFragPosKey = 0;
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000214 }
215
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000216 // Record attribute indices
217 header->fPositionAttributeIndex = drawState.positionAttributeIndex();
218 header->fLocalCoordAttributeIndex = drawState.localCoordAttributeIndex();
skia.committer@gmail.com2d816ad2013-05-23 07:01:22 +0000219
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000220 // For constant color and coverage we need an attribute with an index beyond those already set
221 int availableAttributeIndex = drawState.getVertexAttribCount();
222 if (requiresColorAttrib) {
223 header->fColorAttributeIndex = drawState.colorVertexAttributeIndex();
224 } else if (GrGLProgramDesc::kAttribute_ColorInput == header->fColorInput) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000225 SkASSERT(availableAttributeIndex < GrDrawState::kMaxVertexAttribCnt);
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000226 header->fColorAttributeIndex = availableAttributeIndex;
227 availableAttributeIndex++;
228 } else {
229 header->fColorAttributeIndex = -1;
230 }
skia.committer@gmail.com2d816ad2013-05-23 07:01:22 +0000231
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000232 if (requiresCoverageAttrib) {
233 header->fCoverageAttributeIndex = drawState.coverageVertexAttributeIndex();
234 } else if (GrGLProgramDesc::kAttribute_ColorInput == header->fCoverageInput) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000235 SkASSERT(availableAttributeIndex < GrDrawState::kMaxVertexAttribCnt);
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000236 header->fCoverageAttributeIndex = availableAttributeIndex;
237 } else {
238 header->fCoverageAttributeIndex = -1;
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000239 }
240
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000241 // Here we deal with whether/how we handle color and coverage separately.
skia.committer@gmail.com2d816ad2013-05-23 07:01:22 +0000242
commit-bot@chromium.org8a135882014-02-05 16:29:12 +0000243 // Set this default and then possibly change our mind if there is coverage.
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000244 header->fCoverageOutput = kModulate_CoverageOutput;
245
246 // If we do have coverage determine whether it matters.
247 bool separateCoverageFromColor = false;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000248 if (!drawState.isCoverageDrawing() && !skipCoverage &&
249 (drawState.numCoverageStages() > 0 || requiresCoverageAttrib)) {
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000250
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000251 if (gpu->caps()->dualSourceBlendingSupport() &&
252 !(blendOpts & (GrDrawState::kEmitCoverage_BlendOptFlag |
253 GrDrawState::kCoverageAsAlpha_BlendOptFlag))) {
254 if (kZero_GrBlendCoeff == dstCoeff) {
255 // write the coverage value to second color
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000256 header->fCoverageOutput = kSecondaryCoverage_CoverageOutput;
257 separateCoverageFromColor = true;
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000258 } else if (kSA_GrBlendCoeff == dstCoeff) {
259 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000260 header->fCoverageOutput = kSecondaryCoverageISA_CoverageOutput;
261 separateCoverageFromColor = true;
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000262 } else if (kSC_GrBlendCoeff == dstCoeff) {
263 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000264 header->fCoverageOutput = kSecondaryCoverageISC_CoverageOutput;
265 separateCoverageFromColor = true;
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000266 }
bsalomon@google.com5920ac22013-04-19 13:14:45 +0000267 } else if (readsDst &&
bsalomon@google.com0c89db22013-05-15 17:53:04 +0000268 kOne_GrBlendCoeff == srcCoeff &&
269 kZero_GrBlendCoeff == dstCoeff) {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000270 header->fCoverageOutput = kCombineWithDst_CoverageOutput;
271 separateCoverageFromColor = true;
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000272 }
273 }
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000274 if (!skipColor) {
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +0000275 for (int s = firstEffectiveColorStage; s < drawState.numColorStages(); ++s) {
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000276 colorStages->push_back(&drawState.getColorStage(s));
277 }
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000278 }
279 if (!skipCoverage) {
280 SkTArray<const GrEffectStage*, true>* array;
281 if (separateCoverageFromColor) {
282 array = coverageStages;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000283 } else {
284 array = colorStages;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000285 }
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +0000286 for (int s = firstEffectiveCoverageStage; s < drawState.numCoverageStages(); ++s) {
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000287 array->push_back(&drawState.getCoverageStage(s));
288 }
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000289 }
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +0000290 header->fColorEffectCnt = colorStages->count();
291 header->fCoverageEffectCnt = coverageStages->count();
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000292
bsalomon848faf02014-07-11 10:01:02 -0700293 desc->finalize();
294 return true;
295}
296
297void GrGLProgramDesc::finalize() {
298 int keyLength = fKey.count();
299 SkASSERT(0 == (keyLength % 4));
300 *this->atOffset<uint32_t, kLengthOffset>() = SkToU32(keyLength);
301
302 uint32_t* checksum = this->atOffset<uint32_t, kChecksumOffset>();
303 *checksum = 0;
304 *checksum = SkChecksum::Compute(reinterpret_cast<uint32_t*>(fKey.begin()), keyLength);
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000305}
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000306
307GrGLProgramDesc& GrGLProgramDesc::operator= (const GrGLProgramDesc& other) {
bsalomon848faf02014-07-11 10:01:02 -0700308 size_t keyLength = other.keyLength();
309 fKey.reset(keyLength);
310 memcpy(fKey.begin(), other.fKey.begin(), keyLength);
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000311 return *this;
312}