blob: 27a1fab1e0e1a3e892c1f8866aa38077c64493b7 [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
bsalomon929f29a2014-07-17 07:55:11 -070017bool GrGLProgramDesc::GetEffectKeyAndUpdateStats(const GrEffectStage& stage,
18 const GrGLCaps& caps,
19 bool useExplicitLocalCoords,
20 GrEffectKeyBuilder* b,
21 uint16_t* effectKeySize,
22 bool* setTrueIfReadsDst,
23 bool* setTrueIfReadsPos,
24 bool* setTrueIfHasVertexCode) {
bsalomon848faf02014-07-11 10:01:02 -070025 const GrBackendEffectFactory& factory = stage.getEffect()->getFactory();
bsalomon@google.comeb6879f2013-06-13 19:34:18 +000026 GrDrawEffect drawEffect(stage, useExplicitLocalCoords);
bsalomon848faf02014-07-11 10:01:02 -070027 if (stage.getEffect()->willReadDstColor()) {
bsalomon@google.comeb6879f2013-06-13 19:34:18 +000028 *setTrueIfReadsDst = true;
29 }
bsalomon848faf02014-07-11 10:01:02 -070030 if (stage.getEffect()->willReadFragmentPosition()) {
bsalomon@google.comeb6879f2013-06-13 19:34:18 +000031 *setTrueIfReadsPos = true;
32 }
bsalomon848faf02014-07-11 10:01:02 -070033 if (stage.getEffect()->hasVertexCode()) {
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +000034 *setTrueIfHasVertexCode = true;
35 }
bsalomon929f29a2014-07-17 07:55:11 -070036 factory.getGLEffectKey(drawEffect, caps, b);
37 size_t size = b->size();
38 if (size > SK_MaxU16) {
39 *effectKeySize = 0; // suppresses a warning.
40 return false;
41 }
42 *effectKeySize = SkToU16(size);
43 if (!GrGLProgramEffects::GenEffectMetaKey(drawEffect, caps, b)) {
44 return false;
45 }
46 return true;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +000047}
bsalomon848faf02014-07-11 10:01:02 -070048
49bool GrGLProgramDesc::Build(const GrDrawState& drawState,
commit-bot@chromium.org0a6fe712014-04-23 19:26:26 +000050 GrGpu::DrawType drawType,
bsalomon@google.com798c8c42013-03-27 19:50:27 +000051 GrDrawState::BlendOptFlags blendOpts,
52 GrBlendCoeff srcCoeff,
53 GrBlendCoeff dstCoeff,
54 const GrGpuGL* gpu,
bsalomon@google.com26e18b52013-03-29 19:22:36 +000055 const GrDeviceCoordTexture* dstCopy,
bsalomon@google.com2c84aa32013-06-06 20:28:57 +000056 SkTArray<const GrEffectStage*, true>* colorStages,
57 SkTArray<const GrEffectStage*, true>* coverageStages,
bsalomon@google.com798c8c42013-03-27 19:50:27 +000058 GrGLProgramDesc* desc) {
bsalomon@google.com2c84aa32013-06-06 20:28:57 +000059 colorStages->reset();
60 coverageStages->reset();
61
bsalomon@google.com798c8c42013-03-27 19:50:27 +000062 // This should already have been caught
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +000063 SkASSERT(!(GrDrawState::kSkipDraw_BlendOptFlag & blendOpts));
bsalomon@google.com798c8c42013-03-27 19:50:27 +000064
65 bool skipCoverage = SkToBool(blendOpts & GrDrawState::kEmitTransBlack_BlendOptFlag);
66
67 bool skipColor = SkToBool(blendOpts & (GrDrawState::kEmitTransBlack_BlendOptFlag |
68 GrDrawState::kEmitCoverage_BlendOptFlag));
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +000069 int firstEffectiveColorStage = 0;
70 bool inputColorIsUsed = true;
71 if (!skipColor) {
72 firstEffectiveColorStage = drawState.numColorStages();
73 while (firstEffectiveColorStage > 0 && inputColorIsUsed) {
74 --firstEffectiveColorStage;
bsalomonf99f8842014-07-07 11:54:23 -070075 const GrEffect* effect = drawState.getColorStage(firstEffectiveColorStage).getEffect();
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +000076 inputColorIsUsed = effect->willUseInputColor();
77 }
78 }
79
80 int firstEffectiveCoverageStage = 0;
81 bool inputCoverageIsUsed = true;
82 if (!skipCoverage) {
83 firstEffectiveCoverageStage = drawState.numCoverageStages();
84 while (firstEffectiveCoverageStage > 0 && inputCoverageIsUsed) {
85 --firstEffectiveCoverageStage;
bsalomonf99f8842014-07-07 11:54:23 -070086 const GrEffect* effect = drawState.getCoverageStage(firstEffectiveCoverageStage).getEffect();
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +000087 inputCoverageIsUsed = effect->willUseInputColor();
88 }
89 }
bsalomon@google.com798c8c42013-03-27 19:50:27 +000090
91 // The descriptor is used as a cache key. Thus when a field of the
92 // descriptor will not affect program generation (because of the attribute
93 // bindings in use or other descriptor field settings) it should be set
94 // to a canonical value to avoid duplicate programs with different keys.
95
jvanverth@google.com054ae992013-04-01 20:06:51 +000096 bool requiresColorAttrib = !skipColor && drawState.hasColorVertexAttribute();
97 bool requiresCoverageAttrib = !skipCoverage && drawState.hasCoverageVertexAttribute();
98 // we only need the local coords if we're actually going to generate effect code
99 bool requiresLocalCoordAttrib = !(skipCoverage && skipColor) &&
100 drawState.hasLocalCoordAttribute();
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000101
egdanielc855ca02014-07-11 09:13:37 -0700102 bool colorIsTransBlack = SkToBool(blendOpts & GrDrawState::kEmitTransBlack_BlendOptFlag);
103 bool colorIsSolidWhite = (blendOpts & GrDrawState::kEmitCoverage_BlendOptFlag) ||
104 (!requiresColorAttrib && 0xffffffff == drawState.getColor()) ||
105 (!inputColorIsUsed);
106
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000107 bool readsDst = false;
bsalomon@google.comb5158812013-05-13 18:50:25 +0000108 bool readFragPosition = false;
commit-bot@chromium.org0a6fe712014-04-23 19:26:26 +0000109 // We use vertexshader-less shader programs only when drawing paths.
110 bool hasVertexCode = !(GrGpu::kDrawPath_DrawType == drawType ||
111 GrGpu::kDrawPaths_DrawType == drawType);
bsalomon848faf02014-07-11 10:01:02 -0700112 int numStages = 0;
113 if (!skipColor) {
114 numStages += drawState.numColorStages() - firstEffectiveColorStage;
115 }
116 if (!skipCoverage) {
117 numStages += drawState.numCoverageStages() - firstEffectiveCoverageStage;
118 }
bsalomon929f29a2014-07-17 07:55:11 -0700119 GR_STATIC_ASSERT(0 == kEffectKeyOffsetsAndLengthOffset % sizeof(uint32_t));
bsalomon848faf02014-07-11 10:01:02 -0700120 // Make room for everything up to and including the array of offsets to effect keys.
121 desc->fKey.reset();
bsalomon929f29a2014-07-17 07:55:11 -0700122 desc->fKey.push_back_n(kEffectKeyOffsetsAndLengthOffset + 2 * sizeof(uint16_t) * numStages);
commit-bot@chromium.org0a6fe712014-04-23 19:26:26 +0000123
bsalomon929f29a2014-07-17 07:55:11 -0700124 int offsetAndSizeIndex = 0;
bsalomon848faf02014-07-11 10:01:02 -0700125
126 bool effectKeySuccess = true;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000127 if (!skipColor) {
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +0000128 for (int s = firstEffectiveColorStage; s < drawState.numColorStages(); ++s) {
bsalomon929f29a2014-07-17 07:55:11 -0700129 uint16_t* offsetAndSize =
130 reinterpret_cast<uint16_t*>(desc->fKey.begin() + kEffectKeyOffsetsAndLengthOffset +
131 offsetAndSizeIndex * 2 * sizeof(uint16_t));
bsalomon848faf02014-07-11 10:01:02 -0700132
133 GrEffectKeyBuilder b(&desc->fKey);
bsalomon929f29a2014-07-17 07:55:11 -0700134 uint16_t effectKeySize;
135 uint32_t effectOffset = desc->fKey.count();
136 effectKeySuccess |= GetEffectKeyAndUpdateStats(
137 drawState.getColorStage(s), gpu->glCaps(),
138 requiresLocalCoordAttrib, &b,
139 &effectKeySize, &readsDst,
140 &readFragPosition, &hasVertexCode);
141 effectKeySuccess |= (effectOffset <= SK_MaxU16);
142
143 offsetAndSize[0] = SkToU16(effectOffset);
144 offsetAndSize[1] = effectKeySize;
145 ++offsetAndSizeIndex;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000146 }
147 }
148 if (!skipCoverage) {
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +0000149 for (int s = firstEffectiveCoverageStage; s < drawState.numCoverageStages(); ++s) {
bsalomon929f29a2014-07-17 07:55:11 -0700150 uint16_t* offsetAndSize =
151 reinterpret_cast<uint16_t*>(desc->fKey.begin() + kEffectKeyOffsetsAndLengthOffset +
152 offsetAndSizeIndex * 2 * sizeof(uint16_t));
153
bsalomon848faf02014-07-11 10:01:02 -0700154 GrEffectKeyBuilder b(&desc->fKey);
bsalomon929f29a2014-07-17 07:55:11 -0700155 uint16_t effectKeySize;
156 uint32_t effectOffset = desc->fKey.count();
157 effectKeySuccess |= GetEffectKeyAndUpdateStats(
158 drawState.getCoverageStage(s), gpu->glCaps(),
159 requiresLocalCoordAttrib, &b,
160 &effectKeySize, &readsDst,
161 &readFragPosition, &hasVertexCode);
162 effectKeySuccess |= (effectOffset <= SK_MaxU16);
163
164 offsetAndSize[0] = SkToU16(effectOffset);
165 offsetAndSize[1] = effectKeySize;
166 ++offsetAndSizeIndex;
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000167 }
168 }
bsalomon848faf02014-07-11 10:01:02 -0700169 if (!effectKeySuccess) {
170 desc->fKey.reset();
171 return false;
172 }
173
174 KeyHeader* header = desc->header();
175 // make sure any padding in the header is zeroed.
176 memset(desc->header(), 0, kHeaderSize);
177
178 // Because header is a pointer into the dynamic array, we can't push any new data into the key
179 // below here.
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000180
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000181 header->fHasVertexCode = hasVertexCode || requiresLocalCoordAttrib;
commit-bot@chromium.org0a6fe712014-04-23 19:26:26 +0000182 header->fEmitsPointSize = GrGpu::kDrawPoints_DrawType == drawType;
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000183
184 // Currently the experimental GS will only work with triangle prims (and it doesn't do anything
185 // other than pass through values from the VS to the FS anyway).
186#if GR_GL_EXPERIMENTAL_GS
187#if 0
188 header->fExperimentalGS = gpu->caps().geometryShaderSupport();
189#else
190 header->fExperimentalGS = false;
191#endif
192#endif
commit-bot@chromium.orgc4dc0ad2013-10-09 14:11:33 +0000193 bool defaultToUniformInputs = GR_GL_NO_CONSTANT_ATTRIBUTES || gpu->caps()->pathRenderingSupport();
194
egdanielc855ca02014-07-11 09:13:37 -0700195 if (colorIsTransBlack) {
196 header->fColorInput = kTransBlack_ColorInput;
197 } else if (colorIsSolidWhite) {
198 header->fColorInput = kSolidWhite_ColorInput;
199 } else if (defaultToUniformInputs && !requiresColorAttrib) {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000200 header->fColorInput = kUniform_ColorInput;
201 } else {
202 header->fColorInput = kAttribute_ColorInput;
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000203 header->fHasVertexCode = true;
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000204 }
205
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000206 bool covIsSolidWhite = !requiresCoverageAttrib && 0xffffffff == drawState.getCoverageColor();
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000207
egdanielc855ca02014-07-11 09:13:37 -0700208 if (skipCoverage) {
209 header->fCoverageInput = kTransBlack_ColorInput;
210 } else if (covIsSolidWhite || !inputCoverageIsUsed) {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000211 header->fCoverageInput = kSolidWhite_ColorInput;
commit-bot@chromium.orgc4dc0ad2013-10-09 14:11:33 +0000212 } else if (defaultToUniformInputs && !requiresCoverageAttrib) {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000213 header->fCoverageInput = kUniform_ColorInput;
214 } else {
215 header->fCoverageInput = kAttribute_ColorInput;
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000216 header->fHasVertexCode = true;
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000217 }
218
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000219 if (readsDst) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000220 SkASSERT(NULL != dstCopy || gpu->caps()->dstReadInShaderSupport());
bsalomon@google.com6b0cf022013-05-03 13:35:14 +0000221 const GrTexture* dstCopyTexture = NULL;
222 if (NULL != dstCopy) {
223 dstCopyTexture = dstCopy->texture();
224 }
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000225 header->fDstReadKey = GrGLShaderBuilder::KeyForDstRead(dstCopyTexture, gpu->glCaps());
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000226 SkASSERT(0 != header->fDstReadKey);
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000227 } else {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000228 header->fDstReadKey = 0;
bsalomon@google.comb5158812013-05-13 18:50:25 +0000229 }
230
231 if (readFragPosition) {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000232 header->fFragPosKey = GrGLShaderBuilder::KeyForFragmentPosition(drawState.getRenderTarget(),
bsalomon@google.comb5158812013-05-13 18:50:25 +0000233 gpu->glCaps());
234 } else {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000235 header->fFragPosKey = 0;
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000236 }
237
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000238 // Record attribute indices
239 header->fPositionAttributeIndex = drawState.positionAttributeIndex();
240 header->fLocalCoordAttributeIndex = drawState.localCoordAttributeIndex();
skia.committer@gmail.com2d816ad2013-05-23 07:01:22 +0000241
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000242 // For constant color and coverage we need an attribute with an index beyond those already set
243 int availableAttributeIndex = drawState.getVertexAttribCount();
244 if (requiresColorAttrib) {
245 header->fColorAttributeIndex = drawState.colorVertexAttributeIndex();
246 } else if (GrGLProgramDesc::kAttribute_ColorInput == header->fColorInput) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000247 SkASSERT(availableAttributeIndex < GrDrawState::kMaxVertexAttribCnt);
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000248 header->fColorAttributeIndex = availableAttributeIndex;
249 availableAttributeIndex++;
250 } else {
251 header->fColorAttributeIndex = -1;
252 }
skia.committer@gmail.com2d816ad2013-05-23 07:01:22 +0000253
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000254 if (requiresCoverageAttrib) {
255 header->fCoverageAttributeIndex = drawState.coverageVertexAttributeIndex();
256 } else if (GrGLProgramDesc::kAttribute_ColorInput == header->fCoverageInput) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000257 SkASSERT(availableAttributeIndex < GrDrawState::kMaxVertexAttribCnt);
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000258 header->fCoverageAttributeIndex = availableAttributeIndex;
259 } else {
260 header->fCoverageAttributeIndex = -1;
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000261 }
262
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000263 // Here we deal with whether/how we handle color and coverage separately.
skia.committer@gmail.com2d816ad2013-05-23 07:01:22 +0000264
commit-bot@chromium.org8a135882014-02-05 16:29:12 +0000265 // Set this default and then possibly change our mind if there is coverage.
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000266 header->fCoverageOutput = kModulate_CoverageOutput;
267
268 // If we do have coverage determine whether it matters.
269 bool separateCoverageFromColor = false;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000270 if (!drawState.isCoverageDrawing() && !skipCoverage &&
271 (drawState.numCoverageStages() > 0 || requiresCoverageAttrib)) {
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000272
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000273 if (gpu->caps()->dualSourceBlendingSupport() &&
274 !(blendOpts & (GrDrawState::kEmitCoverage_BlendOptFlag |
275 GrDrawState::kCoverageAsAlpha_BlendOptFlag))) {
276 if (kZero_GrBlendCoeff == dstCoeff) {
277 // write the coverage value to second color
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000278 header->fCoverageOutput = kSecondaryCoverage_CoverageOutput;
279 separateCoverageFromColor = true;
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000280 } else if (kSA_GrBlendCoeff == dstCoeff) {
281 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000282 header->fCoverageOutput = kSecondaryCoverageISA_CoverageOutput;
283 separateCoverageFromColor = true;
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000284 } else if (kSC_GrBlendCoeff == dstCoeff) {
285 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000286 header->fCoverageOutput = kSecondaryCoverageISC_CoverageOutput;
287 separateCoverageFromColor = true;
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000288 }
bsalomon@google.com5920ac22013-04-19 13:14:45 +0000289 } else if (readsDst &&
bsalomon@google.com0c89db22013-05-15 17:53:04 +0000290 kOne_GrBlendCoeff == srcCoeff &&
291 kZero_GrBlendCoeff == dstCoeff) {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000292 header->fCoverageOutput = kCombineWithDst_CoverageOutput;
293 separateCoverageFromColor = true;
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000294 }
295 }
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000296 if (!skipColor) {
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +0000297 for (int s = firstEffectiveColorStage; s < drawState.numColorStages(); ++s) {
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000298 colorStages->push_back(&drawState.getColorStage(s));
299 }
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000300 }
301 if (!skipCoverage) {
302 SkTArray<const GrEffectStage*, true>* array;
303 if (separateCoverageFromColor) {
304 array = coverageStages;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000305 } else {
306 array = colorStages;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000307 }
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +0000308 for (int s = firstEffectiveCoverageStage; s < drawState.numCoverageStages(); ++s) {
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000309 array->push_back(&drawState.getCoverageStage(s));
310 }
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000311 }
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +0000312 header->fColorEffectCnt = colorStages->count();
313 header->fCoverageEffectCnt = coverageStages->count();
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000314
bsalomon848faf02014-07-11 10:01:02 -0700315 desc->finalize();
316 return true;
317}
318
319void GrGLProgramDesc::finalize() {
320 int keyLength = fKey.count();
321 SkASSERT(0 == (keyLength % 4));
322 *this->atOffset<uint32_t, kLengthOffset>() = SkToU32(keyLength);
323
324 uint32_t* checksum = this->atOffset<uint32_t, kChecksumOffset>();
325 *checksum = 0;
326 *checksum = SkChecksum::Compute(reinterpret_cast<uint32_t*>(fKey.begin()), keyLength);
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000327}
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000328
329GrGLProgramDesc& GrGLProgramDesc::operator= (const GrGLProgramDesc& other) {
bsalomon848faf02014-07-11 10:01:02 -0700330 size_t keyLength = other.keyLength();
331 fKey.reset(keyLength);
332 memcpy(fKey.begin(), other.fKey.begin(), keyLength);
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000333 return *this;
334}