blob: fb231526629ba1a707da12adfb7d8a8deed836d7 [file] [log] [blame]
reed@google.comac10a2d2010-12-22 21:39:39 +00001/*
2 Copyright 2010 Google Inc.
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17#include "GrGpuGL.h"
18#include "GrMemory.h"
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +000019#if GR_WIN32_BUILD
20 // need to get wglGetProcAddress
21 #undef WIN32_LEAN_AND_MEAN
22 #define WIN32_LEAN_AND_MEAN 1
23 #include <windows.h>
24 #undef WIN32_LEAN_AND_MEAN
25#endif
26
reed@google.comac10a2d2010-12-22 21:39:39 +000027
28static const GLuint GR_MAX_GLUINT = ~0;
29static const GLint GR_INVAL_GLINT = ~0;
30
bsalomon@google.com316f99232011-01-13 21:28:12 +000031// we use a spare texture unit to avoid
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000032// mucking with the state of any of the stages.
bsalomon@google.com316f99232011-01-13 21:28:12 +000033static const int SPARE_TEX_UNIT = GrGpuGL::kNumStages;
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000034
reed@google.comac10a2d2010-12-22 21:39:39 +000035#define SKIP_CACHE_CHECK true
36
37static const GLenum gXfermodeCoeff2Blend[] = {
38 GL_ZERO,
39 GL_ONE,
40 GL_SRC_COLOR,
41 GL_ONE_MINUS_SRC_COLOR,
42 GL_DST_COLOR,
43 GL_ONE_MINUS_DST_COLOR,
44 GL_SRC_ALPHA,
45 GL_ONE_MINUS_SRC_ALPHA,
46 GL_DST_ALPHA,
47 GL_ONE_MINUS_DST_ALPHA,
48};
49
reed@google.comac10a2d2010-12-22 21:39:39 +000050
reed@google.comac10a2d2010-12-22 21:39:39 +000051
reed@google.comac10a2d2010-12-22 21:39:39 +000052///////////////////////////////////////////////////////////////////////////////
53
bsalomon@google.com42ab7ea2011-01-19 17:19:40 +000054static bool gPrintStartupSpew;
55
56
reed@google.comac10a2d2010-12-22 21:39:39 +000057bool fbo_test(GrGLExts exts, int w, int h) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000058
59 GLint savedFBO;
60 GLint savedTexUnit;
reed@google.com3d8de042011-01-20 02:18:00 +000061 GR_GL_GetIntegerv(GL_ACTIVE_TEXTURE, &savedTexUnit);
62 GR_GL_GetIntegerv(GR_FRAMEBUFFER_BINDING, &savedFBO);
bsalomon@google.com316f99232011-01-13 21:28:12 +000063
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000064 GR_GL(ActiveTexture(GL_TEXTURE0 + SPARE_TEX_UNIT));
bsalomon@google.com316f99232011-01-13 21:28:12 +000065
reed@google.comac10a2d2010-12-22 21:39:39 +000066 GLuint testFBO;
67 GR_GLEXT(exts, GenFramebuffers(1, &testFBO));
68 GR_GLEXT(exts, BindFramebuffer(GR_FRAMEBUFFER, testFBO));
69 GLuint testRTTex;
70 GR_GL(GenTextures(1, &testRTTex));
71 GR_GL(BindTexture(GL_TEXTURE_2D, testRTTex));
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +000072 // some implementations require texture to be mip-map complete before
73 // FBO with level 0 bound as color attachment will be framebuffer complete.
74 GR_GL(TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
reed@google.comac10a2d2010-12-22 21:39:39 +000075 GR_GL(TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h,
76 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL));
77 GR_GL(BindTexture(GL_TEXTURE_2D, 0));
78 GR_GLEXT(exts, FramebufferTexture2D(GR_FRAMEBUFFER, GR_COLOR_ATTACHMENT0,
79 GL_TEXTURE_2D, testRTTex, 0));
80 GLenum status = GR_GLEXT(exts, CheckFramebufferStatus(GR_FRAMEBUFFER));
81 GR_GLEXT(exts, DeleteFramebuffers(1, &testFBO));
82 GR_GL(DeleteTextures(1, &testRTTex));
bsalomon@google.com316f99232011-01-13 21:28:12 +000083
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000084 GR_GL(ActiveTexture(savedTexUnit));
85 GR_GLEXT(exts, BindFramebuffer(GR_FRAMEBUFFER, savedFBO));
bsalomon@google.com316f99232011-01-13 21:28:12 +000086
reed@google.comac10a2d2010-12-22 21:39:39 +000087 return status == GR_FRAMEBUFFER_COMPLETE;
88}
89
reed@google.comac10a2d2010-12-22 21:39:39 +000090GrGpuGL::GrGpuGL() {
reed@google.comeeeb5a02010-12-23 15:12:59 +000091 if (gPrintStartupSpew) {
92 GrPrintf("------------------------- create GrGpuGL %p --------------\n",
93 this);
94 GrPrintf("------ VENDOR %s\n", glGetString(GL_VENDOR));
95 GrPrintf("------ RENDERER %s\n", glGetString(GL_RENDERER));
96 GrPrintf("------ VERSION %s\n", glGetString(GL_VERSION));
97 GrPrintf("------ EXTENSIONS\n %s \n", glGetString(GL_EXTENSIONS));
98 }
reed@google.comac10a2d2010-12-22 21:39:39 +000099
100 GrGLClearErr();
101
102 GrGLInitExtensions(&fExts);
103
104 resetContextHelper();
105
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000106 fHWDrawState.fRenderTarget = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +0000107 fRenderTargetChanged = true;
bsalomon@google.com316f99232011-01-13 21:28:12 +0000108
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000109 GLint maxTextureUnits;
110 // check FS and fixed-function texture unit limits
111 // we only use textures in the fragment stage currently.
112 // checks are > to make sure we have a spare unit.
113#if GR_SUPPORT_GLDESKTOP || GR_SUPPORT_GLES2
reed@google.com3d8de042011-01-20 02:18:00 +0000114 GR_GL_GetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000115 GrAssert(maxTextureUnits > kNumStages);
116#endif
117#if GR_SUPPORT_GLDESKTOP || GR_SUPPORT_GLES1
reed@google.com3d8de042011-01-20 02:18:00 +0000118 GR_GL_GetIntegerv(GL_MAX_TEXTURE_UNITS, &maxTextureUnits);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000119 GrAssert(maxTextureUnits > kNumStages);
120#endif
bsalomon@google.com316f99232011-01-13 21:28:12 +0000121
reed@google.comac10a2d2010-12-22 21:39:39 +0000122 fCurrDrawState = fHWDrawState;
123
124 ////////////////////////////////////////////////////////////////////////////
125 // Check for supported features.
126
127 int major, minor;
128 gl_version(&major, &minor);
129
130 GLint numFormats;
reed@google.comac20fb92011-01-12 17:14:53 +0000131 GR_GL_GetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &numFormats);
reed@google.comac10a2d2010-12-22 21:39:39 +0000132 GrAutoSTMalloc<10, GLint> formats(numFormats);
reed@google.comac20fb92011-01-12 17:14:53 +0000133 GR_GL_GetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, formats);
reed@google.comac10a2d2010-12-22 21:39:39 +0000134 for (int i = 0; i < numFormats; ++i) {
135 if (formats[i] == GR_PALETTE8_RGBA8) {
136 f8bitPaletteSupport = true;
137 break;
138 }
139 }
reed@google.comeeeb5a02010-12-23 15:12:59 +0000140
141 if (gPrintStartupSpew) {
142 GrPrintf("Palette8 support: %s\n", (f8bitPaletteSupport ? "YES" : "NO"));
143 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000144
145 GR_STATIC_ASSERT(0 == kNone_AALevel);
146 GR_STATIC_ASSERT(1 == kLow_AALevel);
147 GR_STATIC_ASSERT(2 == kMed_AALevel);
148 GR_STATIC_ASSERT(3 == kHigh_AALevel);
149
150 memset(fAASamples, 0, sizeof(fAASamples));
151 fMSFBOType = kNone_MSFBO;
152 if (has_gl_extension("GL_IMG_multisampled_render_to_texture")) {
153 fMSFBOType = kIMG_MSFBO;
reed@google.comeeeb5a02010-12-23 15:12:59 +0000154 if (gPrintStartupSpew) {
155 GrPrintf("MSAA Support: IMG ES EXT.\n");
156 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000157 }
158 else if (has_gl_extension("GL_APPLE_framebuffer_multisample")) {
159 fMSFBOType = kApple_MSFBO;
reed@google.comeeeb5a02010-12-23 15:12:59 +0000160 if (gPrintStartupSpew) {
161 GrPrintf("MSAA Support: APPLE ES EXT.\n");
162 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000163 }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000164#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000165 else if ((major >= 3) ||
166 has_gl_extension("GL_ARB_framebuffer_object") ||
167 (has_gl_extension("GL_EXT_framebuffer_multisample") &&
168 has_gl_extension("GL_EXT_framebuffer_blit"))) {
169 fMSFBOType = kDesktop_MSFBO;
reed@google.comeeeb5a02010-12-23 15:12:59 +0000170 if (gPrintStartupSpew) {
171 GrPrintf("MSAA Support: DESKTOP\n");
172 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000173 }
174#endif
175 else {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000176 if (gPrintStartupSpew) {
177 GrPrintf("MSAA Support: NONE\n");
178 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000179 }
180
181 if (kNone_MSFBO != fMSFBOType) {
182 GLint maxSamples;
183 GLenum maxSampleGetter = (kIMG_MSFBO == fMSFBOType) ?
184 GR_MAX_SAMPLES_IMG :
185 GR_MAX_SAMPLES;
reed@google.comac20fb92011-01-12 17:14:53 +0000186 GR_GL_GetIntegerv(maxSampleGetter, &maxSamples);
reed@google.comac10a2d2010-12-22 21:39:39 +0000187 if (maxSamples > 1 ) {
188 fAASamples[kNone_AALevel] = 0;
189 fAASamples[kLow_AALevel] = GrMax(2,
190 GrFixedFloorToInt((GR_FixedHalf) *
191 maxSamples));
192 fAASamples[kMed_AALevel] = GrMax(2,
193 GrFixedFloorToInt(((GR_Fixed1*3)/4) *
194 maxSamples));
195 fAASamples[kHigh_AALevel] = maxSamples;
196 }
reed@google.comeeeb5a02010-12-23 15:12:59 +0000197 if (gPrintStartupSpew) {
198 GrPrintf("\tMax Samples: %d\n", maxSamples);
199 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000200 }
201
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000202#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000203 fHasStencilWrap = (major >= 2 || (major == 1 && minor >= 4)) ||
204 has_gl_extension("GL_EXT_stencil_wrap");
205#else
206 fHasStencilWrap = (major >= 2) || has_gl_extension("GL_OES_stencil_wrap");
207#endif
reed@google.comeeeb5a02010-12-23 15:12:59 +0000208 if (gPrintStartupSpew) {
209 GrPrintf("Stencil Wrap: %s\n", (fHasStencilWrap ? "YES" : "NO"));
210 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000211
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000212#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000213 // we could also look for GL_ATI_separate_stencil extension or
214 // GL_EXT_stencil_two_side but they use different function signatures
215 // than GL2.0+ (and than each other).
216 fSingleStencilPassForWinding = (major >= 2);
217#else
218 // ES 2 has two sided stencil but 1.1 doesn't. There doesn't seem to be
219 // an ES1 extension.
220 fSingleStencilPassForWinding = (major >= 2);
221#endif
reed@google.comeeeb5a02010-12-23 15:12:59 +0000222 if (gPrintStartupSpew) {
223 GrPrintf("Single Stencil Pass For Winding: %s\n", (fSingleStencilPassForWinding ? "YES" : "NO"));
224 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000225
226
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000227#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000228 fRGBA8Renderbuffer = true;
229#else
230 fRGBA8Renderbuffer = has_gl_extension("GL_OES_rgb8_rgba8");
231#endif
reed@google.comeeeb5a02010-12-23 15:12:59 +0000232 if (gPrintStartupSpew) {
233 GrPrintf("RGBA Renderbuffer: %s\n", (fRGBA8Renderbuffer ? "YES" : "NO"));
234 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000235
bsalomon@google.comed3a0682011-01-18 16:54:04 +0000236#if GR_SUPPORT_GLES
237 if (GR_GL_32BPP_COLOR_FORMAT == GR_BGRA) {
238 GrAssert(has_gl_extension("GL_EXT_texture_format_BGRA8888"));
239 }
240#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000241
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000242#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000243 fBufferLockSupport = true; // we require VBO support and the desktop VBO
244 // extension includes glMapBuffer.
245#else
246 fBufferLockSupport = has_gl_extension("GL_OES_mapbuffer");
247#endif
reed@google.comeeeb5a02010-12-23 15:12:59 +0000248 if (gPrintStartupSpew) {
249 GrPrintf("Map Buffer: %s\n", (fBufferLockSupport ? "YES" : "NO"));
250 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000251
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000252#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000253 fNPOTTextureSupport =
254 (major >= 2 || has_gl_extension("GL_ARB_texture_non_power_of_two")) ?
255 kFull_NPOTTextureType :
256 kNone_NPOTTextureType;
257#else
258 if (has_gl_extension("GL_OES_texture_npot")) {
259 fNPOTTextureSupport = kFull_NPOTTextureType;
260 } else if (major >= 2 ||
261 has_gl_extension("GL_APPLE_texture_2D_limited_npot")) {
262 fNPOTTextureSupport = kNoRepeat_NPOTTextureType;
263 } else {
264 fNPOTTextureSupport = kNone_NPOTTextureType;
265 }
266#endif
267 ////////////////////////////////////////////////////////////////////////////
268 // Experiments to determine limitations that can't be queried. TODO: Make
269 // these a preprocess that generate some compile time constants.
270
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000271 // sanity check to make sure we can at least create an FBO from a POT texture
272 if (fNPOTTextureSupport < kFull_NPOTTextureType) {
273 bool npotFBOSuccess = fbo_test(fExts, 128, 128);
274 if (gPrintStartupSpew) {
275 if (!npotFBOSuccess) {
276 GrPrintf("FBO Sanity Test: FAILED\n");
277 } else {
278 GrPrintf("FBO Sanity Test: PASSED\n");
279 }
280 }
281 }
reed@google.comac20fb92011-01-12 17:14:53 +0000282
reed@google.comac10a2d2010-12-22 21:39:39 +0000283 /* Experimentation has found that some GLs that support NPOT textures
284 do not support FBOs with a NPOT texture. They report "unsupported" FBO
285 status. I don't know how to explicitly query for this. Do an
286 experiment. Note they may support NPOT with a renderbuffer but not a
287 texture. Presumably, the implementation bloats the renderbuffer
288 internally to the next POT.
289 */
290 if (fNPOTTextureSupport == kFull_NPOTTextureType) {
291 bool npotFBOSuccess = fbo_test(fExts, 200, 200);
292 if (!npotFBOSuccess) {
293 fNPOTTextureSupport = kNonRendertarget_NPOTTextureType;
reed@google.comeeeb5a02010-12-23 15:12:59 +0000294 if (gPrintStartupSpew) {
295 GrPrintf("NPOT Renderbuffer Test: FAILED\n");
296 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000297 } else {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000298 if (gPrintStartupSpew) {
299 GrPrintf("NPOT Renderbuffer Test: PASSED\n");
300 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000301 }
302 }
reed@google.comeeeb5a02010-12-23 15:12:59 +0000303
304 if (gPrintStartupSpew) {
305 switch (fNPOTTextureSupport) {
306 case kNone_NPOTTextureType:
307 GrPrintf("NPOT Support: NONE\n");
308 break;
309 case kNoRepeat_NPOTTextureType:
310 GrPrintf("NPOT Support: NO REPEAT\n");
311 break;
312 case kNonRendertarget_NPOTTextureType:
313 GrPrintf("NPOT Support: NO FBOTEX\n");
314 break;
315 case kFull_NPOTTextureType:
316 GrPrintf("NPOT Support: FULL\n");
317 break;
318 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000319 }
320
reed@google.comac10a2d2010-12-22 21:39:39 +0000321 /* The iPhone 4 has a restriction that for an FBO with texture color
322 attachment with height <= 8 then the width must be <= height. Here
323 we look for such a limitation.
324 */
325 fMinRenderTargetHeight = GR_INVAL_GLINT;
326 GLint maxRenderSize;
reed@google.comac20fb92011-01-12 17:14:53 +0000327 GR_GL_GetIntegerv(GR_MAX_RENDERBUFFER_SIZE, &maxRenderSize);
reed@google.comac10a2d2010-12-22 21:39:39 +0000328
reed@google.comeeeb5a02010-12-23 15:12:59 +0000329 if (gPrintStartupSpew) {
330 GrPrintf("Small height FBO texture experiments\n");
331 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000332 for (GLuint i = 1; i <= 256;
333 (kFull_NPOTTextureType != fNPOTTextureSupport) ? i *= 2 : ++i) {
334 GLuint w = maxRenderSize;
335 GLuint h = i;
336 if (fbo_test(fExts, w, h)) {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000337 if (gPrintStartupSpew) {
338 GrPrintf("\t[%d, %d]: PASSED\n", w, h);
339 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000340 fMinRenderTargetHeight = i;
341 break;
342 } else {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000343 if (gPrintStartupSpew) {
344 GrPrintf("\t[%d, %d]: FAILED\n", w, h);
345 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000346 }
347 }
348 GrAssert(GR_INVAL_GLINT != fMinRenderTargetHeight);
349
reed@google.comeeeb5a02010-12-23 15:12:59 +0000350 if (gPrintStartupSpew) {
351 GrPrintf("Small width FBO texture experiments\n");
352 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000353 fMinRenderTargetWidth = GR_MAX_GLUINT;
354 for (GLuint i = 1; i <= 256;
355 (kFull_NPOTTextureType != fNPOTTextureSupport) ? i *= 2 : ++i) {
356 GLuint w = i;
357 GLuint h = maxRenderSize;
358 if (fbo_test(fExts, w, h)) {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000359 if (gPrintStartupSpew) {
360 GrPrintf("\t[%d, %d]: PASSED\n", w, h);
361 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000362 fMinRenderTargetWidth = i;
363 break;
364 } else {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000365 if (gPrintStartupSpew) {
366 GrPrintf("\t[%d, %d]: FAILED\n", w, h);
367 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000368 }
369 }
370 GrAssert(GR_INVAL_GLINT != fMinRenderTargetWidth);
371
372#if GR_IOS_BUILD
373 /*
374 The iPad seems to fail, at least sometimes, if the height is < 16,
375 so we pin the values here for now. A better fix might be to
376 conditionalize this based on known that its an iPad (or some other
377 check).
378 */
379 fMinRenderTargetWidth = GrMax<GLuint>(fMinRenderTargetWidth, 16);
380 fMinRenderTargetHeight = GrMax<GLuint>(fMinRenderTargetHeight, 16);
381#endif
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000382
reed@google.com02a7e6c2011-01-28 21:21:49 +0000383 GR_GL_GetIntegerv(GL_MAX_TEXTURE_SIZE, &fMaxTextureDimension);
384
reed@google.comac10a2d2010-12-22 21:39:39 +0000385#if GR_COLLECT_STATS
386 ++fStats.fRenderTargetChngCnt;
387#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000388}
389
390GrGpuGL::~GrGpuGL() {
reed@google.comac10a2d2010-12-22 21:39:39 +0000391}
392
393void GrGpuGL::resetContextHelper() {
394// We detect cases when blending is effectively off
395 fHWBlendDisabled = false;
396 GR_GL(Enable(GL_BLEND));
397
398 // this is always disabled
399 GR_GL(Disable(GL_CULL_FACE));
400
401 GR_GL(Disable(GL_DITHER));
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000402#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000403 GR_GL(Disable(GL_LINE_SMOOTH));
404 GR_GL(Disable(GL_POINT_SMOOTH));
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000405 GR_GL(Disable(GL_MULTISAMPLE));
reed@google.comac10a2d2010-12-22 21:39:39 +0000406#endif
407
408 // we only ever use lines in hairline mode
409 GR_GL(LineWidth(1));
410
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000411 // invalid
412 fActiveTextureUnitIdx = -1;
reed@google.comac10a2d2010-12-22 21:39:39 +0000413
414 fHWDrawState.fFlagBits = 0;
415
416 // illegal values
417 fHWDrawState.fSrcBlend = (BlendCoeff)-1;
418 fHWDrawState.fDstBlend = (BlendCoeff)-1;
419 fHWDrawState.fColor = GrColor_ILLEGAL;
bsalomon@google.com316f99232011-01-13 21:28:12 +0000420
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000421 fHWDrawState.fViewMatrix.setScale(GR_ScalarMax, GR_ScalarMax); // illegal
bsalomon@google.com316f99232011-01-13 21:28:12 +0000422
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000423 for (int s = 0; s < kNumStages; ++s) {
424 fHWDrawState.fTextures[s] = NULL;
425 fHWDrawState.fSamplerStates[s].setRadial2Params(-GR_ScalarMax,
426 -GR_ScalarMax,
427 true);
bsalomon@google.com316f99232011-01-13 21:28:12 +0000428 fHWDrawState.fTextureMatrices[s].setScale(GR_ScalarMax, GR_ScalarMax);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000429 }
bsalomon@google.com316f99232011-01-13 21:28:12 +0000430
reed@google.comac10a2d2010-12-22 21:39:39 +0000431 GR_GL(Scissor(0,0,0,0));
432 fHWBounds.fScissorRect.setLTRB(0,0,0,0);
433 fHWBounds.fScissorEnabled = false;
434 GR_GL(Disable(GL_SCISSOR_TEST));
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000435 fHWBounds.fViewportRect.setLTRB(-1,-1,-1,-1);
reed@google.comac10a2d2010-12-22 21:39:39 +0000436
reed@google.comac10a2d2010-12-22 21:39:39 +0000437 // disabling the stencil test also disables
438 // stencil buffer writes
439 GR_GL(Disable(GL_STENCIL_TEST));
440 GR_GL(StencilMask(0xffffffff));
441 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
442 fHWDrawState.fReverseFill = false;
443 fHWDrawState.fStencilPass = kNone_StencilPass;
444 fHWStencilClip = false;
445
446 fHWGeometryState.fIndexBuffer = NULL;
447 fHWGeometryState.fVertexBuffer = NULL;
448 GR_GL(BindBuffer(GL_ARRAY_BUFFER, 0));
449 GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
450
451 fHWDrawState.fRenderTarget = NULL;
452}
453
454void GrGpuGL::resetContext() {
455 INHERITED::resetContext();
456 resetContextHelper();
457}
458
reed@google.comac10a2d2010-12-22 21:39:39 +0000459GrRenderTarget* GrGpuGL::createPlatformRenderTarget(
460 intptr_t platformRenderTarget,
461 int width, int height) {
462 GrGLRenderTarget::GLRenderTargetIDs rtIDs;
463 rtIDs.fStencilRenderbufferID = 0;
464 rtIDs.fMSColorRenderbufferID = 0;
465 rtIDs.fTexFBOID = 0;
466 rtIDs.fOwnIDs = false;
467
468 GrIRect viewport;
469
470 // viewport is in GL coords (top >= bottom)
471 viewport.setLTRB(0, height, width, 0);
472
473 rtIDs.fRTFBOID = (GLuint)platformRenderTarget;
474 rtIDs.fTexFBOID = (GLuint)platformRenderTarget;
475
476 GrGLRenderTarget* rt = new GrGLRenderTarget(rtIDs, viewport, NULL, this);
477
478 return rt;
479}
480
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000481GrRenderTarget* GrGpuGL::createRenderTargetFrom3DApiState() {
bsalomon@google.com42ab7ea2011-01-19 17:19:40 +0000482
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000483 GrGLRenderTarget::GLRenderTargetIDs rtIDs;
bsalomon@google.com42ab7ea2011-01-19 17:19:40 +0000484
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000485 GR_GL_GetIntegerv(GR_FRAMEBUFFER_BINDING, (GLint*)&rtIDs.fRTFBOID);
486 rtIDs.fTexFBOID = rtIDs.fRTFBOID;
487 rtIDs.fMSColorRenderbufferID = 0;
488 rtIDs.fStencilRenderbufferID = 0;
bsalomon@google.com42ab7ea2011-01-19 17:19:40 +0000489
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000490 GLint vp[4];
491 GR_GL_GetIntegerv(GL_VIEWPORT, vp);
492 GrIRect viewportRect;
493 viewportRect.setLTRB(vp[0],
494 vp[1] + vp[3],
495 vp[0] + vp[2],
496 vp[1]);
497 rtIDs.fOwnIDs = false;
498
499 return new GrGLRenderTarget(rtIDs,
500 viewportRect,
501 NULL,
502 this);
503}
504
bsalomon@google.com5782d712011-01-21 21:03:59 +0000505///////////////////////////////////////////////////////////////////////////////
506
bsalomon@google.com3f3ffd62011-01-18 17:14:52 +0000507// defines stencil formats from more to less preferred
reed@google.com63100f92011-01-18 21:32:14 +0000508GLenum GR_GL_STENCIL_FORMAT_ARRAY[] = {
509 GR_STENCIL_INDEX8,
510
511#if GR_SUPPORT_GLDESKTOP
512 GR_STENCIL_INDEX16,
513#endif
514
515 GR_DEPTH24_STENCIL8,
516 GR_STENCIL_INDEX4,
517
518#if GR_SUPPORT_GLDESKTOP
bsalomon@google.com3f3ffd62011-01-18 17:14:52 +0000519 GL_STENCIL_INDEX,
520 GR_DEPTH_STENCIL,
521#endif
522};
523
524// good to set a break-point here to know when createTexture fails
525static GrTexture* return_null_texture() {
526// GrAssert(!"null texture");
527 return NULL;
528}
529
530#if GR_DEBUG
531static size_t as_size_t(int x) {
532 return x;
533}
534#endif
535
reed@google.comac10a2d2010-12-22 21:39:39 +0000536GrTexture* GrGpuGL::createTexture(const TextureDesc& desc,
537 const void* srcData, size_t rowBytes) {
538
539#if GR_COLLECT_STATS
540 ++fStats.fTextureCreateCnt;
541#endif
reed@google.com1fcd51e2011-01-05 15:50:27 +0000542
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000543 setSpareTextureUnit();
bsalomon@google.com316f99232011-01-13 21:28:12 +0000544
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000545 static const GrGLTexture::TexParams DEFAULT_PARAMS = {
546 GL_NEAREST,
547 GL_CLAMP_TO_EDGE,
548 GL_CLAMP_TO_EDGE
549 };
reed@google.com1fcd51e2011-01-05 15:50:27 +0000550
reed@google.comac10a2d2010-12-22 21:39:39 +0000551 GrGLTexture::GLTextureDesc glDesc;
552 GLenum internalFormat;
553
554 glDesc.fContentWidth = desc.fWidth;
555 glDesc.fContentHeight = desc.fHeight;
556 glDesc.fAllocWidth = desc.fWidth;
557 glDesc.fAllocHeight = desc.fHeight;
558 glDesc.fFormat = desc.fFormat;
559
560 bool renderTarget = 0 != (desc.fFlags & kRenderTarget_TextureFlag);
561 if (!canBeTexture(desc.fFormat,
562 &internalFormat,
563 &glDesc.fUploadFormat,
564 &glDesc.fUploadType)) {
565 return return_null_texture();
566 }
567
568 GrAssert(as_size_t(desc.fAALevel) < GR_ARRAY_COUNT(fAASamples));
569 GLint samples = fAASamples[desc.fAALevel];
570 if (kNone_MSFBO == fMSFBOType && desc.fAALevel != kNone_AALevel) {
571 GrPrintf("AA RT requested but not supported on this platform.");
572 }
573
574 GR_GL(GenTextures(1, &glDesc.fTextureID));
575 if (!glDesc.fTextureID) {
576 return return_null_texture();
577 }
578
579 glDesc.fUploadByteCount = GrTexture::BytesPerPixel(desc.fFormat);
580
581 /*
582 * check if our srcData has extra bytes past each row. If so, we need
583 * to trim those off here, since GL doesn't let us pass the rowBytes as
584 * a parameter to glTexImage2D
585 */
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000586#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000587 if (srcData) {
588 GR_GL(PixelStorei(GL_UNPACK_ROW_LENGTH,
589 rowBytes / glDesc.fUploadByteCount));
590 }
591#else
592 GrAutoSMalloc<128 * 128> trimStorage;
593 size_t trimRowBytes = desc.fWidth * glDesc.fUploadByteCount;
594 if (srcData && (trimRowBytes < rowBytes)) {
595 size_t trimSize = desc.fHeight * trimRowBytes;
596 trimStorage.realloc(trimSize);
597 // now copy the data into our new storage, skipping the trailing bytes
598 const char* src = (const char*)srcData;
599 char* dst = (char*)trimStorage.get();
600 for (uint32_t y = 0; y < desc.fHeight; y++) {
601 memcpy(dst, src, trimRowBytes);
602 src += rowBytes;
603 dst += trimRowBytes;
604 }
605 // now point srcData to our trimmed version
606 srcData = trimStorage.get();
607 }
608#endif
609
610 if (fNPOTTextureSupport < kNonRendertarget_NPOTTextureType ||
611 (fNPOTTextureSupport == kNonRendertarget_NPOTTextureType &&
612 renderTarget)) {
613 glDesc.fAllocWidth = GrNextPow2(desc.fWidth);
614 glDesc.fAllocHeight = GrNextPow2(desc.fHeight);
615 }
616
617 if (renderTarget) {
618 glDesc.fAllocWidth = GrMax<int>(fMinRenderTargetWidth,
619 glDesc.fAllocWidth);
620 glDesc.fAllocHeight = GrMax<int>(fMinRenderTargetHeight,
621 glDesc.fAllocHeight);
622 }
623
624 GR_GL(BindTexture(GL_TEXTURE_2D, glDesc.fTextureID));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000625 GR_GL(TexParameteri(GL_TEXTURE_2D,
626 GL_TEXTURE_MAG_FILTER,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000627 DEFAULT_PARAMS.fFilter));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000628 GR_GL(TexParameteri(GL_TEXTURE_2D,
629 GL_TEXTURE_MIN_FILTER,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000630 DEFAULT_PARAMS.fFilter));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000631 GR_GL(TexParameteri(GL_TEXTURE_2D,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000632 GL_TEXTURE_WRAP_S,
633 DEFAULT_PARAMS.fWrapS));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000634 GR_GL(TexParameteri(GL_TEXTURE_2D,
635 GL_TEXTURE_WRAP_T,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000636 DEFAULT_PARAMS.fWrapT));
reed@google.comac10a2d2010-12-22 21:39:39 +0000637
638 GR_GL(PixelStorei(GL_UNPACK_ALIGNMENT, glDesc.fUploadByteCount));
639 if (GrTexture::kIndex_8_PixelConfig == desc.fFormat &&
640 supports8BitPalette()) {
641 // ES only supports CompressedTexImage2D, not CompressedTexSubimage2D
642 GrAssert(desc.fWidth == glDesc.fAllocWidth);
643 GrAssert(desc.fHeight == glDesc.fAllocHeight);
644 GLsizei imageSize = glDesc.fAllocWidth * glDesc.fAllocHeight +
645 kColorTableSize;
646 GR_GL(CompressedTexImage2D(GL_TEXTURE_2D, 0, glDesc.fUploadFormat,
647 glDesc.fAllocWidth, glDesc.fAllocHeight,
648 0, imageSize, srcData));
649 GrGL_RestoreResetRowLength();
650 } else {
651 if (NULL != srcData && (glDesc.fAllocWidth != desc.fWidth ||
652 glDesc.fAllocHeight != desc.fHeight)) {
653 GR_GL(TexImage2D(GL_TEXTURE_2D, 0, internalFormat,
654 glDesc.fAllocWidth, glDesc.fAllocHeight,
655 0, glDesc.fUploadFormat, glDesc.fUploadType, NULL));
656 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, desc.fWidth,
657 desc.fHeight, glDesc.fUploadFormat,
658 glDesc.fUploadType, srcData));
659 GrGL_RestoreResetRowLength();
660
661 uint32_t extraW = glDesc.fAllocWidth - desc.fWidth;
662 uint32_t extraH = glDesc.fAllocHeight - desc.fHeight;
663 uint32_t maxTexels = extraW * extraH;
664 maxTexels = GrMax(extraW * desc.fHeight, maxTexels);
665 maxTexels = GrMax(desc.fWidth * extraH, maxTexels);
666
667 GrAutoSMalloc<128*128> texels(glDesc.fUploadByteCount * maxTexels);
668
669 uint32_t rowSize = desc.fWidth * glDesc.fUploadByteCount;
670 if (extraH) {
671 uint8_t* lastRowStart = (uint8_t*) srcData +
672 (desc.fHeight - 1) * rowSize;
673 uint8_t* extraRowStart = (uint8_t*)texels.get();
674
675 for (uint32_t i = 0; i < extraH; ++i) {
676 memcpy(extraRowStart, lastRowStart, rowSize);
677 extraRowStart += rowSize;
678 }
679 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, 0, desc.fHeight, desc.fWidth,
680 extraH, glDesc.fUploadFormat, glDesc.fUploadType,
681 texels.get()));
682 }
683 if (extraW) {
684 uint8_t* edgeTexel = (uint8_t*)srcData + rowSize - glDesc.fUploadByteCount;
685 uint8_t* extraTexel = (uint8_t*)texels.get();
686 for (uint32_t j = 0; j < desc.fHeight; ++j) {
687 for (uint32_t i = 0; i < extraW; ++i) {
688 memcpy(extraTexel, edgeTexel, glDesc.fUploadByteCount);
689 extraTexel += glDesc.fUploadByteCount;
690 }
691 edgeTexel += rowSize;
692 }
693 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, desc.fWidth, 0, extraW,
694 desc.fHeight, glDesc.fUploadFormat,
695 glDesc.fUploadType, texels.get()));
696 }
697 if (extraW && extraH) {
698 uint8_t* cornerTexel = (uint8_t*)srcData + desc.fHeight * rowSize
699 - glDesc.fUploadByteCount;
700 uint8_t* extraTexel = (uint8_t*)texels.get();
701 for (uint32_t i = 0; i < extraW*extraH; ++i) {
702 memcpy(extraTexel, cornerTexel, glDesc.fUploadByteCount);
703 extraTexel += glDesc.fUploadByteCount;
704 }
705 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, desc.fWidth, desc.fHeight,
706 extraW, extraH, glDesc.fUploadFormat,
707 glDesc.fUploadType, texels.get()));
708 }
709
710 } else {
711 GR_GL(TexImage2D(GL_TEXTURE_2D, 0, internalFormat, glDesc.fAllocWidth,
712 glDesc.fAllocHeight, 0, glDesc.fUploadFormat,
713 glDesc.fUploadType, srcData));
714 GrGL_RestoreResetRowLength();
715 }
716 }
717
718 glDesc.fOrientation = GrGLTexture::kTopDown_Orientation;
719
720 GrGLRenderTarget::GLRenderTargetIDs rtIDs;
721 rtIDs.fStencilRenderbufferID = 0;
722 rtIDs.fMSColorRenderbufferID = 0;
723 rtIDs.fRTFBOID = 0;
724 rtIDs.fTexFBOID = 0;
725 rtIDs.fOwnIDs = true;
726 GLenum msColorRenderbufferFormat = -1;
727
728 if (renderTarget) {
729#if GR_COLLECT_STATS
730 ++fStats.fRenderTargetCreateCnt;
731#endif
732 bool failed = true;
733 GLenum status;
734 GLint err;
735
736 // If need have both RT flag and srcData we have
737 // to invert the data before uploading because FBO
738 // will be rendered bottom up
739 GrAssert(NULL == srcData);
740 glDesc.fOrientation = GrGLTexture::kBottomUp_Orientation;
741
742 GR_GLEXT(fExts, GenFramebuffers(1, &rtIDs.fTexFBOID));
743 GrAssert(rtIDs.fTexFBOID);
744
745 // If we are using multisampling and any extension other than the IMG
746 // one we will create two FBOs. We render to one and then resolve to
747 // the texture bound to the other. The IMG extension does an implicit
748 // resolve.
749 if (samples > 1 && kIMG_MSFBO != fMSFBOType && kNone_MSFBO != fMSFBOType) {
750 GR_GLEXT(fExts, GenFramebuffers(1, &rtIDs.fRTFBOID));
751 GrAssert(0 != rtIDs.fRTFBOID);
752 GR_GLEXT(fExts, GenRenderbuffers(1, &rtIDs.fMSColorRenderbufferID));
753 GrAssert(0 != rtIDs.fMSColorRenderbufferID);
754 if (!fboInternalFormat(desc.fFormat, &msColorRenderbufferFormat)) {
755 GR_GLEXT(fExts,
756 DeleteRenderbuffers(1, &rtIDs.fMSColorRenderbufferID));
757 GR_GL(DeleteTextures(1, &glDesc.fTextureID));
758 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fTexFBOID));
759 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fRTFBOID));
reed@google.comac10a2d2010-12-22 21:39:39 +0000760 return return_null_texture();
761 }
762 } else {
763 rtIDs.fRTFBOID = rtIDs.fTexFBOID;
764 }
765 int attempts = 1;
766 if (!(kNoPathRendering_TextureFlag & desc.fFlags)) {
767 GR_GLEXT(fExts, GenRenderbuffers(1, &rtIDs.fStencilRenderbufferID));
768 GrAssert(0 != rtIDs.fStencilRenderbufferID);
769 attempts = GR_ARRAY_COUNT(GR_GL_STENCIL_FORMAT_ARRAY);
770 }
771
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000772 // someone suggested that some systems might require
bsalomon@google.com316f99232011-01-13 21:28:12 +0000773 // unbinding the texture before we call FramebufferTexture2D
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000774 // (seems unlikely)
reed@google.comac10a2d2010-12-22 21:39:39 +0000775 GR_GL(BindTexture(GL_TEXTURE_2D, 0));
reed@google.comac10a2d2010-12-22 21:39:39 +0000776
777 err = ~GL_NO_ERROR;
778 for (int i = 0; i < attempts; ++i) {
779 if (rtIDs.fStencilRenderbufferID) {
780 GR_GLEXT(fExts, BindRenderbuffer(GR_RENDERBUFFER,
781 rtIDs.fStencilRenderbufferID));
782 if (samples > 1) {
783 GR_GLEXT_NO_ERR(fExts, RenderbufferStorageMultisample(
784 GR_RENDERBUFFER,
785 samples,
786 GR_GL_STENCIL_FORMAT_ARRAY[i],
787 glDesc.fAllocWidth,
788 glDesc.fAllocHeight));
789 } else {
790 GR_GLEXT_NO_ERR(fExts, RenderbufferStorage(
791 GR_RENDERBUFFER,
792 GR_GL_STENCIL_FORMAT_ARRAY[i],
793 glDesc.fAllocWidth,
794 glDesc.fAllocHeight));
795 }
796 err = glGetError();
797 if (err != GL_NO_ERROR) {
798 continue;
799 }
800 }
801 if (rtIDs.fRTFBOID != rtIDs.fTexFBOID) {
802 GrAssert(samples > 1);
803 GR_GLEXT(fExts, BindRenderbuffer(GR_RENDERBUFFER,
804 rtIDs.fMSColorRenderbufferID));
805 GR_GLEXT_NO_ERR(fExts, RenderbufferStorageMultisample(
806 GR_RENDERBUFFER,
807 samples,
808 msColorRenderbufferFormat,
809 glDesc.fAllocWidth,
810 glDesc.fAllocHeight));
811 err = glGetError();
812 if (err != GL_NO_ERROR) {
813 continue;
814 }
815 }
816 GR_GLEXT(fExts, BindFramebuffer(GR_FRAMEBUFFER, rtIDs.fTexFBOID));
817
818#if GR_COLLECT_STATS
819 ++fStats.fRenderTargetChngCnt;
820#endif
821 if (kIMG_MSFBO == fMSFBOType && samples > 1) {
822 GR_GLEXT(fExts, FramebufferTexture2DMultisample(
823 GR_FRAMEBUFFER,
824 GR_COLOR_ATTACHMENT0,
825 GL_TEXTURE_2D,
826 glDesc.fTextureID,
827 0,
828 samples));
829
830 } else {
831 GR_GLEXT(fExts, FramebufferTexture2D(GR_FRAMEBUFFER,
832 GR_COLOR_ATTACHMENT0,
833 GL_TEXTURE_2D,
834 glDesc.fTextureID, 0));
835 }
836 if (rtIDs.fRTFBOID != rtIDs.fTexFBOID) {
837 GLenum status = GR_GLEXT(fExts,
838 CheckFramebufferStatus(GR_FRAMEBUFFER));
839 if (status != GR_FRAMEBUFFER_COMPLETE) {
840 GrPrintf("-- glCheckFramebufferStatus %x %d %d\n",
841 status, desc.fWidth, desc.fHeight);
842 continue;
843 }
844 GR_GLEXT(fExts, BindFramebuffer(GR_FRAMEBUFFER, rtIDs.fRTFBOID));
845 #if GR_COLLECT_STATS
846 ++fStats.fRenderTargetChngCnt;
847 #endif
848 GR_GLEXT(fExts, FramebufferRenderbuffer(GR_FRAMEBUFFER,
849 GR_COLOR_ATTACHMENT0,
850 GR_RENDERBUFFER,
851 rtIDs.fMSColorRenderbufferID));
852
853 }
854 if (rtIDs.fStencilRenderbufferID) {
855 // bind the stencil to rt fbo if present, othewise the tex fbo
856 GR_GLEXT(fExts, FramebufferRenderbuffer(GR_FRAMEBUFFER,
857 GR_STENCIL_ATTACHMENT,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000858 GR_RENDERBUFFER,
reed@google.comac10a2d2010-12-22 21:39:39 +0000859 rtIDs.fStencilRenderbufferID));
860 }
861 status = GR_GLEXT(fExts, CheckFramebufferStatus(GR_FRAMEBUFFER));
862
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000863#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000864 // On some implementations you have to be bound as DEPTH_STENCIL.
865 // (Even binding to DEPTH and STENCIL separately with the same
866 // buffer doesn't work.)
867 if (rtIDs.fStencilRenderbufferID &&
868 status != GR_FRAMEBUFFER_COMPLETE) {
869 GR_GLEXT(fExts, FramebufferRenderbuffer(GR_FRAMEBUFFER,
870 GR_STENCIL_ATTACHMENT,
871 GR_RENDERBUFFER,
872 0));
873 GR_GLEXT(fExts,
874 FramebufferRenderbuffer(GR_FRAMEBUFFER,
875 GR_DEPTH_STENCIL_ATTACHMENT,
876 GR_RENDERBUFFER,
877 rtIDs.fStencilRenderbufferID));
878 status = GR_GLEXT(fExts, CheckFramebufferStatus(GR_FRAMEBUFFER));
879 }
880#endif
881 if (status != GR_FRAMEBUFFER_COMPLETE) {
882 GrPrintf("-- glCheckFramebufferStatus %x %d %d\n",
883 status, desc.fWidth, desc.fHeight);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000884#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000885 if (rtIDs.fStencilRenderbufferID) {
886 GR_GLEXT(fExts, FramebufferRenderbuffer(GR_FRAMEBUFFER,
887 GR_DEPTH_STENCIL_ATTACHMENT,
888 GR_RENDERBUFFER,
889 0));
890 }
891#endif
892 continue;
893 }
894 // we're successful!
895 failed = false;
896 break;
897 }
898 if (failed) {
899 if (rtIDs.fStencilRenderbufferID) {
900 GR_GLEXT(fExts,
901 DeleteRenderbuffers(1, &rtIDs.fStencilRenderbufferID));
902 }
903 if (rtIDs.fMSColorRenderbufferID) {
904 GR_GLEXT(fExts,
905 DeleteRenderbuffers(1, &rtIDs.fMSColorRenderbufferID));
906 }
907 if (rtIDs.fRTFBOID != rtIDs.fTexFBOID) {
908 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fRTFBOID));
909 }
910 if (rtIDs.fTexFBOID) {
911 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fTexFBOID));
912 }
913 GR_GL(DeleteTextures(1, &glDesc.fTextureID));
914 return return_null_texture();
915 }
916 }
917#ifdef TRACE_TEXTURE_CREATION
918 GrPrintf("--- new texture [%d] size=(%d %d) bpp=%d\n",
919 tex->fTextureID, width, height, tex->fUploadByteCount);
920#endif
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000921 GrGLTexture* tex = new GrGLTexture(glDesc, rtIDs, DEFAULT_PARAMS, this);
reed@google.comac10a2d2010-12-22 21:39:39 +0000922
923 if (0 != rtIDs.fTexFBOID) {
924 GrRenderTarget* rt = tex->asRenderTarget();
925 // We've messed with FBO state but may not have set the correct viewport
926 // so just dirty the rendertarget state to force a resend.
927 fHWDrawState.fRenderTarget = NULL;
928
929 // clear the new stencil buffer if we have one
930 if (!(desc.fFlags & kNoPathRendering_TextureFlag)) {
931 GrRenderTarget* rtSave = fCurrDrawState.fRenderTarget;
932 fCurrDrawState.fRenderTarget = rt;
933 eraseStencil(0, ~0);
934 fCurrDrawState.fRenderTarget = rtSave;
935 }
936 }
937 return tex;
938}
939
reed@google.comac10a2d2010-12-22 21:39:39 +0000940GrVertexBuffer* GrGpuGL::createVertexBuffer(uint32_t size, bool dynamic) {
941 GLuint id;
942 GR_GL(GenBuffers(1, &id));
943 if (id) {
944 GR_GL(BindBuffer(GL_ARRAY_BUFFER, id));
945 GrGLClearErr();
946 // make sure driver can allocate memory for this buffer
947 GR_GL_NO_ERR(BufferData(GL_ARRAY_BUFFER, size, NULL,
948 dynamic ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW));
949 if (glGetError() != GL_NO_ERROR) {
950 GR_GL(DeleteBuffers(1, &id));
951 // deleting bound buffer does implicit bind to 0
952 fHWGeometryState.fVertexBuffer = NULL;
953 return NULL;
954 }
955 GrGLVertexBuffer* vertexBuffer = new GrGLVertexBuffer(id, this,
956 size, dynamic);
957 fHWGeometryState.fVertexBuffer = vertexBuffer;
958 return vertexBuffer;
959 }
960 return NULL;
961}
962
963GrIndexBuffer* GrGpuGL::createIndexBuffer(uint32_t size, bool dynamic) {
964 GLuint id;
965 GR_GL(GenBuffers(1, &id));
966 if (id) {
967 GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, id));
968 GrGLClearErr();
969 // make sure driver can allocate memory for this buffer
970 GR_GL_NO_ERR(BufferData(GL_ELEMENT_ARRAY_BUFFER, size, NULL,
971 dynamic ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW));
972 if (glGetError() != GL_NO_ERROR) {
973 GR_GL(DeleteBuffers(1, &id));
974 // deleting bound buffer does implicit bind to 0
975 fHWGeometryState.fIndexBuffer = NULL;
976 return NULL;
977 }
978 GrIndexBuffer* indexBuffer = new GrGLIndexBuffer(id, this,
979 size, dynamic);
980 fHWGeometryState.fIndexBuffer = indexBuffer;
981 return indexBuffer;
982 }
983 return NULL;
984}
985
reed@google.comac10a2d2010-12-22 21:39:39 +0000986void GrGpuGL::flushScissor(const GrIRect* rect) {
987 GrAssert(NULL != fCurrDrawState.fRenderTarget);
988 const GrIRect& vp =
989 ((GrGLRenderTarget*)fCurrDrawState.fRenderTarget)->viewport();
990
991 if (NULL != rect &&
992 rect->contains(vp)) {
993 rect = NULL;
994 }
995
996 if (NULL != rect) {
997 GrIRect scissor;
998 // viewport is already in GL coords
999 // create a scissor in GL coords (top > bottom)
1000 scissor.setLTRB(vp.fLeft + rect->fLeft,
1001 vp.fTop - rect->fTop,
1002 vp.fLeft + rect->fRight,
1003 vp.fTop - rect->fBottom);
1004
1005 if (fHWBounds.fScissorRect != scissor) {
1006 GR_GL(Scissor(scissor.fLeft, scissor.fBottom,
1007 scissor.width(), -scissor.height()));
1008 fHWBounds.fScissorRect = scissor;
1009 }
1010
1011 if (!fHWBounds.fScissorEnabled) {
1012 GR_GL(Enable(GL_SCISSOR_TEST));
1013 fHWBounds.fScissorEnabled = true;
1014 }
1015 } else {
1016 if (fHWBounds.fScissorEnabled) {
1017 GR_GL(Disable(GL_SCISSOR_TEST));
1018 fHWBounds.fScissorEnabled = false;
1019 }
1020 }
1021}
1022
reed@google.comac10a2d2010-12-22 21:39:39 +00001023void GrGpuGL::eraseColor(GrColor color) {
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +00001024 if (NULL == fCurrDrawState.fRenderTarget) {
1025 return;
1026 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001027 flushRenderTarget();
1028 if (fHWBounds.fScissorEnabled) {
1029 GR_GL(Disable(GL_SCISSOR_TEST));
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +00001030 fHWBounds.fScissorEnabled = false;
reed@google.comac10a2d2010-12-22 21:39:39 +00001031 }
1032 GR_GL(ColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE));
1033 GR_GL(ClearColor(GrColorUnpackR(color)/255.f,
1034 GrColorUnpackG(color)/255.f,
1035 GrColorUnpackB(color)/255.f,
1036 GrColorUnpackA(color)/255.f));
1037 GR_GL(Clear(GL_COLOR_BUFFER_BIT));
reed@google.comac10a2d2010-12-22 21:39:39 +00001038 fWriteMaskChanged = true;
1039}
1040
1041void GrGpuGL::eraseStencil(uint32_t value, uint32_t mask) {
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +00001042 if (NULL == fCurrDrawState.fRenderTarget) {
1043 return;
1044 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001045 flushRenderTarget();
1046 if (fHWBounds.fScissorEnabled) {
1047 GR_GL(Disable(GL_SCISSOR_TEST));
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +00001048 fHWBounds.fScissorEnabled = false;
reed@google.comac10a2d2010-12-22 21:39:39 +00001049 }
1050 GR_GL(StencilMask(mask));
1051 GR_GL(ClearStencil(value));
1052 GR_GL(Clear(GL_STENCIL_BUFFER_BIT));
reed@google.comac10a2d2010-12-22 21:39:39 +00001053 fWriteMaskChanged = true;
1054}
1055
1056void GrGpuGL::eraseStencilClip() {
1057 GLint stencilBitCount;
reed@google.comac20fb92011-01-12 17:14:53 +00001058 GR_GL_GetIntegerv(GL_STENCIL_BITS, &stencilBitCount);
reed@google.comac10a2d2010-12-22 21:39:39 +00001059 GrAssert(stencilBitCount > 0);
1060 GLint clipStencilMask = (1 << (stencilBitCount - 1));
1061 eraseStencil(0, clipStencilMask);
1062}
1063
1064void GrGpuGL::forceRenderTargetFlush() {
1065 flushRenderTarget();
1066}
1067
1068bool GrGpuGL::readPixels(int left, int top, int width, int height,
1069 GrTexture::PixelConfig config, void* buffer) {
1070 GLenum internalFormat; // we don't use this for glReadPixels
1071 GLenum format;
1072 GLenum type;
1073 if (!this->canBeTexture(config, &internalFormat, &format, &type)) {
1074 return false;
1075 }
1076
1077 GrAssert(NULL != fCurrDrawState.fRenderTarget);
1078 const GrIRect& vp = ((GrGLRenderTarget*)fCurrDrawState.fRenderTarget)->viewport();
1079
1080 // Brian says that viewport rects are already upside down (grrrrr)
bsalomon@google.com316f99232011-01-13 21:28:12 +00001081 GR_GL(ReadPixels(left, -vp.height() - top - height, width, height,
1082 format, type, buffer));
reed@google.comac10a2d2010-12-22 21:39:39 +00001083
1084 // now reverse the order of the rows, since GL's are bottom-to-top, but our
1085 // API presents top-to-bottom
1086 {
1087 size_t stride = width * GrTexture::BytesPerPixel(config);
1088 GrAutoMalloc rowStorage(stride);
1089 void* tmp = rowStorage.get();
1090
1091 const int halfY = height >> 1;
1092 char* top = reinterpret_cast<char*>(buffer);
1093 char* bottom = top + (height - 1) * stride;
1094 for (int y = 0; y < halfY; y++) {
1095 memcpy(tmp, top, stride);
1096 memcpy(top, bottom, stride);
1097 memcpy(bottom, tmp, stride);
1098 top += stride;
1099 bottom -= stride;
1100 }
1101 }
1102 return true;
1103}
1104
1105void GrGpuGL::flushRenderTarget() {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001106
1107 GrAssert(NULL != fCurrDrawState.fRenderTarget);
1108
reed@google.comac10a2d2010-12-22 21:39:39 +00001109 if (fHWDrawState.fRenderTarget != fCurrDrawState.fRenderTarget) {
1110 GrGLRenderTarget* rt = (GrGLRenderTarget*)fCurrDrawState.fRenderTarget;
1111 GR_GLEXT(fExts, BindFramebuffer(GR_FRAMEBUFFER, rt->renderFBOID()));
1112 #if GR_COLLECT_STATS
1113 ++fStats.fRenderTargetChngCnt;
1114 #endif
1115 rt->setDirty(true);
1116 #if GR_DEBUG
1117 GLenum status = GR_GLEXT(fExts, CheckFramebufferStatus(GR_FRAMEBUFFER));
1118 if (status != GR_FRAMEBUFFER_COMPLETE) {
1119 GrPrintf("-- glCheckFramebufferStatus %x\n", status);
1120 }
1121 #endif
1122 fHWDrawState.fRenderTarget = fCurrDrawState.fRenderTarget;
1123 const GrIRect& vp = rt->viewport();
1124 fRenderTargetChanged = true;
1125 if (fHWBounds.fViewportRect != vp) {
1126 GR_GL(Viewport(vp.fLeft,
1127 vp.fBottom,
1128 vp.width(),
1129 -vp.height()));
1130 fHWBounds.fViewportRect = vp;
1131 }
1132 }
1133}
1134
1135GLenum gPrimitiveType2GLMode[] = {
1136 GL_TRIANGLES,
1137 GL_TRIANGLE_STRIP,
1138 GL_TRIANGLE_FAN,
1139 GL_POINTS,
1140 GL_LINES,
1141 GL_LINE_STRIP
1142};
1143
1144void GrGpuGL::drawIndexedHelper(PrimitiveType type,
1145 uint32_t startVertex,
1146 uint32_t startIndex,
1147 uint32_t vertexCount,
1148 uint32_t indexCount) {
1149 GrAssert((size_t)type < GR_ARRAY_COUNT(gPrimitiveType2GLMode));
1150
1151 GLvoid* indices = (GLvoid*)(sizeof(uint16_t) * startIndex);
1152 if (kReserved_GeometrySrcType == fGeometrySrc.fIndexSrc) {
1153 indices = (GLvoid*)((intptr_t)indices + (intptr_t)fIndices.get());
1154 } else if (kArray_GeometrySrcType == fGeometrySrc.fIndexSrc) {
1155 indices = (GLvoid*)((intptr_t)indices +
1156 (intptr_t)fGeometrySrc.fIndexArray);
1157 }
1158
1159 GR_GL(DrawElements(gPrimitiveType2GLMode[type], indexCount,
1160 GL_UNSIGNED_SHORT, indices));
1161}
1162
1163void GrGpuGL::drawNonIndexedHelper(PrimitiveType type,
1164 uint32_t startVertex,
1165 uint32_t vertexCount) {
1166 GrAssert((size_t)type < GR_ARRAY_COUNT(gPrimitiveType2GLMode));
1167
1168 GR_GL(DrawArrays(gPrimitiveType2GLMode[type], 0, vertexCount));
1169}
1170
reed@google.comac10a2d2010-12-22 21:39:39 +00001171void GrGpuGL::resolveTextureRenderTarget(GrGLTexture* texture) {
1172 GrGLRenderTarget* rt = (GrGLRenderTarget*) texture->asRenderTarget();
1173
1174 if (NULL != rt && rt->needsResolve()) {
1175 GrAssert(kNone_MSFBO != fMSFBOType);
1176 GrAssert(rt->textureFBOID() != rt->renderFBOID());
1177 GR_GLEXT(fExts, BindFramebuffer(GR_READ_FRAMEBUFFER,
1178 rt->renderFBOID()));
1179 GR_GLEXT(fExts, BindFramebuffer(GR_DRAW_FRAMEBUFFER,
1180 rt->textureFBOID()));
1181 #if GR_COLLECT_STATS
1182 ++fStats.fRenderTargetChngCnt;
1183 #endif
1184 // make sure we go through set render target
1185 fHWDrawState.fRenderTarget = NULL;
1186
1187 GLint left = 0;
1188 GLint right = texture->contentWidth();
1189 // we will have rendered to the top of the FBO.
1190 GLint top = texture->allocHeight();
1191 GLint bottom = texture->allocHeight() - texture->contentHeight();
1192 if (kApple_MSFBO == fMSFBOType) {
1193 GR_GL(Enable(GL_SCISSOR_TEST));
1194 GR_GL(Scissor(left, bottom, right-left, top-bottom));
1195 GR_GLEXT(fExts, ResolveMultisampleFramebuffer());
1196 fHWBounds.fScissorRect.setEmpty();
1197 fHWBounds.fScissorEnabled = true;
1198 } else {
1199 GR_GLEXT(fExts, BlitFramebuffer(left, bottom, right, top,
1200 left, bottom, right, top,
1201 GL_COLOR_BUFFER_BIT, GL_NEAREST));
1202 }
1203 rt->setDirty(false);
1204
1205 }
1206}
1207
1208void GrGpuGL::flushStencil() {
1209
1210 // use stencil for clipping if clipping is enabled and the clip
1211 // has been written into the stencil.
1212 bool stencilClip = fClipState.fClipInStencil &&
1213 (kClip_StateBit & fCurrDrawState.fFlagBits);
1214 bool stencilChange =
1215 fWriteMaskChanged ||
1216 fHWStencilClip != stencilClip ||
1217 fHWDrawState.fStencilPass != fCurrDrawState.fStencilPass ||
1218 (kNone_StencilPass != fCurrDrawState.fStencilPass &&
1219 (StencilPass)kSetClip_StencilPass != fCurrDrawState.fStencilPass &&
1220 fHWDrawState.fReverseFill != fCurrDrawState.fReverseFill);
1221
1222 if (stencilChange) {
1223 GLint stencilBitCount;
1224 GLint clipStencilMask;
1225 GLint pathStencilMask;
reed@google.comac20fb92011-01-12 17:14:53 +00001226 GR_GL_GetIntegerv(GL_STENCIL_BITS, &stencilBitCount);
reed@google.comac10a2d2010-12-22 21:39:39 +00001227 GrAssert(stencilBitCount > 0 ||
1228 kNone_StencilPass == fCurrDrawState.fStencilPass);
1229 clipStencilMask = (1 << (stencilBitCount - 1));
1230 pathStencilMask = clipStencilMask - 1;
1231 switch (fCurrDrawState.fStencilPass) {
1232 case kNone_StencilPass:
1233 if (stencilClip) {
1234 GR_GL(Enable(GL_STENCIL_TEST));
1235 GR_GL(StencilFunc(GL_EQUAL,
1236 clipStencilMask,
1237 clipStencilMask));
1238 GR_GL(StencilOp(GL_KEEP, GL_KEEP, GL_KEEP));
1239 } else {
1240 GR_GL(Disable(GL_STENCIL_TEST));
1241 }
1242 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
1243 if (!fSingleStencilPassForWinding) {
1244 GR_GL(Disable(GL_CULL_FACE));
1245 }
1246 break;
1247 case kEvenOddStencil_StencilPass:
1248 GR_GL(Enable(GL_STENCIL_TEST));
1249 if (stencilClip) {
1250 GR_GL(StencilFunc(GL_EQUAL, clipStencilMask, clipStencilMask));
1251 } else {
1252 GR_GL(StencilFunc(GL_ALWAYS, 0x0, 0x0));
1253 }
1254 GR_GL(StencilMask(pathStencilMask));
1255 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
1256 GR_GL(StencilOp(GL_KEEP, GL_INVERT, GL_INVERT));
1257 GR_GL(ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE));
1258 if (!fSingleStencilPassForWinding) {
1259 GR_GL(Disable(GL_CULL_FACE));
1260 }
1261 break;
1262 case kEvenOddColor_StencilPass: {
1263 GR_GL(Enable(GL_STENCIL_TEST));
1264 GLint funcRef = 0;
1265 GLuint funcMask = pathStencilMask;
1266 if (stencilClip) {
1267 funcRef |= clipStencilMask;
1268 funcMask |= clipStencilMask;
1269 }
1270 if (!fCurrDrawState.fReverseFill) {
1271 funcRef |= pathStencilMask;
1272 }
bsalomon@google.com316f99232011-01-13 21:28:12 +00001273 GR_GL(StencilFunc(GL_EQUAL, funcRef, funcMask));
1274 GR_GL(StencilMask(pathStencilMask));
reed@google.comac10a2d2010-12-22 21:39:39 +00001275 GR_GL(StencilOp(GL_ZERO, GL_ZERO, GL_ZERO));
1276 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
1277 if (!fSingleStencilPassForWinding) {
1278 GR_GL(Disable(GL_CULL_FACE));
1279 }
1280 } break;
1281 case kWindingStencil1_StencilPass:
1282 GR_GL(Enable(GL_STENCIL_TEST));
1283 if (fHasStencilWrap) {
1284 if (stencilClip) {
1285 GR_GL(StencilFunc(GL_EQUAL,
1286 clipStencilMask,
1287 clipStencilMask));
1288 } else {
1289 GR_GL(StencilFunc(GL_ALWAYS, 0x0, 0x0));
1290 }
1291 if (fSingleStencilPassForWinding) {
1292 GR_GL(StencilOpSeparate(GL_FRONT, GL_KEEP,
1293 GL_INCR_WRAP, GL_INCR_WRAP));
1294 GR_GL(StencilOpSeparate(GL_BACK, GL_KEEP,
1295 GL_DECR_WRAP, GL_DECR_WRAP));
1296 } else {
1297 GR_GL(StencilOp(GL_KEEP, GL_INCR_WRAP, GL_INCR_WRAP));
1298 GR_GL(Enable(GL_CULL_FACE));
1299 GR_GL(CullFace(GL_BACK));
1300 }
1301 } else {
1302 // If we don't have wrap then we use the Func to detect
1303 // values that would wrap (0 on decr and mask on incr). We
1304 // make the func fail on these values and use the sfail op
1305 // to effectively wrap by inverting.
1306 // This applies whether we are doing a two-pass (front faces
1307 // followed by back faces) or a single pass (separate func/op)
1308
1309 // Note that in the case where we are also using stencil to
1310 // clip this means we will write into the path bits in clipped
1311 // out pixels. We still apply the clip bit in the color pass
1312 // stencil func so we don't draw color outside the clip.
1313 // We also will clear the stencil bits in clipped pixels by
1314 // using zero in the sfail op with write mask set to the
1315 // path mask.
1316 GR_GL(Enable(GL_STENCIL_TEST));
1317 if (fSingleStencilPassForWinding) {
1318 GR_GL(StencilFuncSeparate(GL_FRONT,
1319 GL_NOTEQUAL,
1320 pathStencilMask,
1321 pathStencilMask));
1322 GR_GL(StencilFuncSeparate(GL_BACK,
1323 GL_NOTEQUAL,
1324 0x0,
1325 pathStencilMask));
1326 GR_GL(StencilOpSeparate(GL_FRONT, GL_INVERT,
1327 GL_INCR, GL_INCR));
1328 GR_GL(StencilOpSeparate(GL_BACK, GL_INVERT,
1329 GL_DECR, GL_DECR));
1330 } else {
1331 GR_GL(StencilFunc(GL_NOTEQUAL,
1332 pathStencilMask,
1333 pathStencilMask));
1334 GR_GL(StencilOp(GL_INVERT, GL_INCR, GL_INCR));
1335 GR_GL(Enable(GL_CULL_FACE));
1336 GR_GL(CullFace(GL_BACK));
1337 }
1338 }
1339 GR_GL(StencilMask(pathStencilMask));
1340 GR_GL(ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE));
1341 break;
1342 case kWindingStencil2_StencilPass:
1343 GrAssert(!fSingleStencilPassForWinding);
1344 GR_GL(Enable(GL_STENCIL_TEST));
1345 if (fHasStencilWrap) {
1346 if (stencilClip) {
1347 GR_GL(StencilFunc(GL_EQUAL,
1348 clipStencilMask,
1349 clipStencilMask));
1350 } else {
1351 GR_GL(StencilFunc(GL_ALWAYS, 0x0, 0x0));
1352 }
1353 GR_GL(StencilOp(GL_DECR_WRAP, GL_DECR_WRAP, GL_DECR_WRAP));
1354 } else {
1355 GR_GL(StencilFunc(GL_NOTEQUAL, 0x0, pathStencilMask));
1356 GR_GL(StencilOp(GL_INVERT, GL_DECR, GL_DECR));
1357 }
1358 GR_GL(StencilMask(pathStencilMask));
1359 GR_GL(Enable(GL_CULL_FACE));
1360 GR_GL(CullFace(GL_FRONT));
1361 GR_GL(ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE));
1362 break;
1363 case kWindingColor_StencilPass: {
1364 GR_GL(Enable(GL_STENCIL_TEST));
1365 GLint funcRef = 0;
1366 GLuint funcMask = pathStencilMask;
1367 GLenum funcFunc;
1368 if (stencilClip) {
1369 funcRef |= clipStencilMask;
1370 funcMask |= clipStencilMask;
1371 }
1372 if (fCurrDrawState.fReverseFill) {
1373 funcFunc = GL_EQUAL;
1374 } else {
1375 funcFunc = GL_LESS;
1376 }
1377 GR_GL(StencilFunc(funcFunc, funcRef, funcMask));
1378 GR_GL(StencilMask(pathStencilMask));
1379 // must zero in sfail because winding w/o wrap will write
1380 // path stencil bits in clipped out pixels
1381 GR_GL(StencilOp(GL_ZERO, GL_ZERO, GL_ZERO));
1382 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
1383 if (!fSingleStencilPassForWinding) {
1384 GR_GL(Disable(GL_CULL_FACE));
1385 }
1386 } break;
1387 case kSetClip_StencilPass:
1388 GR_GL(Enable(GL_STENCIL_TEST));
1389 GR_GL(StencilFunc(GL_ALWAYS, clipStencilMask, clipStencilMask));
1390 GR_GL(StencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE));
1391 GR_GL(StencilMask(clipStencilMask));
1392 GR_GL(ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE));
1393 if (!fSingleStencilPassForWinding) {
1394 GR_GL(Disable(GL_CULL_FACE));
1395 }
1396 break;
1397 default:
1398 GrAssert(!"Unexpected stencil pass.");
1399 break;
1400
1401 }
1402 fHWDrawState.fStencilPass = fCurrDrawState.fStencilPass;
1403 fHWDrawState.fReverseFill = fCurrDrawState.fReverseFill;
1404 fWriteMaskChanged = false;
1405 fHWStencilClip = stencilClip;
1406 }
1407}
1408
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001409bool GrGpuGL::flushGLStateCommon(PrimitiveType type) {
1410
1411 // GrGpu::setupClipAndFlushState should have already checked this
1412 // and bailed if not true.
1413 GrAssert(NULL != fCurrDrawState.fRenderTarget);
reed@google.comac10a2d2010-12-22 21:39:39 +00001414
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001415 for (int s = 0; s < kNumStages; ++s) {
1416 bool usingTexture = VertexUsesStage(s, fGeometrySrc.fVertexLayout);
reed@google.comac10a2d2010-12-22 21:39:39 +00001417
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001418 // bind texture and set sampler state
1419 if (usingTexture) {
1420 GrGLTexture* nextTexture = (GrGLTexture*)fCurrDrawState.fTextures[s];
reed@google.comac10a2d2010-12-22 21:39:39 +00001421
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001422 if (NULL != nextTexture) {
bsalomon@google.com316f99232011-01-13 21:28:12 +00001423 // if we created a rt/tex and rendered to it without using a
1424 // texture and now we're texuring from the rt it will still be
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001425 // the last bound texture, but it needs resolving. So keep this
1426 // out of the "last != next" check.
1427 resolveTextureRenderTarget(nextTexture);
reed@google.comac10a2d2010-12-22 21:39:39 +00001428
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001429 if (fHWDrawState.fTextures[s] != nextTexture) {
1430 setTextureUnit(s);
1431 GR_GL(BindTexture(GL_TEXTURE_2D, nextTexture->textureID()));
1432 #if GR_COLLECT_STATS
1433 ++fStats.fTextureChngCnt;
1434 #endif
1435 //GrPrintf("---- bindtexture %d\n", nextTexture->textureID());
1436 fHWDrawState.fTextures[s] = nextTexture;
1437 }
bsalomon@google.com316f99232011-01-13 21:28:12 +00001438
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001439 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
bsalomon@google.com316f99232011-01-13 21:28:12 +00001440 const GrGLTexture::TexParams& oldTexParams =
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001441 nextTexture->getTexParams();
1442 GrGLTexture::TexParams newTexParams;
bsalomon@google.com316f99232011-01-13 21:28:12 +00001443
1444 newTexParams.fFilter = sampler.isFilter() ? GL_LINEAR :
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001445 GL_NEAREST;
bsalomon@google.com316f99232011-01-13 21:28:12 +00001446 newTexParams.fWrapS =
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001447 GrGLTexture::gWrapMode2GLWrap[sampler.getWrapX()];
bsalomon@google.com316f99232011-01-13 21:28:12 +00001448 newTexParams.fWrapT =
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001449 GrGLTexture::gWrapMode2GLWrap[sampler.getWrapY()];
reed@google.comac10a2d2010-12-22 21:39:39 +00001450
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001451 if (newTexParams.fFilter != oldTexParams.fFilter) {
1452 setTextureUnit(s);
bsalomon@google.com316f99232011-01-13 21:28:12 +00001453 GR_GL(TexParameteri(GL_TEXTURE_2D,
1454 GL_TEXTURE_MAG_FILTER,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001455 newTexParams.fFilter));
bsalomon@google.com316f99232011-01-13 21:28:12 +00001456 GR_GL(TexParameteri(GL_TEXTURE_2D,
1457 GL_TEXTURE_MIN_FILTER,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001458 newTexParams.fFilter));
1459 }
1460 if (newTexParams.fWrapS != oldTexParams.fWrapS) {
1461 setTextureUnit(s);
bsalomon@google.com316f99232011-01-13 21:28:12 +00001462 GR_GL(TexParameteri(GL_TEXTURE_2D,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001463 GL_TEXTURE_WRAP_S,
1464 newTexParams.fWrapS));
1465 }
1466 if (newTexParams.fWrapT != oldTexParams.fWrapT) {
1467 setTextureUnit(s);
bsalomon@google.com316f99232011-01-13 21:28:12 +00001468 GR_GL(TexParameteri(GL_TEXTURE_2D,
1469 GL_TEXTURE_WRAP_T,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001470 newTexParams.fWrapT));
1471 }
1472 nextTexture->setTexParams(newTexParams);
1473 } else {
1474 GrAssert(!"Rendering with texture vert flag set but no texture");
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001475 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +00001476 }
1477 }
1478 }
1479
1480 flushRenderTarget();
1481
1482 if ((fCurrDrawState.fFlagBits & kDither_StateBit) !=
1483 (fHWDrawState.fFlagBits & kDither_StateBit)) {
1484 if (fCurrDrawState.fFlagBits & kDither_StateBit) {
1485 GR_GL(Enable(GL_DITHER));
1486 } else {
1487 GR_GL(Disable(GL_DITHER));
1488 }
1489 }
1490
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001491#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +00001492 // ES doesn't support toggling GL_MULTISAMPLE and doesn't have
1493 // smooth lines.
1494 if (fRenderTargetChanged ||
1495 (fCurrDrawState.fFlagBits & kAntialias_StateBit) !=
1496 (fHWDrawState.fFlagBits & kAntialias_StateBit)) {
1497 GLint msaa = 0;
1498 // only perform query if we know MSAA is supported.
1499 // calling on non-MSAA target caused a crash in one environment,
1500 // though I don't think it should.
1501 if (!fAASamples[kHigh_AALevel]) {
reed@google.comac20fb92011-01-12 17:14:53 +00001502 GR_GL_GetIntegerv(GL_SAMPLE_BUFFERS, &msaa);
reed@google.comac10a2d2010-12-22 21:39:39 +00001503 }
1504 if (fCurrDrawState.fFlagBits & kAntialias_StateBit) {
1505 if (msaa) {
1506 GR_GL(Enable(GL_MULTISAMPLE));
1507 } else {
1508 GR_GL(Enable(GL_LINE_SMOOTH));
1509 }
1510 } else {
1511 if (msaa) {
1512 GR_GL(Disable(GL_MULTISAMPLE));
1513 }
1514 GR_GL(Disable(GL_LINE_SMOOTH));
1515 }
1516 }
1517#endif
1518
1519 bool blendOff = canDisableBlend();
1520 if (fHWBlendDisabled != blendOff) {
1521 if (blendOff) {
1522 GR_GL(Disable(GL_BLEND));
1523 } else {
1524 GR_GL(Enable(GL_BLEND));
1525 }
1526 fHWBlendDisabled = blendOff;
1527 }
1528
1529 if (!blendOff) {
1530 if (fHWDrawState.fSrcBlend != fCurrDrawState.fSrcBlend ||
1531 fHWDrawState.fDstBlend != fCurrDrawState.fDstBlend) {
1532 GR_GL(BlendFunc(gXfermodeCoeff2Blend[fCurrDrawState.fSrcBlend],
1533 gXfermodeCoeff2Blend[fCurrDrawState.fDstBlend]));
1534 fHWDrawState.fSrcBlend = fCurrDrawState.fSrcBlend;
1535 fHWDrawState.fDstBlend = fCurrDrawState.fDstBlend;
1536 }
1537 }
bsalomon@google.com316f99232011-01-13 21:28:12 +00001538
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001539#if GR_DEBUG
reed@google.comac10a2d2010-12-22 21:39:39 +00001540 // check for circular rendering
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001541 for (int s = 0; s < kNumStages; ++s) {
1542 GrAssert(!VertexUsesStage(s, fGeometrySrc.fVertexLayout) ||
1543 NULL == fCurrDrawState.fRenderTarget ||
1544 NULL == fCurrDrawState.fTextures[s] ||
bsalomon@google.com316f99232011-01-13 21:28:12 +00001545 fCurrDrawState.fTextures[s]->asRenderTarget() !=
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001546 fCurrDrawState.fRenderTarget);
1547 }
1548#endif
bsalomon@google.com316f99232011-01-13 21:28:12 +00001549
reed@google.comac10a2d2010-12-22 21:39:39 +00001550 flushStencil();
1551
1552 fHWDrawState.fFlagBits = fCurrDrawState.fFlagBits;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001553 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +00001554}
1555
1556void GrGpuGL::notifyVertexBufferBind(const GrGLVertexBuffer* buffer) {
1557 fHWGeometryState.fVertexBuffer = buffer;
1558}
1559
1560void GrGpuGL::notifyVertexBufferDelete(const GrGLVertexBuffer* buffer) {
1561 GrAssert(!(kBuffer_GeometrySrcType == fGeometrySrc.fVertexSrc &&
1562 buffer == fGeometrySrc.fVertexBuffer));
1563
1564 if (fHWGeometryState.fVertexBuffer == buffer) {
1565 // deleting bound buffer does implied bind to 0
1566 fHWGeometryState.fVertexBuffer = NULL;
1567 }
1568}
1569
1570void GrGpuGL::notifyIndexBufferBind(const GrGLIndexBuffer* buffer) {
1571 fGeometrySrc.fIndexBuffer = buffer;
1572}
1573
1574void GrGpuGL::notifyIndexBufferDelete(const GrGLIndexBuffer* buffer) {
1575 GrAssert(!(kBuffer_GeometrySrcType == fGeometrySrc.fIndexSrc &&
1576 buffer == fGeometrySrc.fIndexBuffer));
1577
1578 if (fHWGeometryState.fIndexBuffer == buffer) {
1579 // deleting bound buffer does implied bind to 0
1580 fHWGeometryState.fIndexBuffer = NULL;
1581 }
1582}
1583
reed@google.comac10a2d2010-12-22 21:39:39 +00001584void GrGpuGL::notifyRenderTargetDelete(GrRenderTarget* renderTarget) {
1585 GrAssert(NULL != renderTarget);
1586
1587 // if the bound FBO is destroyed we can't rely on the implicit bind to 0
1588 // a) we want the default RT which may not be FBO 0
1589 // b) we set more state than just FBO based on the RT
1590 // So trash the HW state to force an RT flush next time
1591 if (fCurrDrawState.fRenderTarget == renderTarget) {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001592 fCurrDrawState.fRenderTarget = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +00001593 }
1594 if (fHWDrawState.fRenderTarget == renderTarget) {
1595 fHWDrawState.fRenderTarget = NULL;
1596 }
1597 if (fClipState.fStencilClipTarget == renderTarget) {
1598 fClipState.fStencilClipTarget = NULL;
1599 }
1600}
1601
1602void GrGpuGL::notifyTextureDelete(GrGLTexture* texture) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001603 for (int s = 0; s < kNumStages; ++s) {
1604 if (fCurrDrawState.fTextures[s] == texture) {
1605 fCurrDrawState.fTextures[s] = NULL;
1606 }
1607 if (fHWDrawState.fTextures[s] == texture) {
1608 // deleting bound texture does implied bind to 0
1609 fHWDrawState.fTextures[s] = NULL;
1610 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001611 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001612}
1613
1614void GrGpuGL::notifyTextureRemoveRenderTarget(GrGLTexture* texture) {
1615 GrAssert(NULL != texture->asRenderTarget());
1616
1617 // if there is a pending resolve, perform it.
1618 resolveTextureRenderTarget(texture);
1619}
1620
1621bool GrGpuGL::canBeTexture(GrTexture::PixelConfig config,
1622 GLenum* internalFormat,
1623 GLenum* format,
1624 GLenum* type) {
1625 switch (config) {
1626 case GrTexture::kRGBA_8888_PixelConfig:
1627 case GrTexture::kRGBX_8888_PixelConfig: // todo: can we tell it our X?
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +00001628 *format = GR_GL_32BPP_COLOR_FORMAT;
reed@google.com63100f92011-01-18 21:32:14 +00001629#if GR_SUPPORT_GLES
1630 // according to GL_EXT_texture_format_BGRA8888 the *internal*
1631 // format for a BGRA is BGRA not RGBA (as on desktop)
1632 *internalFormat = GR_GL_32BPP_COLOR_FORMAT;
1633#else
1634 *internalFormat = GL_RGBA;
bsalomon@google.comed3a0682011-01-18 16:54:04 +00001635#endif
reed@google.comac10a2d2010-12-22 21:39:39 +00001636 *type = GL_UNSIGNED_BYTE;
1637 break;
1638 case GrTexture::kRGB_565_PixelConfig:
1639 *format = GL_RGB;
1640 *internalFormat = GL_RGB;
1641 *type = GL_UNSIGNED_SHORT_5_6_5;
1642 break;
1643 case GrTexture::kRGBA_4444_PixelConfig:
1644 *format = GL_RGBA;
1645 *internalFormat = GL_RGBA;
1646 *type = GL_UNSIGNED_SHORT_4_4_4_4;
1647 break;
1648 case GrTexture::kIndex_8_PixelConfig:
1649 if (this->supports8BitPalette()) {
1650 *format = GR_PALETTE8_RGBA8;
1651 *internalFormat = GR_PALETTE8_RGBA8;
1652 *type = GL_UNSIGNED_BYTE; // unused I think
1653 } else {
1654 return false;
1655 }
1656 break;
1657 case GrTexture::kAlpha_8_PixelConfig:
1658 *format = GL_ALPHA;
1659 *internalFormat = GL_ALPHA;
1660 *type = GL_UNSIGNED_BYTE;
1661 break;
1662 default:
1663 return false;
1664 }
1665 return true;
1666}
1667
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001668void GrGpuGL::setTextureUnit(int unit) {
1669 GrAssert(unit >= 0 && unit < kNumStages);
1670 if (fActiveTextureUnitIdx != unit) {
1671 GR_GL(ActiveTexture(GL_TEXTURE0 + unit));
1672 fActiveTextureUnitIdx = unit;
1673 }
1674}
bsalomon@google.com316f99232011-01-13 21:28:12 +00001675
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001676void GrGpuGL::setSpareTextureUnit() {
1677 if (fActiveTextureUnitIdx != (GL_TEXTURE0 + SPARE_TEX_UNIT)) {
1678 GR_GL(ActiveTexture(GL_TEXTURE0 + SPARE_TEX_UNIT));
1679 fActiveTextureUnitIdx = SPARE_TEX_UNIT;
1680 }
1681}
1682
reed@google.comac10a2d2010-12-22 21:39:39 +00001683/* On ES the internalFormat and format must match for TexImage and we use
1684 GL_RGB, GL_RGBA for color formats. We also generally like having the driver
1685 decide the internalFormat. However, on ES internalFormat for
1686 RenderBufferStorage* has to be a specific format (not a base format like
1687 GL_RGBA).
1688 */
1689bool GrGpuGL::fboInternalFormat(GrTexture::PixelConfig config, GLenum* format) {
1690 switch (config) {
1691 case GrTexture::kRGBA_8888_PixelConfig:
1692 case GrTexture::kRGBX_8888_PixelConfig:
1693 if (fRGBA8Renderbuffer) {
1694 *format = GR_RGBA8;
1695 return true;
1696 } else {
1697 return false;
1698 }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001699#if GR_SUPPORT_GLES // ES2 supports 565. ES1 supports it with FBO extension
1700 // desktop GL has no such internal format
reed@google.comac10a2d2010-12-22 21:39:39 +00001701 case GrTexture::kRGB_565_PixelConfig:
1702 *format = GR_RGB565;
1703 return true;
1704#endif
1705 case GrTexture::kRGBA_4444_PixelConfig:
1706 *format = GL_RGBA4;
1707 return true;
1708 default:
1709 return false;
1710 }
1711}