blob: 5f567912f61975cd1a124289c7f17704661d40a7 [file] [log] [blame]
junov@google.comf93e7172011-03-31 21:26:24 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2011 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.
junov@google.comf93e7172011-03-31 21:26:24 +00006 */
7
8#include "GrGLProgram.h"
9
tomhudson@google.comd8f856c2012-05-10 12:13:36 +000010#include "GrAllocator.h"
bsalomon@google.coma469c282012-10-24 18:28:34 +000011#include "GrEffect.h"
bsalomon@google.comc7818882013-03-20 19:19:53 +000012#include "GrDrawEffect.h"
bsalomon@google.comd698f772012-10-25 13:22:00 +000013#include "GrGLEffect.h"
bsalomon@google.com34cccde2013-01-04 18:34:30 +000014#include "GrGpuGL.h"
bsalomon@google.com4fa66942011-09-20 19:06:12 +000015#include "GrGLShaderVar.h"
bsalomon@google.com396e61f2012-10-25 19:00:29 +000016#include "GrBackendEffectFactory.h"
tomhudson@google.com0c8d93a2011-07-01 17:08:26 +000017#include "SkTrace.h"
Scroggo97c88c22011-05-11 14:05:25 +000018#include "SkXfermode.h"
19
humper@google.com7af56be2013-01-14 18:49:19 +000020#include "SkRTConf.h"
21
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +000022SK_DEFINE_INST_COUNT(GrGLProgram)
23
robertphillips@google.com6177e692013-02-28 20:16:25 +000024#define GL_CALL(X) GR_GL_CALL(fContext.interface(), X)
25#define GL_CALL_RET(R, X) GR_GL_CALL_RET(fContext.interface(), R, X)
bsalomon@google.comecb60aa2012-07-18 13:20:29 +000026
jvanverth@google.com65eb4d52013-03-19 18:51:02 +000027SK_CONF_DECLARE(bool, c_PrintShaders, "gpu.printShaders", false,
28 "Print the source code for all shaders generated.");
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +000029
junov@google.comf93e7172011-03-31 21:26:24 +000030#define COL_ATTR_NAME "aColor"
bsalomon@google.coma3108262011-10-10 14:08:47 +000031#define COV_ATTR_NAME "aCoverage"
bsalomon@google.comaeb21602011-08-30 18:13:44 +000032#define EDGE_ATTR_NAME "aEdge"
junov@google.comf93e7172011-03-31 21:26:24 +000033
bsalomon@google.com4fa66942011-09-20 19:06:12 +000034namespace {
bsalomon@google.com4fa66942011-09-20 19:06:12 +000035inline const char* declared_color_output_name() { return "fsColorOut"; }
36inline const char* dual_source_output_name() { return "dualSourceOut"; }
bsalomon@google.com4fa66942011-09-20 19:06:12 +000037}
junov@google.com6acc9b32011-05-16 18:32:07 +000038
jvanverth@google.com9b855c72013-03-01 18:21:22 +000039const GrGLProgram::AttribLayout GrGLProgram::kAttribLayouts[kGrVertexAttribTypeCount] = {
40 {1, GR_GL_FLOAT, false}, // kFloat_GrVertexAttribType
41 {2, GR_GL_FLOAT, false}, // kVec2f_GrVertexAttribType
42 {3, GR_GL_FLOAT, false}, // kVec3f_GrVertexAttribType
43 {4, GR_GL_FLOAT, false}, // kVec4f_GrVertexAttribType
44 {4, GR_GL_UNSIGNED_BYTE, true}, // kVec4ub_GrVertexAttribType
45};
46
bsalomon@google.com91207482013-02-12 21:45:24 +000047void GrGLProgram::BuildDesc(const GrDrawState& drawState,
48 bool isPoints,
49 GrDrawState::BlendOptFlags blendOpts,
50 GrBlendCoeff srcCoeff,
51 GrBlendCoeff dstCoeff,
52 const GrGpuGL* gpu,
53 Desc* desc) {
54
55 // This should already have been caught
56 GrAssert(!(GrDrawState::kSkipDraw_BlendOptFlag & blendOpts));
57
58 bool skipCoverage = SkToBool(blendOpts & GrDrawState::kEmitTransBlack_BlendOptFlag);
59
60 bool skipColor = SkToBool(blendOpts & (GrDrawState::kEmitTransBlack_BlendOptFlag |
61 GrDrawState::kEmitCoverage_BlendOptFlag));
62
63 // The descriptor is used as a cache key. Thus when a field of the
jvanverth@google.com9b855c72013-03-01 18:21:22 +000064 // descriptor will not affect program generation (because of the attribute
65 // bindings in use or other descriptor field settings) it should be set
bsalomon@google.com91207482013-02-12 21:45:24 +000066 // to a canonical value to avoid duplicate programs with different keys.
67
68 // Must initialize all fields or cache will have false negatives!
jvanverth@google.com9b855c72013-03-01 18:21:22 +000069 desc->fAttribBindings = drawState.getAttribBindings();
bsalomon@google.com91207482013-02-12 21:45:24 +000070
71 desc->fEmitsPointSize = isPoints;
72
jvanverth@google.com65eb4d52013-03-19 18:51:02 +000073 bool requiresAttributeColors =
74 !skipColor && SkToBool(desc->fAttribBindings & GrDrawState::kColor_AttribBindingsBit);
75 bool requiresAttributeCoverage =
76 !skipCoverage && SkToBool(desc->fAttribBindings & GrDrawState::kCoverage_AttribBindingsBit);
bsalomon@google.com91207482013-02-12 21:45:24 +000077
78 // fColorInput/fCoverageInput records how colors are specified for the program So we strip the
jvanverth@google.com9b855c72013-03-01 18:21:22 +000079 // bits from the bindings to avoid false negatives when searching for an existing program in the
bsalomon@google.com91207482013-02-12 21:45:24 +000080 // cache.
jvanverth@google.com65eb4d52013-03-19 18:51:02 +000081 desc->fAttribBindings &=
82 ~(GrDrawState::kColor_AttribBindingsBit | GrDrawState::kCoverage_AttribBindingsBit);
bsalomon@google.com91207482013-02-12 21:45:24 +000083
84 desc->fColorFilterXfermode = skipColor ?
85 SkXfermode::kDst_Mode :
86 drawState.getColorFilterMode();
87
88 // no reason to do edge aa or look at per-vertex coverage if coverage is ignored
89 if (skipCoverage) {
bsalomon@google.com4647f902013-03-26 14:45:27 +000090 desc->fAttribBindings &= ~(GrDrawState::kCoverage_AttribBindingsBit);
bsalomon@google.com91207482013-02-12 21:45:24 +000091 }
92
93 bool colorIsTransBlack = SkToBool(blendOpts & GrDrawState::kEmitTransBlack_BlendOptFlag);
94 bool colorIsSolidWhite = (blendOpts & GrDrawState::kEmitCoverage_BlendOptFlag) ||
95 (!requiresAttributeColors && 0xffffffff == drawState.getColor());
96 if (colorIsTransBlack) {
97 desc->fColorInput = Desc::kTransBlack_ColorInput;
98 } else if (colorIsSolidWhite) {
99 desc->fColorInput = Desc::kSolidWhite_ColorInput;
100 } else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresAttributeColors) {
101 desc->fColorInput = Desc::kUniform_ColorInput;
102 } else {
103 desc->fColorInput = Desc::kAttribute_ColorInput;
104 }
105
106 bool covIsSolidWhite = !requiresAttributeCoverage && 0xffffffff == drawState.getCoverage();
107
108 if (skipCoverage) {
109 desc->fCoverageInput = Desc::kTransBlack_ColorInput;
110 } else if (covIsSolidWhite) {
111 desc->fCoverageInput = Desc::kSolidWhite_ColorInput;
112 } else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresAttributeCoverage) {
113 desc->fCoverageInput = Desc::kUniform_ColorInput;
114 } else {
115 desc->fCoverageInput = Desc::kAttribute_ColorInput;
116 }
117
118 int lastEnabledStage = -1;
119
bsalomon@google.com91207482013-02-12 21:45:24 +0000120 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
121
122 bool skip = s < drawState.getFirstCoverageStage() ? skipColor : skipCoverage;
123 if (!skip && drawState.isStageEnabled(s)) {
124 lastEnabledStage = s;
125 const GrEffectRef& effect = *drawState.getStage(s).getEffect();
126 const GrBackendEffectFactory& factory = effect->getFactory();
bsalomon@google.comc7818882013-03-20 19:19:53 +0000127 bool explicitLocalCoords = (drawState.getAttribBindings() &
128 GrDrawState::kLocalCoords_AttribBindingsBit);
129 GrDrawEffect drawEffect(drawState.getStage(s), explicitLocalCoords);
130 desc->fEffectKeys[s] = factory.glEffectKey(drawEffect, gpu->glCaps());
bsalomon@google.com91207482013-02-12 21:45:24 +0000131 } else {
132 desc->fEffectKeys[s] = 0;
133 }
134 }
135
136 desc->fDualSrcOutput = Desc::kNone_DualSrcOutput;
137
138 // Currently the experimental GS will only work with triangle prims (and it doesn't do anything
139 // other than pass through values from the VS to the FS anyway).
140#if GR_GL_EXPERIMENTAL_GS
141#if 0
bsalomon@google.combcce8922013-03-25 15:38:39 +0000142 desc->fExperimentalGS = gpu->caps().geometryShaderSupport();
bsalomon@google.com91207482013-02-12 21:45:24 +0000143#else
144 desc->fExperimentalGS = false;
145#endif
146#endif
147
bsalomon@google.come9144c62013-03-26 16:42:17 +0000148 // We leave this set to kNumStages until we discover that the coverage/color distinction is
149 // material to the generated program. We do this to avoid distinct keys that generate equivalent
150 // programs.
bsalomon@google.com91207482013-02-12 21:45:24 +0000151 desc->fFirstCoverageStage = GrDrawState::kNumStages;
bsalomon@google.come9144c62013-03-26 16:42:17 +0000152 // This tracks the actual first coverage stage.
153 int firstCoverageStage = GrDrawState::kNumStages;
154 desc->fDiscardIfZeroCoverage = false; // Enabled below if stenciling and there is coverage.
155 bool hasCoverage = false;
156 // If we're rendering coverage-as-color then its as though there are no coverage stages.
157 if (!drawState.isCoverageDrawing()) {
158 // We can have coverage either through a stage or coverage vertex attributes.
159 if (drawState.getFirstCoverageStage() <= lastEnabledStage) {
160 firstCoverageStage = drawState.getFirstCoverageStage();
161 hasCoverage = true;
162 } else {
163 hasCoverage = requiresAttributeCoverage;
164 }
bsalomon@google.com91207482013-02-12 21:45:24 +0000165 }
skia.committer@gmail.com37cbc7f2013-03-27 07:01:04 +0000166
bsalomon@google.com91207482013-02-12 21:45:24 +0000167 if (hasCoverage) {
168 // color filter is applied between color/coverage computation
169 if (SkXfermode::kDst_Mode != desc->fColorFilterXfermode) {
170 desc->fFirstCoverageStage = firstCoverageStage;
171 }
skia.committer@gmail.com37cbc7f2013-03-27 07:01:04 +0000172
bsalomon@google.come9144c62013-03-26 16:42:17 +0000173 // If we're stenciling then we want to discard samples that have zero coverage
174 if (drawState.getStencil().doesWrite()) {
175 desc->fDiscardIfZeroCoverage = true;
176 desc->fFirstCoverageStage = firstCoverageStage;
177 }
bsalomon@google.com91207482013-02-12 21:45:24 +0000178
bsalomon@google.combcce8922013-03-25 15:38:39 +0000179 if (gpu->caps()->dualSourceBlendingSupport() &&
bsalomon@google.com91207482013-02-12 21:45:24 +0000180 !(blendOpts & (GrDrawState::kEmitCoverage_BlendOptFlag |
181 GrDrawState::kCoverageAsAlpha_BlendOptFlag))) {
182 if (kZero_GrBlendCoeff == dstCoeff) {
183 // write the coverage value to second color
184 desc->fDualSrcOutput = Desc::kCoverage_DualSrcOutput;
185 desc->fFirstCoverageStage = firstCoverageStage;
186 } else if (kSA_GrBlendCoeff == dstCoeff) {
187 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
188 desc->fDualSrcOutput = Desc::kCoverageISA_DualSrcOutput;
189 desc->fFirstCoverageStage = firstCoverageStage;
190 } else if (kSC_GrBlendCoeff == dstCoeff) {
191 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
192 desc->fDualSrcOutput = Desc::kCoverageISC_DualSrcOutput;
193 desc->fFirstCoverageStage = firstCoverageStage;
194 }
195 }
196 }
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000197
198 desc->fPositionAttributeIndex = drawState.getAttribIndex(GrDrawState::kPosition_AttribIndex);
199 if (requiresAttributeColors) {
200 desc->fColorAttributeIndex = drawState.getAttribIndex(GrDrawState::kColor_AttribIndex);
201 } else {
202 desc->fColorAttributeIndex = GrDrawState::kColorOverrideAttribIndexValue;
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000203 }
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000204 if (requiresAttributeCoverage) {
205 desc->fCoverageAttributeIndex = drawState.getAttribIndex(GrDrawState::kCoverage_AttribIndex);
206 } else {
207 desc->fCoverageAttributeIndex = GrDrawState::kCoverageOverrideAttribIndexValue;
208 }
bsalomon@google.comc7818882013-03-20 19:19:53 +0000209 if (desc->fAttribBindings & GrDrawState::kLocalCoords_AttribBindingsBit) {
210 desc->fLocalCoordsAttributeIndex = drawState.getAttribIndex(GrDrawState::kLocalCoords_AttribIndex);
robertphillips@google.com37ebe3f2013-03-04 20:03:44 +0000211 }
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000212
213#if GR_DEBUG
214 // verify valid vertex attribute state
215 const GrVertexAttrib* vertexAttribs = drawState.getVertexAttribs();
216 GrAssert(desc->fPositionAttributeIndex < GrDrawState::kVertexAttribCnt);
217 GrAssert(kAttribLayouts[vertexAttribs[desc->fPositionAttributeIndex].fType].fCount == 2);
218 if (requiresAttributeColors) {
219 GrAssert(desc->fColorAttributeIndex < GrDrawState::kVertexAttribCnt);
220 GrAssert(kAttribLayouts[vertexAttribs[desc->fColorAttributeIndex].fType].fCount == 4);
221 }
222 if (requiresAttributeCoverage) {
223 GrAssert(desc->fCoverageAttributeIndex < GrDrawState::kVertexAttribCnt);
224 GrAssert(kAttribLayouts[vertexAttribs[desc->fCoverageAttributeIndex].fType].fCount == 4);
225 }
bsalomon@google.comc7818882013-03-20 19:19:53 +0000226 if (desc->fAttribBindings & GrDrawState::kLocalCoords_AttribBindingsBit) {
227 GrAssert(desc->fLocalCoordsAttributeIndex < GrDrawState::kVertexAttribCnt);
228 GrAssert(kAttribLayouts[vertexAttribs[desc->fLocalCoordsAttributeIndex].fType].fCount == 2);
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000229 }
230#endif
bsalomon@google.com91207482013-02-12 21:45:24 +0000231}
232
robertphillips@google.com6177e692013-02-28 20:16:25 +0000233GrGLProgram* GrGLProgram::Create(const GrGLContext& gl,
bsalomon@google.comecb60aa2012-07-18 13:20:29 +0000234 const Desc& desc,
bsalomon@google.com2eaaefd2012-10-29 19:51:22 +0000235 const GrEffectStage* stages[]) {
236 GrGLProgram* program = SkNEW_ARGS(GrGLProgram, (gl, desc, stages));
bsalomon@google.comecb60aa2012-07-18 13:20:29 +0000237 if (!program->succeeded()) {
238 delete program;
239 program = NULL;
240 }
241 return program;
242}
243
robertphillips@google.com6177e692013-02-28 20:16:25 +0000244GrGLProgram::GrGLProgram(const GrGLContext& gl,
bsalomon@google.comecb60aa2012-07-18 13:20:29 +0000245 const Desc& desc,
bsalomon@google.com2eaaefd2012-10-29 19:51:22 +0000246 const GrEffectStage* stages[])
robertphillips@google.com6177e692013-02-28 20:16:25 +0000247: fContext(gl)
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000248, fUniformManager(gl) {
bsalomon@google.comecb60aa2012-07-18 13:20:29 +0000249 fDesc = desc;
250 fVShaderID = 0;
251 fGShaderID = 0;
252 fFShaderID = 0;
253 fProgramID = 0;
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000254
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000255 fColor = GrColor_ILLEGAL;
256 fColorFilterColor = GrColor_ILLEGAL;
257
bsalomon@google.comecb60aa2012-07-18 13:20:29 +0000258 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com46fba0d2012-10-25 21:42:05 +0000259 fEffects[s] = NULL;
bsalomon@google.comecb60aa2012-07-18 13:20:29 +0000260 }
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000261
bsalomon@google.com2eaaefd2012-10-29 19:51:22 +0000262 this->genProgram(stages);
junov@google.comf93e7172011-03-31 21:26:24 +0000263}
264
265GrGLProgram::~GrGLProgram() {
bsalomon@google.comecb60aa2012-07-18 13:20:29 +0000266 if (fVShaderID) {
267 GL_CALL(DeleteShader(fVShaderID));
268 }
269 if (fGShaderID) {
270 GL_CALL(DeleteShader(fGShaderID));
271 }
272 if (fFShaderID) {
273 GL_CALL(DeleteShader(fFShaderID));
274 }
275 if (fProgramID) {
276 GL_CALL(DeleteProgram(fProgramID));
277 }
278
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000279 for (int i = 0; i < GrDrawState::kNumStages; ++i) {
bsalomon@google.com46fba0d2012-10-25 21:42:05 +0000280 delete fEffects[i];
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000281 }
junov@google.comf93e7172011-03-31 21:26:24 +0000282}
283
bsalomon@google.comecb60aa2012-07-18 13:20:29 +0000284void GrGLProgram::abandon() {
285 fVShaderID = 0;
286 fGShaderID = 0;
287 fFShaderID = 0;
288 fProgramID = 0;
289}
290
tomhudson@google.com0d3f1fb2011-06-01 19:27:31 +0000291void GrGLProgram::overrideBlend(GrBlendCoeff* srcCoeff,
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000292 GrBlendCoeff* dstCoeff) const {
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000293 switch (fDesc.fDualSrcOutput) {
294 case Desc::kNone_DualSrcOutput:
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000295 break;
296 // the prog will write a coverage value to the secondary
297 // output and the dst is blended by one minus that value.
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000298 case Desc::kCoverage_DualSrcOutput:
299 case Desc::kCoverageISA_DualSrcOutput:
300 case Desc::kCoverageISC_DualSrcOutput:
bsalomon@google.com47059542012-06-06 20:51:20 +0000301 *dstCoeff = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000302 break;
303 default:
304 GrCrash("Unexpected dual source blend output");
305 break;
306 }
307}
308
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000309namespace {
310
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000311// given two blend coeffecients determine whether the src
312// and/or dst computation can be omitted.
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000313inline void need_blend_inputs(SkXfermode::Coeff srcCoeff,
314 SkXfermode::Coeff dstCoeff,
315 bool* needSrcValue,
316 bool* needDstValue) {
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000317 if (SkXfermode::kZero_Coeff == srcCoeff) {
318 switch (dstCoeff) {
319 // these all read the src
320 case SkXfermode::kSC_Coeff:
321 case SkXfermode::kISC_Coeff:
322 case SkXfermode::kSA_Coeff:
323 case SkXfermode::kISA_Coeff:
324 *needSrcValue = true;
325 break;
326 default:
327 *needSrcValue = false;
328 break;
329 }
330 } else {
331 *needSrcValue = true;
332 }
333 if (SkXfermode::kZero_Coeff == dstCoeff) {
334 switch (srcCoeff) {
335 // these all read the dst
336 case SkXfermode::kDC_Coeff:
337 case SkXfermode::kIDC_Coeff:
338 case SkXfermode::kDA_Coeff:
339 case SkXfermode::kIDA_Coeff:
340 *needDstValue = true;
341 break;
342 default:
343 *needDstValue = false;
344 break;
345 }
346 } else {
347 *needDstValue = true;
Scroggo97c88c22011-05-11 14:05:25 +0000348 }
349}
350
351/**
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000352 * Create a blend_coeff * value string to be used in shader code. Sets empty
353 * string if result is trivially zero.
354 */
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000355inline void blend_term_string(SkString* str, SkXfermode::Coeff coeff,
356 const char* src, const char* dst,
357 const char* value) {
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000358 switch (coeff) {
359 case SkXfermode::kZero_Coeff: /** 0 */
360 *str = "";
361 break;
362 case SkXfermode::kOne_Coeff: /** 1 */
363 *str = value;
364 break;
365 case SkXfermode::kSC_Coeff:
366 str->printf("(%s * %s)", src, value);
367 break;
368 case SkXfermode::kISC_Coeff:
bsalomon@google.com4af0af62012-08-29 12:59:57 +0000369 str->printf("((%s - %s) * %s)", GrGLSLOnesVecf(4), src, value);
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000370 break;
371 case SkXfermode::kDC_Coeff:
372 str->printf("(%s * %s)", dst, value);
373 break;
374 case SkXfermode::kIDC_Coeff:
bsalomon@google.com4af0af62012-08-29 12:59:57 +0000375 str->printf("((%s - %s) * %s)", GrGLSLOnesVecf(4), dst, value);
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000376 break;
377 case SkXfermode::kSA_Coeff: /** src alpha */
378 str->printf("(%s.a * %s)", src, value);
379 break;
380 case SkXfermode::kISA_Coeff: /** inverse src alpha (i.e. 1 - sa) */
381 str->printf("((1.0 - %s.a) * %s)", src, value);
382 break;
383 case SkXfermode::kDA_Coeff: /** dst alpha */
384 str->printf("(%s.a * %s)", dst, value);
385 break;
386 case SkXfermode::kIDA_Coeff: /** inverse dst alpha (i.e. 1 - da) */
387 str->printf("((1.0 - %s.a) * %s)", dst, value);
388 break;
389 default:
390 GrCrash("Unexpected xfer coeff.");
391 break;
392 }
393}
394/**
Scroggo97c88c22011-05-11 14:05:25 +0000395 * Adds a line to the fragment shader code which modifies the color by
396 * the specified color filter.
397 */
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000398void add_color_filter(GrGLShaderBuilder* builder,
399 const char * outputVar,
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000400 SkXfermode::Coeff uniformCoeff,
401 SkXfermode::Coeff colorCoeff,
402 const char* filterColor,
403 const char* inColor) {
bsalomon@google.comf0a104e2012-07-10 17:51:07 +0000404 SkString colorStr, constStr;
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000405 blend_term_string(&colorStr, colorCoeff, filterColor, inColor, inColor);
406 blend_term_string(&constStr, uniformCoeff, filterColor, inColor, filterColor);
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000407
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000408 SkString sum;
409 GrGLSLAdd4f(&sum, colorStr.c_str(), constStr.c_str());
410 builder->fsCodeAppendf("\t%s = %s;\n", outputVar, sum.c_str());
Scroggo97c88c22011-05-11 14:05:25 +0000411}
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000412}
Scroggo97c88c22011-05-11 14:05:25 +0000413
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000414void GrGLProgram::genInputColor(GrGLShaderBuilder* builder, SkString* inColor) {
415 switch (fDesc.fColorInput) {
416 case GrGLProgram::Desc::kAttribute_ColorInput: {
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000417 builder->addAttribute(kVec4f_GrSLType, COL_ATTR_NAME);
tomhudson@google.com2a2e3ef2011-10-25 19:51:09 +0000418 const char *vsName, *fsName;
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000419 builder->addVarying(kVec4f_GrSLType, "Color", &vsName, &fsName);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000420 builder->vsCodeAppendf("\t%s = " COL_ATTR_NAME ";\n", vsName);
tomhudson@google.com2a2e3ef2011-10-25 19:51:09 +0000421 *inColor = fsName;
422 } break;
bsalomon@google.com777c3aa2012-07-25 20:58:20 +0000423 case GrGLProgram::Desc::kUniform_ColorInput: {
424 const char* name;
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000425 fUniformHandles.fColorUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
426 kVec4f_GrSLType, "Color", &name);
bsalomon@google.com777c3aa2012-07-25 20:58:20 +0000427 *inColor = name;
tomhudson@google.com2a2e3ef2011-10-25 19:51:09 +0000428 break;
bsalomon@google.com777c3aa2012-07-25 20:58:20 +0000429 }
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000430 case GrGLProgram::Desc::kTransBlack_ColorInput:
tomhudson@google.com2a2e3ef2011-10-25 19:51:09 +0000431 GrAssert(!"needComputedColor should be false.");
432 break;
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000433 case GrGLProgram::Desc::kSolidWhite_ColorInput:
tomhudson@google.com2a2e3ef2011-10-25 19:51:09 +0000434 break;
435 default:
436 GrCrash("Unknown color type.");
437 break;
438 }
439}
440
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000441void GrGLProgram::genUniformCoverage(GrGLShaderBuilder* builder, SkString* inOutCoverage) {
bsalomon@google.com777c3aa2012-07-25 20:58:20 +0000442 const char* covUniName;
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000443 fUniformHandles.fCoverageUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
444 kVec4f_GrSLType, "Coverage", &covUniName);
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000445 if (inOutCoverage->size()) {
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000446 builder->fsCodeAppendf("\tvec4 uniCoverage = %s * %s;\n",
447 covUniName, inOutCoverage->c_str());
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000448 *inOutCoverage = "uniCoverage";
449 } else {
bsalomon@google.com777c3aa2012-07-25 20:58:20 +0000450 *inOutCoverage = covUniName;
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000451 }
452}
453
454namespace {
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000455void gen_attribute_coverage(GrGLShaderBuilder* builder,
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000456 SkString* inOutCoverage) {
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000457 builder->addAttribute(kVec4f_GrSLType, COV_ATTR_NAME);
tomhudson@google.com2a2e3ef2011-10-25 19:51:09 +0000458 const char *vsName, *fsName;
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000459 builder->addVarying(kVec4f_GrSLType, "Coverage", &vsName, &fsName);
460 builder->vsCodeAppendf("\t%s = " COV_ATTR_NAME ";\n", vsName);
bsalomon@google.com2401ae82012-01-17 21:03:05 +0000461 if (inOutCoverage->size()) {
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000462 builder->fsCodeAppendf("\tvec4 attrCoverage = %s * %s;\n", fsName, inOutCoverage->c_str());
bsalomon@google.com2401ae82012-01-17 21:03:05 +0000463 *inOutCoverage = "attrCoverage";
tomhudson@google.com2a2e3ef2011-10-25 19:51:09 +0000464 } else {
bsalomon@google.com2401ae82012-01-17 21:03:05 +0000465 *inOutCoverage = fsName;
466 }
467}
bsalomon@google.com4fa66942011-09-20 19:06:12 +0000468}
469
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000470void GrGLProgram::genGeometryShader(GrGLShaderBuilder* builder) const {
bsalomon@google.comedfe1aa2011-09-29 14:40:26 +0000471#if GR_GL_EXPERIMENTAL_GS
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000472 // TODO: The builder should add all this glue code.
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000473 if (fDesc.fExperimentalGS) {
robertphillips@google.com6177e692013-02-28 20:16:25 +0000474 GrAssert(fContext.info().glslGeneration() >= k150_GrGLSLGeneration);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000475 builder->fGSHeader.append("layout(triangles) in;\n"
bsalomon@google.comedfe1aa2011-09-29 14:40:26 +0000476 "layout(triangle_strip, max_vertices = 6) out;\n");
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000477 builder->gsCodeAppend("\tfor (int i = 0; i < 3; ++i) {\n"
478 "\t\tgl_Position = gl_in[i].gl_Position;\n");
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000479 if (fDesc.fEmitsPointSize) {
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000480 builder->gsCodeAppend("\t\tgl_PointSize = 1.0;\n");
bsalomon@google.comedfe1aa2011-09-29 14:40:26 +0000481 }
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000482 GrAssert(builder->fGSInputs.count() == builder->fGSOutputs.count());
483 int count = builder->fGSInputs.count();
bsalomon@google.comedfe1aa2011-09-29 14:40:26 +0000484 for (int i = 0; i < count; ++i) {
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000485 builder->gsCodeAppendf("\t\t%s = %s[i];\n",
486 builder->fGSOutputs[i].getName().c_str(),
487 builder->fGSInputs[i].getName().c_str());
bsalomon@google.comedfe1aa2011-09-29 14:40:26 +0000488 }
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000489 builder->gsCodeAppend("\t\tEmitVertex();\n"
490 "\t}\n"
491 "\tEndPrimitive();\n");
bsalomon@google.comedfe1aa2011-09-29 14:40:26 +0000492 }
493#endif
494}
495
bsalomon@google.comf0a104e2012-07-10 17:51:07 +0000496const char* GrGLProgram::adjustInColor(const SkString& inColor) const {
senorblanco@chromium.orgb3a39b52012-01-05 18:28:56 +0000497 if (inColor.size()) {
498 return inColor.c_str();
499 } else {
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000500 if (Desc::kSolidWhite_ColorInput == fDesc.fColorInput) {
bsalomon@google.com4af0af62012-08-29 12:59:57 +0000501 return GrGLSLOnesVecf(4);
senorblanco@chromium.orgb3a39b52012-01-05 18:28:56 +0000502 } else {
bsalomon@google.com4af0af62012-08-29 12:59:57 +0000503 return GrGLSLZerosVecf(4);
senorblanco@chromium.orgb3a39b52012-01-05 18:28:56 +0000504 }
505 }
506}
507
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000508namespace {
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000509// prints a shader using params similar to glShaderSource
510void print_shader(GrGLint stringCnt,
511 const GrGLchar** strings,
512 GrGLint* stringLengths) {
513 for (int i = 0; i < stringCnt; ++i) {
514 if (NULL == stringLengths || stringLengths[i] < 0) {
515 GrPrintf(strings[i]);
516 } else {
517 GrPrintf("%.*s", stringLengths[i], strings[i]);
518 }
519 }
520}
521
522// Compiles a GL shader, returns shader ID or 0 if failed params have same meaning as glShaderSource
robertphillips@google.com6177e692013-02-28 20:16:25 +0000523GrGLuint compile_shader(const GrGLContext& gl,
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000524 GrGLenum type,
525 int stringCnt,
526 const char** strings,
527 int* stringLengths) {
528 SK_TRACE_EVENT1("GrGLProgram::CompileShader",
529 "stringCount", SkStringPrintf("%i", stringCnt).c_str());
530
531 GrGLuint shader;
bsalomon@google.comecb60aa2012-07-18 13:20:29 +0000532 GR_GL_CALL_RET(gl.interface(), shader, CreateShader(type));
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000533 if (0 == shader) {
534 return 0;
535 }
536
bsalomon@google.comecb60aa2012-07-18 13:20:29 +0000537 const GrGLInterface* gli = gl.interface();
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000538 GrGLint compiled = GR_GL_INIT_ZERO;
bsalomon@google.comecb60aa2012-07-18 13:20:29 +0000539 GR_GL_CALL(gli, ShaderSource(shader, stringCnt, strings, stringLengths));
540 GR_GL_CALL(gli, CompileShader(shader));
541 GR_GL_CALL(gli, GetShaderiv(shader, GR_GL_COMPILE_STATUS, &compiled));
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000542
543 if (!compiled) {
544 GrGLint infoLen = GR_GL_INIT_ZERO;
bsalomon@google.comecb60aa2012-07-18 13:20:29 +0000545 GR_GL_CALL(gli, GetShaderiv(shader, GR_GL_INFO_LOG_LENGTH, &infoLen));
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000546 SkAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
547 if (infoLen > 0) {
548 // retrieve length even though we don't need it to workaround bug in chrome cmd buffer
549 // param validation.
550 GrGLsizei length = GR_GL_INIT_ZERO;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000551 GR_GL_CALL(gli, GetShaderInfoLog(shader, infoLen+1,
bsalomon@google.comecb60aa2012-07-18 13:20:29 +0000552 &length, (char*)log.get()));
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000553 print_shader(stringCnt, strings, stringLengths);
554 GrPrintf("\n%s", log.get());
555 }
556 GrAssert(!"Shader compilation failed!");
bsalomon@google.comecb60aa2012-07-18 13:20:29 +0000557 GR_GL_CALL(gli, DeleteShader(shader));
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000558 return 0;
559 }
560 return shader;
561}
562
563// helper version of above for when shader is already flattened into a single SkString
robertphillips@google.com6177e692013-02-28 20:16:25 +0000564GrGLuint compile_shader(const GrGLContext& gl, GrGLenum type, const SkString& shader) {
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000565 const GrGLchar* str = shader.c_str();
566 int length = shader.size();
567 return compile_shader(gl, type, 1, &str, &length);
568}
569
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000570}
571
572// compiles all the shaders from builder and stores the shader IDs
bsalomon@google.comecb60aa2012-07-18 13:20:29 +0000573bool GrGLProgram::compileShaders(const GrGLShaderBuilder& builder) {
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000574
575 SkString shader;
576
577 builder.getShader(GrGLShaderBuilder::kVertex_ShaderType, &shader);
humper@google.com7af56be2013-01-14 18:49:19 +0000578 if (c_PrintShaders) {
579 GrPrintf(shader.c_str());
580 GrPrintf("\n");
581 }
skia.committer@gmail.com7fc0e0a2013-01-15 02:01:40 +0000582
robertphillips@google.com6177e692013-02-28 20:16:25 +0000583 if (!(fVShaderID = compile_shader(fContext, GR_GL_VERTEX_SHADER, shader))) {
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000584 return false;
585 }
586
587 if (builder.fUsesGS) {
588 builder.getShader(GrGLShaderBuilder::kGeometry_ShaderType, &shader);
humper@google.com7af56be2013-01-14 18:49:19 +0000589 if (c_PrintShaders) {
590 GrPrintf(shader.c_str());
591 GrPrintf("\n");
592 }
robertphillips@google.com6177e692013-02-28 20:16:25 +0000593 if (!(fGShaderID = compile_shader(fContext, GR_GL_GEOMETRY_SHADER, shader))) {
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000594 return false;
595 }
596 } else {
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000597 fGShaderID = 0;
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000598 }
599
600 builder.getShader(GrGLShaderBuilder::kFragment_ShaderType, &shader);
humper@google.com7af56be2013-01-14 18:49:19 +0000601 if (c_PrintShaders) {
602 GrPrintf(shader.c_str());
603 GrPrintf("\n");
604 }
robertphillips@google.com6177e692013-02-28 20:16:25 +0000605 if (!(fFShaderID = compile_shader(fContext, GR_GL_FRAGMENT_SHADER, shader))) {
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000606 return false;
607 }
608
609 return true;
610}
611
bsalomon@google.com2eaaefd2012-10-29 19:51:22 +0000612bool GrGLProgram::genProgram(const GrEffectStage* stages[]) {
bsalomon@google.comecb60aa2012-07-18 13:20:29 +0000613 GrAssert(0 == fProgramID);
614
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000615 const GrAttribBindings& attribBindings = fDesc.fAttribBindings;
bsalomon@google.comc7818882013-03-20 19:19:53 +0000616 bool hasExplicitLocalCoords =
617 SkToBool(attribBindings & GrDrawState::kLocalCoords_AttribBindingsBit);
618 GrGLShaderBuilder builder(fContext.info(), fUniformManager, hasExplicitLocalCoords);
junov@google.comf93e7172011-03-31 21:26:24 +0000619
bsalomon@google.comedfe1aa2011-09-29 14:40:26 +0000620#if GR_GL_EXPERIMENTAL_GS
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000621 builder.fUsesGS = fDesc.fExperimentalGS;
bsalomon@google.comedfe1aa2011-09-29 14:40:26 +0000622#endif
623
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000624 SkXfermode::Coeff colorCoeff, uniformCoeff;
625 // The rest of transfer mode color filters have not been implemented
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000626 if (fDesc.fColorFilterXfermode < SkXfermode::kCoeffModesCnt) {
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000627 GR_DEBUGCODE(bool success =)
tomhudson@google.com0d831722011-06-02 15:37:14 +0000628 SkXfermode::ModeAsCoeff(static_cast<SkXfermode::Mode>
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000629 (fDesc.fColorFilterXfermode),
tomhudson@google.com0d831722011-06-02 15:37:14 +0000630 &uniformCoeff, &colorCoeff);
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000631 GR_DEBUGASSERT(success);
632 } else {
633 colorCoeff = SkXfermode::kOne_Coeff;
634 uniformCoeff = SkXfermode::kZero_Coeff;
635 }
636
bsalomon@google.com67e78c92012-10-17 13:36:14 +0000637 // no need to do the color filter if coverage is 0. The output color is scaled by the coverage.
638 // All the dual source outputs are scaled by the coverage as well.
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000639 if (Desc::kTransBlack_ColorInput == fDesc.fCoverageInput) {
bsalomon@google.com2401ae82012-01-17 21:03:05 +0000640 colorCoeff = SkXfermode::kZero_Coeff;
641 uniformCoeff = SkXfermode::kZero_Coeff;
bsalomon@google.com2401ae82012-01-17 21:03:05 +0000642 }
643
bsalomon@google.com86c1f712011-10-12 14:54:26 +0000644 // If we know the final color is going to be all zeros then we can
bsalomon@google.com67e78c92012-10-17 13:36:14 +0000645 // simplify the color filter coefficients. needComputedColor will then
bsalomon@google.com86c1f712011-10-12 14:54:26 +0000646 // come out false below.
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000647 if (Desc::kTransBlack_ColorInput == fDesc.fColorInput) {
bsalomon@google.com86c1f712011-10-12 14:54:26 +0000648 colorCoeff = SkXfermode::kZero_Coeff;
649 if (SkXfermode::kDC_Coeff == uniformCoeff ||
650 SkXfermode::kDA_Coeff == uniformCoeff) {
651 uniformCoeff = SkXfermode::kZero_Coeff;
652 } else if (SkXfermode::kIDC_Coeff == uniformCoeff ||
653 SkXfermode::kIDA_Coeff == uniformCoeff) {
654 uniformCoeff = SkXfermode::kOne_Coeff;
655 }
656 }
657
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000658 bool needColorFilterUniform;
659 bool needComputedColor;
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000660 need_blend_inputs(uniformCoeff, colorCoeff,
661 &needColorFilterUniform, &needComputedColor);
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000662
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000663 // the dual source output has no canonical var name, have to
664 // declare an output, which is incompatible with gl_FragColor/gl_FragData.
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000665 bool dualSourceOutputWritten = false;
robertphillips@google.com6177e692013-02-28 20:16:25 +0000666 builder.fHeader.append(GrGetGLSLVersionDecl(fContext.info().binding(),
667 fContext.info().glslGeneration()));
bsalomon@google.come55fd0f2012-02-10 15:56:06 +0000668
669 GrGLShaderVar colorOutput;
robertphillips@google.com6177e692013-02-28 20:16:25 +0000670 bool isColorDeclared = GrGLSLSetupFSColorOuput(fContext.info().glslGeneration(),
bsalomon@google.come55fd0f2012-02-10 15:56:06 +0000671 declared_color_output_name(),
672 &colorOutput);
673 if (isColorDeclared) {
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000674 builder.fFSOutputs.push_back(colorOutput);
bsalomon@google.come55fd0f2012-02-10 15:56:06 +0000675 }
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000676
bsalomon@google.com777c3aa2012-07-25 20:58:20 +0000677 const char* viewMName;
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000678 fUniformHandles.fViewMatrixUni = builder.addUniform(GrGLShaderBuilder::kVertex_ShaderType,
679 kMat33f_GrSLType, "ViewM", &viewMName);
bsalomon@google.com341767c2012-05-11 20:47:39 +0000680
skia.committer@gmail.come862d162012-10-31 02:01:18 +0000681
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000682 builder.vsCodeAppendf("\tvec3 pos3 = %s * vec3(%s, 1);\n"
683 "\tgl_Position = vec4(pos3.xy, 0, pos3.z);\n",
684 viewMName, builder.positionAttribute().getName().c_str());
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000685
bsalomon@google.com91961302011-05-09 18:39:58 +0000686 // incoming color to current stage being processed.
bsalomon@google.comf0a104e2012-07-10 17:51:07 +0000687 SkString inColor;
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000688
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000689 if (needComputedColor) {
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000690 this->genInputColor(&builder, &inColor);
junov@google.comf93e7172011-03-31 21:26:24 +0000691 }
692
bsalomon@google.comedfe1aa2011-09-29 14:40:26 +0000693 // we output point size in the GS if present
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000694 if (fDesc.fEmitsPointSize && !builder.fUsesGS){
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000695 builder.vsCodeAppend("\tgl_PointSize = 1.0;\n");
junov@google.comf93e7172011-03-31 21:26:24 +0000696 }
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000697
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000698 ///////////////////////////////////////////////////////////////////////////
699 // compute the final color
Scroggo97c88c22011-05-11 14:05:25 +0000700
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000701 // if we have color stages string them together, feeding the output color
702 // of each to the next and generating code for each stage.
703 if (needComputedColor) {
bsalomon@google.comf0a104e2012-07-10 17:51:07 +0000704 SkString outColor;
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000705 for (int s = 0; s < fDesc.fFirstCoverageStage; ++s) {
bsalomon@google.comdbe49f72012-11-05 16:36:02 +0000706 if (GrGLEffect::kNoEffectKey != fDesc.fEffectKeys[s]) {
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000707 // create var to hold stage result
708 outColor = "color";
709 outColor.appendS32(s);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000710 builder.fsCodeAppendf("\tvec4 %s;\n", outColor.c_str());
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000711
bsalomon@google.comf06df1b2012-09-06 20:22:31 +0000712 builder.setCurrentStage(s);
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000713 fEffects[s] = builder.createAndEmitGLEffect(*stages[s],
714 fDesc.fEffectKeys[s],
715 inColor.size() ? inColor.c_str() : NULL,
716 outColor.c_str(),
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000717 &fUniformHandles.fSamplerUnis[s]);
bsalomon@google.comf06df1b2012-09-06 20:22:31 +0000718 builder.setNonStage();
junov@google.comf93e7172011-03-31 21:26:24 +0000719 inColor = outColor;
junov@google.comf93e7172011-03-31 21:26:24 +0000720 }
721 }
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000722 }
Scroggo97c88c22011-05-11 14:05:25 +0000723
bsalomon@google.com86c1f712011-10-12 14:54:26 +0000724 // if have all ones or zeros for the "dst" input to the color filter then we
725 // may be able to make additional optimizations.
726 if (needColorFilterUniform && needComputedColor && !inColor.size()) {
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000727 GrAssert(Desc::kSolidWhite_ColorInput == fDesc.fColorInput);
bsalomon@google.com86c1f712011-10-12 14:54:26 +0000728 bool uniformCoeffIsZero = SkXfermode::kIDC_Coeff == uniformCoeff ||
729 SkXfermode::kIDA_Coeff == uniformCoeff;
730 if (uniformCoeffIsZero) {
731 uniformCoeff = SkXfermode::kZero_Coeff;
732 bool bogus;
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000733 need_blend_inputs(SkXfermode::kZero_Coeff, colorCoeff,
734 &needColorFilterUniform, &bogus);
bsalomon@google.com86c1f712011-10-12 14:54:26 +0000735 }
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000736 }
bsalomon@google.com777c3aa2012-07-25 20:58:20 +0000737 const char* colorFilterColorUniName = NULL;
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000738 if (needColorFilterUniform) {
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000739 fUniformHandles.fColorFilterUni = builder.addUniform(
740 GrGLShaderBuilder::kFragment_ShaderType,
741 kVec4f_GrSLType, "FilterColor",
742 &colorFilterColorUniName);
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000743 }
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000744 bool wroteFragColorZero = false;
tomhudson@google.com0d831722011-06-02 15:37:14 +0000745 if (SkXfermode::kZero_Coeff == uniformCoeff &&
bsalomon@google.com67e78c92012-10-17 13:36:14 +0000746 SkXfermode::kZero_Coeff == colorCoeff) {
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000747 builder.fsCodeAppendf("\t%s = %s;\n", colorOutput.getName().c_str(), GrGLSLZerosVecf(4));
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000748 wroteFragColorZero = true;
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000749 } else if (SkXfermode::kDst_Mode != fDesc.fColorFilterXfermode) {
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000750 builder.fsCodeAppend("\tvec4 filteredColor;\n");
senorblanco@chromium.orgb3a39b52012-01-05 18:28:56 +0000751 const char* color = adjustInColor(inColor);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000752 add_color_filter(&builder, "filteredColor", uniformCoeff,
753 colorCoeff, colorFilterColorUniName, color);
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000754 inColor = "filteredColor";
755 }
756
757 ///////////////////////////////////////////////////////////////////////////
758 // compute the partial coverage (coverage stages and edge aa)
759
bsalomon@google.comf0a104e2012-07-10 17:51:07 +0000760 SkString inCoverage;
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000761 bool coverageIsZero = Desc::kTransBlack_ColorInput == fDesc.fCoverageInput;
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000762 // we don't need to compute coverage at all if we know the final shader
763 // output will be zero and we don't have a dual src blend output.
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000764 if (!wroteFragColorZero || Desc::kNone_DualSrcOutput != fDesc.fDualSrcOutput) {
bsalomon@google.com66105672011-09-15 15:12:00 +0000765
bsalomon@google.com2401ae82012-01-17 21:03:05 +0000766 if (!coverageIsZero) {
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000767 switch (fDesc.fCoverageInput) {
768 case Desc::kSolidWhite_ColorInput:
bsalomon@google.com2401ae82012-01-17 21:03:05 +0000769 // empty string implies solid white
770 break;
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000771 case Desc::kAttribute_ColorInput:
772 gen_attribute_coverage(&builder, &inCoverage);
bsalomon@google.com2401ae82012-01-17 21:03:05 +0000773 break;
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000774 case Desc::kUniform_ColorInput:
775 this->genUniformCoverage(&builder, &inCoverage);
bsalomon@google.com2401ae82012-01-17 21:03:05 +0000776 break;
777 default:
778 GrCrash("Unexpected input coverage.");
779 }
bsalomon@google.coma3108262011-10-10 14:08:47 +0000780
bsalomon@google.comf0a104e2012-07-10 17:51:07 +0000781 SkString outCoverage;
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000782 const int& startStage = fDesc.fFirstCoverageStage;
bsalomon@google.com2401ae82012-01-17 21:03:05 +0000783 for (int s = startStage; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.comdbe49f72012-11-05 16:36:02 +0000784 if (fDesc.fEffectKeys[s]) {
bsalomon@google.com2401ae82012-01-17 21:03:05 +0000785 // create var to hold stage output
786 outCoverage = "coverage";
787 outCoverage.appendS32(s);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000788 builder.fsCodeAppendf("\tvec4 %s;\n", outCoverage.c_str());
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000789
bsalomon@google.comf06df1b2012-09-06 20:22:31 +0000790 builder.setCurrentStage(s);
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000791 fEffects[s] = builder.createAndEmitGLEffect(
792 *stages[s],
793 fDesc.fEffectKeys[s],
794 inCoverage.size() ? inCoverage.c_str() : NULL,
795 outCoverage.c_str(),
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000796 &fUniformHandles.fSamplerUnis[s]);
bsalomon@google.comf06df1b2012-09-06 20:22:31 +0000797 builder.setNonStage();
bsalomon@google.com2401ae82012-01-17 21:03:05 +0000798 inCoverage = outCoverage;
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000799 }
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000800 }
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000801
802 // discard if coverage is zero
bsalomon@google.come9144c62013-03-26 16:42:17 +0000803 if (fDesc.fDiscardIfZeroCoverage && !outCoverage.isEmpty()) {
jvanverth@google.com65eb4d52013-03-19 18:51:02 +0000804 builder.fsCodeAppendf(
805 "\tif (all(lessThanEqual(%s, vec4(0.0)))) {\n\t\tdiscard;\n\t}\n",
806 outCoverage.c_str());
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000807 }
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000808 }
bsalomon@google.com777c3aa2012-07-25 20:58:20 +0000809
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000810 if (Desc::kNone_DualSrcOutput != fDesc.fDualSrcOutput) {
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000811 builder.fFSOutputs.push_back().set(kVec4f_GrSLType,
812 GrGLShaderVar::kOut_TypeModifier,
813 dual_source_output_name());
bsalomon@google.com2401ae82012-01-17 21:03:05 +0000814 bool outputIsZero = coverageIsZero;
bsalomon@google.comf0a104e2012-07-10 17:51:07 +0000815 SkString coeff;
bsalomon@google.com2401ae82012-01-17 21:03:05 +0000816 if (!outputIsZero &&
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000817 Desc::kCoverage_DualSrcOutput != fDesc.fDualSrcOutput && !wroteFragColorZero) {
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000818 if (!inColor.size()) {
819 outputIsZero = true;
820 } else {
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000821 if (Desc::kCoverageISA_DualSrcOutput == fDesc.fDualSrcOutput) {
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000822 coeff.printf("(1 - %s.a)", inColor.c_str());
823 } else {
824 coeff.printf("(vec4(1,1,1,1) - %s)", inColor.c_str());
825 }
826 }
827 }
828 if (outputIsZero) {
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000829 builder.fsCodeAppendf("\t%s = %s;\n", dual_source_output_name(), GrGLSLZerosVecf(4));
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000830 } else {
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000831 SkString modulate;
832 GrGLSLModulate4f(&modulate, coeff.c_str(), inCoverage.c_str());
833 builder.fsCodeAppendf("\t%s = %s;\n", dual_source_output_name(), modulate.c_str());
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000834 }
835 dualSourceOutputWritten = true;
836 }
junov@google.comf93e7172011-03-31 21:26:24 +0000837 }
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000838
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000839 ///////////////////////////////////////////////////////////////////////////
840 // combine color and coverage as frag color
841
842 if (!wroteFragColorZero) {
bsalomon@google.com2401ae82012-01-17 21:03:05 +0000843 if (coverageIsZero) {
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000844 builder.fsCodeAppendf("\t%s = %s;\n", colorOutput.getName().c_str(), GrGLSLZerosVecf(4));
bsalomon@google.com2401ae82012-01-17 21:03:05 +0000845 } else {
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000846 SkString modulate;
847 GrGLSLModulate4f(&modulate, inColor.c_str(), inCoverage.c_str());
848 builder.fsCodeAppendf("\t%s = %s;\n", colorOutput.getName().c_str(), modulate.c_str());
bsalomon@google.com2401ae82012-01-17 21:03:05 +0000849 }
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000850 }
851
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000852 ///////////////////////////////////////////////////////////////////////////
bsalomon@google.comedfe1aa2011-09-29 14:40:26 +0000853 // insert GS
854#if GR_DEBUG
bsalomon@google.comecb60aa2012-07-18 13:20:29 +0000855 this->genGeometryShader(&builder);
bsalomon@google.comedfe1aa2011-09-29 14:40:26 +0000856#endif
857
858 ///////////////////////////////////////////////////////////////////////////
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000859 // compile and setup attribs and unis
860
bsalomon@google.comecb60aa2012-07-18 13:20:29 +0000861 if (!this->compileShaders(builder)) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000862 return false;
863 }
864
bsalomon@google.com17504f52012-10-30 12:34:25 +0000865 if (!this->bindOutputsAttribsAndLinkProgram(builder,
bsalomon@google.com4fa66942011-09-20 19:06:12 +0000866 isColorDeclared,
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000867 dualSourceOutputWritten)) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000868 return false;
869 }
870
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000871 builder.finished(fProgramID);
872 this->initSamplerUniforms();
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000873 fUniformHandles.fRTHeightUni = builder.getRTHeightUniform();
bsalomon@google.com91961302011-05-09 18:39:58 +0000874
875 return true;
876}
877
bsalomon@google.com17504f52012-10-30 12:34:25 +0000878bool GrGLProgram::bindOutputsAttribsAndLinkProgram(const GrGLShaderBuilder& builder,
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000879 bool bindColorOut,
880 bool bindDualSrcOut) {
881 GL_CALL_RET(fProgramID, CreateProgram());
882 if (!fProgramID) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000883 return false;
884 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000885
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000886 GL_CALL(AttachShader(fProgramID, fVShaderID));
887 if (fGShaderID) {
888 GL_CALL(AttachShader(fProgramID, fGShaderID));
bsalomon@google.comedfe1aa2011-09-29 14:40:26 +0000889 }
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000890 GL_CALL(AttachShader(fProgramID, fFShaderID));
bsalomon@google.com91961302011-05-09 18:39:58 +0000891
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000892 if (bindColorOut) {
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000893 GL_CALL(BindFragDataLocation(fProgramID, 0, declared_color_output_name()));
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000894 }
895 if (bindDualSrcOut) {
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000896 GL_CALL(BindFragDataLocationIndexed(fProgramID, 0, 1, dual_source_output_name()));
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000897 }
898
bsalomon@google.com91961302011-05-09 18:39:58 +0000899 // Bind the attrib locations to same values for all shaders
bsalomon@google.com17504f52012-10-30 12:34:25 +0000900 GL_CALL(BindAttribLocation(fProgramID,
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000901 fDesc.fPositionAttributeIndex,
bsalomon@google.com17504f52012-10-30 12:34:25 +0000902 builder.positionAttribute().c_str()));
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000903 GL_CALL(BindAttribLocation(fProgramID, fDesc.fColorAttributeIndex, COL_ATTR_NAME));
904 GL_CALL(BindAttribLocation(fProgramID, fDesc.fCoverageAttributeIndex, COV_ATTR_NAME));
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000905
bsalomon@google.comc7818882013-03-20 19:19:53 +0000906 if (fDesc.fAttribBindings & GrDrawState::kLocalCoords_AttribBindingsBit) {
907 GL_CALL(BindAttribLocation(fProgramID,
908 fDesc.fLocalCoordsAttributeIndex,
909 builder.localCoordsAttribute().c_str()));
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000910 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000911
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000912 const GrGLShaderBuilder::AttributePair* attribEnd = builder.getEffectAttributes().end();
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000913 for (const GrGLShaderBuilder::AttributePair* attrib = builder.getEffectAttributes().begin();
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000914 attrib != attribEnd;
915 ++attrib) {
916 GL_CALL(BindAttribLocation(fProgramID, attrib->fIndex, attrib->fName.c_str()));
917 }
918
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000919 GL_CALL(LinkProgram(fProgramID));
bsalomon@google.com91961302011-05-09 18:39:58 +0000920
921 GrGLint linked = GR_GL_INIT_ZERO;
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000922 GL_CALL(GetProgramiv(fProgramID, GR_GL_LINK_STATUS, &linked));
bsalomon@google.com91961302011-05-09 18:39:58 +0000923 if (!linked) {
924 GrGLint infoLen = GR_GL_INIT_ZERO;
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000925 GL_CALL(GetProgramiv(fProgramID, GR_GL_INFO_LOG_LENGTH, &infoLen));
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000926 SkAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
bsalomon@google.com91961302011-05-09 18:39:58 +0000927 if (infoLen > 0) {
bsalomon@google.com79afcaa2011-09-14 14:29:18 +0000928 // retrieve length even though we don't need it to workaround
929 // bug in chrome cmd buffer param validation.
930 GrGLsizei length = GR_GL_INIT_ZERO;
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000931 GL_CALL(GetProgramInfoLog(fProgramID,
bsalomon@google.com96399942012-02-13 14:39:16 +0000932 infoLen+1,
933 &length,
934 (char*)log.get()));
bsalomon@google.com91961302011-05-09 18:39:58 +0000935 GrPrintf((char*)log.get());
936 }
937 GrAssert(!"Error linking program");
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000938 GL_CALL(DeleteProgram(fProgramID));
939 fProgramID = 0;
bsalomon@google.com91961302011-05-09 18:39:58 +0000940 return false;
941 }
942 return true;
943}
944
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000945void GrGLProgram::initSamplerUniforms() {
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000946 GL_CALL(UseProgram(fProgramID));
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000947 // We simply bind the uniforms to successive texture units beginning at 0. setData() assumes this
948 // behavior.
949 GrGLint texUnitIdx = 0;
tomhudson@google.com93813632011-10-27 20:21:16 +0000950 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000951 int numSamplers = fUniformHandles.fSamplerUnis[s].count();
952 for (int u = 0; u < numSamplers; ++u) {
953 UniformHandle handle = fUniformHandles.fSamplerUnis[s][u];
954 if (GrGLUniformManager::kInvalidUniformHandle != handle) {
955 fUniformManager.setSampler(handle, texUnitIdx);
956 ++texUnitIdx;
bsalomon@google.com0982d352012-07-31 15:33:25 +0000957 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000958 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000959 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000960}
961
bsalomon@google.comeb715c82012-07-11 15:03:31 +0000962///////////////////////////////////////////////////////////////////////////////
junov@google.comf93e7172011-03-31 21:26:24 +0000963
bsalomon@google.com91207482013-02-12 21:45:24 +0000964void GrGLProgram::setData(GrGpuGL* gpu,
965 GrColor color,
966 GrColor coverage,
967 SharedGLState* sharedState) {
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000968 const GrDrawState& drawState = gpu->getDrawState();
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000969
bsalomon@google.com91207482013-02-12 21:45:24 +0000970 this->setColor(drawState, color, sharedState);
971 this->setCoverage(drawState, coverage, sharedState);
bsalomon@google.com6a51dcb2013-02-13 16:03:51 +0000972 this->setMatrixAndRenderTargetHeight(drawState);
bsalomon@google.com91207482013-02-12 21:45:24 +0000973
974 // Setup the SkXfermode::Mode-based colorfilter uniform if necessary
975 if (GrGLUniformManager::kInvalidUniformHandle != fUniformHandles.fColorFilterUni &&
976 fColorFilterColor != drawState.getColorFilterColor()) {
977 GrGLfloat c[4];
978 GrColorToRGBAFloat(drawState.getColorFilterColor(), c);
979 fUniformManager.set4fv(fUniformHandles.fColorFilterUni, 0, 1, c);
980 fColorFilterColor = drawState.getColorFilterColor();
981 }
982
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000983 GrGLint texUnitIdx = 0;
bsalomon@google.com4285acc2012-10-22 14:11:24 +0000984 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com46fba0d2012-10-25 21:42:05 +0000985 if (NULL != fEffects[s]) {
bsalomon@google.com08283af2012-10-26 13:01:20 +0000986 const GrEffectStage& stage = drawState.getStage(s);
987 GrAssert(NULL != stage.getEffect());
bsalomon@google.comc7818882013-03-20 19:19:53 +0000988
989 bool explicitLocalCoords =
990 (fDesc.fAttribBindings & GrDrawState::kLocalCoords_AttribBindingsBit);
991 GrDrawEffect drawEffect(stage, explicitLocalCoords);
992 fEffects[s]->setData(fUniformManager, drawEffect);
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000993 int numSamplers = fUniformHandles.fSamplerUnis[s].count();
994 for (int u = 0; u < numSamplers; ++u) {
995 UniformHandle handle = fUniformHandles.fSamplerUnis[s][u];
996 if (GrGLUniformManager::kInvalidUniformHandle != handle) {
bsalomon@google.com6340a412013-01-22 19:55:59 +0000997 const GrTextureAccess& access = (*stage.getEffect())->textureAccess(u);
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000998 GrGLTexture* texture = static_cast<GrGLTexture*>(access.getTexture());
999 gpu->bindTexture(texUnitIdx, access.getParams(), texture);
1000 ++texUnitIdx;
1001 }
1002 }
bsalomon@google.com4285acc2012-10-22 14:11:24 +00001003 }
1004 }
skia.committer@gmail.com8ae714b2013-01-05 02:02:05 +00001005}
bsalomon@google.com91207482013-02-12 21:45:24 +00001006
1007void GrGLProgram::setColor(const GrDrawState& drawState,
1008 GrColor color,
1009 SharedGLState* sharedState) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +00001010 if (!(drawState.getAttribBindings() & GrDrawState::kColor_AttribBindingsBit)) {
bsalomon@google.com91207482013-02-12 21:45:24 +00001011 switch (fDesc.fColorInput) {
1012 case GrGLProgram::Desc::kAttribute_ColorInput:
1013 if (sharedState->fConstAttribColor != color) {
1014 // OpenGL ES only supports the float varieties of glVertexAttrib
1015 GrGLfloat c[4];
1016 GrColorToRGBAFloat(color, c);
jvanverth@google.com9b855c72013-03-01 18:21:22 +00001017 GL_CALL(VertexAttrib4fv(fDesc.fColorAttributeIndex, c));
bsalomon@google.com91207482013-02-12 21:45:24 +00001018 sharedState->fConstAttribColor = color;
1019 }
1020 break;
1021 case GrGLProgram::Desc::kUniform_ColorInput:
1022 if (fColor != color) {
1023 // OpenGL ES doesn't support unsigned byte varieties of glUniform
1024 GrGLfloat c[4];
1025 GrColorToRGBAFloat(color, c);
1026 GrAssert(GrGLUniformManager::kInvalidUniformHandle !=
1027 fUniformHandles.fColorUni);
1028 fUniformManager.set4fv(fUniformHandles.fColorUni, 0, 1, c);
1029 fColor = color;
1030 }
1031 break;
1032 case GrGLProgram::Desc::kSolidWhite_ColorInput:
1033 case GrGLProgram::Desc::kTransBlack_ColorInput:
1034 break;
1035 default:
1036 GrCrash("Unknown color type.");
1037 }
1038 }
1039}
1040
1041void GrGLProgram::setCoverage(const GrDrawState& drawState,
1042 GrColor coverage,
1043 SharedGLState* sharedState) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +00001044 if (!(drawState.getAttribBindings() & GrDrawState::kCoverage_AttribBindingsBit)) {
bsalomon@google.com91207482013-02-12 21:45:24 +00001045 switch (fDesc.fCoverageInput) {
1046 case Desc::kAttribute_ColorInput:
1047 if (sharedState->fConstAttribCoverage != coverage) {
1048 // OpenGL ES only supports the float varieties of glVertexAttrib
1049 GrGLfloat c[4];
1050 GrColorToRGBAFloat(coverage, c);
jvanverth@google.com9b855c72013-03-01 18:21:22 +00001051 GL_CALL(VertexAttrib4fv(fDesc.fCoverageAttributeIndex, c));
bsalomon@google.com91207482013-02-12 21:45:24 +00001052 sharedState->fConstAttribCoverage = coverage;
1053 }
1054 break;
1055 case Desc::kUniform_ColorInput:
1056 if (fCoverage != coverage) {
1057 // OpenGL ES doesn't support unsigned byte varieties of glUniform
1058 GrGLfloat c[4];
1059 GrColorToRGBAFloat(coverage, c);
1060 GrAssert(GrGLUniformManager::kInvalidUniformHandle !=
1061 fUniformHandles.fCoverageUni);
1062 fUniformManager.set4fv(fUniformHandles.fCoverageUni, 0, 1, c);
1063 fCoverage = coverage;
1064 }
1065 break;
1066 case Desc::kSolidWhite_ColorInput:
1067 case Desc::kTransBlack_ColorInput:
1068 break;
1069 default:
1070 GrCrash("Unknown coverage type.");
1071 }
1072 }
1073}
bsalomon@google.com6a51dcb2013-02-13 16:03:51 +00001074
1075void GrGLProgram::setMatrixAndRenderTargetHeight(const GrDrawState& drawState) {
1076 const GrRenderTarget* rt = drawState.getRenderTarget();
1077 SkISize size;
1078 size.set(rt->width(), rt->height());
1079
1080 // Load the RT height uniform if it is needed to y-flip gl_FragCoord.
1081 if (GrGLUniformManager::kInvalidUniformHandle != fUniformHandles.fRTHeightUni &&
1082 fMatrixState.fRenderTargetSize.fHeight != size.fHeight) {
1083 fUniformManager.set1f(fUniformHandles.fRTHeightUni, SkIntToScalar(size.fHeight));
1084 }
1085
1086 if (fMatrixState.fRenderTargetOrigin != rt->origin() ||
1087 !fMatrixState.fViewMatrix.cheapEqualTo(drawState.getViewMatrix()) ||
1088 fMatrixState.fRenderTargetSize != size) {
1089 SkMatrix m;
1090 if (kBottomLeft_GrSurfaceOrigin == rt->origin()) {
1091 m.setAll(
1092 SkIntToScalar(2) / size.fWidth, 0, -SK_Scalar1,
1093 0,-SkIntToScalar(2) / size.fHeight, SK_Scalar1,
1094 0, 0, SkMatrix::I()[8]);
1095 } else {
1096 m.setAll(
1097 SkIntToScalar(2) / size.fWidth, 0, -SK_Scalar1,
1098 0, SkIntToScalar(2) / size.fHeight,-SK_Scalar1,
1099 0, 0, SkMatrix::I()[8]);
1100 }
1101 m.setConcat(m, drawState.getViewMatrix());
1102
1103 // ES doesn't allow you to pass true to the transpose param so we do our own transpose.
1104 GrGLfloat mt[] = {
1105 SkScalarToFloat(m[SkMatrix::kMScaleX]),
1106 SkScalarToFloat(m[SkMatrix::kMSkewY]),
1107 SkScalarToFloat(m[SkMatrix::kMPersp0]),
1108 SkScalarToFloat(m[SkMatrix::kMSkewX]),
1109 SkScalarToFloat(m[SkMatrix::kMScaleY]),
1110 SkScalarToFloat(m[SkMatrix::kMPersp1]),
1111 SkScalarToFloat(m[SkMatrix::kMTransX]),
1112 SkScalarToFloat(m[SkMatrix::kMTransY]),
1113 SkScalarToFloat(m[SkMatrix::kMPersp2])
1114 };
1115 fUniformManager.setMatrix3f(fUniformHandles.fViewMatrixUni, mt);
1116 fMatrixState.fViewMatrix = drawState.getViewMatrix();
1117 fMatrixState.fRenderTargetSize = size;
1118 fMatrixState.fRenderTargetOrigin = rt->origin();
1119 }
1120}