blob: b49cff97af739ed22d0b804475914c232d54757a [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
joshualitt30ba4362014-08-21 20:18:45 -07008#include "gl/builders/GrGLProgramBuilder.h"
bsalomon@google.com798c8c42013-03-27 19:50:27 +00009#include "GrGLProgramDesc.h"
10#include "GrBackendEffectFactory.h"
bsalomon@google.com798c8c42013-03-27 19:50:27 +000011#include "GrEffect.h"
12#include "GrGpuGL.h"
egdaniel170f90b2014-09-16 12:54:40 -070013#include "GrOptDrawState.h"
bsalomon@google.com798c8c42013-03-27 19:50:27 +000014
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,
kkinnunenec56e452014-08-25 22:21:16 -070024 bool* setTrueIfRequiresVertexShader) {
bsalomon848faf02014-07-11 10:01:02 -070025 const GrBackendEffectFactory& factory = stage.getEffect()->getFactory();
joshualitt49586be2014-09-16 08:21:41 -070026 const GrEffect& effect = *stage.getEffect();
27 if (effect.willReadDstColor()) {
bsalomon@google.comeb6879f2013-06-13 19:34:18 +000028 *setTrueIfReadsDst = true;
29 }
joshualitt49586be2014-09-16 08:21:41 -070030 if (effect.willReadFragmentPosition()) {
bsalomon@google.comeb6879f2013-06-13 19:34:18 +000031 *setTrueIfReadsPos = true;
32 }
joshualitt49586be2014-09-16 08:21:41 -070033 if (effect.requiresVertexShader()) {
kkinnunenec56e452014-08-25 22:21:16 -070034 *setTrueIfRequiresVertexShader = true;
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +000035 }
joshualitt49586be2014-09-16 08:21:41 -070036 factory.getGLEffectKey(effect, caps, b);
bsalomon929f29a2014-07-17 07:55:11 -070037 size_t size = b->size();
38 if (size > SK_MaxU16) {
39 *effectKeySize = 0; // suppresses a warning.
40 return false;
41 }
42 *effectKeySize = SkToU16(size);
joshualitt49586be2014-09-16 08:21:41 -070043 if (!GrGLProgramEffects::GenEffectMetaKey(stage,
44 useExplicitLocalCoords,
45 caps,
46 b)) {
bsalomon929f29a2014-07-17 07:55:11 -070047 return false;
48 }
49 return true;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +000050}
bsalomon848faf02014-07-11 10:01:02 -070051
egdaniel170f90b2014-09-16 12:54:40 -070052bool GrGLProgramDesc::Build(const GrOptDrawState& optState,
commit-bot@chromium.org0a6fe712014-04-23 19:26:26 +000053 GrGpu::DrawType drawType,
bsalomon@google.com798c8c42013-03-27 19:50:27 +000054 GrBlendCoeff srcCoeff,
55 GrBlendCoeff dstCoeff,
56 const GrGpuGL* gpu,
bsalomon@google.com26e18b52013-03-29 19:22:36 +000057 const GrDeviceCoordTexture* dstCopy,
joshualittbd769d02014-09-04 08:56:46 -070058 const GrEffectStage** geometryProcessor,
bsalomon@google.com2c84aa32013-06-06 20:28:57 +000059 SkTArray<const GrEffectStage*, true>* colorStages,
60 SkTArray<const GrEffectStage*, true>* coverageStages,
bsalomon@google.com798c8c42013-03-27 19:50:27 +000061 GrGLProgramDesc* desc) {
bsalomon@google.com2c84aa32013-06-06 20:28:57 +000062 colorStages->reset();
63 coverageStages->reset();
64
egdaniel170f90b2014-09-16 12:54:40 -070065 bool inputColorIsUsed = optState.inputColorIsUsed();
66 bool inputCoverageIsUsed = optState.inputColorIsUsed();
bsalomon@google.com798c8c42013-03-27 19:50:27 +000067
68 // The descriptor is used as a cache key. Thus when a field of the
69 // descriptor will not affect program generation (because of the attribute
70 // bindings in use or other descriptor field settings) it should be set
71 // to a canonical value to avoid duplicate programs with different keys.
72
egdaniel170f90b2014-09-16 12:54:40 -070073 bool requiresColorAttrib = optState.hasColorVertexAttribute();
74 bool requiresCoverageAttrib = optState.hasCoverageVertexAttribute();
jvanverth@google.com054ae992013-04-01 20:06:51 +000075 // we only need the local coords if we're actually going to generate effect code
egdaniel170f90b2014-09-16 12:54:40 -070076 bool requiresLocalCoordAttrib = optState.numTotalStages() > 0 &&
77 optState.hasLocalCoordAttribute();
bsalomon@google.com798c8c42013-03-27 19:50:27 +000078
bsalomon@google.com26e18b52013-03-29 19:22:36 +000079 bool readsDst = false;
bsalomon@google.comb5158812013-05-13 18:50:25 +000080 bool readFragPosition = false;
kkinnunenec56e452014-08-25 22:21:16 -070081
82 // Provide option for shader programs without vertex shader only when drawing paths.
83 bool requiresVertexShader = !GrGpu::IsPathRenderingDrawType(drawType);
84
egdaniel170f90b2014-09-16 12:54:40 -070085 int numStages = optState.numTotalStages();
86
bsalomon929f29a2014-07-17 07:55:11 -070087 GR_STATIC_ASSERT(0 == kEffectKeyOffsetsAndLengthOffset % sizeof(uint32_t));
bsalomon848faf02014-07-11 10:01:02 -070088 // Make room for everything up to and including the array of offsets to effect keys.
89 desc->fKey.reset();
bsalomon929f29a2014-07-17 07:55:11 -070090 desc->fKey.push_back_n(kEffectKeyOffsetsAndLengthOffset + 2 * sizeof(uint16_t) * numStages);
commit-bot@chromium.org0a6fe712014-04-23 19:26:26 +000091
bsalomon929f29a2014-07-17 07:55:11 -070092 int offsetAndSizeIndex = 0;
bsalomon848faf02014-07-11 10:01:02 -070093 bool effectKeySuccess = true;
joshualittbd769d02014-09-04 08:56:46 -070094
95 KeyHeader* header = desc->header();
96 // make sure any padding in the header is zeroed.
97 memset(desc->header(), 0, kHeaderSize);
98
99 // We can only have one effect which touches the vertex shader
egdaniel170f90b2014-09-16 12:54:40 -0700100 if (optState.hasGeometryProcessor()) {
joshualittbd769d02014-09-04 08:56:46 -0700101 uint16_t* offsetAndSize =
bsalomon929f29a2014-07-17 07:55:11 -0700102 reinterpret_cast<uint16_t*>(desc->fKey.begin() + kEffectKeyOffsetsAndLengthOffset +
103 offsetAndSizeIndex * 2 * sizeof(uint16_t));
bsalomon848faf02014-07-11 10:01:02 -0700104
105 GrEffectKeyBuilder b(&desc->fKey);
bsalomon929f29a2014-07-17 07:55:11 -0700106 uint16_t effectKeySize;
107 uint32_t effectOffset = desc->fKey.count();
108 effectKeySuccess |= GetEffectKeyAndUpdateStats(
egdaniel170f90b2014-09-16 12:54:40 -0700109 *optState.getGeometryProcessor(), gpu->glCaps(),
bsalomon929f29a2014-07-17 07:55:11 -0700110 requiresLocalCoordAttrib, &b,
111 &effectKeySize, &readsDst,
kkinnunenec56e452014-08-25 22:21:16 -0700112 &readFragPosition, &requiresVertexShader);
bsalomon929f29a2014-07-17 07:55:11 -0700113 effectKeySuccess |= (effectOffset <= SK_MaxU16);
114
115 offsetAndSize[0] = SkToU16(effectOffset);
116 offsetAndSize[1] = effectKeySize;
117 ++offsetAndSizeIndex;
egdaniel170f90b2014-09-16 12:54:40 -0700118 *geometryProcessor = optState.getGeometryProcessor();
joshualittbd769d02014-09-04 08:56:46 -0700119 SkASSERT(requiresVertexShader);
120 header->fHasGeometryProcessor = true;
121 }
122
egdaniel170f90b2014-09-16 12:54:40 -0700123 for (int s = 0; s < optState.numColorStages(); ++s) {
124 uint16_t* offsetAndSize =
125 reinterpret_cast<uint16_t*>(desc->fKey.begin() + kEffectKeyOffsetsAndLengthOffset +
126 offsetAndSizeIndex * 2 * sizeof(uint16_t));
joshualittbd769d02014-09-04 08:56:46 -0700127
egdaniel170f90b2014-09-16 12:54:40 -0700128 bool effectRequiresVertexShader = false;
129 GrEffectKeyBuilder b(&desc->fKey);
130 uint16_t effectKeySize;
131 uint32_t effectOffset = desc->fKey.count();
132 effectKeySuccess |= GetEffectKeyAndUpdateStats(
133 optState.getColorStage(s), gpu->glCaps(),
134 requiresLocalCoordAttrib, &b,
135 &effectKeySize, &readsDst,
136 &readFragPosition, &effectRequiresVertexShader);
137 effectKeySuccess |= (effectOffset <= SK_MaxU16);
joshualittbd769d02014-09-04 08:56:46 -0700138
egdaniel170f90b2014-09-16 12:54:40 -0700139 offsetAndSize[0] = SkToU16(effectOffset);
140 offsetAndSize[1] = effectKeySize;
141 ++offsetAndSizeIndex;
142 SkASSERT(!effectRequiresVertexShader);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000143 }
bsalomon929f29a2014-07-17 07:55:11 -0700144
egdaniel170f90b2014-09-16 12:54:40 -0700145 for (int s = 0; s < optState.numCoverageStages(); ++s) {
146 uint16_t* offsetAndSize =
147 reinterpret_cast<uint16_t*>(desc->fKey.begin() + kEffectKeyOffsetsAndLengthOffset +
148 offsetAndSizeIndex * 2 * sizeof(uint16_t));
bsalomon929f29a2014-07-17 07:55:11 -0700149
egdaniel170f90b2014-09-16 12:54:40 -0700150 bool effectRequiresVertexShader = false;
151 GrEffectKeyBuilder b(&desc->fKey);
152 uint16_t effectKeySize;
153 uint32_t effectOffset = desc->fKey.count();
154 effectKeySuccess |= GetEffectKeyAndUpdateStats(
155 optState.getCoverageStage(s), gpu->glCaps(),
156 requiresLocalCoordAttrib, &b,
157 &effectKeySize, &readsDst,
158 &readFragPosition, &effectRequiresVertexShader);
159 effectKeySuccess |= (effectOffset <= SK_MaxU16);
160
161 offsetAndSize[0] = SkToU16(effectOffset);
162 offsetAndSize[1] = effectKeySize;
163 ++offsetAndSizeIndex;
164 SkASSERT(!effectRequiresVertexShader);
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000165 }
egdaniel170f90b2014-09-16 12:54:40 -0700166
bsalomon848faf02014-07-11 10:01:02 -0700167 if (!effectKeySuccess) {
168 desc->fKey.reset();
169 return false;
170 }
171
bsalomon848faf02014-07-11 10:01:02 -0700172 // Because header is a pointer into the dynamic array, we can't push any new data into the key
173 // below here.
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000174
kkinnunenec56e452014-08-25 22:21:16 -0700175 header->fRequiresVertexShader = requiresVertexShader || requiresLocalCoordAttrib;
commit-bot@chromium.org0a6fe712014-04-23 19:26:26 +0000176 header->fEmitsPointSize = GrGpu::kDrawPoints_DrawType == drawType;
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000177
178 // Currently the experimental GS will only work with triangle prims (and it doesn't do anything
179 // other than pass through values from the VS to the FS anyway).
180#if GR_GL_EXPERIMENTAL_GS
181#if 0
182 header->fExperimentalGS = gpu->caps().geometryShaderSupport();
183#else
184 header->fExperimentalGS = false;
185#endif
186#endif
commit-bot@chromium.orgc4dc0ad2013-10-09 14:11:33 +0000187 bool defaultToUniformInputs = GR_GL_NO_CONSTANT_ATTRIBUTES || gpu->caps()->pathRenderingSupport();
188
egdaniel170f90b2014-09-16 12:54:40 -0700189 if (!inputColorIsUsed) {
egdaniel842b0862014-09-02 10:01:30 -0700190 header->fColorInput = kAllOnes_ColorInput;
egdaniel170f90b2014-09-16 12:54:40 -0700191 } else if (defaultToUniformInputs && !requiresColorAttrib) {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000192 header->fColorInput = kUniform_ColorInput;
193 } else {
194 header->fColorInput = kAttribute_ColorInput;
kkinnunenec56e452014-08-25 22:21:16 -0700195 header->fRequiresVertexShader = true;
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000196 }
197
egdaniel170f90b2014-09-16 12:54:40 -0700198 bool covIsSolidWhite = !requiresCoverageAttrib && 0xffffffff == optState.getCoverageColor();
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000199
egdaniel170f90b2014-09-16 12:54:40 -0700200 if (covIsSolidWhite || !inputCoverageIsUsed) {
egdaniel842b0862014-09-02 10:01:30 -0700201 header->fCoverageInput = kAllOnes_ColorInput;
egdaniel170f90b2014-09-16 12:54:40 -0700202 } else if (defaultToUniformInputs && !requiresCoverageAttrib) {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000203 header->fCoverageInput = kUniform_ColorInput;
204 } else {
205 header->fCoverageInput = kAttribute_ColorInput;
kkinnunenec56e452014-08-25 22:21:16 -0700206 header->fRequiresVertexShader = true;
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000207 }
208
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000209 if (readsDst) {
bsalomon49f085d2014-09-05 13:34:00 -0700210 SkASSERT(dstCopy || gpu->caps()->dstReadInShaderSupport());
bsalomon@google.com6b0cf022013-05-03 13:35:14 +0000211 const GrTexture* dstCopyTexture = NULL;
bsalomon49f085d2014-09-05 13:34:00 -0700212 if (dstCopy) {
bsalomon@google.com6b0cf022013-05-03 13:35:14 +0000213 dstCopyTexture = dstCopy->texture();
214 }
joshualitt30ba4362014-08-21 20:18:45 -0700215 header->fDstReadKey = GrGLFragmentShaderBuilder::KeyForDstRead(dstCopyTexture,
216 gpu->glCaps());
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000217 SkASSERT(0 != header->fDstReadKey);
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000218 } else {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000219 header->fDstReadKey = 0;
bsalomon@google.comb5158812013-05-13 18:50:25 +0000220 }
221
222 if (readFragPosition) {
joshualitt30ba4362014-08-21 20:18:45 -0700223 header->fFragPosKey = GrGLFragmentShaderBuilder::KeyForFragmentPosition(
egdaniel170f90b2014-09-16 12:54:40 -0700224 optState.getRenderTarget(), gpu->glCaps());
bsalomon@google.comb5158812013-05-13 18:50:25 +0000225 } else {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000226 header->fFragPosKey = 0;
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000227 }
228
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000229 // Record attribute indices
egdaniel170f90b2014-09-16 12:54:40 -0700230 header->fPositionAttributeIndex = optState.positionAttributeIndex();
231 header->fLocalCoordAttributeIndex = optState.localCoordAttributeIndex();
skia.committer@gmail.com2d816ad2013-05-23 07:01:22 +0000232
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000233 // For constant color and coverage we need an attribute with an index beyond those already set
egdaniel170f90b2014-09-16 12:54:40 -0700234 int availableAttributeIndex = optState.getVertexAttribCount();
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000235 if (requiresColorAttrib) {
egdaniel170f90b2014-09-16 12:54:40 -0700236 header->fColorAttributeIndex = optState.colorVertexAttributeIndex();
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000237 } else if (GrGLProgramDesc::kAttribute_ColorInput == header->fColorInput) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000238 SkASSERT(availableAttributeIndex < GrDrawState::kMaxVertexAttribCnt);
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000239 header->fColorAttributeIndex = availableAttributeIndex;
240 availableAttributeIndex++;
241 } else {
242 header->fColorAttributeIndex = -1;
243 }
skia.committer@gmail.com2d816ad2013-05-23 07:01:22 +0000244
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000245 if (requiresCoverageAttrib) {
egdaniel170f90b2014-09-16 12:54:40 -0700246 header->fCoverageAttributeIndex = optState.coverageVertexAttributeIndex();
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000247 } else if (GrGLProgramDesc::kAttribute_ColorInput == header->fCoverageInput) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000248 SkASSERT(availableAttributeIndex < GrDrawState::kMaxVertexAttribCnt);
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000249 header->fCoverageAttributeIndex = availableAttributeIndex;
250 } else {
251 header->fCoverageAttributeIndex = -1;
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000252 }
253
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000254 // Here we deal with whether/how we handle color and coverage separately.
skia.committer@gmail.com2d816ad2013-05-23 07:01:22 +0000255
commit-bot@chromium.org8a135882014-02-05 16:29:12 +0000256 // Set this default and then possibly change our mind if there is coverage.
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000257 header->fCoverageOutput = kModulate_CoverageOutput;
258
259 // If we do have coverage determine whether it matters.
egdaniel170f90b2014-09-16 12:54:40 -0700260 bool separateCoverageFromColor = optState.hasGeometryProcessor();
261 if (!optState.isCoverageDrawing() &&
262 (optState.numCoverageStages() > 0 ||
263 optState.hasGeometryProcessor() ||
joshualittbd769d02014-09-04 08:56:46 -0700264 requiresCoverageAttrib)) {
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000265
egdaniel170f90b2014-09-16 12:54:40 -0700266 if (gpu->caps()->dualSourceBlendingSupport()) {
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000267 if (kZero_GrBlendCoeff == dstCoeff) {
268 // write the coverage value to second color
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000269 header->fCoverageOutput = kSecondaryCoverage_CoverageOutput;
270 separateCoverageFromColor = true;
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000271 } else if (kSA_GrBlendCoeff == dstCoeff) {
272 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000273 header->fCoverageOutput = kSecondaryCoverageISA_CoverageOutput;
274 separateCoverageFromColor = true;
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000275 } else if (kSC_GrBlendCoeff == dstCoeff) {
276 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000277 header->fCoverageOutput = kSecondaryCoverageISC_CoverageOutput;
278 separateCoverageFromColor = true;
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000279 }
bsalomon@google.com5920ac22013-04-19 13:14:45 +0000280 } else if (readsDst &&
bsalomon@google.com0c89db22013-05-15 17:53:04 +0000281 kOne_GrBlendCoeff == srcCoeff &&
282 kZero_GrBlendCoeff == dstCoeff) {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000283 header->fCoverageOutput = kCombineWithDst_CoverageOutput;
284 separateCoverageFromColor = true;
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000285 }
286 }
joshualittbd769d02014-09-04 08:56:46 -0700287
egdaniel170f90b2014-09-16 12:54:40 -0700288 for (int s = 0; s < optState.numColorStages(); ++s) {
289 colorStages->push_back(&optState.getColorStage(s));
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000290 }
egdaniel170f90b2014-09-16 12:54:40 -0700291 SkTArray<const GrEffectStage*, true>* array;
292 if (separateCoverageFromColor) {
293 array = coverageStages;
294 } else {
295 array = colorStages;
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000296 }
egdaniel170f90b2014-09-16 12:54:40 -0700297 for (int s = 0; s < optState.numCoverageStages(); ++s) {
298 array->push_back(&optState.getCoverageStage(s));
299 }
300
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +0000301 header->fColorEffectCnt = colorStages->count();
302 header->fCoverageEffectCnt = coverageStages->count();
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000303
bsalomon848faf02014-07-11 10:01:02 -0700304 desc->finalize();
305 return true;
306}
307
308void GrGLProgramDesc::finalize() {
309 int keyLength = fKey.count();
310 SkASSERT(0 == (keyLength % 4));
311 *this->atOffset<uint32_t, kLengthOffset>() = SkToU32(keyLength);
312
313 uint32_t* checksum = this->atOffset<uint32_t, kChecksumOffset>();
314 *checksum = 0;
315 *checksum = SkChecksum::Compute(reinterpret_cast<uint32_t*>(fKey.begin()), keyLength);
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000316}
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000317
318GrGLProgramDesc& GrGLProgramDesc::operator= (const GrGLProgramDesc& other) {
bsalomon848faf02014-07-11 10:01:02 -0700319 size_t keyLength = other.keyLength();
320 fKey.reset(keyLength);
321 memcpy(fKey.begin(), other.fKey.begin(), keyLength);
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000322 return *this;
323}