blob: b8740912643012d2bbef2008774bc2b8fc7e6874 [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
egdaniela7dc0a82014-09-17 08:25:05 -070017bool GrGLProgramDesc::GetEffectKey(const GrEffectStage& stage, const GrGLCaps& caps,
18 bool useExplicitLocalCoords, GrEffectKeyBuilder* b,
19 uint16_t* effectKeySize) {
bsalomon848faf02014-07-11 10:01:02 -070020 const GrBackendEffectFactory& factory = stage.getEffect()->getFactory();
joshualitt49586be2014-09-16 08:21:41 -070021 const GrEffect& effect = *stage.getEffect();
joshualitt49586be2014-09-16 08:21:41 -070022 factory.getGLEffectKey(effect, caps, b);
bsalomon929f29a2014-07-17 07:55:11 -070023 size_t size = b->size();
24 if (size > SK_MaxU16) {
25 *effectKeySize = 0; // suppresses a warning.
26 return false;
27 }
28 *effectKeySize = SkToU16(size);
joshualitt49586be2014-09-16 08:21:41 -070029 if (!GrGLProgramEffects::GenEffectMetaKey(stage,
30 useExplicitLocalCoords,
31 caps,
32 b)) {
bsalomon929f29a2014-07-17 07:55:11 -070033 return false;
34 }
35 return true;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +000036}
bsalomon848faf02014-07-11 10:01:02 -070037
egdaniel170f90b2014-09-16 12:54:40 -070038bool GrGLProgramDesc::Build(const GrOptDrawState& optState,
commit-bot@chromium.org0a6fe712014-04-23 19:26:26 +000039 GrGpu::DrawType drawType,
bsalomon@google.com798c8c42013-03-27 19:50:27 +000040 GrBlendCoeff srcCoeff,
41 GrBlendCoeff dstCoeff,
42 const GrGpuGL* gpu,
bsalomon@google.com26e18b52013-03-29 19:22:36 +000043 const GrDeviceCoordTexture* dstCopy,
joshualittbd769d02014-09-04 08:56:46 -070044 const GrEffectStage** geometryProcessor,
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
egdaniel170f90b2014-09-16 12:54:40 -070051 bool inputColorIsUsed = optState.inputColorIsUsed();
52 bool inputCoverageIsUsed = optState.inputColorIsUsed();
bsalomon@google.com798c8c42013-03-27 19:50:27 +000053
54 // The descriptor is used as a cache key. Thus when a field of the
55 // descriptor will not affect program generation (because of the attribute
56 // bindings in use or other descriptor field settings) it should be set
57 // to a canonical value to avoid duplicate programs with different keys.
58
egdaniel170f90b2014-09-16 12:54:40 -070059 bool requiresColorAttrib = optState.hasColorVertexAttribute();
60 bool requiresCoverageAttrib = optState.hasCoverageVertexAttribute();
egdaniela7dc0a82014-09-17 08:25:05 -070061 bool requiresLocalCoordAttrib = optState.requiresLocalCoordAttrib();
kkinnunenec56e452014-08-25 22:21:16 -070062
egdaniel170f90b2014-09-16 12:54:40 -070063 int numStages = optState.numTotalStages();
64
bsalomon929f29a2014-07-17 07:55:11 -070065 GR_STATIC_ASSERT(0 == kEffectKeyOffsetsAndLengthOffset % sizeof(uint32_t));
bsalomon848faf02014-07-11 10:01:02 -070066 // Make room for everything up to and including the array of offsets to effect keys.
67 desc->fKey.reset();
bsalomon929f29a2014-07-17 07:55:11 -070068 desc->fKey.push_back_n(kEffectKeyOffsetsAndLengthOffset + 2 * sizeof(uint16_t) * numStages);
commit-bot@chromium.org0a6fe712014-04-23 19:26:26 +000069
bsalomon929f29a2014-07-17 07:55:11 -070070 int offsetAndSizeIndex = 0;
bsalomon848faf02014-07-11 10:01:02 -070071 bool effectKeySuccess = true;
joshualittbd769d02014-09-04 08:56:46 -070072
73 KeyHeader* header = desc->header();
74 // make sure any padding in the header is zeroed.
75 memset(desc->header(), 0, kHeaderSize);
76
77 // We can only have one effect which touches the vertex shader
egdaniel170f90b2014-09-16 12:54:40 -070078 if (optState.hasGeometryProcessor()) {
joshualittbd769d02014-09-04 08:56:46 -070079 uint16_t* offsetAndSize =
bsalomon929f29a2014-07-17 07:55:11 -070080 reinterpret_cast<uint16_t*>(desc->fKey.begin() + kEffectKeyOffsetsAndLengthOffset +
81 offsetAndSizeIndex * 2 * sizeof(uint16_t));
bsalomon848faf02014-07-11 10:01:02 -070082
83 GrEffectKeyBuilder b(&desc->fKey);
bsalomon929f29a2014-07-17 07:55:11 -070084 uint16_t effectKeySize;
85 uint32_t effectOffset = desc->fKey.count();
egdaniela7dc0a82014-09-17 08:25:05 -070086 effectKeySuccess |= GetEffectKey(*optState.getGeometryProcessor(), gpu->glCaps(),
87 requiresLocalCoordAttrib, &b, &effectKeySize);
bsalomon929f29a2014-07-17 07:55:11 -070088 effectKeySuccess |= (effectOffset <= SK_MaxU16);
89
90 offsetAndSize[0] = SkToU16(effectOffset);
91 offsetAndSize[1] = effectKeySize;
92 ++offsetAndSizeIndex;
egdaniel170f90b2014-09-16 12:54:40 -070093 *geometryProcessor = optState.getGeometryProcessor();
joshualittbd769d02014-09-04 08:56:46 -070094 header->fHasGeometryProcessor = true;
95 }
96
egdaniel170f90b2014-09-16 12:54:40 -070097 for (int s = 0; s < optState.numColorStages(); ++s) {
98 uint16_t* offsetAndSize =
99 reinterpret_cast<uint16_t*>(desc->fKey.begin() + kEffectKeyOffsetsAndLengthOffset +
100 offsetAndSizeIndex * 2 * sizeof(uint16_t));
joshualittbd769d02014-09-04 08:56:46 -0700101
egdaniel170f90b2014-09-16 12:54:40 -0700102 GrEffectKeyBuilder b(&desc->fKey);
103 uint16_t effectKeySize;
104 uint32_t effectOffset = desc->fKey.count();
egdaniela7dc0a82014-09-17 08:25:05 -0700105 effectKeySuccess |= GetEffectKey(optState.getColorStage(s), gpu->glCaps(),
106 requiresLocalCoordAttrib, &b, &effectKeySize);
egdaniel170f90b2014-09-16 12:54:40 -0700107 effectKeySuccess |= (effectOffset <= SK_MaxU16);
joshualittbd769d02014-09-04 08:56:46 -0700108
egdaniel170f90b2014-09-16 12:54:40 -0700109 offsetAndSize[0] = SkToU16(effectOffset);
110 offsetAndSize[1] = effectKeySize;
111 ++offsetAndSizeIndex;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000112 }
bsalomon929f29a2014-07-17 07:55:11 -0700113
egdaniel170f90b2014-09-16 12:54:40 -0700114 for (int s = 0; s < optState.numCoverageStages(); ++s) {
115 uint16_t* offsetAndSize =
116 reinterpret_cast<uint16_t*>(desc->fKey.begin() + kEffectKeyOffsetsAndLengthOffset +
117 offsetAndSizeIndex * 2 * sizeof(uint16_t));
bsalomon929f29a2014-07-17 07:55:11 -0700118
egdaniel170f90b2014-09-16 12:54:40 -0700119 GrEffectKeyBuilder b(&desc->fKey);
120 uint16_t effectKeySize;
121 uint32_t effectOffset = desc->fKey.count();
egdaniela7dc0a82014-09-17 08:25:05 -0700122 effectKeySuccess |= GetEffectKey(optState.getCoverageStage(s), gpu->glCaps(),
123 requiresLocalCoordAttrib, &b, &effectKeySize);
egdaniel170f90b2014-09-16 12:54:40 -0700124 effectKeySuccess |= (effectOffset <= SK_MaxU16);
125
126 offsetAndSize[0] = SkToU16(effectOffset);
127 offsetAndSize[1] = effectKeySize;
128 ++offsetAndSizeIndex;
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000129 }
egdaniel170f90b2014-09-16 12:54:40 -0700130
bsalomon848faf02014-07-11 10:01:02 -0700131 if (!effectKeySuccess) {
132 desc->fKey.reset();
133 return false;
134 }
135
bsalomon848faf02014-07-11 10:01:02 -0700136 // Because header is a pointer into the dynamic array, we can't push any new data into the key
137 // below here.
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000138
egdaniela7dc0a82014-09-17 08:25:05 -0700139 // We will only require a vertex shader if we have more than just the position VA attrib.
140 // If we have a geom processor we must us a vertex shader and we should not have a geometry
141 // processor if we are doing path rendering.
142 SkASSERT(!GrGpu::IsPathRenderingDrawType(drawType) || !optState.requiresVertexShader());
143 header->fRequiresVertexShader = optState.requiresVertexShader() ||
144 !GrGpu::IsPathRenderingDrawType(drawType);
commit-bot@chromium.org0a6fe712014-04-23 19:26:26 +0000145 header->fEmitsPointSize = GrGpu::kDrawPoints_DrawType == drawType;
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000146
147 // Currently the experimental GS will only work with triangle prims (and it doesn't do anything
148 // other than pass through values from the VS to the FS anyway).
149#if GR_GL_EXPERIMENTAL_GS
150#if 0
151 header->fExperimentalGS = gpu->caps().geometryShaderSupport();
152#else
153 header->fExperimentalGS = false;
154#endif
155#endif
commit-bot@chromium.orgc4dc0ad2013-10-09 14:11:33 +0000156 bool defaultToUniformInputs = GR_GL_NO_CONSTANT_ATTRIBUTES || gpu->caps()->pathRenderingSupport();
157
egdaniel170f90b2014-09-16 12:54:40 -0700158 if (!inputColorIsUsed) {
egdaniel842b0862014-09-02 10:01:30 -0700159 header->fColorInput = kAllOnes_ColorInput;
egdaniel170f90b2014-09-16 12:54:40 -0700160 } else if (defaultToUniformInputs && !requiresColorAttrib) {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000161 header->fColorInput = kUniform_ColorInput;
162 } else {
163 header->fColorInput = kAttribute_ColorInput;
kkinnunenec56e452014-08-25 22:21:16 -0700164 header->fRequiresVertexShader = true;
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000165 }
166
egdaniel170f90b2014-09-16 12:54:40 -0700167 bool covIsSolidWhite = !requiresCoverageAttrib && 0xffffffff == optState.getCoverageColor();
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000168
egdaniel170f90b2014-09-16 12:54:40 -0700169 if (covIsSolidWhite || !inputCoverageIsUsed) {
egdaniel842b0862014-09-02 10:01:30 -0700170 header->fCoverageInput = kAllOnes_ColorInput;
egdaniel170f90b2014-09-16 12:54:40 -0700171 } else if (defaultToUniformInputs && !requiresCoverageAttrib) {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000172 header->fCoverageInput = kUniform_ColorInput;
173 } else {
174 header->fCoverageInput = kAttribute_ColorInput;
kkinnunenec56e452014-08-25 22:21:16 -0700175 header->fRequiresVertexShader = true;
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000176 }
177
egdaniela7dc0a82014-09-17 08:25:05 -0700178 if (optState.readsDst()) {
bsalomon49f085d2014-09-05 13:34:00 -0700179 SkASSERT(dstCopy || gpu->caps()->dstReadInShaderSupport());
bsalomon@google.com6b0cf022013-05-03 13:35:14 +0000180 const GrTexture* dstCopyTexture = NULL;
bsalomon49f085d2014-09-05 13:34:00 -0700181 if (dstCopy) {
bsalomon@google.com6b0cf022013-05-03 13:35:14 +0000182 dstCopyTexture = dstCopy->texture();
183 }
joshualitt30ba4362014-08-21 20:18:45 -0700184 header->fDstReadKey = GrGLFragmentShaderBuilder::KeyForDstRead(dstCopyTexture,
185 gpu->glCaps());
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000186 SkASSERT(0 != header->fDstReadKey);
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000187 } else {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000188 header->fDstReadKey = 0;
bsalomon@google.comb5158812013-05-13 18:50:25 +0000189 }
190
egdaniela7dc0a82014-09-17 08:25:05 -0700191 if (optState.readsFragPosition()) {
joshualitt30ba4362014-08-21 20:18:45 -0700192 header->fFragPosKey = GrGLFragmentShaderBuilder::KeyForFragmentPosition(
egdaniel170f90b2014-09-16 12:54:40 -0700193 optState.getRenderTarget(), gpu->glCaps());
bsalomon@google.comb5158812013-05-13 18:50:25 +0000194 } else {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000195 header->fFragPosKey = 0;
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000196 }
197
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000198 // Record attribute indices
egdaniel170f90b2014-09-16 12:54:40 -0700199 header->fPositionAttributeIndex = optState.positionAttributeIndex();
200 header->fLocalCoordAttributeIndex = optState.localCoordAttributeIndex();
skia.committer@gmail.com2d816ad2013-05-23 07:01:22 +0000201
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000202 // For constant color and coverage we need an attribute with an index beyond those already set
egdaniel170f90b2014-09-16 12:54:40 -0700203 int availableAttributeIndex = optState.getVertexAttribCount();
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000204 if (requiresColorAttrib) {
egdaniel170f90b2014-09-16 12:54:40 -0700205 header->fColorAttributeIndex = optState.colorVertexAttributeIndex();
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000206 } else if (GrGLProgramDesc::kAttribute_ColorInput == header->fColorInput) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000207 SkASSERT(availableAttributeIndex < GrDrawState::kMaxVertexAttribCnt);
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000208 header->fColorAttributeIndex = availableAttributeIndex;
209 availableAttributeIndex++;
210 } else {
211 header->fColorAttributeIndex = -1;
212 }
skia.committer@gmail.com2d816ad2013-05-23 07:01:22 +0000213
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000214 if (requiresCoverageAttrib) {
egdaniel170f90b2014-09-16 12:54:40 -0700215 header->fCoverageAttributeIndex = optState.coverageVertexAttributeIndex();
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000216 } else if (GrGLProgramDesc::kAttribute_ColorInput == header->fCoverageInput) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000217 SkASSERT(availableAttributeIndex < GrDrawState::kMaxVertexAttribCnt);
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000218 header->fCoverageAttributeIndex = availableAttributeIndex;
219 } else {
220 header->fCoverageAttributeIndex = -1;
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000221 }
222
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000223 // Here we deal with whether/how we handle color and coverage separately.
skia.committer@gmail.com2d816ad2013-05-23 07:01:22 +0000224
commit-bot@chromium.org8a135882014-02-05 16:29:12 +0000225 // Set this default and then possibly change our mind if there is coverage.
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000226 header->fCoverageOutput = kModulate_CoverageOutput;
227
228 // If we do have coverage determine whether it matters.
egdaniel170f90b2014-09-16 12:54:40 -0700229 bool separateCoverageFromColor = optState.hasGeometryProcessor();
230 if (!optState.isCoverageDrawing() &&
231 (optState.numCoverageStages() > 0 ||
232 optState.hasGeometryProcessor() ||
joshualittbd769d02014-09-04 08:56:46 -0700233 requiresCoverageAttrib)) {
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000234
egdaniel170f90b2014-09-16 12:54:40 -0700235 if (gpu->caps()->dualSourceBlendingSupport()) {
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000236 if (kZero_GrBlendCoeff == dstCoeff) {
237 // write the coverage value to second color
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000238 header->fCoverageOutput = kSecondaryCoverage_CoverageOutput;
239 separateCoverageFromColor = true;
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000240 } else if (kSA_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 = kSecondaryCoverageISA_CoverageOutput;
243 separateCoverageFromColor = true;
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000244 } else if (kSC_GrBlendCoeff == dstCoeff) {
245 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000246 header->fCoverageOutput = kSecondaryCoverageISC_CoverageOutput;
247 separateCoverageFromColor = true;
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000248 }
egdaniela7dc0a82014-09-17 08:25:05 -0700249 } else if (optState.readsDst() &&
bsalomon@google.com0c89db22013-05-15 17:53:04 +0000250 kOne_GrBlendCoeff == srcCoeff &&
251 kZero_GrBlendCoeff == dstCoeff) {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000252 header->fCoverageOutput = kCombineWithDst_CoverageOutput;
253 separateCoverageFromColor = true;
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000254 }
255 }
joshualittbd769d02014-09-04 08:56:46 -0700256
egdaniel170f90b2014-09-16 12:54:40 -0700257 for (int s = 0; s < optState.numColorStages(); ++s) {
258 colorStages->push_back(&optState.getColorStage(s));
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000259 }
egdaniel170f90b2014-09-16 12:54:40 -0700260 SkTArray<const GrEffectStage*, true>* array;
261 if (separateCoverageFromColor) {
262 array = coverageStages;
263 } else {
264 array = colorStages;
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000265 }
egdaniel170f90b2014-09-16 12:54:40 -0700266 for (int s = 0; s < optState.numCoverageStages(); ++s) {
267 array->push_back(&optState.getCoverageStage(s));
268 }
269
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +0000270 header->fColorEffectCnt = colorStages->count();
271 header->fCoverageEffectCnt = coverageStages->count();
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000272
bsalomon848faf02014-07-11 10:01:02 -0700273 desc->finalize();
274 return true;
275}
276
277void GrGLProgramDesc::finalize() {
278 int keyLength = fKey.count();
279 SkASSERT(0 == (keyLength % 4));
280 *this->atOffset<uint32_t, kLengthOffset>() = SkToU32(keyLength);
281
282 uint32_t* checksum = this->atOffset<uint32_t, kChecksumOffset>();
283 *checksum = 0;
284 *checksum = SkChecksum::Compute(reinterpret_cast<uint32_t*>(fKey.begin()), keyLength);
bsalomon@google.com798c8c42013-03-27 19:50:27 +0000285}
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000286
287GrGLProgramDesc& GrGLProgramDesc::operator= (const GrGLProgramDesc& other) {
bsalomon848faf02014-07-11 10:01:02 -0700288 size_t keyLength = other.keyLength();
289 fKey.reset(keyLength);
290 memcpy(fKey.begin(), other.fKey.begin(), keyLength);
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000291 return *this;
292}