blob: 9b6600bf485b062b2decfd510b876275863074d7 [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
epoger@google.comec3ed6a2011-07-28 14:26:00 +00008
tomhudson@google.comd8f856c2012-05-10 12:13:36 +00009#include "GrBinHashKey.h"
10#include "effects/GrConvolutionEffect.h"
tomhudson@google.com07eecdc2012-04-20 18:35:38 +000011#include "GrCustomStage.h"
junov@google.comf93e7172011-03-31 21:26:24 +000012#include "GrGLProgram.h"
tomhudson@google.com07eecdc2012-04-20 18:35:38 +000013#include "GrGLProgramStage.h"
tomhudson@google.com086e5352011-12-08 14:44:10 +000014#include "GrGLSL.h"
junov@google.comf93e7172011-03-31 21:26:24 +000015#include "GrGpuGLShaders.h"
tomhudson@google.comd8f856c2012-05-10 12:13:36 +000016#include "GrGpuVertex.h"
junov@google.comf93e7172011-03-31 21:26:24 +000017#include "GrNoncopyable.h"
tomhudson@google.comd8f856c2012-05-10 12:13:36 +000018#include "GrProgramStageFactory.h"
19#include "GrRandom.h"
20#include "GrStringBuilder.h"
junov@google.comf93e7172011-03-31 21:26:24 +000021
junov@google.comf93e7172011-03-31 21:26:24 +000022#define SKIP_CACHE_CHECK true
23#define GR_UINT32_MAX static_cast<uint32_t>(-1)
24
tomhudson@google.comdd182cb2012-02-10 21:01:00 +000025#include "../GrTHashCache.h"
junov@google.comf93e7172011-03-31 21:26:24 +000026
27class GrGpuGLShaders::ProgramCache : public ::GrNoncopyable {
28private:
29 class Entry;
30
junov@google.comf7c00f62011-08-18 18:15:16 +000031 typedef GrBinHashKey<Entry, GrGLProgram::kProgramKeySize> ProgramHashKey;
junov@google.comf93e7172011-03-31 21:26:24 +000032
33 class Entry : public ::GrNoncopyable {
34 public:
35 Entry() {}
junov@google.comf93e7172011-03-31 21:26:24 +000036 void copyAndTakeOwnership(Entry& entry) {
37 fProgramData.copyAndTakeOwnership(entry.fProgramData);
junov@google.comf7c00f62011-08-18 18:15:16 +000038 fKey = entry.fKey; // ownership transfer
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +000039 fLRUStamp = entry.fLRUStamp;
junov@google.comf93e7172011-03-31 21:26:24 +000040 }
41
42 public:
43 int compare(const ProgramHashKey& key) const { return fKey.compare(key); }
44
45 public:
46 GrGLProgram::CachedData fProgramData;
47 ProgramHashKey fKey;
48 unsigned int fLRUStamp;
49 };
50
51 GrTHashTable<Entry, ProgramHashKey, 8> fHashCache;
52
bsalomon@google.com2d9ddf92011-05-11 16:52:59 +000053 // We may have kMaxEntries+1 shaders in the GL context because
54 // we create a new shader before evicting from the cache.
junov@google.comf93e7172011-03-31 21:26:24 +000055 enum {
56 kMaxEntries = 32
57 };
bsalomon@google.com4fa66942011-09-20 19:06:12 +000058 Entry fEntries[kMaxEntries];
59 int fCount;
60 unsigned int fCurrLRUStamp;
bsalomon@google.com96399942012-02-13 14:39:16 +000061 const GrGLContextInfo& fGL;
bsalomon@google.com4fa66942011-09-20 19:06:12 +000062
junov@google.comf93e7172011-03-31 21:26:24 +000063public:
bsalomon@google.com96399942012-02-13 14:39:16 +000064 ProgramCache(const GrGLContextInfo& gl)
junov@google.comf93e7172011-03-31 21:26:24 +000065 : fCount(0)
bsalomon@google.com0b77d682011-08-19 13:28:54 +000066 , fCurrLRUStamp(0)
bsalomon@google.com96399942012-02-13 14:39:16 +000067 , fGL(gl) {
junov@google.comf93e7172011-03-31 21:26:24 +000068 }
69
70 ~ProgramCache() {
71 for (int i = 0; i < fCount; ++i) {
bsalomon@google.com96399942012-02-13 14:39:16 +000072 GrGpuGLShaders::DeleteProgram(fGL.interface(),
73 &fEntries[i].fProgramData);
junov@google.comf93e7172011-03-31 21:26:24 +000074 }
75 }
76
77 void abandon() {
78 fCount = 0;
79 }
80
81 void invalidateViewMatrices() {
82 for (int i = 0; i < fCount; ++i) {
83 // set to illegal matrix
84 fEntries[i].fProgramData.fViewMatrix = GrMatrix::InvalidMatrix();
85 }
86 }
87
tomhudson@google.com07eecdc2012-04-20 18:35:38 +000088 GrGLProgram::CachedData* getProgramData(const GrGLProgram& desc,
89 GrCustomStage** stages) {
bsalomon@google.com2d9ddf92011-05-11 16:52:59 +000090 Entry newEntry;
junov@google.comf7c00f62011-08-18 18:15:16 +000091 newEntry.fKey.setKeyData(desc.keyData());
92
bsalomon@google.com2d9ddf92011-05-11 16:52:59 +000093 Entry* entry = fHashCache.find(newEntry.fKey);
junov@google.comf93e7172011-03-31 21:26:24 +000094 if (NULL == entry) {
tomhudson@google.com07eecdc2012-04-20 18:35:38 +000095 if (!desc.genProgram(fGL, stages, &newEntry.fProgramData)) {
bsalomon@google.com2d9ddf92011-05-11 16:52:59 +000096 return NULL;
97 }
junov@google.comf93e7172011-03-31 21:26:24 +000098 if (fCount < kMaxEntries) {
99 entry = fEntries + fCount;
100 ++fCount;
101 } else {
102 GrAssert(kMaxEntries == fCount);
103 entry = fEntries;
104 for (int i = 1; i < kMaxEntries; ++i) {
105 if (fEntries[i].fLRUStamp < entry->fLRUStamp) {
106 entry = fEntries + i;
107 }
108 }
109 fHashCache.remove(entry->fKey, entry);
bsalomon@google.com96399942012-02-13 14:39:16 +0000110 GrGpuGLShaders::DeleteProgram(fGL.interface(),
111 &entry->fProgramData);
junov@google.comf93e7172011-03-31 21:26:24 +0000112 }
bsalomon@google.com2d9ddf92011-05-11 16:52:59 +0000113 entry->copyAndTakeOwnership(newEntry);
junov@google.comf93e7172011-03-31 21:26:24 +0000114 fHashCache.insert(entry->fKey, entry);
115 }
116
117 entry->fLRUStamp = fCurrLRUStamp;
118 if (GR_UINT32_MAX == fCurrLRUStamp) {
119 // wrap around! just trash our LRU, one time hit.
120 for (int i = 0; i < fCount; ++i) {
121 fEntries[i].fLRUStamp = 0;
122 }
123 }
124 ++fCurrLRUStamp;
125 return &entry->fProgramData;
126 }
127};
128
junov@google.com53a55842011-06-08 22:55:10 +0000129void GrGpuGLShaders::abandonResources(){
130 INHERITED::abandonResources();
131 fProgramCache->abandon();
robertphillips@google.comf6f123d2012-03-21 17:57:55 +0000132 fHWProgramID = 0;
junov@google.com53a55842011-06-08 22:55:10 +0000133}
134
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000135void GrGpuGLShaders::DeleteProgram(const GrGLInterface* gl,
136 CachedData* programData) {
137 GR_GL_CALL(gl, DeleteShader(programData->fVShaderID));
bsalomon@google.comedfe1aa2011-09-29 14:40:26 +0000138 if (programData->fGShaderID) {
139 GR_GL_CALL(gl, DeleteShader(programData->fGShaderID));
140 }
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000141 GR_GL_CALL(gl, DeleteShader(programData->fFShaderID));
142 GR_GL_CALL(gl, DeleteProgram(programData->fProgramID));
junov@google.comf93e7172011-03-31 21:26:24 +0000143 GR_DEBUGCODE(memset(programData, 0, sizeof(*programData));)
144}
145
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000146////////////////////////////////////////////////////////////////////////////////
147
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000148#define GL_CALL(X) GR_GL_CALL(this->glInterface(), X)
149
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000150namespace {
bsalomon@google.com4fa66942011-09-20 19:06:12 +0000151
bsalomon@google.com74b98712011-11-11 19:46:16 +0000152// GrRandoms nextU() values have patterns in the low bits
153// So using nextU() % array_count might never take some values.
154int random_int(GrRandom* r, int count) {
155 return (int)(r->nextF() * count);
156}
157
158// min is inclusive, max is exclusive
159int random_int(GrRandom* r, int min, int max) {
160 return (int)(r->nextF() * (max-min)) + min;
161}
162
163bool random_bool(GrRandom* r) {
164 return r->nextF() > .5f;
bsalomon@google.com4fa66942011-09-20 19:06:12 +0000165}
166
167}
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000168
bsalomon@google.coma8e686e2011-08-16 15:45:58 +0000169bool GrGpuGLShaders::programUnitTest() {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000170
tomhudson@google.com086e5352011-12-08 14:44:10 +0000171 GrGLSLGeneration glslGeneration =
bsalomon@google.come55fd0f2012-02-10 15:56:06 +0000172 GrGetGLSLGeneration(this->glBinding(), this->glInterface());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000173 static const int STAGE_OPTS[] = {
174 0,
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000175 StageDesc::kNoPerspective_OptFlagBit,
176 StageDesc::kIdentity_CoordMapping
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000177 };
bsalomon@google.com74b98712011-11-11 19:46:16 +0000178 static const int IN_CONFIG_FLAGS[] = {
179 StageDesc::kNone_InConfigFlag,
180 StageDesc::kSwapRAndB_InConfigFlag,
bsalomon@google.coma91e9232012-02-23 15:39:54 +0000181 StageDesc::kSwapRAndB_InConfigFlag |
182 StageDesc::kMulRGBByAlpha_RoundUp_InConfigFlag,
183 StageDesc::kMulRGBByAlpha_RoundDown_InConfigFlag,
bsalomon@google.com74b98712011-11-11 19:46:16 +0000184 StageDesc::kSmearAlpha_InConfigFlag,
robertphillips@google.com443e5a52012-04-30 20:01:21 +0000185 StageDesc::kSmearRed_InConfigFlag,
bsalomon@google.com74b98712011-11-11 19:46:16 +0000186 };
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000187 GrGLProgram program;
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000188 ProgramDesc& pdesc = program.fProgramDesc;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000189
190 static const int NUM_TESTS = 512;
191
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000192 GrRandom random;
193 for (int t = 0; t < NUM_TESTS; ++t) {
194
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000195#if 0
196 GrPrintf("\nTest Program %d\n-------------\n", t);
197 static const int stop = -1;
198 if (t == stop) {
199 int breakpointhere = 9;
200 }
201#endif
202
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000203 pdesc.fVertexLayout = 0;
204 pdesc.fEmitsPointSize = random.nextF() > .5f;
bsalomon@google.com74b98712011-11-11 19:46:16 +0000205 pdesc.fColorInput = random_int(&random, ProgramDesc::kColorInputCnt);
bsalomon@google.com2401ae82012-01-17 21:03:05 +0000206 pdesc.fCoverageInput = random_int(&random, ProgramDesc::kColorInputCnt);
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000207
bsalomon@google.com74b98712011-11-11 19:46:16 +0000208 pdesc.fColorFilterXfermode = random_int(&random, SkXfermode::kCoeffModesCnt);
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000209
bsalomon@google.com74b98712011-11-11 19:46:16 +0000210 pdesc.fFirstCoverageStage = random_int(&random, GrDrawState::kNumStages);
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000211
bsalomon@google.com74b98712011-11-11 19:46:16 +0000212 pdesc.fVertexLayout |= random_bool(&random) ?
bsalomon@google.coma3108262011-10-10 14:08:47 +0000213 GrDrawTarget::kCoverage_VertexLayoutBit :
214 0;
215
bsalomon@google.comedfe1aa2011-09-29 14:40:26 +0000216#if GR_GL_EXPERIMENTAL_GS
bsalomon@google.com6f92f182011-09-29 15:05:48 +0000217 pdesc.fExperimentalGS = this->getCaps().fGeometryShaderSupport &&
bsalomon@google.com74b98712011-11-11 19:46:16 +0000218 random_bool(&random);
bsalomon@google.comedfe1aa2011-09-29 14:40:26 +0000219#endif
bsalomon@google.coma91e9232012-02-23 15:39:54 +0000220 pdesc.fOutputConfig = random_int(&random, ProgramDesc::kOutputConfigCnt);
bsalomon@google.comedfe1aa2011-09-29 14:40:26 +0000221
bsalomon@google.com74b98712011-11-11 19:46:16 +0000222 bool edgeAA = random_bool(&random);
bsalomon@google.comaeb21602011-08-30 18:13:44 +0000223 if (edgeAA) {
bsalomon@google.com74b98712011-11-11 19:46:16 +0000224 bool vertexEdgeAA = random_bool(&random);
bsalomon@google.comaeb21602011-08-30 18:13:44 +0000225 if (vertexEdgeAA) {
226 pdesc.fVertexLayout |= GrDrawTarget::kEdge_VertexLayoutBit;
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000227 if (this->getCaps().fShaderDerivativeSupport) {
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000228 pdesc.fVertexEdgeType = (GrDrawState::VertexEdgeType) random_int(&random, GrDrawState::kVertexEdgeTypeCnt);
bsalomon@google.comaeb21602011-08-30 18:13:44 +0000229 } else {
tomhudson@google.com93813632011-10-27 20:21:16 +0000230 pdesc.fVertexEdgeType = GrDrawState::kHairLine_EdgeType;
bsalomon@google.comaeb21602011-08-30 18:13:44 +0000231 }
232 pdesc.fEdgeAANumEdges = 0;
233 } else {
bsalomon@google.com74b98712011-11-11 19:46:16 +0000234 pdesc.fEdgeAANumEdges = random_int(&random, 1, this->getMaxEdges());
235 pdesc.fEdgeAAConcave = random_bool(&random);
bsalomon@google.comaeb21602011-08-30 18:13:44 +0000236 }
237 } else {
238 pdesc.fEdgeAANumEdges = 0;
bsalomon@google.coma8e686e2011-08-16 15:45:58 +0000239 }
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000240
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +0000241 pdesc.fColorMatrixEnabled = random_bool(&random);
242
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000243 if (this->getCaps().fDualSourceBlendingSupport) {
bsalomon@google.com74b98712011-11-11 19:46:16 +0000244 pdesc.fDualSrcOutput = random_int(&random, ProgramDesc::kDualSrcOutputCnt);
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000245 } else {
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000246 pdesc.fDualSrcOutput = ProgramDesc::kNone_DualSrcOutput;
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000247 }
248
tomhudson@google.com07eecdc2012-04-20 18:35:38 +0000249 GrCustomStage* customStages[GrDrawState::kNumStages];
250
tomhudson@google.com93813632011-10-27 20:21:16 +0000251 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000252 // enable the stage?
bsalomon@google.com74b98712011-11-11 19:46:16 +0000253 if (random_bool(&random)) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000254 // use separate tex coords?
bsalomon@google.com74b98712011-11-11 19:46:16 +0000255 if (random_bool(&random)) {
256 int t = random_int(&random, GrDrawState::kMaxTexCoords);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000257 pdesc.fVertexLayout |= StageTexCoordVertexLayoutBit(s, t);
258 } else {
259 pdesc.fVertexLayout |= StagePosAsTexCoordVertexLayoutBit(s);
260 }
261 }
262 // use text-formatted verts?
bsalomon@google.com74b98712011-11-11 19:46:16 +0000263 if (random_bool(&random)) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000264 pdesc.fVertexLayout |= kTextFormat_VertexLayoutBit;
265 }
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000266 StageDesc& stage = pdesc.fStages[s];
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000267
268 stage.fCustomStageKey = 0;
269 customStages[s] = NULL;
270
bsalomon@google.com74b98712011-11-11 19:46:16 +0000271 stage.fOptFlags = STAGE_OPTS[random_int(&random, GR_ARRAY_COUNT(STAGE_OPTS))];
272 stage.fInConfigFlags = IN_CONFIG_FLAGS[random_int(&random, GR_ARRAY_COUNT(IN_CONFIG_FLAGS))];
273 stage.fCoordMapping = random_int(&random, StageDesc::kCoordMappingCnt);
274 stage.fFetchMode = random_int(&random, StageDesc::kFetchModeCnt);
bsalomon@google.coma8e686e2011-08-16 15:45:58 +0000275 // convolution shaders don't work with persp tex matrix
senorblanco@chromium.org05054f12012-03-02 21:05:45 +0000276 if (stage.fFetchMode == StageDesc::kConvolution_FetchMode ||
277 stage.fFetchMode == StageDesc::kDilate_FetchMode ||
278 stage.fFetchMode == StageDesc::kErode_FetchMode) {
bsalomon@google.coma8e686e2011-08-16 15:45:58 +0000279 stage.fOptFlags |= StageDesc::kNoPerspective_OptFlagBit;
280 }
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000281 stage.setEnabled(VertexUsesStage(s, pdesc.fVertexLayout));
bsalomon@google.coma91e9232012-02-23 15:39:54 +0000282 static const uint32_t kMulByAlphaMask =
283 StageDesc::kMulRGBByAlpha_RoundUp_InConfigFlag |
284 StageDesc::kMulRGBByAlpha_RoundDown_InConfigFlag;
robertphillips@google.com443e5a52012-04-30 20:01:21 +0000285
bsalomon@google.com74b98712011-11-11 19:46:16 +0000286 switch (stage.fFetchMode) {
287 case StageDesc::kSingle_FetchMode:
288 stage.fKernelWidth = 0;
289 break;
290 case StageDesc::kConvolution_FetchMode:
senorblanco@chromium.org05054f12012-03-02 21:05:45 +0000291 case StageDesc::kDilate_FetchMode:
292 case StageDesc::kErode_FetchMode:
bsalomon@google.com74b98712011-11-11 19:46:16 +0000293 stage.fKernelWidth = random_int(&random, 2, 8);
bsalomon@google.coma91e9232012-02-23 15:39:54 +0000294 stage.fInConfigFlags &= ~kMulByAlphaMask;
bsalomon@google.com74b98712011-11-11 19:46:16 +0000295 break;
296 case StageDesc::k2x2_FetchMode:
297 stage.fKernelWidth = 0;
bsalomon@google.coma91e9232012-02-23 15:39:54 +0000298 stage.fInConfigFlags &= ~kMulByAlphaMask;
bsalomon@google.com74b98712011-11-11 19:46:16 +0000299 break;
300 }
tomhudson@google.com07eecdc2012-04-20 18:35:38 +0000301
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000302 // TODO: is there a more elegant way to express this?
303 if (stage.fFetchMode == StageDesc::kConvolution_FetchMode) {
304 int direction = random_int(&random, 2);
305 float kernel[stage.fKernelWidth];
306 for (int i = 0; i < stage.fKernelWidth; i++) {
307 kernel[i] = random.nextF();
308 }
309 customStages[s] = new GrConvolutionEffect(
310 (GrSamplerState::FilterDirection)direction,
311 stage.fKernelWidth, kernel);
312 stage.fCustomStageKey =
313 customStages[s]->getFactory()->stageKey(customStages[s]);
314 }
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000315 }
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000316 CachedData cachedData;
tomhudson@google.com07eecdc2012-04-20 18:35:38 +0000317 if (!program.genProgram(this->glContextInfo(), customStages,
318 &cachedData)) {
bsalomon@google.coma8e686e2011-08-16 15:45:58 +0000319 return false;
320 }
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000321 DeleteProgram(this->glInterface(), &cachedData);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000322 }
bsalomon@google.coma8e686e2011-08-16 15:45:58 +0000323 return true;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000324}
325
bsalomon@google.com89ec61e2012-02-10 20:05:18 +0000326GrGpuGLShaders::GrGpuGLShaders(const GrGLContextInfo& ctxInfo)
327 : GrGpuGL(ctxInfo) {
bsalomon@google.comedfe1aa2011-09-29 14:40:26 +0000328
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000329 // Enable supported shader-related caps
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000330 if (kDesktop_GrGLBinding == this->glBinding()) {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000331 fCaps.fDualSourceBlendingSupport =
bsalomon@google.comc82b8892011-09-22 14:10:33 +0000332 this->glVersion() >= GR_GL_VER(3,3) ||
bsalomon@google.com2c17fcd2011-07-06 17:47:02 +0000333 this->hasExtension("GL_ARB_blend_func_extended");
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000334 fCaps.fShaderDerivativeSupport = true;
bsalomon@google.comedfe1aa2011-09-29 14:40:26 +0000335 // we don't support GL_ARB_geometry_shader4, just GL 3.2+ GS
336 fCaps.fGeometryShaderSupport =
337 this->glVersion() >= GR_GL_VER(3,2) &&
bsalomon@google.com89ec61e2012-02-10 20:05:18 +0000338 this->glslGeneration() >= k150_GrGLSLGeneration;
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000339 } else {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000340 fCaps.fShaderDerivativeSupport =
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000341 this->hasExtension("GL_OES_standard_derivatives");
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000342 }
junov@google.comf93e7172011-03-31 21:26:24 +0000343
bsalomon@google.com89ec61e2012-02-10 20:05:18 +0000344 GR_GL_GetIntegerv(this->glInterface(),
345 GR_GL_MAX_VERTEX_ATTRIBS,
346 &fMaxVertexAttribs);
bsalomon@google.comb5b5eaf2011-10-19 13:25:46 +0000347
junov@google.comf93e7172011-03-31 21:26:24 +0000348 fProgramData = NULL;
bsalomon@google.com96399942012-02-13 14:39:16 +0000349 fProgramCache = new ProgramCache(this->glContextInfo());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000350
351#if 0
bsalomon@google.coma8e686e2011-08-16 15:45:58 +0000352 this->programUnitTest();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000353#endif
junov@google.comf93e7172011-03-31 21:26:24 +0000354}
355
356GrGpuGLShaders::~GrGpuGLShaders() {
robertphillips@google.comf6f123d2012-03-21 17:57:55 +0000357
358 if (fProgramData && 0 != fHWProgramID) {
359 // detach the current program so there is no confusion on OpenGL's part
360 // that we want it to be deleted
361 SkASSERT(fHWProgramID == fProgramData->fProgramID);
362 GL_CALL(UseProgram(0));
363 }
junov@google.comf93e7172011-03-31 21:26:24 +0000364 delete fProgramCache;
365}
366
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000367const GrMatrix& GrGpuGLShaders::getHWViewMatrix() {
368 GrAssert(fProgramData);
369
370 if (GrGLProgram::kSetAsAttribute ==
371 fProgramData->fUniLocations.fViewMatrixUni) {
372 return fHWDrawState.getViewMatrix();
373 } else {
374 return fProgramData->fViewMatrix;
375 }
376}
377
378void GrGpuGLShaders::recordHWViewMatrix(const GrMatrix& matrix) {
379 GrAssert(fProgramData);
380 if (GrGLProgram::kSetAsAttribute ==
381 fProgramData->fUniLocations.fViewMatrixUni) {
382 fHWDrawState.setViewMatrix(matrix);
383 } else {
384 fProgramData->fViewMatrix = matrix;
385 }
386}
387
junov@google.comf93e7172011-03-31 21:26:24 +0000388const GrMatrix& GrGpuGLShaders::getHWSamplerMatrix(int stage) {
junov@google.comf93e7172011-03-31 21:26:24 +0000389 GrAssert(fProgramData);
bsalomon@google.com91961302011-05-09 18:39:58 +0000390
391 if (GrGLProgram::kSetAsAttribute ==
392 fProgramData->fUniLocations.fStages[stage].fTextureMatrixUni) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000393 return fHWDrawState.getSampler(stage).getMatrix();
bsalomon@google.com91961302011-05-09 18:39:58 +0000394 } else {
395 return fProgramData->fTextureMatrices[stage];
396 }
junov@google.comf93e7172011-03-31 21:26:24 +0000397}
398
399void GrGpuGLShaders::recordHWSamplerMatrix(int stage, const GrMatrix& matrix) {
junov@google.comf93e7172011-03-31 21:26:24 +0000400 GrAssert(fProgramData);
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000401 if (GrGLProgram::kSetAsAttribute ==
bsalomon@google.com91961302011-05-09 18:39:58 +0000402 fProgramData->fUniLocations.fStages[stage].fTextureMatrixUni) {
bsalomon@google.comaa814fe2011-12-12 18:45:07 +0000403 *fHWDrawState.sampler(stage)->matrix() = matrix;
bsalomon@google.com91961302011-05-09 18:39:58 +0000404 } else {
405 fProgramData->fTextureMatrices[stage] = matrix;
406 }
junov@google.comf93e7172011-03-31 21:26:24 +0000407}
408
bsalomon@google.com1bf1c212011-11-05 12:18:58 +0000409void GrGpuGLShaders::onResetContext() {
410 INHERITED::onResetContext();
junov@google.comf93e7172011-03-31 21:26:24 +0000411
junov@google.comf93e7172011-03-31 21:26:24 +0000412 fHWGeometryState.fVertexOffset = ~0;
bsalomon@google.comb5b5eaf2011-10-19 13:25:46 +0000413
414 // Third party GL code may have left vertex attributes enabled. Some GL
415 // implementations (osmesa) may read vetex attributes that are not required
416 // by the current shader. Therefore, we have to ensure that only the
417 // attributes we require for the current draw are enabled or we may cause an
418 // invalid read.
419
420 // Disable all vertex layout bits so that next flush will assume all
421 // optional vertex attributes are disabled.
422 fHWGeometryState.fVertexLayout = 0;
423
424 // We always use the this attribute and assume it is always enabled.
425 int posAttrIdx = GrGLProgram::PositionAttributeIdx();
426 GL_CALL(EnableVertexAttribArray(posAttrIdx));
427 // Disable all other vertex attributes.
428 for (int va = 0; va < fMaxVertexAttribs; ++va) {
429 if (va != posAttrIdx) {
430 GL_CALL(DisableVertexAttribArray(va));
431 }
junov@google.comf93e7172011-03-31 21:26:24 +0000432 }
junov@google.comf93e7172011-03-31 21:26:24 +0000433
434 fHWProgramID = 0;
435}
436
437void GrGpuGLShaders::flushViewMatrix() {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000438 const GrMatrix& vm = this->getDrawState().getViewMatrix();
bsalomon@google.com8fe84b52012-03-26 15:24:27 +0000439 if (!GrGpuGLShaders::getHWViewMatrix().cheapEqualTo(vm)) {
junov@google.comf93e7172011-03-31 21:26:24 +0000440
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000441 const GrRenderTarget* rt = this->getDrawState().getRenderTarget();
442 GrAssert(NULL != rt);
443 GrMatrix m;
444 m.setAll(
445 GrIntToScalar(2) / rt->width(), 0, -GR_Scalar1,
446 0,-GrIntToScalar(2) / rt->height(), GR_Scalar1,
447 0, 0, GrMatrix::I()[8]);
448 m.setConcat(m, vm);
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000449
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000450 // ES doesn't allow you to pass true to the transpose param,
451 // so do our own transpose
452 GrGLfloat mt[] = {
453 GrScalarToFloat(m[GrMatrix::kMScaleX]),
454 GrScalarToFloat(m[GrMatrix::kMSkewY]),
455 GrScalarToFloat(m[GrMatrix::kMPersp0]),
456 GrScalarToFloat(m[GrMatrix::kMSkewX]),
457 GrScalarToFloat(m[GrMatrix::kMScaleY]),
458 GrScalarToFloat(m[GrMatrix::kMPersp1]),
459 GrScalarToFloat(m[GrMatrix::kMTransX]),
460 GrScalarToFloat(m[GrMatrix::kMTransY]),
461 GrScalarToFloat(m[GrMatrix::kMPersp2])
462 };
463
464 if (GrGLProgram::kSetAsAttribute ==
465 fProgramData->fUniLocations.fViewMatrixUni) {
466 int baseIdx = GrGLProgram::ViewMatrixAttributeIdx();
467 GL_CALL(VertexAttrib4fv(baseIdx + 0, mt+0));
468 GL_CALL(VertexAttrib4fv(baseIdx + 1, mt+3));
469 GL_CALL(VertexAttrib4fv(baseIdx + 2, mt+6));
470 } else {
471 GrAssert(GrGLProgram::kUnusedUniform !=
472 fProgramData->fUniLocations.fViewMatrixUni);
473 GL_CALL(UniformMatrix3fv(fProgramData->fUniLocations.fViewMatrixUni,
474 1, false, mt));
475 }
476 this->recordHWViewMatrix(vm);
bsalomon@google.com91961302011-05-09 18:39:58 +0000477 }
junov@google.comf93e7172011-03-31 21:26:24 +0000478}
479
junov@google.com6acc9b32011-05-16 18:32:07 +0000480void GrGpuGLShaders::flushTextureDomain(int s) {
481 const GrGLint& uni = fProgramData->fUniLocations.fStages[s].fTexDomUni;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000482 const GrDrawState& drawState = this->getDrawState();
junov@google.com6acc9b32011-05-16 18:32:07 +0000483 if (GrGLProgram::kUnusedUniform != uni) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000484 const GrRect &texDom = drawState.getSampler(s).getTextureDomain();
junov@google.com6acc9b32011-05-16 18:32:07 +0000485
twiz@google.com76b82742011-06-02 20:30:02 +0000486 if (((1 << s) & fDirtyFlags.fTextureChangedMask) ||
487 fProgramData->fTextureDomain[s] != texDom) {
junov@google.com6acc9b32011-05-16 18:32:07 +0000488
junov@google.com2f839402011-05-24 15:13:01 +0000489 fProgramData->fTextureDomain[s] = texDom;
junov@google.com6acc9b32011-05-16 18:32:07 +0000490
junov@google.com2f839402011-05-24 15:13:01 +0000491 float values[4] = {
twiz@google.com76b82742011-06-02 20:30:02 +0000492 GrScalarToFloat(texDom.left()),
493 GrScalarToFloat(texDom.top()),
494 GrScalarToFloat(texDom.right()),
495 GrScalarToFloat(texDom.bottom())
junov@google.com2f839402011-05-24 15:13:01 +0000496 };
497
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000498 const GrGLTexture* texture =
499 static_cast<const GrGLTexture*>(drawState.getTexture(s));
junov@google.com2f839402011-05-24 15:13:01 +0000500 GrGLTexture::Orientation orientation = texture->orientation();
501
502 // vertical flip if necessary
503 if (GrGLTexture::kBottomUp_Orientation == orientation) {
504 values[1] = 1.0f - values[1];
505 values[3] = 1.0f - values[3];
twiz@google.com76b82742011-06-02 20:30:02 +0000506 // The top and bottom were just flipped, so correct the ordering
507 // of elements so that values = (l, t, r, b).
508 SkTSwap(values[1], values[3]);
junov@google.com2f839402011-05-24 15:13:01 +0000509 }
510
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000511 GL_CALL(Uniform4fv(uni, 1, values));
junov@google.com6acc9b32011-05-16 18:32:07 +0000512 }
junov@google.com6acc9b32011-05-16 18:32:07 +0000513 }
514}
515
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000516void GrGpuGLShaders::flushTextureMatrix(int s) {
junov@google.com6acc9b32011-05-16 18:32:07 +0000517 const GrGLint& uni = fProgramData->fUniLocations.fStages[s].fTextureMatrixUni;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000518 const GrDrawState& drawState = this->getDrawState();
519 const GrGLTexture* texture =
520 static_cast<const GrGLTexture*>(drawState.getTexture(s));
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000521 if (NULL != texture) {
bsalomon@google.com8fe84b52012-03-26 15:24:27 +0000522 const GrMatrix& hwMatrix = this->getHWSamplerMatrix(s);
523 const GrMatrix& samplerMatrix = drawState.getSampler(s).getMatrix();
bsalomon@google.com91961302011-05-09 18:39:58 +0000524 if (GrGLProgram::kUnusedUniform != uni &&
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000525 (((1 << s) & fDirtyFlags.fTextureChangedMask) ||
bsalomon@google.com8fe84b52012-03-26 15:24:27 +0000526 !hwMatrix.cheapEqualTo(samplerMatrix))) {
junov@google.comf93e7172011-03-31 21:26:24 +0000527
bsalomon@google.com8fe84b52012-03-26 15:24:27 +0000528 GrMatrix m = samplerMatrix;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000529 GrSamplerState::SampleMode mode =
530 drawState.getSampler(s).getSampleMode();
bsalomon@google.com91961302011-05-09 18:39:58 +0000531 AdjustTextureMatrix(texture, mode, &m);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000532
bsalomon@google.com91961302011-05-09 18:39:58 +0000533 // ES doesn't allow you to pass true to the transpose param,
534 // so do our own transpose
bsalomon@google.com27a4dc42011-05-16 13:14:03 +0000535 GrGLfloat mt[] = {
536 GrScalarToFloat(m[GrMatrix::kMScaleX]),
537 GrScalarToFloat(m[GrMatrix::kMSkewY]),
538 GrScalarToFloat(m[GrMatrix::kMPersp0]),
539 GrScalarToFloat(m[GrMatrix::kMSkewX]),
540 GrScalarToFloat(m[GrMatrix::kMScaleY]),
541 GrScalarToFloat(m[GrMatrix::kMPersp1]),
542 GrScalarToFloat(m[GrMatrix::kMTransX]),
543 GrScalarToFloat(m[GrMatrix::kMTransY]),
544 GrScalarToFloat(m[GrMatrix::kMPersp2])
bsalomon@google.com91961302011-05-09 18:39:58 +0000545 };
bsalomon@google.com27a4dc42011-05-16 13:14:03 +0000546
bsalomon@google.com91961302011-05-09 18:39:58 +0000547 if (GrGLProgram::kSetAsAttribute ==
548 fProgramData->fUniLocations.fStages[s].fTextureMatrixUni) {
549 int baseIdx = GrGLProgram::TextureMatrixAttributeIdx(s);
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000550 GL_CALL(VertexAttrib4fv(baseIdx + 0, mt+0));
551 GL_CALL(VertexAttrib4fv(baseIdx + 1, mt+3));
552 GL_CALL(VertexAttrib4fv(baseIdx + 2, mt+6));
bsalomon@google.com91961302011-05-09 18:39:58 +0000553 } else {
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000554 GL_CALL(UniformMatrix3fv(uni, 1, false, mt));
bsalomon@google.com91961302011-05-09 18:39:58 +0000555 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000556 this->recordHWSamplerMatrix(s, drawState.getSampler(s).getMatrix());
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000557 }
558 }
junov@google.comf93e7172011-03-31 21:26:24 +0000559}
560
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000561void GrGpuGLShaders::flushRadial2(int s) {
junov@google.comf93e7172011-03-31 21:26:24 +0000562
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000563 const int &uni = fProgramData->fUniLocations.fStages[s].fRadial2Uni;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000564 const GrSamplerState& sampler = this->getDrawState().getSampler(s);
bsalomon@google.com91961302011-05-09 18:39:58 +0000565 if (GrGLProgram::kUnusedUniform != uni &&
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000566 (fProgramData->fRadial2CenterX1[s] != sampler.getRadial2CenterX1() ||
567 fProgramData->fRadial2Radius0[s] != sampler.getRadial2Radius0() ||
568 fProgramData->fRadial2PosRoot[s] != sampler.isRadial2PosRoot())) {
junov@google.comf93e7172011-03-31 21:26:24 +0000569
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000570 GrScalar centerX1 = sampler.getRadial2CenterX1();
571 GrScalar radius0 = sampler.getRadial2Radius0();
junov@google.comf93e7172011-03-31 21:26:24 +0000572
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000573 GrScalar a = GrMul(centerX1, centerX1) - GR_Scalar1;
junov@google.comf93e7172011-03-31 21:26:24 +0000574
bsalomon@google.com22c5dea2011-07-07 14:38:03 +0000575 // when were in the degenerate (linear) case the second
576 // value will be INF but the program doesn't read it. (We
577 // use the same 6 uniforms even though we don't need them
578 // all in the linear case just to keep the code complexity
579 // down).
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000580 float values[6] = {
581 GrScalarToFloat(a),
bsalomon@google.com2cdfade2011-11-23 16:53:42 +0000582 1 / (2.f * GrScalarToFloat(a)),
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000583 GrScalarToFloat(centerX1),
584 GrScalarToFloat(radius0),
585 GrScalarToFloat(GrMul(radius0, radius0)),
586 sampler.isRadial2PosRoot() ? 1.f : -1.f
587 };
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000588 GL_CALL(Uniform1fv(uni, 6, values));
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000589 fProgramData->fRadial2CenterX1[s] = sampler.getRadial2CenterX1();
590 fProgramData->fRadial2Radius0[s] = sampler.getRadial2Radius0();
591 fProgramData->fRadial2PosRoot[s] = sampler.isRadial2PosRoot();
592 }
593}
594
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000595void GrGpuGLShaders::flushConvolution(int s) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000596 const GrSamplerState& sampler = this->getDrawState().getSampler(s);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000597 int kernelUni = fProgramData->fUniLocations.fStages[s].fKernelUni;
598 if (GrGLProgram::kUnusedUniform != kernelUni) {
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000599 GL_CALL(Uniform1fv(kernelUni, sampler.getKernelWidth(),
600 sampler.getKernel()));
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000601 }
602 int imageIncrementUni = fProgramData->fUniLocations.fStages[s].fImageIncrementUni;
603 if (GrGLProgram::kUnusedUniform != imageIncrementUni) {
senorblanco@chromium.org05054f12012-03-02 21:05:45 +0000604 const GrGLTexture* texture =
605 static_cast<const GrGLTexture*>(this->getDrawState().getTexture(s));
606 float imageIncrement[2] = { 0 };
607 switch (sampler.getFilterDirection()) {
608 case GrSamplerState::kX_FilterDirection:
609 imageIncrement[0] = 1.0f / texture->width();
610 break;
611 case GrSamplerState::kY_FilterDirection:
612 imageIncrement[1] = 1.0f / texture->height();
613 break;
614 default:
615 GrCrash("Unknown filter direction.");
616 }
617 GL_CALL(Uniform2fv(imageIncrementUni, 1, imageIncrement));
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000618 }
619}
620
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000621void GrGpuGLShaders::flushTexelSize(int s) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000622 const int& uni = fProgramData->fUniLocations.fStages[s].fNormalizedTexelSizeUni;
bsalomon@google.com91961302011-05-09 18:39:58 +0000623 if (GrGLProgram::kUnusedUniform != uni) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000624 const GrGLTexture* texture =
625 static_cast<const GrGLTexture*>(this->getDrawState().getTexture(s));
bsalomon@google.com99621082011-11-15 16:47:16 +0000626 if (texture->width() != fProgramData->fTextureWidth[s] ||
627 texture->height() != fProgramData->fTextureHeight[s]) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000628
bsalomon@google.com99621082011-11-15 16:47:16 +0000629 float texelSize[] = {1.f / texture->width(),
630 1.f / texture->height()};
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000631 GL_CALL(Uniform2fv(uni, 1, texelSize));
bsalomon@google.com99621082011-11-15 16:47:16 +0000632 fProgramData->fTextureWidth[s] = texture->width();
633 fProgramData->fTextureHeight[s] = texture->height();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000634 }
635 }
junov@google.comf93e7172011-03-31 21:26:24 +0000636}
637
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000638void GrGpuGLShaders::flushEdgeAAData() {
639 const int& uni = fProgramData->fUniLocations.fEdgesUni;
640 if (GrGLProgram::kUnusedUniform != uni) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000641 int count = this->getDrawState().getNumAAEdges();
tomhudson@google.com93813632011-10-27 20:21:16 +0000642 GrDrawState::Edge edges[GrDrawState::kMaxEdges];
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000643 // Flip the edges in Y
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000644 float height =
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000645 static_cast<float>(this->getDrawState().getRenderTarget()->height());
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000646 for (int i = 0; i < count; ++i) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000647 edges[i] = this->getDrawState().getAAEdges()[i];
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000648 float b = edges[i].fY;
649 edges[i].fY = -b;
650 edges[i].fZ += b * height;
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000651 }
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000652 GL_CALL(Uniform3fv(uni, count, &edges[0].fX));
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000653 }
654}
655
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +0000656void GrGpuGLShaders::flushColorMatrix() {
657 const ProgramDesc& desc = fCurrentProgram.getDesc();
658 int matrixUni = fProgramData->fUniLocations.fColorMatrixUni;
659 int vecUni = fProgramData->fUniLocations.fColorMatrixVecUni;
660 if (GrGLProgram::kUnusedUniform != matrixUni
661 && GrGLProgram::kUnusedUniform != vecUni) {
662 const float* m = this->getDrawState().getColorMatrix();
663 GrGLfloat mt[] = {
664 m[0], m[5], m[10], m[15],
665 m[1], m[6], m[11], m[16],
666 m[2], m[7], m[12], m[17],
667 m[3], m[8], m[13], m[18],
668 };
669 static float scale = 1.0f / 255.0f;
670 GrGLfloat vec[] = {
671 m[4] * scale, m[9] * scale, m[14] * scale, m[19] * scale,
672 };
673 GL_CALL(UniformMatrix4fv(matrixUni, 1, false, mt));
674 GL_CALL(Uniform4fv(vecUni, 1, vec));
675 }
676}
677
Scroggo01b87ec2011-05-11 18:05:38 +0000678static const float ONE_OVER_255 = 1.f / 255.f;
679
680#define GR_COLOR_TO_VEC4(color) {\
681 GrColorUnpackR(color) * ONE_OVER_255,\
682 GrColorUnpackG(color) * ONE_OVER_255,\
683 GrColorUnpackB(color) * ONE_OVER_255,\
684 GrColorUnpackA(color) * ONE_OVER_255 \
685}
686
bsalomon@google.com86c1f712011-10-12 14:54:26 +0000687void GrGpuGLShaders::flushColor(GrColor color) {
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000688 const ProgramDesc& desc = fCurrentProgram.getDesc();
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000689 const GrDrawState& drawState = this->getDrawState();
690
bsalomon@google.come79c8152012-03-29 19:07:12 +0000691 if (this->getVertexLayout() & kColor_VertexLayoutBit) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000692 // color will be specified per-vertex as an attribute
693 // invalidate the const vertex attrib color
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000694 fHWDrawState.setColor(GrColor_ILLEGAL);
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000695 } else {
bsalomon@google.com85b505b2011-11-07 14:56:51 +0000696 switch (desc.fColorInput) {
697 case ProgramDesc::kAttribute_ColorInput:
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000698 if (fHWDrawState.getColor() != color) {
bsalomon@google.com2401ae82012-01-17 21:03:05 +0000699 // OpenGL ES only supports the float varieties of
700 // glVertexAttrib
bsalomon@google.com86c1f712011-10-12 14:54:26 +0000701 float c[] = GR_COLOR_TO_VEC4(color);
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000702 GL_CALL(VertexAttrib4fv(GrGLProgram::ColorAttributeIdx(),
703 c));
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000704 fHWDrawState.setColor(color);
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000705 }
706 break;
bsalomon@google.com85b505b2011-11-07 14:56:51 +0000707 case ProgramDesc::kUniform_ColorInput:
bsalomon@google.com86c1f712011-10-12 14:54:26 +0000708 if (fProgramData->fColor != color) {
bsalomon@google.com2401ae82012-01-17 21:03:05 +0000709 // OpenGL ES doesn't support unsigned byte varieties of
710 // glUniform
bsalomon@google.com86c1f712011-10-12 14:54:26 +0000711 float c[] = GR_COLOR_TO_VEC4(color);
bsalomon@google.com91961302011-05-09 18:39:58 +0000712 GrAssert(GrGLProgram::kUnusedUniform !=
713 fProgramData->fUniLocations.fColorUni);
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000714 GL_CALL(Uniform4fv(fProgramData->fUniLocations.fColorUni,
715 1, c));
bsalomon@google.com86c1f712011-10-12 14:54:26 +0000716 fProgramData->fColor = color;
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000717 }
718 break;
bsalomon@google.com85b505b2011-11-07 14:56:51 +0000719 case ProgramDesc::kSolidWhite_ColorInput:
720 case ProgramDesc::kTransBlack_ColorInput:
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000721 break;
722 default:
723 GrCrash("Unknown color type.");
724 }
725 }
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000726 if (fProgramData->fUniLocations.fColorFilterUni
727 != GrGLProgram::kUnusedUniform
728 && fProgramData->fColorFilterColor
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000729 != drawState.getColorFilterColor()) {
730 float c[] = GR_COLOR_TO_VEC4(drawState.getColorFilterColor());
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000731 GL_CALL(Uniform4fv(fProgramData->fUniLocations.fColorFilterUni, 1, c));
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000732 fProgramData->fColorFilterColor = drawState.getColorFilterColor();
Scroggo97c88c22011-05-11 14:05:25 +0000733 }
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000734}
735
bsalomon@google.com2401ae82012-01-17 21:03:05 +0000736void GrGpuGLShaders::flushCoverage(GrColor coverage) {
737 const ProgramDesc& desc = fCurrentProgram.getDesc();
738 const GrDrawState& drawState = this->getDrawState();
739
740
bsalomon@google.come79c8152012-03-29 19:07:12 +0000741 if (this->getVertexLayout() & kCoverage_VertexLayoutBit) {
bsalomon@google.com2401ae82012-01-17 21:03:05 +0000742 // coverage will be specified per-vertex as an attribute
743 // invalidate the const vertex attrib coverage
744 fHWDrawState.setCoverage4(GrColor_ILLEGAL);
745 } else {
746 switch (desc.fCoverageInput) {
747 case ProgramDesc::kAttribute_ColorInput:
748 if (fHWDrawState.getCoverage() != coverage) {
749 // OpenGL ES only supports the float varieties of
750 // glVertexAttrib
751 float c[] = GR_COLOR_TO_VEC4(coverage);
752 GL_CALL(VertexAttrib4fv(GrGLProgram::CoverageAttributeIdx(),
753 c));
754 fHWDrawState.setCoverage(coverage);
755 }
756 break;
757 case ProgramDesc::kUniform_ColorInput:
758 if (fProgramData->fCoverage != coverage) {
759 // OpenGL ES doesn't support unsigned byte varieties of
760 // glUniform
761 float c[] = GR_COLOR_TO_VEC4(coverage);
762 GrAssert(GrGLProgram::kUnusedUniform !=
763 fProgramData->fUniLocations.fCoverageUni);
764 GL_CALL(Uniform4fv(fProgramData->fUniLocations.fCoverageUni,
765 1, c));
766 fProgramData->fCoverage = coverage;
767 }
768 break;
769 case ProgramDesc::kSolidWhite_ColorInput:
770 case ProgramDesc::kTransBlack_ColorInput:
771 break;
772 default:
773 GrCrash("Unknown coverage type.");
774 }
775 }
776}
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000777
junov@google.comf93e7172011-03-31 21:26:24 +0000778bool GrGpuGLShaders::flushGraphicsState(GrPrimitiveType type) {
779 if (!flushGLStateCommon(type)) {
780 return false;
781 }
782
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000783 const GrDrawState& drawState = this->getDrawState();
784
junov@google.comf93e7172011-03-31 21:26:24 +0000785 if (fDirtyFlags.fRenderTargetChanged) {
786 // our coords are in pixel space and the GL matrices map to NDC
787 // so if the viewport changed, our matrix is now wrong.
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000788 fHWDrawState.setViewMatrix(GrMatrix::InvalidMatrix());
junov@google.comf93e7172011-03-31 21:26:24 +0000789 // we assume all shader matrices may be wrong after viewport changes
790 fProgramCache->invalidateViewMatrices();
junov@google.comf93e7172011-03-31 21:26:24 +0000791 }
792
bsalomon@google.com86c1f712011-10-12 14:54:26 +0000793 GrBlendCoeff srcCoeff;
794 GrBlendCoeff dstCoeff;
795 BlendOptFlags blendOpts = this->getBlendOpts(false, &srcCoeff, &dstCoeff);
796 if (kSkipDraw_BlendOptFlag & blendOpts) {
797 return false;
798 }
799
tomhudson@google.com07eecdc2012-04-20 18:35:38 +0000800 GrCustomStage* customStages [GrDrawState::kNumStages];
801 this->buildProgram(type, blendOpts, dstCoeff, customStages);
802 fProgramData = fProgramCache->getProgramData(fCurrentProgram,
803 customStages);
bsalomon@google.com91961302011-05-09 18:39:58 +0000804 if (NULL == fProgramData) {
805 GrAssert(!"Failed to create program!");
806 return false;
807 }
junov@google.comf93e7172011-03-31 21:26:24 +0000808
809 if (fHWProgramID != fProgramData->fProgramID) {
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000810 GL_CALL(UseProgram(fProgramData->fProgramID));
junov@google.comf93e7172011-03-31 21:26:24 +0000811 fHWProgramID = fProgramData->fProgramID;
812 }
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000813 fCurrentProgram.overrideBlend(&srcCoeff, &dstCoeff);
814 this->flushBlend(type, srcCoeff, dstCoeff);
junov@google.comf93e7172011-03-31 21:26:24 +0000815
bsalomon@google.com86c1f712011-10-12 14:54:26 +0000816 GrColor color;
bsalomon@google.com2401ae82012-01-17 21:03:05 +0000817 GrColor coverage;
bsalomon@google.com86c1f712011-10-12 14:54:26 +0000818 if (blendOpts & kEmitTransBlack_BlendOptFlag) {
819 color = 0;
bsalomon@google.com2401ae82012-01-17 21:03:05 +0000820 coverage = 0;
bsalomon@google.com86c1f712011-10-12 14:54:26 +0000821 } else if (blendOpts & kEmitCoverage_BlendOptFlag) {
822 color = 0xffffffff;
bsalomon@google.com2401ae82012-01-17 21:03:05 +0000823 coverage = drawState.getCoverage();
bsalomon@google.com86c1f712011-10-12 14:54:26 +0000824 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000825 color = drawState.getColor();
bsalomon@google.com2401ae82012-01-17 21:03:05 +0000826 coverage = drawState.getCoverage();
bsalomon@google.com86c1f712011-10-12 14:54:26 +0000827 }
828 this->flushColor(color);
bsalomon@google.com2401ae82012-01-17 21:03:05 +0000829 this->flushCoverage(coverage);
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000830
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000831 this->flushViewMatrix();
junov@google.comf93e7172011-03-31 21:26:24 +0000832
tomhudson@google.com93813632011-10-27 20:21:16 +0000833 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com40d92932011-12-13 18:40:47 +0000834 if (this->isStageEnabled(s)) {
835 this->flushTextureMatrix(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000836
bsalomon@google.com40d92932011-12-13 18:40:47 +0000837 this->flushRadial2(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000838
bsalomon@google.com40d92932011-12-13 18:40:47 +0000839 this->flushConvolution(s);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000840
bsalomon@google.com40d92932011-12-13 18:40:47 +0000841 this->flushTexelSize(s);
junov@google.com6acc9b32011-05-16 18:32:07 +0000842
bsalomon@google.com40d92932011-12-13 18:40:47 +0000843 this->flushTextureDomain(s);
tomhudson@google.com07eecdc2012-04-20 18:35:38 +0000844
845 if (NULL != fProgramData->fCustomStage[s]) {
846 const GrSamplerState& sampler =
847 this->getDrawState().getSampler(s);
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000848 const GrGLTexture* texture =
849 static_cast<const GrGLTexture*>(
850 this->getDrawState().getTexture(s));
tomhudson@google.com07eecdc2012-04-20 18:35:38 +0000851 fProgramData->fCustomStage[s]->setData(
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000852 this->glInterface(), sampler.getCustomStage(), texture);
tomhudson@google.com07eecdc2012-04-20 18:35:38 +0000853 }
bsalomon@google.com40d92932011-12-13 18:40:47 +0000854 }
junov@google.comf93e7172011-03-31 21:26:24 +0000855 }
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000856 this->flushEdgeAAData();
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +0000857 this->flushColorMatrix();
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000858 resetDirtyFlags();
junov@google.comf93e7172011-03-31 21:26:24 +0000859 return true;
860}
861
862void GrGpuGLShaders::postDraw() {
junov@google.comf93e7172011-03-31 21:26:24 +0000863}
864
bsalomon@google.com2717d562012-05-07 19:10:52 +0000865#if GR_TEXT_SCALAR_IS_USHORT
866 #define TEXT_COORDS_GL_TYPE GR_GL_UNSIGNED_SHORT
867 #define TEXT_COORDS_ARE_NORMALIZED 1
868#elif GR_TEXT_SCALAR_IS_FLOAT
869 #define TEXT_COORDS_GL_TYPE GR_GL_FLOAT
870 #define TEXT_COORDS_ARE_NORMALIZED 0
871#elif GR_TEXT_SCALAR_IS_FIXED
872 #define TEXT_COORDS_GL_TYPE GR_GL_FIXED
873 #define TEXT_COORDS_ARE_NORMALIZED 0
874#else
875 #error "unknown GR_TEXT_SCALAR type"
876#endif
877
junov@google.comf93e7172011-03-31 21:26:24 +0000878void GrGpuGLShaders::setupGeometry(int* startVertex,
879 int* startIndex,
880 int vertexCount,
881 int indexCount) {
882
883 int newColorOffset;
bsalomon@google.coma3108262011-10-10 14:08:47 +0000884 int newCoverageOffset;
tomhudson@google.com93813632011-10-27 20:21:16 +0000885 int newTexCoordOffsets[GrDrawState::kMaxTexCoords];
bsalomon@google.comaeb21602011-08-30 18:13:44 +0000886 int newEdgeOffset;
junov@google.comf93e7172011-03-31 21:26:24 +0000887
bsalomon@google.come79c8152012-03-29 19:07:12 +0000888 GrVertexLayout currLayout = this->getVertexLayout();
889
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000890 GrGLsizei newStride = VertexSizeAndOffsetsByIdx(
bsalomon@google.come79c8152012-03-29 19:07:12 +0000891 currLayout,
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000892 newTexCoordOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +0000893 &newColorOffset,
bsalomon@google.coma3108262011-10-10 14:08:47 +0000894 &newCoverageOffset,
bsalomon@google.comaeb21602011-08-30 18:13:44 +0000895 &newEdgeOffset);
junov@google.comf93e7172011-03-31 21:26:24 +0000896 int oldColorOffset;
bsalomon@google.coma3108262011-10-10 14:08:47 +0000897 int oldCoverageOffset;
tomhudson@google.com93813632011-10-27 20:21:16 +0000898 int oldTexCoordOffsets[GrDrawState::kMaxTexCoords];
bsalomon@google.comaeb21602011-08-30 18:13:44 +0000899 int oldEdgeOffset;
900
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000901 GrGLsizei oldStride = VertexSizeAndOffsetsByIdx(
902 fHWGeometryState.fVertexLayout,
903 oldTexCoordOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +0000904 &oldColorOffset,
bsalomon@google.coma3108262011-10-10 14:08:47 +0000905 &oldCoverageOffset,
bsalomon@google.comaeb21602011-08-30 18:13:44 +0000906 &oldEdgeOffset);
junov@google.comf93e7172011-03-31 21:26:24 +0000907 bool indexed = NULL != startIndex;
908
909 int extraVertexOffset;
910 int extraIndexOffset;
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000911 this->setBuffers(indexed, &extraVertexOffset, &extraIndexOffset);
junov@google.comf93e7172011-03-31 21:26:24 +0000912
913 GrGLenum scalarType;
914 bool texCoordNorm;
bsalomon@google.come79c8152012-03-29 19:07:12 +0000915 if (currLayout & kTextFormat_VertexLayoutBit) {
bsalomon@google.com2717d562012-05-07 19:10:52 +0000916 scalarType = TEXT_COORDS_GL_TYPE;
917 texCoordNorm = SkToBool(TEXT_COORDS_ARE_NORMALIZED);
junov@google.comf93e7172011-03-31 21:26:24 +0000918 } else {
bsalomon@google.com2717d562012-05-07 19:10:52 +0000919 GR_STATIC_ASSERT(GR_SCALAR_IS_FLOAT);
920 scalarType = GR_GL_FLOAT;
junov@google.comf93e7172011-03-31 21:26:24 +0000921 texCoordNorm = false;
922 }
923
924 size_t vertexOffset = (*startVertex + extraVertexOffset) * newStride;
925 *startVertex = 0;
926 if (indexed) {
927 *startIndex += extraIndexOffset;
928 }
929
930 // all the Pointers must be set if any of these are true
931 bool allOffsetsChange = fHWGeometryState.fArrayPtrsDirty ||
932 vertexOffset != fHWGeometryState.fVertexOffset ||
933 newStride != oldStride;
934
935 // position and tex coord offsets change if above conditions are true
936 // or the type/normalization changed based on text vs nontext type coords.
937 bool posAndTexChange = allOffsetsChange ||
bsalomon@google.com2717d562012-05-07 19:10:52 +0000938 (((TEXT_COORDS_GL_TYPE != GR_GL_FLOAT) || TEXT_COORDS_ARE_NORMALIZED) &&
junov@google.comf93e7172011-03-31 21:26:24 +0000939 (kTextFormat_VertexLayoutBit &
bsalomon@google.come79c8152012-03-29 19:07:12 +0000940 (fHWGeometryState.fVertexLayout ^ currLayout)));
junov@google.comf93e7172011-03-31 21:26:24 +0000941
942 if (posAndTexChange) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000943 int idx = GrGLProgram::PositionAttributeIdx();
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000944 GL_CALL(VertexAttribPointer(idx, 2, scalarType, false, newStride,
bsalomon@google.com91961302011-05-09 18:39:58 +0000945 (GrGLvoid*)vertexOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000946 fHWGeometryState.fVertexOffset = vertexOffset;
947 }
948
tomhudson@google.com93813632011-10-27 20:21:16 +0000949 for (int t = 0; t < GrDrawState::kMaxTexCoords; ++t) {
junov@google.comf93e7172011-03-31 21:26:24 +0000950 if (newTexCoordOffsets[t] > 0) {
951 GrGLvoid* texCoordOffset = (GrGLvoid*)(vertexOffset + newTexCoordOffsets[t]);
bsalomon@google.com91961302011-05-09 18:39:58 +0000952 int idx = GrGLProgram::TexCoordAttributeIdx(t);
junov@google.comf93e7172011-03-31 21:26:24 +0000953 if (oldTexCoordOffsets[t] <= 0) {
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000954 GL_CALL(EnableVertexAttribArray(idx));
955 GL_CALL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
bsalomon@google.com91961302011-05-09 18:39:58 +0000956 newStride, texCoordOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000957 } else if (posAndTexChange ||
958 newTexCoordOffsets[t] != oldTexCoordOffsets[t]) {
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000959 GL_CALL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
bsalomon@google.com91961302011-05-09 18:39:58 +0000960 newStride, texCoordOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000961 }
962 } else if (oldTexCoordOffsets[t] > 0) {
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000963 GL_CALL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t)));
junov@google.comf93e7172011-03-31 21:26:24 +0000964 }
965 }
966
967 if (newColorOffset > 0) {
968 GrGLvoid* colorOffset = (int8_t*)(vertexOffset + newColorOffset);
bsalomon@google.com91961302011-05-09 18:39:58 +0000969 int idx = GrGLProgram::ColorAttributeIdx();
junov@google.comf93e7172011-03-31 21:26:24 +0000970 if (oldColorOffset <= 0) {
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000971 GL_CALL(EnableVertexAttribArray(idx));
972 GL_CALL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
junov@google.comf93e7172011-03-31 21:26:24 +0000973 true, newStride, colorOffset));
974 } else if (allOffsetsChange || newColorOffset != oldColorOffset) {
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000975 GL_CALL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
junov@google.comf93e7172011-03-31 21:26:24 +0000976 true, newStride, colorOffset));
977 }
978 } else if (oldColorOffset > 0) {
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000979 GL_CALL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx()));
junov@google.comf93e7172011-03-31 21:26:24 +0000980 }
981
bsalomon@google.coma3108262011-10-10 14:08:47 +0000982 if (newCoverageOffset > 0) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +0000983 GrGLvoid* coverageOffset = (int8_t*)(vertexOffset + newCoverageOffset);
bsalomon@google.coma3108262011-10-10 14:08:47 +0000984 int idx = GrGLProgram::CoverageAttributeIdx();
985 if (oldCoverageOffset <= 0) {
986 GL_CALL(EnableVertexAttribArray(idx));
bsalomon@google.com2401ae82012-01-17 21:03:05 +0000987 GL_CALL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
bsalomon@google.coma3108262011-10-10 14:08:47 +0000988 true, newStride, coverageOffset));
989 } else if (allOffsetsChange || newCoverageOffset != oldCoverageOffset) {
bsalomon@google.com2401ae82012-01-17 21:03:05 +0000990 GL_CALL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
bsalomon@google.coma3108262011-10-10 14:08:47 +0000991 true, newStride, coverageOffset));
992 }
993 } else if (oldCoverageOffset > 0) {
994 GL_CALL(DisableVertexAttribArray(GrGLProgram::CoverageAttributeIdx()));
995 }
996
bsalomon@google.comaeb21602011-08-30 18:13:44 +0000997 if (newEdgeOffset > 0) {
998 GrGLvoid* edgeOffset = (int8_t*)(vertexOffset + newEdgeOffset);
999 int idx = GrGLProgram::EdgeAttributeIdx();
1000 if (oldEdgeOffset <= 0) {
1001 GL_CALL(EnableVertexAttribArray(idx));
1002 GL_CALL(VertexAttribPointer(idx, 4, scalarType,
1003 false, newStride, edgeOffset));
1004 } else if (allOffsetsChange || newEdgeOffset != oldEdgeOffset) {
1005 GL_CALL(VertexAttribPointer(idx, 4, scalarType,
1006 false, newStride, edgeOffset));
1007 }
1008 } else if (oldEdgeOffset > 0) {
1009 GL_CALL(DisableVertexAttribArray(GrGLProgram::EdgeAttributeIdx()));
1010 }
1011
bsalomon@google.come79c8152012-03-29 19:07:12 +00001012 fHWGeometryState.fVertexLayout = currLayout;
junov@google.comf93e7172011-03-31 21:26:24 +00001013 fHWGeometryState.fArrayPtrsDirty = false;
1014}
1015
tomhudson@google.com07eecdc2012-04-20 18:35:38 +00001016namespace {
1017
1018void setup_custom_stage(GrGLProgram::ProgramDesc::StageDesc* stage,
1019 const GrSamplerState& sampler,
1020 GrCustomStage** customStages,
1021 GrGLProgram* program, int index) {
1022 GrCustomStage* customStage = sampler.getCustomStage();
1023 if (customStage) {
tomhudson@google.comd8f856c2012-05-10 12:13:36 +00001024 GrProgramStageFactory* factory = customStage->getFactory();
tomhudson@google.com07eecdc2012-04-20 18:35:38 +00001025 stage->fCustomStageKey = factory->stageKey(customStage);
1026 customStages[index] = customStage;
1027 } else {
1028 stage->fCustomStageKey = 0;
1029 customStages[index] = NULL;
1030 }
1031}
1032
1033}
1034
bsalomon@google.com86c1f712011-10-12 14:54:26 +00001035void GrGpuGLShaders::buildProgram(GrPrimitiveType type,
1036 BlendOptFlags blendOpts,
tomhudson@google.com07eecdc2012-04-20 18:35:38 +00001037 GrBlendCoeff dstCoeff,
1038 GrCustomStage** customStages) {
bsalomon@google.com1e257a52011-07-06 19:52:16 +00001039 ProgramDesc& desc = fCurrentProgram.fProgramDesc;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001040 const GrDrawState& drawState = this->getDrawState();
junov@google.comf93e7172011-03-31 21:26:24 +00001041
bsalomon@google.com86c1f712011-10-12 14:54:26 +00001042 // This should already have been caught
1043 GrAssert(!(kSkipDraw_BlendOptFlag & blendOpts));
1044
1045 bool skipCoverage = SkToBool(blendOpts & kEmitTransBlack_BlendOptFlag);
1046
1047 bool skipColor = SkToBool(blendOpts & (kEmitTransBlack_BlendOptFlag |
1048 kEmitCoverage_BlendOptFlag));
1049
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001050 // The descriptor is used as a cache key. Thus when a field of the
1051 // descriptor will not affect program generation (because of the vertex
1052 // layout in use or other descriptor field settings) it should be set
1053 // to a canonical value to avoid duplicate programs with different keys.
1054
bsalomon@google.com4be283f2011-04-19 21:15:09 +00001055 // Must initialize all fields or cache will have false negatives!
bsalomon@google.come79c8152012-03-29 19:07:12 +00001056 desc.fVertexLayout = this->getVertexLayout();
bsalomon@google.com4be283f2011-04-19 21:15:09 +00001057
1058 desc.fEmitsPointSize = kPoints_PrimitiveType == type;
1059
bsalomon@google.com86c1f712011-10-12 14:54:26 +00001060 bool requiresAttributeColors =
1061 !skipColor && SkToBool(desc.fVertexLayout & kColor_VertexLayoutBit);
bsalomon@google.com2401ae82012-01-17 21:03:05 +00001062 bool requiresAttributeCoverage =
1063 !skipCoverage && SkToBool(desc.fVertexLayout &
1064 kCoverage_VertexLayoutBit);
1065
1066 // fColorInput/fCoverageInput records how colors are specified for the.
1067 // program. So we strip the bits from the layout to avoid false negatives
1068 // when searching for an existing program in the cache.
1069 desc.fVertexLayout &= ~(kColor_VertexLayoutBit | kCoverage_VertexLayoutBit);
bsalomon@google.com4be283f2011-04-19 21:15:09 +00001070
bsalomon@google.com86c1f712011-10-12 14:54:26 +00001071 desc.fColorFilterXfermode = skipColor ?
1072 SkXfermode::kDst_Mode :
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001073 drawState.getColorFilterMode();
bsalomon@google.comf2d91552011-05-16 20:56:06 +00001074
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001075 desc.fColorMatrixEnabled = drawState.isStateFlagEnabled(GrDrawState::kColorMatrix_StateBit);
1076
bsalomon@google.com86c1f712011-10-12 14:54:26 +00001077 // no reason to do edge aa or look at per-vertex coverage if coverage is
1078 // ignored
1079 if (skipCoverage) {
1080 desc.fVertexLayout &= ~(kEdge_VertexLayoutBit |
1081 kCoverage_VertexLayoutBit);
1082 }
1083
1084 bool colorIsTransBlack = SkToBool(blendOpts & kEmitTransBlack_BlendOptFlag);
1085 bool colorIsSolidWhite = (blendOpts & kEmitCoverage_BlendOptFlag) ||
1086 (!requiresAttributeColors &&
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001087 0xffffffff == drawState.getColor());
bsalomon@google.com86c1f712011-10-12 14:54:26 +00001088 if (GR_AGGRESSIVE_SHADER_OPTS && colorIsTransBlack) {
bsalomon@google.com85b505b2011-11-07 14:56:51 +00001089 desc.fColorInput = ProgramDesc::kTransBlack_ColorInput;
bsalomon@google.com86c1f712011-10-12 14:54:26 +00001090 } else if (GR_AGGRESSIVE_SHADER_OPTS && colorIsSolidWhite) {
bsalomon@google.com85b505b2011-11-07 14:56:51 +00001091 desc.fColorInput = ProgramDesc::kSolidWhite_ColorInput;
bsalomon@google.com86c1f712011-10-12 14:54:26 +00001092 } else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresAttributeColors) {
bsalomon@google.com85b505b2011-11-07 14:56:51 +00001093 desc.fColorInput = ProgramDesc::kUniform_ColorInput;
bsalomon@google.com86c1f712011-10-12 14:54:26 +00001094 } else {
bsalomon@google.com85b505b2011-11-07 14:56:51 +00001095 desc.fColorInput = ProgramDesc::kAttribute_ColorInput;
bsalomon@google.com4be283f2011-04-19 21:15:09 +00001096 }
bsalomon@google.com2401ae82012-01-17 21:03:05 +00001097
1098 bool covIsSolidWhite = !requiresAttributeCoverage &&
1099 0xffffffff == drawState.getCoverage();
1100
1101 if (skipCoverage) {
1102 desc.fCoverageInput = ProgramDesc::kTransBlack_ColorInput;
1103 } else if (covIsSolidWhite) {
1104 desc.fCoverageInput = ProgramDesc::kSolidWhite_ColorInput;
1105 } else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresAttributeCoverage) {
1106 desc.fCoverageInput = ProgramDesc::kUniform_ColorInput;
1107 } else {
1108 desc.fCoverageInput = ProgramDesc::kAttribute_ColorInput;
1109 }
junov@google.comf93e7172011-03-31 21:26:24 +00001110
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001111 desc.fEdgeAANumEdges = skipCoverage ? 0 : drawState.getNumAAEdges();
bsalomon@google.com86c1f712011-10-12 14:54:26 +00001112 desc.fEdgeAAConcave = desc.fEdgeAANumEdges > 0 &&
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001113 drawState.isConcaveEdgeAAState();
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +00001114
bsalomon@google.com271cffc2011-05-20 14:13:56 +00001115 int lastEnabledStage = -1;
1116
bsalomon@google.com86c1f712011-10-12 14:54:26 +00001117 if (!skipCoverage && (desc.fVertexLayout &
1118 GrDrawTarget::kEdge_VertexLayoutBit)) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001119 desc.fVertexEdgeType = drawState.getVertexEdgeType();
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001120 } else {
1121 // use canonical value when not set to avoid cache misses
tomhudson@google.com93813632011-10-27 20:21:16 +00001122 desc.fVertexEdgeType = GrDrawState::kHairLine_EdgeType;
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001123 }
1124
bsalomon@google.com88939ae2011-12-14 15:58:11 +00001125 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com1e257a52011-07-06 19:52:16 +00001126 StageDesc& stage = desc.fStages[s];
bsalomon@google.com88939ae2011-12-14 15:58:11 +00001127
1128 stage.fOptFlags = 0;
1129 stage.setEnabled(this->isStageEnabled(s));
1130
1131 bool skip = s < drawState.getFirstCoverageStage() ? skipColor :
1132 skipCoverage;
1133
1134 if (!skip && stage.isEnabled()) {
1135 lastEnabledStage = s;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001136 const GrGLTexture* texture =
1137 static_cast<const GrGLTexture*>(drawState.getTexture(s));
bsalomon@google.com88939ae2011-12-14 15:58:11 +00001138 GrAssert(NULL != texture);
1139 const GrSamplerState& sampler = drawState.getSampler(s);
1140 // we matrix to invert when orientation is TopDown, so make sure
1141 // we aren't in that case before flagging as identity.
1142 if (TextureMatrixIsIdentity(texture, sampler)) {
1143 stage.fOptFlags |= StageDesc::kIdentityMatrix_OptFlagBit;
1144 } else if (!sampler.getMatrix().hasPerspective()) {
1145 stage.fOptFlags |= StageDesc::kNoPerspective_OptFlagBit;
1146 }
1147 switch (sampler.getSampleMode()) {
1148 case GrSamplerState::kNormal_SampleMode:
1149 stage.fCoordMapping = StageDesc::kIdentity_CoordMapping;
1150 break;
1151 case GrSamplerState::kRadial_SampleMode:
1152 stage.fCoordMapping = StageDesc::kRadialGradient_CoordMapping;
1153 break;
1154 case GrSamplerState::kRadial2_SampleMode:
1155 if (sampler.radial2IsDegenerate()) {
1156 stage.fCoordMapping =
1157 StageDesc::kRadial2GradientDegenerate_CoordMapping;
1158 } else {
1159 stage.fCoordMapping =
1160 StageDesc::kRadial2Gradient_CoordMapping;
1161 }
1162 break;
1163 case GrSamplerState::kSweep_SampleMode:
1164 stage.fCoordMapping = StageDesc::kSweepGradient_CoordMapping;
1165 break;
1166 default:
1167 GrCrash("Unexpected sample mode!");
1168 break;
1169 }
1170
1171 switch (sampler.getFilter()) {
1172 // these both can use a regular texture2D()
1173 case GrSamplerState::kNearest_Filter:
1174 case GrSamplerState::kBilinear_Filter:
1175 stage.fFetchMode = StageDesc::kSingle_FetchMode;
1176 break;
1177 // performs 4 texture2D()s
1178 case GrSamplerState::k4x4Downsample_Filter:
1179 stage.fFetchMode = StageDesc::k2x2_FetchMode;
1180 break;
1181 // performs fKernelWidth texture2D()s
1182 case GrSamplerState::kConvolution_Filter:
1183 stage.fFetchMode = StageDesc::kConvolution_FetchMode;
1184 break;
senorblanco@chromium.org05054f12012-03-02 21:05:45 +00001185 case GrSamplerState::kDilate_Filter:
1186 stage.fFetchMode = StageDesc::kDilate_FetchMode;
1187 break;
1188 case GrSamplerState::kErode_Filter:
1189 stage.fFetchMode = StageDesc::kErode_FetchMode;
1190 break;
bsalomon@google.com88939ae2011-12-14 15:58:11 +00001191 default:
1192 GrCrash("Unexpected filter!");
1193 break;
1194 }
1195
1196 if (sampler.hasTextureDomain()) {
1197 GrAssert(GrSamplerState::kClamp_WrapMode ==
1198 sampler.getWrapX() &&
1199 GrSamplerState::kClamp_WrapMode ==
1200 sampler.getWrapY());
1201 stage.fOptFlags |= StageDesc::kCustomTextureDomain_OptFlagBit;
1202 }
1203
1204 stage.fInConfigFlags = 0;
bsalomon@google.comf7fa8062012-02-14 14:09:57 +00001205 if (!this->glCaps().textureSwizzleSupport()) {
bsalomon@google.com88939ae2011-12-14 15:58:11 +00001206 if (GrPixelConfigIsAlphaOnly(texture->config())) {
1207 // if we don't have texture swizzle support then
robertphillips@google.com443e5a52012-04-30 20:01:21 +00001208 // the shader must smear the single channel after
1209 // reading the texture
1210 if (this->glCaps().textureRedSupport()) {
1211 // we can use R8 textures so use kSmearRed
1212 stage.fInConfigFlags |=
1213 StageDesc::kSmearRed_InConfigFlag;
1214 } else {
1215 // we can use A8 textures so use kSmearAlpha
1216 stage.fInConfigFlags |=
1217 StageDesc::kSmearAlpha_InConfigFlag;
1218 }
bsalomon@google.com88939ae2011-12-14 15:58:11 +00001219 } else if (sampler.swapsRAndB()) {
1220 stage.fInConfigFlags |= StageDesc::kSwapRAndB_InConfigFlag;
1221 }
1222 }
1223 if (GrPixelConfigIsUnpremultiplied(texture->config())) {
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001224 // The shader generator assumes that color channels are bytes
1225 // when rounding.
1226 GrAssert(4 == GrBytesPerPixel(texture->config()));
1227 if (kUpOnWrite_DownOnRead_UnpremulConversion ==
1228 fUnpremulConversion) {
1229 stage.fInConfigFlags |=
1230 StageDesc::kMulRGBByAlpha_RoundDown_InConfigFlag;
1231 } else {
1232 stage.fInConfigFlags |=
1233 StageDesc::kMulRGBByAlpha_RoundUp_InConfigFlag;
1234 }
bsalomon@google.com88939ae2011-12-14 15:58:11 +00001235 }
1236
tomhudson@google.comd8f856c2012-05-10 12:13:36 +00001237 if (sampler.getFilter() == GrSamplerState::kDilate_Filter ||
senorblanco@chromium.org05054f12012-03-02 21:05:45 +00001238 sampler.getFilter() == GrSamplerState::kErode_Filter) {
bsalomon@google.com88939ae2011-12-14 15:58:11 +00001239 stage.fKernelWidth = sampler.getKernelWidth();
1240 } else {
1241 stage.fKernelWidth = 0;
1242 }
tomhudson@google.com07eecdc2012-04-20 18:35:38 +00001243
1244 setup_custom_stage(&stage, sampler, customStages,
1245 &fCurrentProgram, s);
1246
junov@google.comf93e7172011-03-31 21:26:24 +00001247 } else {
bsalomon@google.com88939ae2011-12-14 15:58:11 +00001248 stage.fOptFlags = 0;
1249 stage.fCoordMapping = (StageDesc::CoordMapping) 0;
1250 stage.fInConfigFlags = 0;
1251 stage.fFetchMode = (StageDesc::FetchMode) 0;
1252 stage.fKernelWidth = 0;
tomhudson@google.com07eecdc2012-04-20 18:35:38 +00001253 stage.fCustomStageKey = 0;
1254 customStages[s] = NULL;
junov@google.comf93e7172011-03-31 21:26:24 +00001255 }
1256 }
bsalomon@google.com271cffc2011-05-20 14:13:56 +00001257
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001258 if (GrPixelConfigIsUnpremultiplied(drawState.getRenderTarget()->config())) {
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001259 // The shader generator assumes that color channels are bytes
1260 // when rounding.
1261 GrAssert(4 == GrBytesPerPixel(drawState.getRenderTarget()->config()));
1262 if (kUpOnWrite_DownOnRead_UnpremulConversion == fUnpremulConversion) {
1263 desc.fOutputConfig =
1264 ProgramDesc::kUnpremultiplied_RoundUp_OutputConfig;
1265 } else {
1266 desc.fOutputConfig =
1267 ProgramDesc::kUnpremultiplied_RoundDown_OutputConfig;
1268 }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001269 } else {
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001270 desc.fOutputConfig = ProgramDesc::kPremultiplied_OutputConfig;
bsalomon@google.comc4364992011-11-07 15:54:49 +00001271 }
1272
bsalomon@google.com1e257a52011-07-06 19:52:16 +00001273 desc.fDualSrcOutput = ProgramDesc::kNone_DualSrcOutput;
bsalomon@google.comedfe1aa2011-09-29 14:40:26 +00001274
1275 // currently the experimental GS will only work with triangle prims
1276 // (and it doesn't do anything other than pass through values from
1277 // the VS to the FS anyway).
1278#if 0 && GR_GL_EXPERIMENTAL_GS
1279 desc.fExperimentalGS = this->getCaps().fGeometryShaderSupport;
1280#endif
1281
bsalomon@google.coma3108262011-10-10 14:08:47 +00001282 // we want to avoid generating programs with different "first cov stage"
1283 // values when they would compute the same result.
1284 // We set field in the desc to kNumStages when either there are no
1285 // coverage stages or the distinction between coverage and color is
1286 // immaterial.
bsalomon@google.com88939ae2011-12-14 15:58:11 +00001287 int firstCoverageStage = GrDrawState::kNumStages;
tomhudson@google.com93813632011-10-27 20:21:16 +00001288 desc.fFirstCoverageStage = GrDrawState::kNumStages;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001289 bool hasCoverage = drawState.getFirstCoverageStage() <= lastEnabledStage;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001290 if (hasCoverage) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001291 firstCoverageStage = drawState.getFirstCoverageStage();
bsalomon@google.coma3108262011-10-10 14:08:47 +00001292 }
1293
1294 // other coverage inputs
1295 if (!hasCoverage) {
1296 hasCoverage =
1297 desc.fEdgeAANumEdges ||
bsalomon@google.com2401ae82012-01-17 21:03:05 +00001298 requiresAttributeCoverage ||
bsalomon@google.coma3108262011-10-10 14:08:47 +00001299 (desc.fVertexLayout & GrDrawTarget::kEdge_VertexLayoutBit);
1300 }
1301
1302 if (hasCoverage) {
bsalomon@google.com271cffc2011-05-20 14:13:56 +00001303 // color filter is applied between color/coverage computation
1304 if (SkXfermode::kDst_Mode != desc.fColorFilterXfermode) {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001305 desc.fFirstCoverageStage = firstCoverageStage;
bsalomon@google.com271cffc2011-05-20 14:13:56 +00001306 }
1307
bsalomon@google.com86c1f712011-10-12 14:54:26 +00001308 if (this->getCaps().fDualSourceBlendingSupport &&
1309 !(blendOpts & (kEmitCoverage_BlendOptFlag |
1310 kCoverageAsAlpha_BlendOptFlag))) {
1311 if (kZero_BlendCoeff == dstCoeff) {
bsalomon@google.com271cffc2011-05-20 14:13:56 +00001312 // write the coverage value to second color
bsalomon@google.com1e257a52011-07-06 19:52:16 +00001313 desc.fDualSrcOutput = ProgramDesc::kCoverage_DualSrcOutput;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001314 desc.fFirstCoverageStage = firstCoverageStage;
bsalomon@google.com86c1f712011-10-12 14:54:26 +00001315 } else if (kSA_BlendCoeff == dstCoeff) {
bsalomon@google.com271cffc2011-05-20 14:13:56 +00001316 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially
1317 // cover
bsalomon@google.com1e257a52011-07-06 19:52:16 +00001318 desc.fDualSrcOutput = ProgramDesc::kCoverageISA_DualSrcOutput;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001319 desc.fFirstCoverageStage = firstCoverageStage;
bsalomon@google.com86c1f712011-10-12 14:54:26 +00001320 } else if (kSC_BlendCoeff == dstCoeff) {
bsalomon@google.com271cffc2011-05-20 14:13:56 +00001321 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially
1322 // cover
bsalomon@google.com1e257a52011-07-06 19:52:16 +00001323 desc.fDualSrcOutput = ProgramDesc::kCoverageISC_DualSrcOutput;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001324 desc.fFirstCoverageStage = firstCoverageStage;
bsalomon@google.com271cffc2011-05-20 14:13:56 +00001325 }
1326 }
1327 }
junov@google.comf93e7172011-03-31 21:26:24 +00001328}