blob: 89f5f584bf0ba564481fb224b8d99323cf5e4924 [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.com77af6802013-10-02 13:04:56 +000012#include "GrCoordTransform.h"
bsalomon@google.comc7818882013-03-20 19:19:53 +000013#include "GrDrawEffect.h"
bsalomon@google.comd698f772012-10-25 13:22:00 +000014#include "GrGLEffect.h"
bsalomon@google.com34cccde2013-01-04 18:34:30 +000015#include "GrGpuGL.h"
bsalomon@google.com4fa66942011-09-20 19:06:12 +000016#include "GrGLShaderVar.h"
bsalomon@google.com018f1792013-04-18 19:36:09 +000017#include "GrGLSL.h"
Scroggo97c88c22011-05-11 14:05:25 +000018#include "SkXfermode.h"
19
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +000020SK_DEFINE_INST_COUNT(GrGLProgram)
21
commit-bot@chromium.org9188a152013-09-05 18:28:24 +000022#define GL_CALL(X) GR_GL_CALL(fGpu->glInterface(), X)
23#define GL_CALL_RET(R, X) GR_GL_CALL_RET(fGpu->glInterface(), R, X)
bsalomon@google.comecb60aa2012-07-18 13:20:29 +000024
commit-bot@chromium.org9188a152013-09-05 18:28:24 +000025GrGLProgram* GrGLProgram::Create(GrGpuGL* gpu,
bsalomon@google.com31ec7982013-03-27 18:14:57 +000026 const GrGLProgramDesc& desc,
bsalomon@google.com2c84aa32013-06-06 20:28:57 +000027 const GrEffectStage* colorStages[],
28 const GrEffectStage* coverageStages[]) {
commit-bot@chromium.org9188a152013-09-05 18:28:24 +000029 GrGLProgram* program = SkNEW_ARGS(GrGLProgram, (gpu, desc, colorStages, coverageStages));
bsalomon@google.comecb60aa2012-07-18 13:20:29 +000030 if (!program->succeeded()) {
31 delete program;
32 program = NULL;
33 }
34 return program;
35}
36
commit-bot@chromium.org9188a152013-09-05 18:28:24 +000037GrGLProgram::GrGLProgram(GrGpuGL* gpu,
bsalomon@google.com31ec7982013-03-27 18:14:57 +000038 const GrGLProgramDesc& desc,
bsalomon@google.com2c84aa32013-06-06 20:28:57 +000039 const GrEffectStage* colorStages[],
40 const GrEffectStage* coverageStages[])
commit-bot@chromium.org9188a152013-09-05 18:28:24 +000041: fGpu(gpu)
42, fUniformManager(gpu) {
bsalomon@google.comecb60aa2012-07-18 13:20:29 +000043 fDesc = desc;
bsalomon@google.comecb60aa2012-07-18 13:20:29 +000044 fProgramID = 0;
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000045
bsalomon@google.com804e9942013-06-06 18:04:38 +000046 fDstCopyTexUnit = -1;
47
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000048 fColor = GrColor_ILLEGAL;
49 fColorFilterColor = GrColor_ILLEGAL;
50
bsalomon@google.com2c84aa32013-06-06 20:28:57 +000051 fColorEffects.reset(desc.numColorEffects());
52 fCoverageEffects.reset(desc.numCoverageEffects());
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000053
bsalomon@google.com2c84aa32013-06-06 20:28:57 +000054 this->genProgram(colorStages, coverageStages);
junov@google.comf93e7172011-03-31 21:26:24 +000055}
56
57GrGLProgram::~GrGLProgram() {
bsalomon@google.comecb60aa2012-07-18 13:20:29 +000058 if (fProgramID) {
59 GL_CALL(DeleteProgram(fProgramID));
60 }
junov@google.comf93e7172011-03-31 21:26:24 +000061}
62
bsalomon@google.comecb60aa2012-07-18 13:20:29 +000063void GrGLProgram::abandon() {
bsalomon@google.comecb60aa2012-07-18 13:20:29 +000064 fProgramID = 0;
65}
66
tomhudson@google.com0d3f1fb2011-06-01 19:27:31 +000067void GrGLProgram::overrideBlend(GrBlendCoeff* srcCoeff,
bsalomon@google.com271cffc2011-05-20 14:13:56 +000068 GrBlendCoeff* dstCoeff) const {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +000069 switch (fDesc.getHeader().fCoverageOutput) {
bsalomon@google.com5920ac22013-04-19 13:14:45 +000070 case GrGLProgramDesc::kModulate_CoverageOutput:
bsalomon@google.com271cffc2011-05-20 14:13:56 +000071 break;
bsalomon@google.com5920ac22013-04-19 13:14:45 +000072 // The prog will write a coverage value to the secondary
bsalomon@google.com271cffc2011-05-20 14:13:56 +000073 // output and the dst is blended by one minus that value.
bsalomon@google.com5920ac22013-04-19 13:14:45 +000074 case GrGLProgramDesc::kSecondaryCoverage_CoverageOutput:
75 case GrGLProgramDesc::kSecondaryCoverageISA_CoverageOutput:
76 case GrGLProgramDesc::kSecondaryCoverageISC_CoverageOutput:
77 *dstCoeff = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
78 break;
79 case GrGLProgramDesc::kCombineWithDst_CoverageOutput:
80 // We should only have set this if the blend was specified as (1, 0)
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +000081 SkASSERT(kOne_GrBlendCoeff == *srcCoeff && kZero_GrBlendCoeff == *dstCoeff);
bsalomon@google.com5920ac22013-04-19 13:14:45 +000082 break;
bsalomon@google.com271cffc2011-05-20 14:13:56 +000083 default:
bsalomon@google.com5920ac22013-04-19 13:14:45 +000084 GrCrash("Unexpected coverage output");
bsalomon@google.com271cffc2011-05-20 14:13:56 +000085 break;
86 }
87}
88
bsalomon@google.com34cccde2013-01-04 18:34:30 +000089namespace {
bsalomon@google.com5920ac22013-04-19 13:14:45 +000090// given two blend coefficients determine whether the src
bsalomon@google.comf2d91552011-05-16 20:56:06 +000091// and/or dst computation can be omitted.
bsalomon@google.com34cccde2013-01-04 18:34:30 +000092inline void need_blend_inputs(SkXfermode::Coeff srcCoeff,
93 SkXfermode::Coeff dstCoeff,
94 bool* needSrcValue,
95 bool* needDstValue) {
bsalomon@google.comf2d91552011-05-16 20:56:06 +000096 if (SkXfermode::kZero_Coeff == srcCoeff) {
97 switch (dstCoeff) {
98 // these all read the src
99 case SkXfermode::kSC_Coeff:
100 case SkXfermode::kISC_Coeff:
101 case SkXfermode::kSA_Coeff:
102 case SkXfermode::kISA_Coeff:
103 *needSrcValue = true;
104 break;
105 default:
106 *needSrcValue = false;
107 break;
108 }
109 } else {
110 *needSrcValue = true;
111 }
112 if (SkXfermode::kZero_Coeff == dstCoeff) {
113 switch (srcCoeff) {
114 // these all read the dst
115 case SkXfermode::kDC_Coeff:
116 case SkXfermode::kIDC_Coeff:
117 case SkXfermode::kDA_Coeff:
118 case SkXfermode::kIDA_Coeff:
119 *needDstValue = true;
120 break;
121 default:
122 *needDstValue = false;
123 break;
124 }
125 } else {
126 *needDstValue = true;
Scroggo97c88c22011-05-11 14:05:25 +0000127 }
128}
129
130/**
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000131 * Create a blend_coeff * value string to be used in shader code. Sets empty
132 * string if result is trivially zero.
133 */
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000134inline void blend_term_string(SkString* str, SkXfermode::Coeff coeff,
135 const char* src, const char* dst,
136 const char* value) {
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000137 switch (coeff) {
138 case SkXfermode::kZero_Coeff: /** 0 */
139 *str = "";
140 break;
141 case SkXfermode::kOne_Coeff: /** 1 */
142 *str = value;
143 break;
144 case SkXfermode::kSC_Coeff:
145 str->printf("(%s * %s)", src, value);
146 break;
147 case SkXfermode::kISC_Coeff:
bsalomon@google.com4af0af62012-08-29 12:59:57 +0000148 str->printf("((%s - %s) * %s)", GrGLSLOnesVecf(4), src, value);
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000149 break;
150 case SkXfermode::kDC_Coeff:
151 str->printf("(%s * %s)", dst, value);
152 break;
153 case SkXfermode::kIDC_Coeff:
bsalomon@google.com4af0af62012-08-29 12:59:57 +0000154 str->printf("((%s - %s) * %s)", GrGLSLOnesVecf(4), dst, value);
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000155 break;
156 case SkXfermode::kSA_Coeff: /** src alpha */
157 str->printf("(%s.a * %s)", src, value);
158 break;
159 case SkXfermode::kISA_Coeff: /** inverse src alpha (i.e. 1 - sa) */
160 str->printf("((1.0 - %s.a) * %s)", src, value);
161 break;
162 case SkXfermode::kDA_Coeff: /** dst alpha */
163 str->printf("(%s.a * %s)", dst, value);
164 break;
165 case SkXfermode::kIDA_Coeff: /** inverse dst alpha (i.e. 1 - da) */
166 str->printf("((1.0 - %s.a) * %s)", dst, value);
167 break;
168 default:
169 GrCrash("Unexpected xfer coeff.");
170 break;
171 }
172}
173/**
Scroggo97c88c22011-05-11 14:05:25 +0000174 * Adds a line to the fragment shader code which modifies the color by
175 * the specified color filter.
176 */
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000177void add_color_filter(GrGLShaderBuilder* builder,
178 const char * outputVar,
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000179 SkXfermode::Coeff uniformCoeff,
180 SkXfermode::Coeff colorCoeff,
181 const char* filterColor,
182 const char* inColor) {
bsalomon@google.comf0a104e2012-07-10 17:51:07 +0000183 SkString colorStr, constStr;
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000184 blend_term_string(&colorStr, colorCoeff, filterColor, inColor, inColor);
185 blend_term_string(&constStr, uniformCoeff, filterColor, inColor, filterColor);
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000186
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000187 SkString sum;
bsalomon@google.com018f1792013-04-18 19:36:09 +0000188 GrGLSLAddf<4>(&sum, colorStr.c_str(), constStr.c_str());
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000189 builder->fsCodeAppendf("\t%s = %s;\n", outputVar, sum.c_str());
Scroggo97c88c22011-05-11 14:05:25 +0000190}
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000191}
Scroggo97c88c22011-05-11 14:05:25 +0000192
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000193namespace {
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000194
bsalomon@google.com5920ac22013-04-19 13:14:45 +0000195void expand_known_value4f(SkString* string, GrSLConstantVec vec) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000196 SkASSERT(string->isEmpty() == (vec != kNone_GrSLConstantVec));
bsalomon@google.com5920ac22013-04-19 13:14:45 +0000197 switch (vec) {
198 case kNone_GrSLConstantVec:
199 break;
200 case kZeros_GrSLConstantVec:
201 *string = GrGLSLZerosVecf(4);
202 break;
203 case kOnes_GrSLConstantVec:
204 *string = GrGLSLOnesVecf(4);
205 break;
206 }
207}
208
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000209}
210
bsalomon@google.com2c84aa32013-06-06 20:28:57 +0000211bool GrGLProgram::genProgram(const GrEffectStage* colorStages[],
212 const GrEffectStage* coverageStages[]) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000213 SkASSERT(0 == fProgramID);
bsalomon@google.comecb60aa2012-07-18 13:20:29 +0000214
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000215 const GrGLProgramDesc::KeyHeader& header = fDesc.getHeader();
216
commit-bot@chromium.orga4acf122013-09-30 15:13:58 +0000217 bool needsVertexShader = true;
commit-bot@chromium.org5a02cb42013-08-30 20:17:31 +0000218
commit-bot@chromium.org410552a2013-09-30 15:30:27 +0000219 GrGLShaderBuilder builder(fGpu, fUniformManager, fDesc, needsVertexShader);
commit-bot@chromium.org5a02cb42013-08-30 20:17:31 +0000220 if (GrGLShaderBuilder::VertexBuilder* vertexBuilder = builder.getVertexBuilder()) {
commit-bot@chromium.org410552a2013-09-30 15:30:27 +0000221 fUniformHandles.fViewMatrixUni = vertexBuilder->getViewMatrixUniform();
bsalomon@google.come55fd0f2012-02-10 15:56:06 +0000222 }
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000223
bsalomon@google.com91961302011-05-09 18:39:58 +0000224 // incoming color to current stage being processed.
commit-bot@chromium.org410552a2013-09-30 15:30:27 +0000225 SkString inColor = builder.getInputColor();
226 GrSLConstantVec knownColorValue = builder.getKnownColorValue();
junov@google.comf93e7172011-03-31 21:26:24 +0000227
commit-bot@chromium.orga4acf122013-09-30 15:13:58 +0000228 // Get the coeffs for the Mode-based color filter, determine if color is needed.
229 SkXfermode::Coeff colorCoeff;
230 SkXfermode::Coeff filterColorCoeff;
231 SkAssertResult(
commit-bot@chromium.org949eef02013-10-01 18:43:29 +0000232 SkXfermode::ModeAsCoeff(header.fColorFilterXfermode,
commit-bot@chromium.orga4acf122013-09-30 15:13:58 +0000233 &filterColorCoeff,
234 &colorCoeff));
235 bool needColor, needFilterColor;
236 need_blend_inputs(filterColorCoeff, colorCoeff, &needFilterColor, &needColor);
237
bsalomon@google.com504976e2013-05-09 13:45:02 +0000238 // used in order for builder to return the per-stage uniform handles.
bsalomon@google.com77af6802013-10-02 13:04:56 +0000239 typedef SkTArray<GrGLCoordTransform, false>* CoordTransformArrayPtr;
bsalomon@google.com804e9942013-06-06 18:04:38 +0000240 typedef SkTArray<GrGLUniformManager::UniformHandle, true>* UniHandleArrayPtr;
241 int maxColorOrCovEffectCnt = GrMax(fDesc.numColorEffects(), fDesc.numCoverageEffects());
bsalomon@google.com77af6802013-10-02 13:04:56 +0000242 SkAutoTArray<CoordTransformArrayPtr> effectCoordTransformArrays(maxColorOrCovEffectCnt);
bsalomon@google.com804e9942013-06-06 18:04:38 +0000243 SkAutoTArray<UniHandleArrayPtr> effectUniformArrays(maxColorOrCovEffectCnt);
244 SkAutoTArray<GrGLEffect*> glEffects(maxColorOrCovEffectCnt);
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000245
bsalomon@google.com504976e2013-05-09 13:45:02 +0000246 if (needColor) {
bsalomon@google.com804e9942013-06-06 18:04:38 +0000247 for (int e = 0; e < fDesc.numColorEffects(); ++e) {
bsalomon@google.com77af6802013-10-02 13:04:56 +0000248 effectCoordTransformArrays[e] = &fColorEffects[e].fCoordTransforms;
bsalomon@google.com2c84aa32013-06-06 20:28:57 +0000249 effectUniformArrays[e] = &fColorEffects[e].fSamplerUnis;
junov@google.comf93e7172011-03-31 21:26:24 +0000250 }
bsalomon@google.com504976e2013-05-09 13:45:02 +0000251
commit-bot@chromium.orga4acf122013-09-30 15:13:58 +0000252 builder.emitEffects(colorStages,
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000253 fDesc.effectKeys(),
254 fDesc.numColorEffects(),
bsalomon@google.com504976e2013-05-09 13:45:02 +0000255 &inColor,
256 &knownColorValue,
bsalomon@google.com77af6802013-10-02 13:04:56 +0000257 effectCoordTransformArrays.get(),
commit-bot@chromium.orga4acf122013-09-30 15:13:58 +0000258 effectUniformArrays.get(),
259 glEffects.get());
260
261 for (int e = 0; e < fDesc.numColorEffects(); ++e) {
262 fColorEffects[e].fGLEffect = glEffects[e];
263 }
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000264 }
Scroggo97c88c22011-05-11 14:05:25 +0000265
bsalomon@google.com018f1792013-04-18 19:36:09 +0000266 // Insert the color filter. This will soon be replaced by a color effect.
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000267 if (SkXfermode::kDst_Mode != header.fColorFilterXfermode) {
bsalomon@google.com018f1792013-04-18 19:36:09 +0000268 const char* colorFilterColorUniName = NULL;
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +0000269 fUniformHandles.fColorFilterUni = builder.addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.com018f1792013-04-18 19:36:09 +0000270 kVec4f_GrSLType, "FilterColor",
271 &colorFilterColorUniName);
272
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000273 builder.fsCodeAppend("\tvec4 filteredColor;\n");
bsalomon@google.com018f1792013-04-18 19:36:09 +0000274 const char* color;
275 // add_color_filter requires a real input string.
276 if (knownColorValue == kOnes_GrSLConstantVec) {
277 color = GrGLSLOnesVecf(4);
278 } else if (knownColorValue == kZeros_GrSLConstantVec) {
279 color = GrGLSLZerosVecf(4);
280 } else {
281 color = inColor.c_str();
282 }
283 add_color_filter(&builder, "filteredColor", filterColorCoeff,
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000284 colorCoeff, colorFilterColorUniName, color);
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000285 inColor = "filteredColor";
286 }
287
288 ///////////////////////////////////////////////////////////////////////////
bsalomon@google.com018f1792013-04-18 19:36:09 +0000289 // compute the partial coverage
commit-bot@chromium.org410552a2013-09-30 15:30:27 +0000290 SkString inCoverage = builder.getInputCoverage();
291 GrSLConstantVec knownCoverageValue = builder.getKnownCoverageValue();
skia.committer@gmail.comcb6dc752013-04-19 07:01:00 +0000292
bsalomon@google.com804e9942013-06-06 18:04:38 +0000293 for (int e = 0; e < fDesc.numCoverageEffects(); ++e) {
bsalomon@google.com77af6802013-10-02 13:04:56 +0000294 effectCoordTransformArrays[e] = &fCoverageEffects[e].fCoordTransforms;
bsalomon@google.com2c84aa32013-06-06 20:28:57 +0000295 effectUniformArrays[e] = &fCoverageEffects[e].fSamplerUnis;
bsalomon@google.com018f1792013-04-18 19:36:09 +0000296 }
bsalomon@google.com777c3aa2012-07-25 20:58:20 +0000297
commit-bot@chromium.orga4acf122013-09-30 15:13:58 +0000298 builder.emitEffects(coverageStages,
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000299 fDesc.getEffectKeys() + fDesc.numColorEffects(),
300 fDesc.numCoverageEffects(),
bsalomon@google.com504976e2013-05-09 13:45:02 +0000301 &inCoverage,
302 &knownCoverageValue,
bsalomon@google.com77af6802013-10-02 13:04:56 +0000303 effectCoordTransformArrays.get(),
commit-bot@chromium.orga4acf122013-09-30 15:13:58 +0000304 effectUniformArrays.get(),
305 glEffects.get());
306 for (int e = 0; e < fDesc.numCoverageEffects(); ++e) {
307 fCoverageEffects[e].fGLEffect = glEffects[e];
308 }
bsalomon@google.com504976e2013-05-09 13:45:02 +0000309
bsalomon@google.com018f1792013-04-18 19:36:09 +0000310 // discard if coverage is zero
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000311 if (header.fDiscardIfZeroCoverage && kOnes_GrSLConstantVec != knownCoverageValue) {
bsalomon@google.com018f1792013-04-18 19:36:09 +0000312 if (kZeros_GrSLConstantVec == knownCoverageValue) {
313 // This is unfortunate.
314 builder.fsCodeAppend("\tdiscard;\n");
315 } else {
316 builder.fsCodeAppendf("\tif (all(lessThanEqual(%s, vec4(0.0)))) {\n\t\tdiscard;\n\t}\n",
317 inCoverage.c_str());
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000318 }
junov@google.comf93e7172011-03-31 21:26:24 +0000319 }
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000320
commit-bot@chromium.org949eef02013-10-01 18:43:29 +0000321 if (GrGLProgramDesc::CoverageOutputUsesSecondaryOutput(header.fCoverageOutput)) {
commit-bot@chromium.org410552a2013-09-30 15:30:27 +0000322 const char* secondaryOutputName = builder.enableSecondaryOutput();
323
bsalomon@google.com018f1792013-04-18 19:36:09 +0000324 // default coeff to ones for kCoverage_DualSrcOutput
325 SkString coeff;
326 GrSLConstantVec knownCoeffValue = kOnes_GrSLConstantVec;
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000327 if (GrGLProgramDesc::kSecondaryCoverageISA_CoverageOutput == header.fCoverageOutput) {
bsalomon@google.com018f1792013-04-18 19:36:09 +0000328 // Get (1-A) into coeff
329 SkString inColorAlpha;
330 GrGLSLGetComponent4f(&inColorAlpha,
331 inColor.c_str(),
332 kA_GrColorComponentFlag,
333 knownColorValue,
334 true);
335 knownCoeffValue = GrGLSLSubtractf<1>(&coeff,
336 NULL,
337 inColorAlpha.c_str(),
338 kOnes_GrSLConstantVec,
339 knownColorValue,
340 true);
commit-bot@chromium.org949eef02013-10-01 18:43:29 +0000341 } else if (GrGLProgramDesc::kSecondaryCoverageISC_CoverageOutput == header.fCoverageOutput) {
bsalomon@google.com018f1792013-04-18 19:36:09 +0000342 // Get (1-RGBA) into coeff
343 knownCoeffValue = GrGLSLSubtractf<4>(&coeff,
344 NULL,
345 inColor.c_str(),
346 kOnes_GrSLConstantVec,
347 knownColorValue,
348 true);
349 }
350 // Get coeff * coverage into modulate and then write that to the dual source output.
351 SkString modulate;
352 GrGLSLModulatef<4>(&modulate,
353 coeff.c_str(),
354 inCoverage.c_str(),
355 knownCoeffValue,
356 knownCoverageValue,
357 false);
commit-bot@chromium.org410552a2013-09-30 15:30:27 +0000358 builder.fsCodeAppendf("\t%s = %s;\n", secondaryOutputName, modulate.c_str());
bsalomon@google.com018f1792013-04-18 19:36:09 +0000359 }
360
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000361 ///////////////////////////////////////////////////////////////////////////
362 // combine color and coverage as frag color
363
bsalomon@google.com5920ac22013-04-19 13:14:45 +0000364 // Get "color * coverage" into fragColor
365 SkString fragColor;
366 GrSLConstantVec knownFragColorValue = GrGLSLModulatef<4>(&fragColor,
367 inColor.c_str(),
368 inCoverage.c_str(),
369 knownColorValue,
370 knownCoverageValue,
371 true);
372 // 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 +0000373 if (GrGLProgramDesc::kCombineWithDst_CoverageOutput == header.fCoverageOutput) {
bsalomon@google.com5920ac22013-04-19 13:14:45 +0000374 SkString dstCoeff;
375 GrSLConstantVec knownDstCoeffValue = GrGLSLSubtractf<4>(&dstCoeff,
376 NULL,
377 inCoverage.c_str(),
378 kOnes_GrSLConstantVec,
379 knownCoverageValue,
380 true);
381 SkString dstContribution;
382 GrSLConstantVec knownDstContributionValue = GrGLSLModulatef<4>(&dstContribution,
383 dstCoeff.c_str(),
384 builder.dstColor(),
385 knownDstCoeffValue,
386 kNone_GrSLConstantVec,
387 true);
388 SkString oldFragColor = fragColor;
389 fragColor.reset();
390 GrGLSLAddf<4>(&fragColor,
391 oldFragColor.c_str(),
392 dstContribution.c_str(),
393 knownFragColorValue,
394 knownDstContributionValue,
395 false);
396 } else {
397 expand_known_value4f(&fragColor, knownFragColorValue);
398 }
commit-bot@chromium.org410552a2013-09-30 15:30:27 +0000399 builder.fsCodeAppendf("\t%s = %s;\n", builder.getColorOutputName(), fragColor.c_str());
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000400
commit-bot@chromium.org410552a2013-09-30 15:30:27 +0000401 if (!builder.finish(&fProgramID)) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000402 return false;
403 }
404
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000405 fUniformHandles.fRTHeightUni = builder.getRTHeightUniform();
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000406 fUniformHandles.fDstCopyTopLeftUni = builder.getDstCopyTopLeftUniform();
407 fUniformHandles.fDstCopyScaleUni = builder.getDstCopyScaleUniform();
commit-bot@chromium.org410552a2013-09-30 15:30:27 +0000408 fUniformHandles.fColorUni = builder.getColorUniform();
409 fUniformHandles.fCoverageUni = builder.getCoverageUniform();
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000410 fUniformHandles.fDstCopySamplerUni = builder.getDstCopySamplerUniform();
411 // This must be called after we set fDstCopySamplerUni above.
412 this->initSamplerUniforms();
bsalomon@google.com91961302011-05-09 18:39:58 +0000413
414 return true;
415}
416
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000417void GrGLProgram::initSamplerUniforms() {
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000418 GL_CALL(UseProgram(fProgramID));
bsalomon@google.com34cccde2013-01-04 18:34:30 +0000419 GrGLint texUnitIdx = 0;
commit-bot@chromium.org7425c122013-08-14 18:14:19 +0000420 if (fUniformHandles.fDstCopySamplerUni.isValid()) {
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000421 fUniformManager.setSampler(fUniformHandles.fDstCopySamplerUni, texUnitIdx);
bsalomon@google.com804e9942013-06-06 18:04:38 +0000422 fDstCopyTexUnit = texUnitIdx++;
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000423 }
424
bsalomon@google.com2c84aa32013-06-06 20:28:57 +0000425 for (int e = 0; e < fColorEffects.count(); ++e) {
426 this->initEffectSamplerUniforms(&fColorEffects[e], &texUnitIdx);
427 }
428
429 for (int e = 0; e < fCoverageEffects.count(); ++e) {
430 this->initEffectSamplerUniforms(&fCoverageEffects[e], &texUnitIdx);
431 }
432}
433
434void GrGLProgram::initEffectSamplerUniforms(EffectAndSamplers* effect, int* texUnitIdx) {
435 int numSamplers = effect->fSamplerUnis.count();
436 effect->fTextureUnits.reset(numSamplers);
437 for (int s = 0; s < numSamplers; ++s) {
438 UniformHandle handle = effect->fSamplerUnis[s];
commit-bot@chromium.org7425c122013-08-14 18:14:19 +0000439 if (handle.isValid()) {
bsalomon@google.com2c84aa32013-06-06 20:28:57 +0000440 fUniformManager.setSampler(handle, *texUnitIdx);
441 effect->fTextureUnits[s] = (*texUnitIdx)++;
bsalomon@google.com91961302011-05-09 18:39:58 +0000442 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000443 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000444}
445
bsalomon@google.comeb715c82012-07-11 15:03:31 +0000446///////////////////////////////////////////////////////////////////////////////
junov@google.comf93e7172011-03-31 21:26:24 +0000447
commit-bot@chromium.org9188a152013-09-05 18:28:24 +0000448void GrGLProgram::setEffectData(const GrEffectStage& stage,
bsalomon@google.com77af6802013-10-02 13:04:56 +0000449 EffectAndSamplers& effect) {
bsalomon@google.com2c84aa32013-06-06 20:28:57 +0000450
451 // Let the GrGLEffect set its data.
452 bool explicitLocalCoords = -1 != fDesc.getHeader().fLocalCoordAttributeIndex;
453 GrDrawEffect drawEffect(stage, explicitLocalCoords);
454 effect.fGLEffect->setData(fUniformManager, drawEffect);
455
bsalomon@google.com77af6802013-10-02 13:04:56 +0000456 // Set the effect's coord transform matrices.
457 int numTransforms = effect.fCoordTransforms.count();
458 SkASSERT((*stage.getEffect())->numTransforms() == numTransforms);
459 for (int c = 0; c < numTransforms; ++c) {
460 effect.fCoordTransforms[c].setData(fUniformManager, drawEffect, c);
461 }
462
bsalomon@google.com2c84aa32013-06-06 20:28:57 +0000463 // Bind the texures for the effect.
464 int numSamplers = effect.fSamplerUnis.count();
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000465 SkASSERT((*stage.getEffect())->numTextures() == numSamplers);
bsalomon@google.com2c84aa32013-06-06 20:28:57 +0000466 for (int s = 0; s < numSamplers; ++s) {
467 UniformHandle handle = effect.fSamplerUnis[s];
commit-bot@chromium.org7425c122013-08-14 18:14:19 +0000468 if (handle.isValid()) {
bsalomon@google.com2c84aa32013-06-06 20:28:57 +0000469 const GrTextureAccess& access = (*stage.getEffect())->textureAccess(s);
470 GrGLTexture* texture = static_cast<GrGLTexture*>(access.getTexture());
471 int unit = effect.fTextureUnits[s];
commit-bot@chromium.org9188a152013-09-05 18:28:24 +0000472 fGpu->bindTexture(unit, access.getParams(), texture);
bsalomon@google.com2c84aa32013-06-06 20:28:57 +0000473 }
474 }
475}
476
commit-bot@chromium.org9188a152013-09-05 18:28:24 +0000477void GrGLProgram::setData(GrDrawState::BlendOptFlags blendOpts,
bsalomon@google.com2c84aa32013-06-06 20:28:57 +0000478 const GrEffectStage* colorStages[],
479 const GrEffectStage* coverageStages[],
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000480 const GrDeviceCoordTexture* dstCopy,
bsalomon@google.com91207482013-02-12 21:45:24 +0000481 SharedGLState* sharedState) {
commit-bot@chromium.org9188a152013-09-05 18:28:24 +0000482 const GrDrawState& drawState = fGpu->getDrawState();
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000483
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000484 GrColor color;
485 GrColor coverage;
486 if (blendOpts & GrDrawState::kEmitTransBlack_BlendOptFlag) {
487 color = 0;
488 coverage = 0;
489 } else if (blendOpts & GrDrawState::kEmitCoverage_BlendOptFlag) {
490 color = 0xffffffff;
491 coverage = drawState.getCoverage();
492 } else {
493 color = drawState.getColor();
494 coverage = drawState.getCoverage();
495 }
496
bsalomon@google.com91207482013-02-12 21:45:24 +0000497 this->setColor(drawState, color, sharedState);
498 this->setCoverage(drawState, coverage, sharedState);
bsalomon@google.com6a51dcb2013-02-13 16:03:51 +0000499 this->setMatrixAndRenderTargetHeight(drawState);
bsalomon@google.com91207482013-02-12 21:45:24 +0000500
501 // Setup the SkXfermode::Mode-based colorfilter uniform if necessary
commit-bot@chromium.org7425c122013-08-14 18:14:19 +0000502 if (fUniformHandles.fColorFilterUni.isValid() &&
bsalomon@google.com91207482013-02-12 21:45:24 +0000503 fColorFilterColor != drawState.getColorFilterColor()) {
504 GrGLfloat c[4];
505 GrColorToRGBAFloat(drawState.getColorFilterColor(), c);
506 fUniformManager.set4fv(fUniformHandles.fColorFilterUni, 0, 1, c);
507 fColorFilterColor = drawState.getColorFilterColor();
508 }
509
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000510 if (NULL != dstCopy) {
commit-bot@chromium.org7425c122013-08-14 18:14:19 +0000511 if (fUniformHandles.fDstCopyTopLeftUni.isValid()) {
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000512 fUniformManager.set2f(fUniformHandles.fDstCopyTopLeftUni,
513 static_cast<GrGLfloat>(dstCopy->offset().fX),
514 static_cast<GrGLfloat>(dstCopy->offset().fY));
515 fUniformManager.set2f(fUniformHandles.fDstCopyScaleUni,
516 1.f / dstCopy->texture()->width(),
517 1.f / dstCopy->texture()->height());
518 GrGLTexture* texture = static_cast<GrGLTexture*>(dstCopy->texture());
519 static GrTextureParams kParams; // the default is clamp, nearest filtering.
commit-bot@chromium.org9188a152013-09-05 18:28:24 +0000520 fGpu->bindTexture(fDstCopyTexUnit, kParams, texture);
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000521 } else {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000522 SkASSERT(!fUniformHandles.fDstCopyScaleUni.isValid());
523 SkASSERT(!fUniformHandles.fDstCopySamplerUni.isValid());
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000524 }
525 } else {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000526 SkASSERT(!fUniformHandles.fDstCopyTopLeftUni.isValid());
527 SkASSERT(!fUniformHandles.fDstCopyScaleUni.isValid());
528 SkASSERT(!fUniformHandles.fDstCopySamplerUni.isValid());
bsalomon@google.com26e18b52013-03-29 19:22:36 +0000529 }
bsalomon@google.comc7818882013-03-20 19:19:53 +0000530
bsalomon@google.com2c84aa32013-06-06 20:28:57 +0000531 for (int e = 0; e < fColorEffects.count(); ++e) {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000532 // We may have omitted the GrGLEffect because of the color filter logic in genProgram.
533 // This can be removed when the color filter is an effect.
bsalomon@google.com2c84aa32013-06-06 20:28:57 +0000534 if (NULL != fColorEffects[e].fGLEffect) {
commit-bot@chromium.org9188a152013-09-05 18:28:24 +0000535 this->setEffectData(*colorStages[e], fColorEffects[e]);
bsalomon@google.com2c84aa32013-06-06 20:28:57 +0000536 }
537 }
538
539 for (int e = 0; e < fCoverageEffects.count(); ++e) {
540 if (NULL != fCoverageEffects[e].fGLEffect) {
commit-bot@chromium.org9188a152013-09-05 18:28:24 +0000541 this->setEffectData(*coverageStages[e], fCoverageEffects[e]);
bsalomon@google.com4285acc2012-10-22 14:11:24 +0000542 }
543 }
skia.committer@gmail.com8ae714b2013-01-05 02:02:05 +0000544}
bsalomon@google.com91207482013-02-12 21:45:24 +0000545
546void GrGLProgram::setColor(const GrDrawState& drawState,
547 GrColor color,
548 SharedGLState* sharedState) {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000549 const GrGLProgramDesc::KeyHeader& header = fDesc.getHeader();
jvanverth@google.com054ae992013-04-01 20:06:51 +0000550 if (!drawState.hasColorVertexAttribute()) {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000551 switch (header.fColorInput) {
bsalomon@google.com31ec7982013-03-27 18:14:57 +0000552 case GrGLProgramDesc::kAttribute_ColorInput:
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000553 SkASSERT(-1 != header.fColorAttributeIndex);
jvanverth@google.com054ae992013-04-01 20:06:51 +0000554 if (sharedState->fConstAttribColor != color ||
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000555 sharedState->fConstAttribColorIndex != header.fColorAttributeIndex) {
bsalomon@google.com91207482013-02-12 21:45:24 +0000556 // OpenGL ES only supports the float varieties of glVertexAttrib
557 GrGLfloat c[4];
558 GrColorToRGBAFloat(color, c);
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000559 GL_CALL(VertexAttrib4fv(header.fColorAttributeIndex, c));
bsalomon@google.com91207482013-02-12 21:45:24 +0000560 sharedState->fConstAttribColor = color;
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000561 sharedState->fConstAttribColorIndex = header.fColorAttributeIndex;
bsalomon@google.com91207482013-02-12 21:45:24 +0000562 }
563 break;
bsalomon@google.com31ec7982013-03-27 18:14:57 +0000564 case GrGLProgramDesc::kUniform_ColorInput:
bsalomon@google.com91207482013-02-12 21:45:24 +0000565 if (fColor != color) {
566 // OpenGL ES doesn't support unsigned byte varieties of glUniform
567 GrGLfloat c[4];
568 GrColorToRGBAFloat(color, c);
bsalomon@google.com91207482013-02-12 21:45:24 +0000569 fUniformManager.set4fv(fUniformHandles.fColorUni, 0, 1, c);
570 fColor = color;
571 }
jvanverth@google.com054ae992013-04-01 20:06:51 +0000572 sharedState->fConstAttribColorIndex = -1;
bsalomon@google.com91207482013-02-12 21:45:24 +0000573 break;
bsalomon@google.com31ec7982013-03-27 18:14:57 +0000574 case GrGLProgramDesc::kSolidWhite_ColorInput:
575 case GrGLProgramDesc::kTransBlack_ColorInput:
jvanverth@google.com054ae992013-04-01 20:06:51 +0000576 sharedState->fConstAttribColorIndex = -1;
bsalomon@google.com91207482013-02-12 21:45:24 +0000577 break;
578 default:
579 GrCrash("Unknown color type.");
580 }
jvanverth@google.com054ae992013-04-01 20:06:51 +0000581 } else {
582 sharedState->fConstAttribColorIndex = -1;
bsalomon@google.com91207482013-02-12 21:45:24 +0000583 }
584}
585
586void GrGLProgram::setCoverage(const GrDrawState& drawState,
587 GrColor coverage,
588 SharedGLState* sharedState) {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000589 const GrGLProgramDesc::KeyHeader& header = fDesc.getHeader();
jvanverth@google.com054ae992013-04-01 20:06:51 +0000590 if (!drawState.hasCoverageVertexAttribute()) {
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000591 switch (header.fCoverageInput) {
bsalomon@google.com31ec7982013-03-27 18:14:57 +0000592 case GrGLProgramDesc::kAttribute_ColorInput:
jvanverth@google.com054ae992013-04-01 20:06:51 +0000593 if (sharedState->fConstAttribCoverage != coverage ||
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000594 sharedState->fConstAttribCoverageIndex != header.fCoverageAttributeIndex) {
bsalomon@google.com91207482013-02-12 21:45:24 +0000595 // OpenGL ES only supports the float varieties of glVertexAttrib
596 GrGLfloat c[4];
597 GrColorToRGBAFloat(coverage, c);
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000598 GL_CALL(VertexAttrib4fv(header.fCoverageAttributeIndex, c));
bsalomon@google.com91207482013-02-12 21:45:24 +0000599 sharedState->fConstAttribCoverage = coverage;
bsalomon@google.com2db3ded2013-05-22 14:34:04 +0000600 sharedState->fConstAttribCoverageIndex = header.fCoverageAttributeIndex;
bsalomon@google.com91207482013-02-12 21:45:24 +0000601 }
602 break;
bsalomon@google.com31ec7982013-03-27 18:14:57 +0000603 case GrGLProgramDesc::kUniform_ColorInput:
bsalomon@google.com91207482013-02-12 21:45:24 +0000604 if (fCoverage != coverage) {
605 // OpenGL ES doesn't support unsigned byte varieties of glUniform
606 GrGLfloat c[4];
607 GrColorToRGBAFloat(coverage, c);
bsalomon@google.com91207482013-02-12 21:45:24 +0000608 fUniformManager.set4fv(fUniformHandles.fCoverageUni, 0, 1, c);
609 fCoverage = coverage;
610 }
jvanverth@google.com054ae992013-04-01 20:06:51 +0000611 sharedState->fConstAttribCoverageIndex = -1;
bsalomon@google.com91207482013-02-12 21:45:24 +0000612 break;
bsalomon@google.com31ec7982013-03-27 18:14:57 +0000613 case GrGLProgramDesc::kSolidWhite_ColorInput:
614 case GrGLProgramDesc::kTransBlack_ColorInput:
jvanverth@google.com054ae992013-04-01 20:06:51 +0000615 sharedState->fConstAttribCoverageIndex = -1;
bsalomon@google.com91207482013-02-12 21:45:24 +0000616 break;
617 default:
618 GrCrash("Unknown coverage type.");
619 }
jvanverth@google.com054ae992013-04-01 20:06:51 +0000620 } else {
621 sharedState->fConstAttribCoverageIndex = -1;
bsalomon@google.com91207482013-02-12 21:45:24 +0000622 }
623}
bsalomon@google.com6a51dcb2013-02-13 16:03:51 +0000624
625void GrGLProgram::setMatrixAndRenderTargetHeight(const GrDrawState& drawState) {
626 const GrRenderTarget* rt = drawState.getRenderTarget();
627 SkISize size;
628 size.set(rt->width(), rt->height());
629
630 // Load the RT height uniform if it is needed to y-flip gl_FragCoord.
commit-bot@chromium.org7425c122013-08-14 18:14:19 +0000631 if (fUniformHandles.fRTHeightUni.isValid() &&
bsalomon@google.com6a51dcb2013-02-13 16:03:51 +0000632 fMatrixState.fRenderTargetSize.fHeight != size.fHeight) {
633 fUniformManager.set1f(fUniformHandles.fRTHeightUni, SkIntToScalar(size.fHeight));
634 }
635
636 if (fMatrixState.fRenderTargetOrigin != rt->origin() ||
637 !fMatrixState.fViewMatrix.cheapEqualTo(drawState.getViewMatrix()) ||
638 fMatrixState.fRenderTargetSize != size) {
bsalomon@google.com6a51dcb2013-02-13 16:03:51 +0000639
bsalomon@google.com6a51dcb2013-02-13 16:03:51 +0000640 fMatrixState.fViewMatrix = drawState.getViewMatrix();
641 fMatrixState.fRenderTargetSize = size;
642 fMatrixState.fRenderTargetOrigin = rt->origin();
commit-bot@chromium.org215a6822013-09-05 18:28:42 +0000643
644 GrGLfloat viewMatrix[3 * 3];
645 fMatrixState.getGLMatrix<3>(viewMatrix);
646 fUniformManager.setMatrix3f(fUniformHandles.fViewMatrixUni, viewMatrix);
bsalomon@google.com6a51dcb2013-02-13 16:03:51 +0000647 }
648}