blob: 2f8e8076636abcfdc7e99117b5b2c532e2fe7771 [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.com018f1792013-04-18 19:36:09 +000016#include "GrGLSL.h"
Scroggo97c88c22011-05-11 14:05:25 +000017#include "SkXfermode.h"
18
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +000019SK_DEFINE_INST_COUNT(GrGLProgram)
20
commit-bot@chromium.org9188a152013-09-05 18:28:24 +000021#define GL_CALL(X) GR_GL_CALL(fGpu->glInterface(), X)
22#define GL_CALL_RET(R, X) GR_GL_CALL_RET(fGpu->glInterface(), R, X)
bsalomon@google.comecb60aa2012-07-18 13:20:29 +000023
commit-bot@chromium.org9188a152013-09-05 18:28:24 +000024GrGLProgram* GrGLProgram::Create(GrGpuGL* gpu,
bsalomon@google.com31ec7982013-03-27 18:14:57 +000025 const GrGLProgramDesc& desc,
bsalomon@google.com2c84aa32013-06-06 20:28:57 +000026 const GrEffectStage* colorStages[],
27 const GrEffectStage* coverageStages[]) {
commit-bot@chromium.org9188a152013-09-05 18:28:24 +000028 GrGLProgram* program = SkNEW_ARGS(GrGLProgram, (gpu, desc, colorStages, coverageStages));
bsalomon@google.comecb60aa2012-07-18 13:20:29 +000029 if (!program->succeeded()) {
30 delete program;
31 program = NULL;
32 }
33 return program;
34}
35
commit-bot@chromium.org9188a152013-09-05 18:28:24 +000036GrGLProgram::GrGLProgram(GrGpuGL* gpu,
bsalomon@google.com31ec7982013-03-27 18:14:57 +000037 const GrGLProgramDesc& desc,
bsalomon@google.com2c84aa32013-06-06 20:28:57 +000038 const GrEffectStage* colorStages[],
39 const GrEffectStage* coverageStages[])
commit-bot@chromium.org9188a152013-09-05 18:28:24 +000040: fGpu(gpu)
41, fUniformManager(gpu) {
bsalomon@google.comecb60aa2012-07-18 13:20:29 +000042 fDesc = desc;
bsalomon@google.comecb60aa2012-07-18 13:20:29 +000043 fProgramID = 0;
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000044
bsalomon@google.com804e9942013-06-06 18:04:38 +000045 fDstCopyTexUnit = -1;
46
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000047 fColor = GrColor_ILLEGAL;
48 fColorFilterColor = GrColor_ILLEGAL;
49
bsalomon@google.com2c84aa32013-06-06 20:28:57 +000050 fColorEffects.reset(desc.numColorEffects());
51 fCoverageEffects.reset(desc.numCoverageEffects());
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000052
bsalomon@google.com2c84aa32013-06-06 20:28:57 +000053 this->genProgram(colorStages, coverageStages);
junov@google.comf93e7172011-03-31 21:26:24 +000054}
55
56GrGLProgram::~GrGLProgram() {
bsalomon@google.comecb60aa2012-07-18 13:20:29 +000057 if (fProgramID) {
58 GL_CALL(DeleteProgram(fProgramID));
59 }
junov@google.comf93e7172011-03-31 21:26:24 +000060}
61
bsalomon@google.comecb60aa2012-07-18 13:20:29 +000062void GrGLProgram::abandon() {
bsalomon@google.comecb60aa2012-07-18 13:20:29 +000063 fProgramID = 0;
64}
65
tomhudson@google.com0d3f1fb2011-06-01 19:27:31 +000066void GrGLProgram::overrideBlend(GrBlendCoeff* srcCoeff,
bsalomon@google.com271cffc2011-05-20 14:13:56 +000067 GrBlendCoeff* dstCoeff) const {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +000068 switch (fDesc.getHeader().fCoverageOutput) {
bsalomon@google.com5920ac22013-04-19 13:14:45 +000069 case GrGLProgramDesc::kModulate_CoverageOutput:
bsalomon@google.com271cffc2011-05-20 14:13:56 +000070 break;
bsalomon@google.com5920ac22013-04-19 13:14:45 +000071 // The prog will write a coverage value to the secondary
bsalomon@google.com271cffc2011-05-20 14:13:56 +000072 // output and the dst is blended by one minus that value.
bsalomon@google.com5920ac22013-04-19 13:14:45 +000073 case GrGLProgramDesc::kSecondaryCoverage_CoverageOutput:
74 case GrGLProgramDesc::kSecondaryCoverageISA_CoverageOutput:
75 case GrGLProgramDesc::kSecondaryCoverageISC_CoverageOutput:
76 *dstCoeff = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
77 break;
78 case GrGLProgramDesc::kCombineWithDst_CoverageOutput:
79 // We should only have set this if the blend was specified as (1, 0)
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +000080 SkASSERT(kOne_GrBlendCoeff == *srcCoeff && kZero_GrBlendCoeff == *dstCoeff);
bsalomon@google.com5920ac22013-04-19 13:14:45 +000081 break;
bsalomon@google.com271cffc2011-05-20 14:13:56 +000082 default:
bsalomon@google.com5920ac22013-04-19 13:14:45 +000083 GrCrash("Unexpected coverage output");
bsalomon@google.com271cffc2011-05-20 14:13:56 +000084 break;
85 }
86}
87
bsalomon@google.com34cccde2013-01-04 18:34:30 +000088namespace {
bsalomon@google.com5920ac22013-04-19 13:14:45 +000089// given two blend coefficients determine whether the src
bsalomon@google.comf2d91552011-05-16 20:56:06 +000090// and/or dst computation can be omitted.
bsalomon@google.com34cccde2013-01-04 18:34:30 +000091inline void need_blend_inputs(SkXfermode::Coeff srcCoeff,
92 SkXfermode::Coeff dstCoeff,
93 bool* needSrcValue,
94 bool* needDstValue) {
bsalomon@google.comf2d91552011-05-16 20:56:06 +000095 if (SkXfermode::kZero_Coeff == srcCoeff) {
96 switch (dstCoeff) {
97 // these all read the src
98 case SkXfermode::kSC_Coeff:
99 case SkXfermode::kISC_Coeff:
100 case SkXfermode::kSA_Coeff:
101 case SkXfermode::kISA_Coeff:
102 *needSrcValue = true;
103 break;
104 default:
105 *needSrcValue = false;
106 break;
107 }
108 } else {
109 *needSrcValue = true;
110 }
111 if (SkXfermode::kZero_Coeff == dstCoeff) {
112 switch (srcCoeff) {
113 // these all read the dst
114 case SkXfermode::kDC_Coeff:
115 case SkXfermode::kIDC_Coeff:
116 case SkXfermode::kDA_Coeff:
117 case SkXfermode::kIDA_Coeff:
118 *needDstValue = true;
119 break;
120 default:
121 *needDstValue = false;
122 break;
123 }
124 } else {
125 *needDstValue = true;
Scroggo97c88c22011-05-11 14:05:25 +0000126 }
127}
128
129/**
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000130 * Create a blend_coeff * value string to be used in shader code. Sets empty
131 * string if result is trivially zero.
132 */
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000133inline void blend_term_string(SkString* str, SkXfermode::Coeff coeff,
134 const char* src, const char* dst,
135 const char* value) {
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000136 switch (coeff) {
137 case SkXfermode::kZero_Coeff: /** 0 */
138 *str = "";
139 break;
140 case SkXfermode::kOne_Coeff: /** 1 */
141 *str = value;
142 break;
143 case SkXfermode::kSC_Coeff:
144 str->printf("(%s * %s)", src, value);
145 break;
146 case SkXfermode::kISC_Coeff:
bsalomon@google.com4af0af62012-08-29 12:59:57 +0000147 str->printf("((%s - %s) * %s)", GrGLSLOnesVecf(4), src, value);
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000148 break;
149 case SkXfermode::kDC_Coeff:
150 str->printf("(%s * %s)", dst, value);
151 break;
152 case SkXfermode::kIDC_Coeff:
bsalomon@google.com4af0af62012-08-29 12:59:57 +0000153 str->printf("((%s - %s) * %s)", GrGLSLOnesVecf(4), dst, value);
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000154 break;
155 case SkXfermode::kSA_Coeff: /** src alpha */
156 str->printf("(%s.a * %s)", src, value);
157 break;
158 case SkXfermode::kISA_Coeff: /** inverse src alpha (i.e. 1 - sa) */
159 str->printf("((1.0 - %s.a) * %s)", src, value);
160 break;
161 case SkXfermode::kDA_Coeff: /** dst alpha */
162 str->printf("(%s.a * %s)", dst, value);
163 break;
164 case SkXfermode::kIDA_Coeff: /** inverse dst alpha (i.e. 1 - da) */
165 str->printf("((1.0 - %s.a) * %s)", dst, value);
166 break;
167 default:
168 GrCrash("Unexpected xfer coeff.");
169 break;
170 }
171}
172/**
Scroggo97c88c22011-05-11 14:05:25 +0000173 * Adds a line to the fragment shader code which modifies the color by
174 * the specified color filter.
175 */
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000176void add_color_filter(GrGLShaderBuilder* builder,
177 const char * outputVar,
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000178 SkXfermode::Coeff uniformCoeff,
179 SkXfermode::Coeff colorCoeff,
180 const char* filterColor,
181 const char* inColor) {
bsalomon@google.comf0a104e2012-07-10 17:51:07 +0000182 SkString colorStr, constStr;
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000183 blend_term_string(&colorStr, colorCoeff, filterColor, inColor, inColor);
184 blend_term_string(&constStr, uniformCoeff, filterColor, inColor, filterColor);
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000185
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000186 SkString sum;
bsalomon@google.com018f1792013-04-18 19:36:09 +0000187 GrGLSLAddf<4>(&sum, colorStr.c_str(), constStr.c_str());
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000188 builder->fsCodeAppendf("\t%s = %s;\n", outputVar, sum.c_str());
Scroggo97c88c22011-05-11 14:05:25 +0000189}
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000190}
Scroggo97c88c22011-05-11 14:05:25 +0000191
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000192namespace {
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000193
bsalomon@google.com5920ac22013-04-19 13:14:45 +0000194void expand_known_value4f(SkString* string, GrSLConstantVec vec) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000195 SkASSERT(string->isEmpty() == (vec != kNone_GrSLConstantVec));
bsalomon@google.com5920ac22013-04-19 13:14:45 +0000196 switch (vec) {
197 case kNone_GrSLConstantVec:
198 break;
199 case kZeros_GrSLConstantVec:
200 *string = GrGLSLZerosVecf(4);
201 break;
202 case kOnes_GrSLConstantVec:
203 *string = GrGLSLOnesVecf(4);
204 break;
205 }
206}
207
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000208}
209
bsalomon@google.com2c84aa32013-06-06 20:28:57 +0000210bool GrGLProgram::genProgram(const GrEffectStage* colorStages[],
211 const GrEffectStage* coverageStages[]) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000212 SkASSERT(0 == fProgramID);
bsalomon@google.comecb60aa2012-07-18 13:20:29 +0000213
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000214 const GrGLProgramDesc::KeyHeader& header = fDesc.getHeader();
215
commit-bot@chromium.orga4acf122013-09-30 15:13:58 +0000216 bool needsVertexShader = true;
commit-bot@chromium.org5a02cb42013-08-30 20:17:31 +0000217
commit-bot@chromium.org410552a2013-09-30 15:30:27 +0000218 GrGLShaderBuilder builder(fGpu, fUniformManager, fDesc, needsVertexShader);
commit-bot@chromium.org5a02cb42013-08-30 20:17:31 +0000219 if (GrGLShaderBuilder::VertexBuilder* vertexBuilder = builder.getVertexBuilder()) {
commit-bot@chromium.org410552a2013-09-30 15:30:27 +0000220 fUniformHandles.fViewMatrixUni = vertexBuilder->getViewMatrixUniform();
bsalomon@google.come55fd0f2012-02-10 15:56:06 +0000221 }
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000222
bsalomon@google.com91961302011-05-09 18:39:58 +0000223 // incoming color to current stage being processed.
commit-bot@chromium.org410552a2013-09-30 15:30:27 +0000224 SkString inColor = builder.getInputColor();
225 GrSLConstantVec knownColorValue = builder.getKnownColorValue();
junov@google.comf93e7172011-03-31 21:26:24 +0000226
commit-bot@chromium.orga4acf122013-09-30 15:13:58 +0000227 // Get the coeffs for the Mode-based color filter, determine if color is needed.
228 SkXfermode::Coeff colorCoeff;
229 SkXfermode::Coeff filterColorCoeff;
230 SkAssertResult(
commit-bot@chromium.org949eef02013-10-01 18:43:29 +0000231 SkXfermode::ModeAsCoeff(header.fColorFilterXfermode,
commit-bot@chromium.orga4acf122013-09-30 15:13:58 +0000232 &filterColorCoeff,
233 &colorCoeff));
234 bool needColor, needFilterColor;
235 need_blend_inputs(filterColorCoeff, colorCoeff, &needFilterColor, &needColor);
236
bsalomon@google.com504976e2013-05-09 13:45:02 +0000237 // used in order for builder to return the per-stage uniform handles.
bsalomon@google.com804e9942013-06-06 18:04:38 +0000238 typedef SkTArray<GrGLUniformManager::UniformHandle, true>* UniHandleArrayPtr;
239 int maxColorOrCovEffectCnt = GrMax(fDesc.numColorEffects(), fDesc.numCoverageEffects());
240 SkAutoTArray<UniHandleArrayPtr> effectUniformArrays(maxColorOrCovEffectCnt);
241 SkAutoTArray<GrGLEffect*> glEffects(maxColorOrCovEffectCnt);
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000242
bsalomon@google.com504976e2013-05-09 13:45:02 +0000243 if (needColor) {
bsalomon@google.com804e9942013-06-06 18:04:38 +0000244 for (int e = 0; e < fDesc.numColorEffects(); ++e) {
bsalomon@google.com2c84aa32013-06-06 20:28:57 +0000245 effectUniformArrays[e] = &fColorEffects[e].fSamplerUnis;
junov@google.comf93e7172011-03-31 21:26:24 +0000246 }
bsalomon@google.com504976e2013-05-09 13:45:02 +0000247
commit-bot@chromium.orga4acf122013-09-30 15:13:58 +0000248 builder.emitEffects(colorStages,
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000249 fDesc.effectKeys(),
250 fDesc.numColorEffects(),
bsalomon@google.com504976e2013-05-09 13:45:02 +0000251 &inColor,
252 &knownColorValue,
commit-bot@chromium.orga4acf122013-09-30 15:13:58 +0000253 effectUniformArrays.get(),
254 glEffects.get());
255
256 for (int e = 0; e < fDesc.numColorEffects(); ++e) {
257 fColorEffects[e].fGLEffect = glEffects[e];
258 }
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000259 }
Scroggo97c88c22011-05-11 14:05:25 +0000260
bsalomon@google.com018f1792013-04-18 19:36:09 +0000261 // Insert the color filter. This will soon be replaced by a color effect.
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000262 if (SkXfermode::kDst_Mode != header.fColorFilterXfermode) {
bsalomon@google.com018f1792013-04-18 19:36:09 +0000263 const char* colorFilterColorUniName = NULL;
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +0000264 fUniformHandles.fColorFilterUni = builder.addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.com018f1792013-04-18 19:36:09 +0000265 kVec4f_GrSLType, "FilterColor",
266 &colorFilterColorUniName);
267
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000268 builder.fsCodeAppend("\tvec4 filteredColor;\n");
bsalomon@google.com018f1792013-04-18 19:36:09 +0000269 const char* color;
270 // add_color_filter requires a real input string.
271 if (knownColorValue == kOnes_GrSLConstantVec) {
272 color = GrGLSLOnesVecf(4);
273 } else if (knownColorValue == kZeros_GrSLConstantVec) {
274 color = GrGLSLZerosVecf(4);
275 } else {
276 color = inColor.c_str();
277 }
278 add_color_filter(&builder, "filteredColor", filterColorCoeff,
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000279 colorCoeff, colorFilterColorUniName, color);
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000280 inColor = "filteredColor";
281 }
282
283 ///////////////////////////////////////////////////////////////////////////
bsalomon@google.com018f1792013-04-18 19:36:09 +0000284 // compute the partial coverage
commit-bot@chromium.org410552a2013-09-30 15:30:27 +0000285 SkString inCoverage = builder.getInputCoverage();
286 GrSLConstantVec knownCoverageValue = builder.getKnownCoverageValue();
skia.committer@gmail.comcb6dc752013-04-19 07:01:00 +0000287
bsalomon@google.com804e9942013-06-06 18:04:38 +0000288 for (int e = 0; e < fDesc.numCoverageEffects(); ++e) {
bsalomon@google.com2c84aa32013-06-06 20:28:57 +0000289 effectUniformArrays[e] = &fCoverageEffects[e].fSamplerUnis;
bsalomon@google.com018f1792013-04-18 19:36:09 +0000290 }
bsalomon@google.com777c3aa2012-07-25 20:58:20 +0000291
commit-bot@chromium.orga4acf122013-09-30 15:13:58 +0000292 builder.emitEffects(coverageStages,
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000293 fDesc.getEffectKeys() + fDesc.numColorEffects(),
294 fDesc.numCoverageEffects(),
bsalomon@google.com504976e2013-05-09 13:45:02 +0000295 &inCoverage,
296 &knownCoverageValue,
commit-bot@chromium.orga4acf122013-09-30 15:13:58 +0000297 effectUniformArrays.get(),
298 glEffects.get());
299 for (int e = 0; e < fDesc.numCoverageEffects(); ++e) {
300 fCoverageEffects[e].fGLEffect = glEffects[e];
301 }
bsalomon@google.com504976e2013-05-09 13:45:02 +0000302
bsalomon@google.com018f1792013-04-18 19:36:09 +0000303 // discard if coverage is zero
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000304 if (header.fDiscardIfZeroCoverage && kOnes_GrSLConstantVec != knownCoverageValue) {
bsalomon@google.com018f1792013-04-18 19:36:09 +0000305 if (kZeros_GrSLConstantVec == knownCoverageValue) {
306 // This is unfortunate.
307 builder.fsCodeAppend("\tdiscard;\n");
308 } else {
309 builder.fsCodeAppendf("\tif (all(lessThanEqual(%s, vec4(0.0)))) {\n\t\tdiscard;\n\t}\n",
310 inCoverage.c_str());
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000311 }
junov@google.comf93e7172011-03-31 21:26:24 +0000312 }
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000313
commit-bot@chromium.org949eef02013-10-01 18:43:29 +0000314 if (GrGLProgramDesc::CoverageOutputUsesSecondaryOutput(header.fCoverageOutput)) {
commit-bot@chromium.org410552a2013-09-30 15:30:27 +0000315 const char* secondaryOutputName = builder.enableSecondaryOutput();
316
bsalomon@google.com018f1792013-04-18 19:36:09 +0000317 // default coeff to ones for kCoverage_DualSrcOutput
318 SkString coeff;
319 GrSLConstantVec knownCoeffValue = kOnes_GrSLConstantVec;
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000320 if (GrGLProgramDesc::kSecondaryCoverageISA_CoverageOutput == header.fCoverageOutput) {
bsalomon@google.com018f1792013-04-18 19:36:09 +0000321 // Get (1-A) into coeff
322 SkString inColorAlpha;
323 GrGLSLGetComponent4f(&inColorAlpha,
324 inColor.c_str(),
325 kA_GrColorComponentFlag,
326 knownColorValue,
327 true);
328 knownCoeffValue = GrGLSLSubtractf<1>(&coeff,
329 NULL,
330 inColorAlpha.c_str(),
331 kOnes_GrSLConstantVec,
332 knownColorValue,
333 true);
commit-bot@chromium.org949eef02013-10-01 18:43:29 +0000334 } else if (GrGLProgramDesc::kSecondaryCoverageISC_CoverageOutput == header.fCoverageOutput) {
bsalomon@google.com018f1792013-04-18 19:36:09 +0000335 // Get (1-RGBA) into coeff
336 knownCoeffValue = GrGLSLSubtractf<4>(&coeff,
337 NULL,
338 inColor.c_str(),
339 kOnes_GrSLConstantVec,
340 knownColorValue,
341 true);
342 }
343 // Get coeff * coverage into modulate and then write that to the dual source output.
344 SkString modulate;
345 GrGLSLModulatef<4>(&modulate,
346 coeff.c_str(),
347 inCoverage.c_str(),
348 knownCoeffValue,
349 knownCoverageValue,
350 false);
commit-bot@chromium.org410552a2013-09-30 15:30:27 +0000351 builder.fsCodeAppendf("\t%s = %s;\n", secondaryOutputName, modulate.c_str());
bsalomon@google.com018f1792013-04-18 19:36:09 +0000352 }
353
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000354 ///////////////////////////////////////////////////////////////////////////
355 // combine color and coverage as frag color
356
bsalomon@google.com5920ac22013-04-19 13:14:45 +0000357 // Get "color * coverage" into fragColor
358 SkString fragColor;
359 GrSLConstantVec knownFragColorValue = GrGLSLModulatef<4>(&fragColor,
360 inColor.c_str(),
361 inCoverage.c_str(),
362 knownColorValue,
363 knownCoverageValue,
364 true);
365 // Now tack on "+(1-coverage)dst onto the frag color if we were asked to do so.
commit-bot@chromium.org949eef02013-10-01 18:43:29 +0000366 if (GrGLProgramDesc::kCombineWithDst_CoverageOutput == header.fCoverageOutput) {
bsalomon@google.com5920ac22013-04-19 13:14:45 +0000367 SkString dstCoeff;
368 GrSLConstantVec knownDstCoeffValue = GrGLSLSubtractf<4>(&dstCoeff,
369 NULL,
370 inCoverage.c_str(),
371 kOnes_GrSLConstantVec,
372 knownCoverageValue,
373 true);
374 SkString dstContribution;
375 GrSLConstantVec knownDstContributionValue = GrGLSLModulatef<4>(&dstContribution,
376 dstCoeff.c_str(),
377 builder.dstColor(),
378 knownDstCoeffValue,
379 kNone_GrSLConstantVec,
380 true);
381 SkString oldFragColor = fragColor;
382 fragColor.reset();
383 GrGLSLAddf<4>(&fragColor,
384 oldFragColor.c_str(),
385 dstContribution.c_str(),
386 knownFragColorValue,
387 knownDstContributionValue,
388 false);
389 } else {
390 expand_known_value4f(&fragColor, knownFragColorValue);
391 }
commit-bot@chromium.org410552a2013-09-30 15:30:27 +0000392 builder.fsCodeAppendf("\t%s = %s;\n", builder.getColorOutputName(), fragColor.c_str());
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000393
commit-bot@chromium.org410552a2013-09-30 15:30:27 +0000394 if (!builder.finish(&fProgramID)) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000395 return false;
396 }
397
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000398 fUniformHandles.fRTHeightUni = builder.getRTHeightUniform();
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000399 fUniformHandles.fDstCopyTopLeftUni = builder.getDstCopyTopLeftUniform();
400 fUniformHandles.fDstCopyScaleUni = builder.getDstCopyScaleUniform();
commit-bot@chromium.org410552a2013-09-30 15:30:27 +0000401 fUniformHandles.fColorUni = builder.getColorUniform();
402 fUniformHandles.fCoverageUni = builder.getCoverageUniform();
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000403 fUniformHandles.fDstCopySamplerUni = builder.getDstCopySamplerUniform();
404 // This must be called after we set fDstCopySamplerUni above.
405 this->initSamplerUniforms();
bsalomon@google.com91961302011-05-09 18:39:58 +0000406
407 return true;
408}
409
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000410void GrGLProgram::initSamplerUniforms() {
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000411 GL_CALL(UseProgram(fProgramID));
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000412 GrGLint texUnitIdx = 0;
commit-bot@chromium.org7425c122013-08-14 18:14:19 +0000413 if (fUniformHandles.fDstCopySamplerUni.isValid()) {
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000414 fUniformManager.setSampler(fUniformHandles.fDstCopySamplerUni, texUnitIdx);
bsalomon@google.com804e9942013-06-06 18:04:38 +0000415 fDstCopyTexUnit = texUnitIdx++;
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000416 }
417
bsalomon@google.com2c84aa32013-06-06 20:28:57 +0000418 for (int e = 0; e < fColorEffects.count(); ++e) {
419 this->initEffectSamplerUniforms(&fColorEffects[e], &texUnitIdx);
420 }
421
422 for (int e = 0; e < fCoverageEffects.count(); ++e) {
423 this->initEffectSamplerUniforms(&fCoverageEffects[e], &texUnitIdx);
424 }
425}
426
427void GrGLProgram::initEffectSamplerUniforms(EffectAndSamplers* effect, int* texUnitIdx) {
428 int numSamplers = effect->fSamplerUnis.count();
429 effect->fTextureUnits.reset(numSamplers);
430 for (int s = 0; s < numSamplers; ++s) {
431 UniformHandle handle = effect->fSamplerUnis[s];
commit-bot@chromium.org7425c122013-08-14 18:14:19 +0000432 if (handle.isValid()) {
bsalomon@google.com2c84aa32013-06-06 20:28:57 +0000433 fUniformManager.setSampler(handle, *texUnitIdx);
434 effect->fTextureUnits[s] = (*texUnitIdx)++;
bsalomon@google.com91961302011-05-09 18:39:58 +0000435 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000436 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000437}
438
bsalomon@google.comeb715c82012-07-11 15:03:31 +0000439///////////////////////////////////////////////////////////////////////////////
junov@google.comf93e7172011-03-31 21:26:24 +0000440
commit-bot@chromium.org9188a152013-09-05 18:28:24 +0000441void GrGLProgram::setEffectData(const GrEffectStage& stage,
bsalomon@google.com2c84aa32013-06-06 20:28:57 +0000442 const EffectAndSamplers& effect) {
443
444 // Let the GrGLEffect set its data.
445 bool explicitLocalCoords = -1 != fDesc.getHeader().fLocalCoordAttributeIndex;
446 GrDrawEffect drawEffect(stage, explicitLocalCoords);
447 effect.fGLEffect->setData(fUniformManager, drawEffect);
448
449 // Bind the texures for the effect.
450 int numSamplers = effect.fSamplerUnis.count();
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000451 SkASSERT((*stage.getEffect())->numTextures() == numSamplers);
bsalomon@google.com2c84aa32013-06-06 20:28:57 +0000452 for (int s = 0; s < numSamplers; ++s) {
453 UniformHandle handle = effect.fSamplerUnis[s];
commit-bot@chromium.org7425c122013-08-14 18:14:19 +0000454 if (handle.isValid()) {
bsalomon@google.com2c84aa32013-06-06 20:28:57 +0000455 const GrTextureAccess& access = (*stage.getEffect())->textureAccess(s);
456 GrGLTexture* texture = static_cast<GrGLTexture*>(access.getTexture());
457 int unit = effect.fTextureUnits[s];
commit-bot@chromium.org9188a152013-09-05 18:28:24 +0000458 fGpu->bindTexture(unit, access.getParams(), texture);
bsalomon@google.com2c84aa32013-06-06 20:28:57 +0000459 }
460 }
461}
462
commit-bot@chromium.org9188a152013-09-05 18:28:24 +0000463void GrGLProgram::setData(GrDrawState::BlendOptFlags blendOpts,
bsalomon@google.com2c84aa32013-06-06 20:28:57 +0000464 const GrEffectStage* colorStages[],
465 const GrEffectStage* coverageStages[],
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000466 const GrDeviceCoordTexture* dstCopy,
bsalomon@google.com91207482013-02-12 21:45:24 +0000467 SharedGLState* sharedState) {
commit-bot@chromium.org9188a152013-09-05 18:28:24 +0000468 const GrDrawState& drawState = fGpu->getDrawState();
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000469
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000470 GrColor color;
471 GrColor coverage;
472 if (blendOpts & GrDrawState::kEmitTransBlack_BlendOptFlag) {
473 color = 0;
474 coverage = 0;
475 } else if (blendOpts & GrDrawState::kEmitCoverage_BlendOptFlag) {
476 color = 0xffffffff;
477 coverage = drawState.getCoverage();
478 } else {
479 color = drawState.getColor();
480 coverage = drawState.getCoverage();
481 }
482
bsalomon@google.com91207482013-02-12 21:45:24 +0000483 this->setColor(drawState, color, sharedState);
484 this->setCoverage(drawState, coverage, sharedState);
bsalomon@google.com6a51dcb2013-02-13 16:03:51 +0000485 this->setMatrixAndRenderTargetHeight(drawState);
bsalomon@google.com91207482013-02-12 21:45:24 +0000486
487 // Setup the SkXfermode::Mode-based colorfilter uniform if necessary
commit-bot@chromium.org7425c122013-08-14 18:14:19 +0000488 if (fUniformHandles.fColorFilterUni.isValid() &&
bsalomon@google.com91207482013-02-12 21:45:24 +0000489 fColorFilterColor != drawState.getColorFilterColor()) {
490 GrGLfloat c[4];
491 GrColorToRGBAFloat(drawState.getColorFilterColor(), c);
492 fUniformManager.set4fv(fUniformHandles.fColorFilterUni, 0, 1, c);
493 fColorFilterColor = drawState.getColorFilterColor();
494 }
495
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000496 if (NULL != dstCopy) {
commit-bot@chromium.org7425c122013-08-14 18:14:19 +0000497 if (fUniformHandles.fDstCopyTopLeftUni.isValid()) {
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000498 fUniformManager.set2f(fUniformHandles.fDstCopyTopLeftUni,
499 static_cast<GrGLfloat>(dstCopy->offset().fX),
500 static_cast<GrGLfloat>(dstCopy->offset().fY));
501 fUniformManager.set2f(fUniformHandles.fDstCopyScaleUni,
502 1.f / dstCopy->texture()->width(),
503 1.f / dstCopy->texture()->height());
504 GrGLTexture* texture = static_cast<GrGLTexture*>(dstCopy->texture());
505 static GrTextureParams kParams; // the default is clamp, nearest filtering.
commit-bot@chromium.org9188a152013-09-05 18:28:24 +0000506 fGpu->bindTexture(fDstCopyTexUnit, kParams, texture);
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000507 } else {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000508 SkASSERT(!fUniformHandles.fDstCopyScaleUni.isValid());
509 SkASSERT(!fUniformHandles.fDstCopySamplerUni.isValid());
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000510 }
511 } else {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000512 SkASSERT(!fUniformHandles.fDstCopyTopLeftUni.isValid());
513 SkASSERT(!fUniformHandles.fDstCopyScaleUni.isValid());
514 SkASSERT(!fUniformHandles.fDstCopySamplerUni.isValid());
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000515 }
bsalomon@google.comc7818882013-03-20 19:19:53 +0000516
bsalomon@google.com2c84aa32013-06-06 20:28:57 +0000517 for (int e = 0; e < fColorEffects.count(); ++e) {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000518 // We may have omitted the GrGLEffect because of the color filter logic in genProgram.
519 // This can be removed when the color filter is an effect.
bsalomon@google.com2c84aa32013-06-06 20:28:57 +0000520 if (NULL != fColorEffects[e].fGLEffect) {
commit-bot@chromium.org9188a152013-09-05 18:28:24 +0000521 this->setEffectData(*colorStages[e], fColorEffects[e]);
bsalomon@google.com2c84aa32013-06-06 20:28:57 +0000522 }
523 }
524
525 for (int e = 0; e < fCoverageEffects.count(); ++e) {
526 if (NULL != fCoverageEffects[e].fGLEffect) {
commit-bot@chromium.org9188a152013-09-05 18:28:24 +0000527 this->setEffectData(*coverageStages[e], fCoverageEffects[e]);
bsalomon@google.com4285acc2012-10-22 14:11:24 +0000528 }
529 }
skia.committer@gmail.com8ae714b2013-01-05 02:02:05 +0000530}
bsalomon@google.com91207482013-02-12 21:45:24 +0000531
532void GrGLProgram::setColor(const GrDrawState& drawState,
533 GrColor color,
534 SharedGLState* sharedState) {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000535 const GrGLProgramDesc::KeyHeader& header = fDesc.getHeader();
jvanverth@google.com054ae992013-04-01 20:06:51 +0000536 if (!drawState.hasColorVertexAttribute()) {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000537 switch (header.fColorInput) {
bsalomon@google.com31ec7982013-03-27 18:14:57 +0000538 case GrGLProgramDesc::kAttribute_ColorInput:
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000539 SkASSERT(-1 != header.fColorAttributeIndex);
jvanverth@google.com054ae992013-04-01 20:06:51 +0000540 if (sharedState->fConstAttribColor != color ||
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000541 sharedState->fConstAttribColorIndex != header.fColorAttributeIndex) {
bsalomon@google.com91207482013-02-12 21:45:24 +0000542 // OpenGL ES only supports the float varieties of glVertexAttrib
543 GrGLfloat c[4];
544 GrColorToRGBAFloat(color, c);
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000545 GL_CALL(VertexAttrib4fv(header.fColorAttributeIndex, c));
bsalomon@google.com91207482013-02-12 21:45:24 +0000546 sharedState->fConstAttribColor = color;
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000547 sharedState->fConstAttribColorIndex = header.fColorAttributeIndex;
bsalomon@google.com91207482013-02-12 21:45:24 +0000548 }
549 break;
bsalomon@google.com31ec7982013-03-27 18:14:57 +0000550 case GrGLProgramDesc::kUniform_ColorInput:
bsalomon@google.com91207482013-02-12 21:45:24 +0000551 if (fColor != color) {
552 // OpenGL ES doesn't support unsigned byte varieties of glUniform
553 GrGLfloat c[4];
554 GrColorToRGBAFloat(color, c);
bsalomon@google.com91207482013-02-12 21:45:24 +0000555 fUniformManager.set4fv(fUniformHandles.fColorUni, 0, 1, c);
556 fColor = color;
557 }
jvanverth@google.com054ae992013-04-01 20:06:51 +0000558 sharedState->fConstAttribColorIndex = -1;
bsalomon@google.com91207482013-02-12 21:45:24 +0000559 break;
bsalomon@google.com31ec7982013-03-27 18:14:57 +0000560 case GrGLProgramDesc::kSolidWhite_ColorInput:
561 case GrGLProgramDesc::kTransBlack_ColorInput:
jvanverth@google.com054ae992013-04-01 20:06:51 +0000562 sharedState->fConstAttribColorIndex = -1;
bsalomon@google.com91207482013-02-12 21:45:24 +0000563 break;
564 default:
565 GrCrash("Unknown color type.");
566 }
jvanverth@google.com054ae992013-04-01 20:06:51 +0000567 } else {
568 sharedState->fConstAttribColorIndex = -1;
bsalomon@google.com91207482013-02-12 21:45:24 +0000569 }
570}
571
572void GrGLProgram::setCoverage(const GrDrawState& drawState,
573 GrColor coverage,
574 SharedGLState* sharedState) {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000575 const GrGLProgramDesc::KeyHeader& header = fDesc.getHeader();
jvanverth@google.com054ae992013-04-01 20:06:51 +0000576 if (!drawState.hasCoverageVertexAttribute()) {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000577 switch (header.fCoverageInput) {
bsalomon@google.com31ec7982013-03-27 18:14:57 +0000578 case GrGLProgramDesc::kAttribute_ColorInput:
jvanverth@google.com054ae992013-04-01 20:06:51 +0000579 if (sharedState->fConstAttribCoverage != coverage ||
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000580 sharedState->fConstAttribCoverageIndex != header.fCoverageAttributeIndex) {
bsalomon@google.com91207482013-02-12 21:45:24 +0000581 // OpenGL ES only supports the float varieties of glVertexAttrib
582 GrGLfloat c[4];
583 GrColorToRGBAFloat(coverage, c);
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000584 GL_CALL(VertexAttrib4fv(header.fCoverageAttributeIndex, c));
bsalomon@google.com91207482013-02-12 21:45:24 +0000585 sharedState->fConstAttribCoverage = coverage;
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000586 sharedState->fConstAttribCoverageIndex = header.fCoverageAttributeIndex;
bsalomon@google.com91207482013-02-12 21:45:24 +0000587 }
588 break;
bsalomon@google.com31ec7982013-03-27 18:14:57 +0000589 case GrGLProgramDesc::kUniform_ColorInput:
bsalomon@google.com91207482013-02-12 21:45:24 +0000590 if (fCoverage != coverage) {
591 // OpenGL ES doesn't support unsigned byte varieties of glUniform
592 GrGLfloat c[4];
593 GrColorToRGBAFloat(coverage, c);
bsalomon@google.com91207482013-02-12 21:45:24 +0000594 fUniformManager.set4fv(fUniformHandles.fCoverageUni, 0, 1, c);
595 fCoverage = coverage;
596 }
jvanverth@google.com054ae992013-04-01 20:06:51 +0000597 sharedState->fConstAttribCoverageIndex = -1;
bsalomon@google.com91207482013-02-12 21:45:24 +0000598 break;
bsalomon@google.com31ec7982013-03-27 18:14:57 +0000599 case GrGLProgramDesc::kSolidWhite_ColorInput:
600 case GrGLProgramDesc::kTransBlack_ColorInput:
jvanverth@google.com054ae992013-04-01 20:06:51 +0000601 sharedState->fConstAttribCoverageIndex = -1;
bsalomon@google.com91207482013-02-12 21:45:24 +0000602 break;
603 default:
604 GrCrash("Unknown coverage type.");
605 }
jvanverth@google.com054ae992013-04-01 20:06:51 +0000606 } else {
607 sharedState->fConstAttribCoverageIndex = -1;
bsalomon@google.com91207482013-02-12 21:45:24 +0000608 }
609}
bsalomon@google.com6a51dcb2013-02-13 16:03:51 +0000610
611void GrGLProgram::setMatrixAndRenderTargetHeight(const GrDrawState& drawState) {
612 const GrRenderTarget* rt = drawState.getRenderTarget();
613 SkISize size;
614 size.set(rt->width(), rt->height());
615
616 // Load the RT height uniform if it is needed to y-flip gl_FragCoord.
commit-bot@chromium.org7425c122013-08-14 18:14:19 +0000617 if (fUniformHandles.fRTHeightUni.isValid() &&
bsalomon@google.com6a51dcb2013-02-13 16:03:51 +0000618 fMatrixState.fRenderTargetSize.fHeight != size.fHeight) {
619 fUniformManager.set1f(fUniformHandles.fRTHeightUni, SkIntToScalar(size.fHeight));
620 }
621
622 if (fMatrixState.fRenderTargetOrigin != rt->origin() ||
623 !fMatrixState.fViewMatrix.cheapEqualTo(drawState.getViewMatrix()) ||
624 fMatrixState.fRenderTargetSize != size) {
bsalomon@google.com6a51dcb2013-02-13 16:03:51 +0000625
bsalomon@google.com6a51dcb2013-02-13 16:03:51 +0000626 fMatrixState.fViewMatrix = drawState.getViewMatrix();
627 fMatrixState.fRenderTargetSize = size;
628 fMatrixState.fRenderTargetOrigin = rt->origin();
commit-bot@chromium.org215a6822013-09-05 18:28:42 +0000629
630 GrGLfloat viewMatrix[3 * 3];
631 fMatrixState.getGLMatrix<3>(viewMatrix);
632 fUniformManager.setMatrix3f(fUniformHandles.fViewMatrixUni, viewMatrix);
bsalomon@google.com6a51dcb2013-02-13 16:03:51 +0000633 }
634}