blob: 3d86d1b5e57fdad46ae0a627a2326654d65106a2 [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
bsalomon@google.com0748f212011-02-01 22:56:16 +0000253 if (major >= 2 || has_gl_extension("GL_ARB_texture_non_power_of_two")) {
254 fNPOTTextureTileSupport = true;
255 fNPOTTextureSupport = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000256 } else {
bsalomon@google.com0748f212011-02-01 22:56:16 +0000257 fNPOTTextureTileSupport = false;
258 fNPOTTextureSupport = false;
259 }
260#else
261 if (major >= 2) {
262 fNPOTTextureSupport = true;
263 fNPOTTextureTileSupport = has_gl_extension("GL_OES_texture_npot");
264 } else {
265 fNPOTTextureSupport = has_gl_extension("GL_APPLE_texture_2D_limited_npot");
266 fNPOTTextureTileSupport = false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000267 }
268#endif
269 ////////////////////////////////////////////////////////////////////////////
270 // Experiments to determine limitations that can't be queried. TODO: Make
271 // these a preprocess that generate some compile time constants.
272
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000273 // sanity check to make sure we can at least create an FBO from a POT texture
bsalomon@google.com0748f212011-02-01 22:56:16 +0000274
275 bool simpleFBOSuccess = fbo_test(fExts, 128, 128);
276 if (gPrintStartupSpew) {
277 if (!simpleFBOSuccess) {
278 GrPrintf("FBO Sanity Test: FAILED\n");
279 } else {
280 GrPrintf("FBO Sanity Test: PASSED\n");
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000281 }
282 }
bsalomon@google.com0748f212011-02-01 22:56:16 +0000283 GrAssert(simpleFBOSuccess);
reed@google.comac20fb92011-01-12 17:14:53 +0000284
reed@google.comac10a2d2010-12-22 21:39:39 +0000285 /* Experimentation has found that some GLs that support NPOT textures
286 do not support FBOs with a NPOT texture. They report "unsupported" FBO
287 status. I don't know how to explicitly query for this. Do an
288 experiment. Note they may support NPOT with a renderbuffer but not a
289 texture. Presumably, the implementation bloats the renderbuffer
290 internally to the next POT.
291 */
bsalomon@google.com0748f212011-02-01 22:56:16 +0000292 bool fNPOTRenderTargetSupport = false;
293 if (fNPOTTextureSupport) {
294 fNPOTRenderTargetSupport = fbo_test(fExts, 200, 200);
295 }
296
297 if (gPrintStartupSpew) {
298 if (fNPOTTextureSupport) {
299 GrPrintf("NPOT textures supported\n");
300 if (fNPOTTextureTileSupport) {
301 GrPrintf("NPOT texture tiling supported\n");
302 } else {
303 GrPrintf("NPOT texture tiling NOT supported\n");
304 }
305 if (fNPOTRenderTargetSupport) {
306 GrPrintf("NPOT render targets supported\n");
307 } else {
308 GrPrintf("NPOT render targets NOT supported\n");
reed@google.comeeeb5a02010-12-23 15:12:59 +0000309 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000310 } else {
bsalomon@google.com0748f212011-02-01 22:56:16 +0000311 GrPrintf("NPOT textures NOT supported\n");
reed@google.comeeeb5a02010-12-23 15:12:59 +0000312 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000313 }
314
reed@google.comac10a2d2010-12-22 21:39:39 +0000315 /* The iPhone 4 has a restriction that for an FBO with texture color
316 attachment with height <= 8 then the width must be <= height. Here
317 we look for such a limitation.
318 */
319 fMinRenderTargetHeight = GR_INVAL_GLINT;
320 GLint maxRenderSize;
reed@google.comac20fb92011-01-12 17:14:53 +0000321 GR_GL_GetIntegerv(GR_MAX_RENDERBUFFER_SIZE, &maxRenderSize);
reed@google.comac10a2d2010-12-22 21:39:39 +0000322
reed@google.comeeeb5a02010-12-23 15:12:59 +0000323 if (gPrintStartupSpew) {
324 GrPrintf("Small height FBO texture experiments\n");
325 }
bsalomon@google.com0748f212011-02-01 22:56:16 +0000326
327 for (GLuint i = 1; i <= 256; fNPOTRenderTargetSupport ? ++i : i *= 2) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000328 GLuint w = maxRenderSize;
329 GLuint h = i;
330 if (fbo_test(fExts, w, h)) {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000331 if (gPrintStartupSpew) {
332 GrPrintf("\t[%d, %d]: PASSED\n", w, h);
333 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000334 fMinRenderTargetHeight = i;
335 break;
336 } else {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000337 if (gPrintStartupSpew) {
338 GrPrintf("\t[%d, %d]: FAILED\n", w, h);
339 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000340 }
341 }
342 GrAssert(GR_INVAL_GLINT != fMinRenderTargetHeight);
343
reed@google.comeeeb5a02010-12-23 15:12:59 +0000344 if (gPrintStartupSpew) {
345 GrPrintf("Small width FBO texture experiments\n");
346 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000347 fMinRenderTargetWidth = GR_MAX_GLUINT;
bsalomon@google.com0748f212011-02-01 22:56:16 +0000348 for (GLuint i = 1; i <= 256; fNPOTRenderTargetSupport ? i *= 2 : ++i) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000349 GLuint w = i;
350 GLuint h = maxRenderSize;
351 if (fbo_test(fExts, w, h)) {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000352 if (gPrintStartupSpew) {
353 GrPrintf("\t[%d, %d]: PASSED\n", w, h);
354 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000355 fMinRenderTargetWidth = i;
356 break;
357 } else {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000358 if (gPrintStartupSpew) {
359 GrPrintf("\t[%d, %d]: FAILED\n", w, h);
360 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000361 }
362 }
363 GrAssert(GR_INVAL_GLINT != fMinRenderTargetWidth);
364
reed@google.com02a7e6c2011-01-28 21:21:49 +0000365 GR_GL_GetIntegerv(GL_MAX_TEXTURE_SIZE, &fMaxTextureDimension);
reed@google.comac10a2d2010-12-22 21:39:39 +0000366}
367
368GrGpuGL::~GrGpuGL() {
reed@google.comac10a2d2010-12-22 21:39:39 +0000369}
370
371void GrGpuGL::resetContextHelper() {
372// We detect cases when blending is effectively off
373 fHWBlendDisabled = false;
374 GR_GL(Enable(GL_BLEND));
375
376 // this is always disabled
377 GR_GL(Disable(GL_CULL_FACE));
378
379 GR_GL(Disable(GL_DITHER));
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000380#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000381 GR_GL(Disable(GL_LINE_SMOOTH));
382 GR_GL(Disable(GL_POINT_SMOOTH));
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000383 GR_GL(Disable(GL_MULTISAMPLE));
reed@google.comac10a2d2010-12-22 21:39:39 +0000384#endif
385
386 // we only ever use lines in hairline mode
387 GR_GL(LineWidth(1));
388
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000389 // invalid
390 fActiveTextureUnitIdx = -1;
reed@google.comac10a2d2010-12-22 21:39:39 +0000391
392 fHWDrawState.fFlagBits = 0;
393
394 // illegal values
395 fHWDrawState.fSrcBlend = (BlendCoeff)-1;
396 fHWDrawState.fDstBlend = (BlendCoeff)-1;
397 fHWDrawState.fColor = GrColor_ILLEGAL;
bsalomon@google.com316f99232011-01-13 21:28:12 +0000398
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000399 fHWDrawState.fViewMatrix.setScale(GR_ScalarMax, GR_ScalarMax); // illegal
bsalomon@google.com316f99232011-01-13 21:28:12 +0000400
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000401 for (int s = 0; s < kNumStages; ++s) {
402 fHWDrawState.fTextures[s] = NULL;
403 fHWDrawState.fSamplerStates[s].setRadial2Params(-GR_ScalarMax,
404 -GR_ScalarMax,
405 true);
bsalomon@google.com316f99232011-01-13 21:28:12 +0000406 fHWDrawState.fTextureMatrices[s].setScale(GR_ScalarMax, GR_ScalarMax);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000407 }
bsalomon@google.com316f99232011-01-13 21:28:12 +0000408
reed@google.comac10a2d2010-12-22 21:39:39 +0000409 GR_GL(Scissor(0,0,0,0));
410 fHWBounds.fScissorRect.setLTRB(0,0,0,0);
411 fHWBounds.fScissorEnabled = false;
412 GR_GL(Disable(GL_SCISSOR_TEST));
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000413 fHWBounds.fViewportRect.setLTRB(-1,-1,-1,-1);
reed@google.comac10a2d2010-12-22 21:39:39 +0000414
reed@google.comac10a2d2010-12-22 21:39:39 +0000415 // disabling the stencil test also disables
416 // stencil buffer writes
417 GR_GL(Disable(GL_STENCIL_TEST));
418 GR_GL(StencilMask(0xffffffff));
419 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
420 fHWDrawState.fReverseFill = false;
421 fHWDrawState.fStencilPass = kNone_StencilPass;
422 fHWStencilClip = false;
423
424 fHWGeometryState.fIndexBuffer = NULL;
425 fHWGeometryState.fVertexBuffer = NULL;
426 GR_GL(BindBuffer(GL_ARRAY_BUFFER, 0));
427 GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
428
429 fHWDrawState.fRenderTarget = NULL;
430}
431
432void GrGpuGL::resetContext() {
433 INHERITED::resetContext();
434 resetContextHelper();
435}
436
reed@google.comac10a2d2010-12-22 21:39:39 +0000437GrRenderTarget* GrGpuGL::createPlatformRenderTarget(
438 intptr_t platformRenderTarget,
439 int width, int height) {
440 GrGLRenderTarget::GLRenderTargetIDs rtIDs;
441 rtIDs.fStencilRenderbufferID = 0;
442 rtIDs.fMSColorRenderbufferID = 0;
443 rtIDs.fTexFBOID = 0;
444 rtIDs.fOwnIDs = false;
445
446 GrIRect viewport;
447
448 // viewport is in GL coords (top >= bottom)
449 viewport.setLTRB(0, height, width, 0);
450
451 rtIDs.fRTFBOID = (GLuint)platformRenderTarget;
452 rtIDs.fTexFBOID = (GLuint)platformRenderTarget;
453
454 GrGLRenderTarget* rt = new GrGLRenderTarget(rtIDs, viewport, NULL, this);
455
456 return rt;
457}
458
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000459GrRenderTarget* GrGpuGL::createRenderTargetFrom3DApiState() {
bsalomon@google.com42ab7ea2011-01-19 17:19:40 +0000460
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000461 GrGLRenderTarget::GLRenderTargetIDs rtIDs;
bsalomon@google.com42ab7ea2011-01-19 17:19:40 +0000462
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000463 GR_GL_GetIntegerv(GR_FRAMEBUFFER_BINDING, (GLint*)&rtIDs.fRTFBOID);
464 rtIDs.fTexFBOID = rtIDs.fRTFBOID;
465 rtIDs.fMSColorRenderbufferID = 0;
466 rtIDs.fStencilRenderbufferID = 0;
bsalomon@google.com42ab7ea2011-01-19 17:19:40 +0000467
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000468 GLint vp[4];
469 GR_GL_GetIntegerv(GL_VIEWPORT, vp);
470 GrIRect viewportRect;
471 viewportRect.setLTRB(vp[0],
472 vp[1] + vp[3],
473 vp[0] + vp[2],
474 vp[1]);
475 rtIDs.fOwnIDs = false;
476
477 return new GrGLRenderTarget(rtIDs,
478 viewportRect,
479 NULL,
480 this);
481}
482
bsalomon@google.com5782d712011-01-21 21:03:59 +0000483///////////////////////////////////////////////////////////////////////////////
484
bsalomon@google.com3f3ffd62011-01-18 17:14:52 +0000485// defines stencil formats from more to less preferred
reed@google.com63100f92011-01-18 21:32:14 +0000486GLenum GR_GL_STENCIL_FORMAT_ARRAY[] = {
487 GR_STENCIL_INDEX8,
488
489#if GR_SUPPORT_GLDESKTOP
490 GR_STENCIL_INDEX16,
491#endif
492
493 GR_DEPTH24_STENCIL8,
494 GR_STENCIL_INDEX4,
495
496#if GR_SUPPORT_GLDESKTOP
bsalomon@google.com3f3ffd62011-01-18 17:14:52 +0000497 GL_STENCIL_INDEX,
498 GR_DEPTH_STENCIL,
499#endif
500};
501
502// good to set a break-point here to know when createTexture fails
503static GrTexture* return_null_texture() {
504// GrAssert(!"null texture");
505 return NULL;
506}
507
508#if GR_DEBUG
509static size_t as_size_t(int x) {
510 return x;
511}
512#endif
513
reed@google.comac10a2d2010-12-22 21:39:39 +0000514GrTexture* GrGpuGL::createTexture(const TextureDesc& desc,
515 const void* srcData, size_t rowBytes) {
516
517#if GR_COLLECT_STATS
518 ++fStats.fTextureCreateCnt;
519#endif
reed@google.com1fcd51e2011-01-05 15:50:27 +0000520
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000521 setSpareTextureUnit();
bsalomon@google.com316f99232011-01-13 21:28:12 +0000522
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000523 static const GrGLTexture::TexParams DEFAULT_PARAMS = {
524 GL_NEAREST,
525 GL_CLAMP_TO_EDGE,
526 GL_CLAMP_TO_EDGE
527 };
reed@google.com1fcd51e2011-01-05 15:50:27 +0000528
reed@google.comac10a2d2010-12-22 21:39:39 +0000529 GrGLTexture::GLTextureDesc glDesc;
530 GLenum internalFormat;
531
532 glDesc.fContentWidth = desc.fWidth;
533 glDesc.fContentHeight = desc.fHeight;
534 glDesc.fAllocWidth = desc.fWidth;
535 glDesc.fAllocHeight = desc.fHeight;
536 glDesc.fFormat = desc.fFormat;
537
538 bool renderTarget = 0 != (desc.fFlags & kRenderTarget_TextureFlag);
539 if (!canBeTexture(desc.fFormat,
540 &internalFormat,
541 &glDesc.fUploadFormat,
542 &glDesc.fUploadType)) {
543 return return_null_texture();
544 }
545
546 GrAssert(as_size_t(desc.fAALevel) < GR_ARRAY_COUNT(fAASamples));
547 GLint samples = fAASamples[desc.fAALevel];
548 if (kNone_MSFBO == fMSFBOType && desc.fAALevel != kNone_AALevel) {
549 GrPrintf("AA RT requested but not supported on this platform.");
550 }
551
552 GR_GL(GenTextures(1, &glDesc.fTextureID));
553 if (!glDesc.fTextureID) {
554 return return_null_texture();
555 }
556
557 glDesc.fUploadByteCount = GrTexture::BytesPerPixel(desc.fFormat);
558
559 /*
560 * check if our srcData has extra bytes past each row. If so, we need
561 * to trim those off here, since GL doesn't let us pass the rowBytes as
562 * a parameter to glTexImage2D
563 */
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000564#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000565 if (srcData) {
566 GR_GL(PixelStorei(GL_UNPACK_ROW_LENGTH,
567 rowBytes / glDesc.fUploadByteCount));
568 }
569#else
570 GrAutoSMalloc<128 * 128> trimStorage;
571 size_t trimRowBytes = desc.fWidth * glDesc.fUploadByteCount;
572 if (srcData && (trimRowBytes < rowBytes)) {
573 size_t trimSize = desc.fHeight * trimRowBytes;
574 trimStorage.realloc(trimSize);
575 // now copy the data into our new storage, skipping the trailing bytes
576 const char* src = (const char*)srcData;
577 char* dst = (char*)trimStorage.get();
578 for (uint32_t y = 0; y < desc.fHeight; y++) {
579 memcpy(dst, src, trimRowBytes);
580 src += rowBytes;
581 dst += trimRowBytes;
582 }
583 // now point srcData to our trimmed version
584 srcData = trimStorage.get();
585 }
586#endif
587
reed@google.comac10a2d2010-12-22 21:39:39 +0000588 if (renderTarget) {
bsalomon@google.com0748f212011-02-01 22:56:16 +0000589 if (!this->npotRenderTargetSupport()) {
590 glDesc.fAllocWidth = GrNextPow2(desc.fWidth);
591 glDesc.fAllocHeight = GrNextPow2(desc.fHeight);
592 }
593
reed@google.comac10a2d2010-12-22 21:39:39 +0000594 glDesc.fAllocWidth = GrMax<int>(fMinRenderTargetWidth,
595 glDesc.fAllocWidth);
596 glDesc.fAllocHeight = GrMax<int>(fMinRenderTargetHeight,
597 glDesc.fAllocHeight);
bsalomon@google.com0748f212011-02-01 22:56:16 +0000598 } else if (!this->npotTextureSupport()) {
599 glDesc.fAllocWidth = GrNextPow2(desc.fWidth);
600 glDesc.fAllocHeight = GrNextPow2(desc.fHeight);
reed@google.comac10a2d2010-12-22 21:39:39 +0000601 }
602
603 GR_GL(BindTexture(GL_TEXTURE_2D, glDesc.fTextureID));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000604 GR_GL(TexParameteri(GL_TEXTURE_2D,
605 GL_TEXTURE_MAG_FILTER,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000606 DEFAULT_PARAMS.fFilter));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000607 GR_GL(TexParameteri(GL_TEXTURE_2D,
608 GL_TEXTURE_MIN_FILTER,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000609 DEFAULT_PARAMS.fFilter));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000610 GR_GL(TexParameteri(GL_TEXTURE_2D,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000611 GL_TEXTURE_WRAP_S,
612 DEFAULT_PARAMS.fWrapS));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000613 GR_GL(TexParameteri(GL_TEXTURE_2D,
614 GL_TEXTURE_WRAP_T,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000615 DEFAULT_PARAMS.fWrapT));
reed@google.comac10a2d2010-12-22 21:39:39 +0000616
617 GR_GL(PixelStorei(GL_UNPACK_ALIGNMENT, glDesc.fUploadByteCount));
618 if (GrTexture::kIndex_8_PixelConfig == desc.fFormat &&
619 supports8BitPalette()) {
620 // ES only supports CompressedTexImage2D, not CompressedTexSubimage2D
621 GrAssert(desc.fWidth == glDesc.fAllocWidth);
622 GrAssert(desc.fHeight == glDesc.fAllocHeight);
623 GLsizei imageSize = glDesc.fAllocWidth * glDesc.fAllocHeight +
624 kColorTableSize;
625 GR_GL(CompressedTexImage2D(GL_TEXTURE_2D, 0, glDesc.fUploadFormat,
626 glDesc.fAllocWidth, glDesc.fAllocHeight,
627 0, imageSize, srcData));
628 GrGL_RestoreResetRowLength();
629 } else {
630 if (NULL != srcData && (glDesc.fAllocWidth != desc.fWidth ||
631 glDesc.fAllocHeight != desc.fHeight)) {
632 GR_GL(TexImage2D(GL_TEXTURE_2D, 0, internalFormat,
633 glDesc.fAllocWidth, glDesc.fAllocHeight,
634 0, glDesc.fUploadFormat, glDesc.fUploadType, NULL));
635 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, desc.fWidth,
636 desc.fHeight, glDesc.fUploadFormat,
637 glDesc.fUploadType, srcData));
638 GrGL_RestoreResetRowLength();
639
640 uint32_t extraW = glDesc.fAllocWidth - desc.fWidth;
641 uint32_t extraH = glDesc.fAllocHeight - desc.fHeight;
642 uint32_t maxTexels = extraW * extraH;
643 maxTexels = GrMax(extraW * desc.fHeight, maxTexels);
644 maxTexels = GrMax(desc.fWidth * extraH, maxTexels);
645
646 GrAutoSMalloc<128*128> texels(glDesc.fUploadByteCount * maxTexels);
647
648 uint32_t rowSize = desc.fWidth * glDesc.fUploadByteCount;
649 if (extraH) {
650 uint8_t* lastRowStart = (uint8_t*) srcData +
651 (desc.fHeight - 1) * rowSize;
652 uint8_t* extraRowStart = (uint8_t*)texels.get();
653
654 for (uint32_t i = 0; i < extraH; ++i) {
655 memcpy(extraRowStart, lastRowStart, rowSize);
656 extraRowStart += rowSize;
657 }
658 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, 0, desc.fHeight, desc.fWidth,
659 extraH, glDesc.fUploadFormat, glDesc.fUploadType,
660 texels.get()));
661 }
662 if (extraW) {
663 uint8_t* edgeTexel = (uint8_t*)srcData + rowSize - glDesc.fUploadByteCount;
664 uint8_t* extraTexel = (uint8_t*)texels.get();
665 for (uint32_t j = 0; j < desc.fHeight; ++j) {
666 for (uint32_t i = 0; i < extraW; ++i) {
667 memcpy(extraTexel, edgeTexel, glDesc.fUploadByteCount);
668 extraTexel += glDesc.fUploadByteCount;
669 }
670 edgeTexel += rowSize;
671 }
672 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, desc.fWidth, 0, extraW,
673 desc.fHeight, glDesc.fUploadFormat,
674 glDesc.fUploadType, texels.get()));
675 }
676 if (extraW && extraH) {
677 uint8_t* cornerTexel = (uint8_t*)srcData + desc.fHeight * rowSize
678 - glDesc.fUploadByteCount;
679 uint8_t* extraTexel = (uint8_t*)texels.get();
680 for (uint32_t i = 0; i < extraW*extraH; ++i) {
681 memcpy(extraTexel, cornerTexel, glDesc.fUploadByteCount);
682 extraTexel += glDesc.fUploadByteCount;
683 }
684 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, desc.fWidth, desc.fHeight,
685 extraW, extraH, glDesc.fUploadFormat,
686 glDesc.fUploadType, texels.get()));
687 }
688
689 } else {
690 GR_GL(TexImage2D(GL_TEXTURE_2D, 0, internalFormat, glDesc.fAllocWidth,
691 glDesc.fAllocHeight, 0, glDesc.fUploadFormat,
692 glDesc.fUploadType, srcData));
693 GrGL_RestoreResetRowLength();
694 }
695 }
696
697 glDesc.fOrientation = GrGLTexture::kTopDown_Orientation;
698
699 GrGLRenderTarget::GLRenderTargetIDs rtIDs;
700 rtIDs.fStencilRenderbufferID = 0;
701 rtIDs.fMSColorRenderbufferID = 0;
702 rtIDs.fRTFBOID = 0;
703 rtIDs.fTexFBOID = 0;
704 rtIDs.fOwnIDs = true;
705 GLenum msColorRenderbufferFormat = -1;
706
707 if (renderTarget) {
708#if GR_COLLECT_STATS
709 ++fStats.fRenderTargetCreateCnt;
710#endif
711 bool failed = true;
712 GLenum status;
713 GLint err;
714
715 // If need have both RT flag and srcData we have
716 // to invert the data before uploading because FBO
717 // will be rendered bottom up
718 GrAssert(NULL == srcData);
719 glDesc.fOrientation = GrGLTexture::kBottomUp_Orientation;
720
721 GR_GLEXT(fExts, GenFramebuffers(1, &rtIDs.fTexFBOID));
722 GrAssert(rtIDs.fTexFBOID);
723
724 // If we are using multisampling and any extension other than the IMG
725 // one we will create two FBOs. We render to one and then resolve to
726 // the texture bound to the other. The IMG extension does an implicit
727 // resolve.
728 if (samples > 1 && kIMG_MSFBO != fMSFBOType && kNone_MSFBO != fMSFBOType) {
729 GR_GLEXT(fExts, GenFramebuffers(1, &rtIDs.fRTFBOID));
730 GrAssert(0 != rtIDs.fRTFBOID);
731 GR_GLEXT(fExts, GenRenderbuffers(1, &rtIDs.fMSColorRenderbufferID));
732 GrAssert(0 != rtIDs.fMSColorRenderbufferID);
733 if (!fboInternalFormat(desc.fFormat, &msColorRenderbufferFormat)) {
734 GR_GLEXT(fExts,
735 DeleteRenderbuffers(1, &rtIDs.fMSColorRenderbufferID));
736 GR_GL(DeleteTextures(1, &glDesc.fTextureID));
737 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fTexFBOID));
738 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fRTFBOID));
reed@google.comac10a2d2010-12-22 21:39:39 +0000739 return return_null_texture();
740 }
741 } else {
742 rtIDs.fRTFBOID = rtIDs.fTexFBOID;
743 }
744 int attempts = 1;
745 if (!(kNoPathRendering_TextureFlag & desc.fFlags)) {
746 GR_GLEXT(fExts, GenRenderbuffers(1, &rtIDs.fStencilRenderbufferID));
747 GrAssert(0 != rtIDs.fStencilRenderbufferID);
748 attempts = GR_ARRAY_COUNT(GR_GL_STENCIL_FORMAT_ARRAY);
749 }
750
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000751 // someone suggested that some systems might require
bsalomon@google.com316f99232011-01-13 21:28:12 +0000752 // unbinding the texture before we call FramebufferTexture2D
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000753 // (seems unlikely)
reed@google.comac10a2d2010-12-22 21:39:39 +0000754 GR_GL(BindTexture(GL_TEXTURE_2D, 0));
reed@google.comac10a2d2010-12-22 21:39:39 +0000755
756 err = ~GL_NO_ERROR;
757 for (int i = 0; i < attempts; ++i) {
758 if (rtIDs.fStencilRenderbufferID) {
759 GR_GLEXT(fExts, BindRenderbuffer(GR_RENDERBUFFER,
760 rtIDs.fStencilRenderbufferID));
761 if (samples > 1) {
762 GR_GLEXT_NO_ERR(fExts, RenderbufferStorageMultisample(
763 GR_RENDERBUFFER,
764 samples,
765 GR_GL_STENCIL_FORMAT_ARRAY[i],
766 glDesc.fAllocWidth,
767 glDesc.fAllocHeight));
768 } else {
769 GR_GLEXT_NO_ERR(fExts, RenderbufferStorage(
770 GR_RENDERBUFFER,
771 GR_GL_STENCIL_FORMAT_ARRAY[i],
772 glDesc.fAllocWidth,
773 glDesc.fAllocHeight));
774 }
775 err = glGetError();
776 if (err != GL_NO_ERROR) {
777 continue;
778 }
779 }
780 if (rtIDs.fRTFBOID != rtIDs.fTexFBOID) {
781 GrAssert(samples > 1);
782 GR_GLEXT(fExts, BindRenderbuffer(GR_RENDERBUFFER,
783 rtIDs.fMSColorRenderbufferID));
784 GR_GLEXT_NO_ERR(fExts, RenderbufferStorageMultisample(
785 GR_RENDERBUFFER,
786 samples,
787 msColorRenderbufferFormat,
788 glDesc.fAllocWidth,
789 glDesc.fAllocHeight));
790 err = glGetError();
791 if (err != GL_NO_ERROR) {
792 continue;
793 }
794 }
795 GR_GLEXT(fExts, BindFramebuffer(GR_FRAMEBUFFER, rtIDs.fTexFBOID));
796
797#if GR_COLLECT_STATS
798 ++fStats.fRenderTargetChngCnt;
799#endif
800 if (kIMG_MSFBO == fMSFBOType && samples > 1) {
801 GR_GLEXT(fExts, FramebufferTexture2DMultisample(
802 GR_FRAMEBUFFER,
803 GR_COLOR_ATTACHMENT0,
804 GL_TEXTURE_2D,
805 glDesc.fTextureID,
806 0,
807 samples));
808
809 } else {
810 GR_GLEXT(fExts, FramebufferTexture2D(GR_FRAMEBUFFER,
811 GR_COLOR_ATTACHMENT0,
812 GL_TEXTURE_2D,
813 glDesc.fTextureID, 0));
814 }
815 if (rtIDs.fRTFBOID != rtIDs.fTexFBOID) {
816 GLenum status = GR_GLEXT(fExts,
817 CheckFramebufferStatus(GR_FRAMEBUFFER));
818 if (status != GR_FRAMEBUFFER_COMPLETE) {
819 GrPrintf("-- glCheckFramebufferStatus %x %d %d\n",
820 status, desc.fWidth, desc.fHeight);
821 continue;
822 }
823 GR_GLEXT(fExts, BindFramebuffer(GR_FRAMEBUFFER, rtIDs.fRTFBOID));
824 #if GR_COLLECT_STATS
825 ++fStats.fRenderTargetChngCnt;
826 #endif
827 GR_GLEXT(fExts, FramebufferRenderbuffer(GR_FRAMEBUFFER,
828 GR_COLOR_ATTACHMENT0,
829 GR_RENDERBUFFER,
830 rtIDs.fMSColorRenderbufferID));
831
832 }
833 if (rtIDs.fStencilRenderbufferID) {
834 // bind the stencil to rt fbo if present, othewise the tex fbo
835 GR_GLEXT(fExts, FramebufferRenderbuffer(GR_FRAMEBUFFER,
836 GR_STENCIL_ATTACHMENT,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000837 GR_RENDERBUFFER,
reed@google.comac10a2d2010-12-22 21:39:39 +0000838 rtIDs.fStencilRenderbufferID));
839 }
840 status = GR_GLEXT(fExts, CheckFramebufferStatus(GR_FRAMEBUFFER));
841
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000842#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000843 // On some implementations you have to be bound as DEPTH_STENCIL.
844 // (Even binding to DEPTH and STENCIL separately with the same
845 // buffer doesn't work.)
846 if (rtIDs.fStencilRenderbufferID &&
847 status != GR_FRAMEBUFFER_COMPLETE) {
848 GR_GLEXT(fExts, FramebufferRenderbuffer(GR_FRAMEBUFFER,
849 GR_STENCIL_ATTACHMENT,
850 GR_RENDERBUFFER,
851 0));
852 GR_GLEXT(fExts,
853 FramebufferRenderbuffer(GR_FRAMEBUFFER,
854 GR_DEPTH_STENCIL_ATTACHMENT,
855 GR_RENDERBUFFER,
856 rtIDs.fStencilRenderbufferID));
857 status = GR_GLEXT(fExts, CheckFramebufferStatus(GR_FRAMEBUFFER));
858 }
859#endif
860 if (status != GR_FRAMEBUFFER_COMPLETE) {
861 GrPrintf("-- glCheckFramebufferStatus %x %d %d\n",
862 status, desc.fWidth, desc.fHeight);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000863#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000864 if (rtIDs.fStencilRenderbufferID) {
865 GR_GLEXT(fExts, FramebufferRenderbuffer(GR_FRAMEBUFFER,
866 GR_DEPTH_STENCIL_ATTACHMENT,
867 GR_RENDERBUFFER,
868 0));
869 }
870#endif
871 continue;
872 }
873 // we're successful!
874 failed = false;
875 break;
876 }
877 if (failed) {
878 if (rtIDs.fStencilRenderbufferID) {
879 GR_GLEXT(fExts,
880 DeleteRenderbuffers(1, &rtIDs.fStencilRenderbufferID));
881 }
882 if (rtIDs.fMSColorRenderbufferID) {
883 GR_GLEXT(fExts,
884 DeleteRenderbuffers(1, &rtIDs.fMSColorRenderbufferID));
885 }
886 if (rtIDs.fRTFBOID != rtIDs.fTexFBOID) {
887 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fRTFBOID));
888 }
889 if (rtIDs.fTexFBOID) {
890 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fTexFBOID));
891 }
892 GR_GL(DeleteTextures(1, &glDesc.fTextureID));
893 return return_null_texture();
894 }
895 }
896#ifdef TRACE_TEXTURE_CREATION
897 GrPrintf("--- new texture [%d] size=(%d %d) bpp=%d\n",
898 tex->fTextureID, width, height, tex->fUploadByteCount);
899#endif
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000900 GrGLTexture* tex = new GrGLTexture(glDesc, rtIDs, DEFAULT_PARAMS, this);
reed@google.comac10a2d2010-12-22 21:39:39 +0000901
902 if (0 != rtIDs.fTexFBOID) {
903 GrRenderTarget* rt = tex->asRenderTarget();
904 // We've messed with FBO state but may not have set the correct viewport
905 // so just dirty the rendertarget state to force a resend.
906 fHWDrawState.fRenderTarget = NULL;
907
908 // clear the new stencil buffer if we have one
909 if (!(desc.fFlags & kNoPathRendering_TextureFlag)) {
910 GrRenderTarget* rtSave = fCurrDrawState.fRenderTarget;
911 fCurrDrawState.fRenderTarget = rt;
912 eraseStencil(0, ~0);
913 fCurrDrawState.fRenderTarget = rtSave;
914 }
915 }
916 return tex;
917}
918
reed@google.comac10a2d2010-12-22 21:39:39 +0000919GrVertexBuffer* GrGpuGL::createVertexBuffer(uint32_t size, bool dynamic) {
920 GLuint id;
921 GR_GL(GenBuffers(1, &id));
922 if (id) {
923 GR_GL(BindBuffer(GL_ARRAY_BUFFER, id));
924 GrGLClearErr();
925 // make sure driver can allocate memory for this buffer
926 GR_GL_NO_ERR(BufferData(GL_ARRAY_BUFFER, size, NULL,
927 dynamic ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW));
928 if (glGetError() != GL_NO_ERROR) {
929 GR_GL(DeleteBuffers(1, &id));
930 // deleting bound buffer does implicit bind to 0
931 fHWGeometryState.fVertexBuffer = NULL;
932 return NULL;
933 }
934 GrGLVertexBuffer* vertexBuffer = new GrGLVertexBuffer(id, this,
935 size, dynamic);
936 fHWGeometryState.fVertexBuffer = vertexBuffer;
937 return vertexBuffer;
938 }
939 return NULL;
940}
941
942GrIndexBuffer* GrGpuGL::createIndexBuffer(uint32_t size, bool dynamic) {
943 GLuint id;
944 GR_GL(GenBuffers(1, &id));
945 if (id) {
946 GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, id));
947 GrGLClearErr();
948 // make sure driver can allocate memory for this buffer
949 GR_GL_NO_ERR(BufferData(GL_ELEMENT_ARRAY_BUFFER, size, NULL,
950 dynamic ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW));
951 if (glGetError() != GL_NO_ERROR) {
952 GR_GL(DeleteBuffers(1, &id));
953 // deleting bound buffer does implicit bind to 0
954 fHWGeometryState.fIndexBuffer = NULL;
955 return NULL;
956 }
957 GrIndexBuffer* indexBuffer = new GrGLIndexBuffer(id, this,
958 size, dynamic);
959 fHWGeometryState.fIndexBuffer = indexBuffer;
960 return indexBuffer;
961 }
962 return NULL;
963}
964
reed@google.comac10a2d2010-12-22 21:39:39 +0000965void GrGpuGL::flushScissor(const GrIRect* rect) {
966 GrAssert(NULL != fCurrDrawState.fRenderTarget);
967 const GrIRect& vp =
968 ((GrGLRenderTarget*)fCurrDrawState.fRenderTarget)->viewport();
969
970 if (NULL != rect &&
971 rect->contains(vp)) {
972 rect = NULL;
973 }
974
975 if (NULL != rect) {
976 GrIRect scissor;
977 // viewport is already in GL coords
978 // create a scissor in GL coords (top > bottom)
979 scissor.setLTRB(vp.fLeft + rect->fLeft,
980 vp.fTop - rect->fTop,
981 vp.fLeft + rect->fRight,
982 vp.fTop - rect->fBottom);
983
984 if (fHWBounds.fScissorRect != scissor) {
985 GR_GL(Scissor(scissor.fLeft, scissor.fBottom,
986 scissor.width(), -scissor.height()));
987 fHWBounds.fScissorRect = scissor;
988 }
989
990 if (!fHWBounds.fScissorEnabled) {
991 GR_GL(Enable(GL_SCISSOR_TEST));
992 fHWBounds.fScissorEnabled = true;
993 }
994 } else {
995 if (fHWBounds.fScissorEnabled) {
996 GR_GL(Disable(GL_SCISSOR_TEST));
997 fHWBounds.fScissorEnabled = false;
998 }
999 }
1000}
1001
reed@google.comac10a2d2010-12-22 21:39:39 +00001002void GrGpuGL::eraseColor(GrColor color) {
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +00001003 if (NULL == fCurrDrawState.fRenderTarget) {
1004 return;
1005 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001006 flushRenderTarget();
1007 if (fHWBounds.fScissorEnabled) {
1008 GR_GL(Disable(GL_SCISSOR_TEST));
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +00001009 fHWBounds.fScissorEnabled = false;
reed@google.comac10a2d2010-12-22 21:39:39 +00001010 }
1011 GR_GL(ColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE));
1012 GR_GL(ClearColor(GrColorUnpackR(color)/255.f,
1013 GrColorUnpackG(color)/255.f,
1014 GrColorUnpackB(color)/255.f,
1015 GrColorUnpackA(color)/255.f));
1016 GR_GL(Clear(GL_COLOR_BUFFER_BIT));
reed@google.comac10a2d2010-12-22 21:39:39 +00001017 fWriteMaskChanged = true;
1018}
1019
1020void GrGpuGL::eraseStencil(uint32_t value, uint32_t mask) {
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +00001021 if (NULL == fCurrDrawState.fRenderTarget) {
1022 return;
1023 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001024 flushRenderTarget();
1025 if (fHWBounds.fScissorEnabled) {
1026 GR_GL(Disable(GL_SCISSOR_TEST));
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +00001027 fHWBounds.fScissorEnabled = false;
reed@google.comac10a2d2010-12-22 21:39:39 +00001028 }
1029 GR_GL(StencilMask(mask));
1030 GR_GL(ClearStencil(value));
1031 GR_GL(Clear(GL_STENCIL_BUFFER_BIT));
reed@google.comac10a2d2010-12-22 21:39:39 +00001032 fWriteMaskChanged = true;
1033}
1034
1035void GrGpuGL::eraseStencilClip() {
1036 GLint stencilBitCount;
reed@google.comac20fb92011-01-12 17:14:53 +00001037 GR_GL_GetIntegerv(GL_STENCIL_BITS, &stencilBitCount);
reed@google.comac10a2d2010-12-22 21:39:39 +00001038 GrAssert(stencilBitCount > 0);
1039 GLint clipStencilMask = (1 << (stencilBitCount - 1));
1040 eraseStencil(0, clipStencilMask);
1041}
1042
1043void GrGpuGL::forceRenderTargetFlush() {
1044 flushRenderTarget();
1045}
1046
1047bool GrGpuGL::readPixels(int left, int top, int width, int height,
1048 GrTexture::PixelConfig config, void* buffer) {
1049 GLenum internalFormat; // we don't use this for glReadPixels
1050 GLenum format;
1051 GLenum type;
1052 if (!this->canBeTexture(config, &internalFormat, &format, &type)) {
1053 return false;
1054 }
1055
1056 GrAssert(NULL != fCurrDrawState.fRenderTarget);
1057 const GrIRect& vp = ((GrGLRenderTarget*)fCurrDrawState.fRenderTarget)->viewport();
1058
1059 // Brian says that viewport rects are already upside down (grrrrr)
bsalomon@google.com316f99232011-01-13 21:28:12 +00001060 GR_GL(ReadPixels(left, -vp.height() - top - height, width, height,
1061 format, type, buffer));
reed@google.comac10a2d2010-12-22 21:39:39 +00001062
1063 // now reverse the order of the rows, since GL's are bottom-to-top, but our
1064 // API presents top-to-bottom
1065 {
1066 size_t stride = width * GrTexture::BytesPerPixel(config);
1067 GrAutoMalloc rowStorage(stride);
1068 void* tmp = rowStorage.get();
1069
1070 const int halfY = height >> 1;
1071 char* top = reinterpret_cast<char*>(buffer);
1072 char* bottom = top + (height - 1) * stride;
1073 for (int y = 0; y < halfY; y++) {
1074 memcpy(tmp, top, stride);
1075 memcpy(top, bottom, stride);
1076 memcpy(bottom, tmp, stride);
1077 top += stride;
1078 bottom -= stride;
1079 }
1080 }
1081 return true;
1082}
1083
1084void GrGpuGL::flushRenderTarget() {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001085
1086 GrAssert(NULL != fCurrDrawState.fRenderTarget);
1087
reed@google.comac10a2d2010-12-22 21:39:39 +00001088 if (fHWDrawState.fRenderTarget != fCurrDrawState.fRenderTarget) {
1089 GrGLRenderTarget* rt = (GrGLRenderTarget*)fCurrDrawState.fRenderTarget;
1090 GR_GLEXT(fExts, BindFramebuffer(GR_FRAMEBUFFER, rt->renderFBOID()));
1091 #if GR_COLLECT_STATS
1092 ++fStats.fRenderTargetChngCnt;
1093 #endif
1094 rt->setDirty(true);
1095 #if GR_DEBUG
1096 GLenum status = GR_GLEXT(fExts, CheckFramebufferStatus(GR_FRAMEBUFFER));
1097 if (status != GR_FRAMEBUFFER_COMPLETE) {
1098 GrPrintf("-- glCheckFramebufferStatus %x\n", status);
1099 }
1100 #endif
1101 fHWDrawState.fRenderTarget = fCurrDrawState.fRenderTarget;
1102 const GrIRect& vp = rt->viewport();
1103 fRenderTargetChanged = true;
1104 if (fHWBounds.fViewportRect != vp) {
1105 GR_GL(Viewport(vp.fLeft,
1106 vp.fBottom,
1107 vp.width(),
1108 -vp.height()));
1109 fHWBounds.fViewportRect = vp;
1110 }
1111 }
1112}
1113
1114GLenum gPrimitiveType2GLMode[] = {
1115 GL_TRIANGLES,
1116 GL_TRIANGLE_STRIP,
1117 GL_TRIANGLE_FAN,
1118 GL_POINTS,
1119 GL_LINES,
1120 GL_LINE_STRIP
1121};
1122
1123void GrGpuGL::drawIndexedHelper(PrimitiveType type,
1124 uint32_t startVertex,
1125 uint32_t startIndex,
1126 uint32_t vertexCount,
1127 uint32_t indexCount) {
1128 GrAssert((size_t)type < GR_ARRAY_COUNT(gPrimitiveType2GLMode));
1129
1130 GLvoid* indices = (GLvoid*)(sizeof(uint16_t) * startIndex);
1131 if (kReserved_GeometrySrcType == fGeometrySrc.fIndexSrc) {
1132 indices = (GLvoid*)((intptr_t)indices + (intptr_t)fIndices.get());
1133 } else if (kArray_GeometrySrcType == fGeometrySrc.fIndexSrc) {
1134 indices = (GLvoid*)((intptr_t)indices +
1135 (intptr_t)fGeometrySrc.fIndexArray);
1136 }
1137
1138 GR_GL(DrawElements(gPrimitiveType2GLMode[type], indexCount,
1139 GL_UNSIGNED_SHORT, indices));
1140}
1141
1142void GrGpuGL::drawNonIndexedHelper(PrimitiveType type,
1143 uint32_t startVertex,
1144 uint32_t vertexCount) {
1145 GrAssert((size_t)type < GR_ARRAY_COUNT(gPrimitiveType2GLMode));
1146
1147 GR_GL(DrawArrays(gPrimitiveType2GLMode[type], 0, vertexCount));
1148}
1149
reed@google.comac10a2d2010-12-22 21:39:39 +00001150void GrGpuGL::resolveTextureRenderTarget(GrGLTexture* texture) {
1151 GrGLRenderTarget* rt = (GrGLRenderTarget*) texture->asRenderTarget();
1152
1153 if (NULL != rt && rt->needsResolve()) {
1154 GrAssert(kNone_MSFBO != fMSFBOType);
1155 GrAssert(rt->textureFBOID() != rt->renderFBOID());
1156 GR_GLEXT(fExts, BindFramebuffer(GR_READ_FRAMEBUFFER,
1157 rt->renderFBOID()));
1158 GR_GLEXT(fExts, BindFramebuffer(GR_DRAW_FRAMEBUFFER,
1159 rt->textureFBOID()));
1160 #if GR_COLLECT_STATS
1161 ++fStats.fRenderTargetChngCnt;
1162 #endif
1163 // make sure we go through set render target
1164 fHWDrawState.fRenderTarget = NULL;
1165
1166 GLint left = 0;
1167 GLint right = texture->contentWidth();
1168 // we will have rendered to the top of the FBO.
1169 GLint top = texture->allocHeight();
1170 GLint bottom = texture->allocHeight() - texture->contentHeight();
1171 if (kApple_MSFBO == fMSFBOType) {
1172 GR_GL(Enable(GL_SCISSOR_TEST));
1173 GR_GL(Scissor(left, bottom, right-left, top-bottom));
1174 GR_GLEXT(fExts, ResolveMultisampleFramebuffer());
1175 fHWBounds.fScissorRect.setEmpty();
1176 fHWBounds.fScissorEnabled = true;
1177 } else {
1178 GR_GLEXT(fExts, BlitFramebuffer(left, bottom, right, top,
1179 left, bottom, right, top,
1180 GL_COLOR_BUFFER_BIT, GL_NEAREST));
1181 }
1182 rt->setDirty(false);
1183
1184 }
1185}
1186
1187void GrGpuGL::flushStencil() {
1188
1189 // use stencil for clipping if clipping is enabled and the clip
1190 // has been written into the stencil.
1191 bool stencilClip = fClipState.fClipInStencil &&
1192 (kClip_StateBit & fCurrDrawState.fFlagBits);
1193 bool stencilChange =
1194 fWriteMaskChanged ||
1195 fHWStencilClip != stencilClip ||
1196 fHWDrawState.fStencilPass != fCurrDrawState.fStencilPass ||
1197 (kNone_StencilPass != fCurrDrawState.fStencilPass &&
1198 (StencilPass)kSetClip_StencilPass != fCurrDrawState.fStencilPass &&
1199 fHWDrawState.fReverseFill != fCurrDrawState.fReverseFill);
1200
1201 if (stencilChange) {
1202 GLint stencilBitCount;
1203 GLint clipStencilMask;
1204 GLint pathStencilMask;
reed@google.comac20fb92011-01-12 17:14:53 +00001205 GR_GL_GetIntegerv(GL_STENCIL_BITS, &stencilBitCount);
reed@google.comac10a2d2010-12-22 21:39:39 +00001206 GrAssert(stencilBitCount > 0 ||
1207 kNone_StencilPass == fCurrDrawState.fStencilPass);
1208 clipStencilMask = (1 << (stencilBitCount - 1));
1209 pathStencilMask = clipStencilMask - 1;
1210 switch (fCurrDrawState.fStencilPass) {
1211 case kNone_StencilPass:
1212 if (stencilClip) {
1213 GR_GL(Enable(GL_STENCIL_TEST));
1214 GR_GL(StencilFunc(GL_EQUAL,
1215 clipStencilMask,
1216 clipStencilMask));
1217 GR_GL(StencilOp(GL_KEEP, GL_KEEP, GL_KEEP));
1218 } else {
1219 GR_GL(Disable(GL_STENCIL_TEST));
1220 }
1221 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
1222 if (!fSingleStencilPassForWinding) {
1223 GR_GL(Disable(GL_CULL_FACE));
1224 }
1225 break;
1226 case kEvenOddStencil_StencilPass:
1227 GR_GL(Enable(GL_STENCIL_TEST));
1228 if (stencilClip) {
1229 GR_GL(StencilFunc(GL_EQUAL, clipStencilMask, clipStencilMask));
1230 } else {
1231 GR_GL(StencilFunc(GL_ALWAYS, 0x0, 0x0));
1232 }
1233 GR_GL(StencilMask(pathStencilMask));
1234 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
1235 GR_GL(StencilOp(GL_KEEP, GL_INVERT, GL_INVERT));
1236 GR_GL(ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE));
1237 if (!fSingleStencilPassForWinding) {
1238 GR_GL(Disable(GL_CULL_FACE));
1239 }
1240 break;
1241 case kEvenOddColor_StencilPass: {
1242 GR_GL(Enable(GL_STENCIL_TEST));
1243 GLint funcRef = 0;
1244 GLuint funcMask = pathStencilMask;
1245 if (stencilClip) {
1246 funcRef |= clipStencilMask;
1247 funcMask |= clipStencilMask;
1248 }
1249 if (!fCurrDrawState.fReverseFill) {
1250 funcRef |= pathStencilMask;
1251 }
bsalomon@google.com316f99232011-01-13 21:28:12 +00001252 GR_GL(StencilFunc(GL_EQUAL, funcRef, funcMask));
1253 GR_GL(StencilMask(pathStencilMask));
reed@google.comac10a2d2010-12-22 21:39:39 +00001254 GR_GL(StencilOp(GL_ZERO, GL_ZERO, GL_ZERO));
1255 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
1256 if (!fSingleStencilPassForWinding) {
1257 GR_GL(Disable(GL_CULL_FACE));
1258 }
1259 } break;
1260 case kWindingStencil1_StencilPass:
1261 GR_GL(Enable(GL_STENCIL_TEST));
1262 if (fHasStencilWrap) {
1263 if (stencilClip) {
1264 GR_GL(StencilFunc(GL_EQUAL,
1265 clipStencilMask,
1266 clipStencilMask));
1267 } else {
1268 GR_GL(StencilFunc(GL_ALWAYS, 0x0, 0x0));
1269 }
1270 if (fSingleStencilPassForWinding) {
1271 GR_GL(StencilOpSeparate(GL_FRONT, GL_KEEP,
1272 GL_INCR_WRAP, GL_INCR_WRAP));
1273 GR_GL(StencilOpSeparate(GL_BACK, GL_KEEP,
1274 GL_DECR_WRAP, GL_DECR_WRAP));
1275 } else {
1276 GR_GL(StencilOp(GL_KEEP, GL_INCR_WRAP, GL_INCR_WRAP));
1277 GR_GL(Enable(GL_CULL_FACE));
1278 GR_GL(CullFace(GL_BACK));
1279 }
1280 } else {
1281 // If we don't have wrap then we use the Func to detect
1282 // values that would wrap (0 on decr and mask on incr). We
1283 // make the func fail on these values and use the sfail op
1284 // to effectively wrap by inverting.
1285 // This applies whether we are doing a two-pass (front faces
1286 // followed by back faces) or a single pass (separate func/op)
1287
1288 // Note that in the case where we are also using stencil to
1289 // clip this means we will write into the path bits in clipped
1290 // out pixels. We still apply the clip bit in the color pass
1291 // stencil func so we don't draw color outside the clip.
1292 // We also will clear the stencil bits in clipped pixels by
1293 // using zero in the sfail op with write mask set to the
1294 // path mask.
1295 GR_GL(Enable(GL_STENCIL_TEST));
1296 if (fSingleStencilPassForWinding) {
1297 GR_GL(StencilFuncSeparate(GL_FRONT,
1298 GL_NOTEQUAL,
1299 pathStencilMask,
1300 pathStencilMask));
1301 GR_GL(StencilFuncSeparate(GL_BACK,
1302 GL_NOTEQUAL,
1303 0x0,
1304 pathStencilMask));
1305 GR_GL(StencilOpSeparate(GL_FRONT, GL_INVERT,
1306 GL_INCR, GL_INCR));
1307 GR_GL(StencilOpSeparate(GL_BACK, GL_INVERT,
1308 GL_DECR, GL_DECR));
1309 } else {
1310 GR_GL(StencilFunc(GL_NOTEQUAL,
1311 pathStencilMask,
1312 pathStencilMask));
1313 GR_GL(StencilOp(GL_INVERT, GL_INCR, GL_INCR));
1314 GR_GL(Enable(GL_CULL_FACE));
1315 GR_GL(CullFace(GL_BACK));
1316 }
1317 }
1318 GR_GL(StencilMask(pathStencilMask));
1319 GR_GL(ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE));
1320 break;
1321 case kWindingStencil2_StencilPass:
1322 GrAssert(!fSingleStencilPassForWinding);
1323 GR_GL(Enable(GL_STENCIL_TEST));
1324 if (fHasStencilWrap) {
1325 if (stencilClip) {
1326 GR_GL(StencilFunc(GL_EQUAL,
1327 clipStencilMask,
1328 clipStencilMask));
1329 } else {
1330 GR_GL(StencilFunc(GL_ALWAYS, 0x0, 0x0));
1331 }
1332 GR_GL(StencilOp(GL_DECR_WRAP, GL_DECR_WRAP, GL_DECR_WRAP));
1333 } else {
1334 GR_GL(StencilFunc(GL_NOTEQUAL, 0x0, pathStencilMask));
1335 GR_GL(StencilOp(GL_INVERT, GL_DECR, GL_DECR));
1336 }
1337 GR_GL(StencilMask(pathStencilMask));
1338 GR_GL(Enable(GL_CULL_FACE));
1339 GR_GL(CullFace(GL_FRONT));
1340 GR_GL(ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE));
1341 break;
1342 case kWindingColor_StencilPass: {
1343 GR_GL(Enable(GL_STENCIL_TEST));
1344 GLint funcRef = 0;
1345 GLuint funcMask = pathStencilMask;
1346 GLenum funcFunc;
1347 if (stencilClip) {
1348 funcRef |= clipStencilMask;
1349 funcMask |= clipStencilMask;
1350 }
1351 if (fCurrDrawState.fReverseFill) {
1352 funcFunc = GL_EQUAL;
1353 } else {
1354 funcFunc = GL_LESS;
1355 }
1356 GR_GL(StencilFunc(funcFunc, funcRef, funcMask));
1357 GR_GL(StencilMask(pathStencilMask));
1358 // must zero in sfail because winding w/o wrap will write
1359 // path stencil bits in clipped out pixels
1360 GR_GL(StencilOp(GL_ZERO, GL_ZERO, GL_ZERO));
1361 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
1362 if (!fSingleStencilPassForWinding) {
1363 GR_GL(Disable(GL_CULL_FACE));
1364 }
1365 } break;
1366 case kSetClip_StencilPass:
1367 GR_GL(Enable(GL_STENCIL_TEST));
1368 GR_GL(StencilFunc(GL_ALWAYS, clipStencilMask, clipStencilMask));
1369 GR_GL(StencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE));
1370 GR_GL(StencilMask(clipStencilMask));
1371 GR_GL(ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE));
1372 if (!fSingleStencilPassForWinding) {
1373 GR_GL(Disable(GL_CULL_FACE));
1374 }
1375 break;
1376 default:
1377 GrAssert(!"Unexpected stencil pass.");
1378 break;
1379
1380 }
1381 fHWDrawState.fStencilPass = fCurrDrawState.fStencilPass;
1382 fHWDrawState.fReverseFill = fCurrDrawState.fReverseFill;
1383 fWriteMaskChanged = false;
1384 fHWStencilClip = stencilClip;
1385 }
1386}
1387
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001388bool GrGpuGL::flushGLStateCommon(PrimitiveType type) {
1389
1390 // GrGpu::setupClipAndFlushState should have already checked this
1391 // and bailed if not true.
1392 GrAssert(NULL != fCurrDrawState.fRenderTarget);
reed@google.comac10a2d2010-12-22 21:39:39 +00001393
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001394 for (int s = 0; s < kNumStages; ++s) {
1395 bool usingTexture = VertexUsesStage(s, fGeometrySrc.fVertexLayout);
reed@google.comac10a2d2010-12-22 21:39:39 +00001396
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001397 // bind texture and set sampler state
1398 if (usingTexture) {
1399 GrGLTexture* nextTexture = (GrGLTexture*)fCurrDrawState.fTextures[s];
reed@google.comac10a2d2010-12-22 21:39:39 +00001400
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001401 if (NULL != nextTexture) {
bsalomon@google.com316f99232011-01-13 21:28:12 +00001402 // if we created a rt/tex and rendered to it without using a
1403 // texture and now we're texuring from the rt it will still be
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001404 // the last bound texture, but it needs resolving. So keep this
1405 // out of the "last != next" check.
1406 resolveTextureRenderTarget(nextTexture);
reed@google.comac10a2d2010-12-22 21:39:39 +00001407
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001408 if (fHWDrawState.fTextures[s] != nextTexture) {
1409 setTextureUnit(s);
1410 GR_GL(BindTexture(GL_TEXTURE_2D, nextTexture->textureID()));
1411 #if GR_COLLECT_STATS
1412 ++fStats.fTextureChngCnt;
1413 #endif
1414 //GrPrintf("---- bindtexture %d\n", nextTexture->textureID());
1415 fHWDrawState.fTextures[s] = nextTexture;
1416 }
bsalomon@google.com316f99232011-01-13 21:28:12 +00001417
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001418 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
bsalomon@google.com316f99232011-01-13 21:28:12 +00001419 const GrGLTexture::TexParams& oldTexParams =
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001420 nextTexture->getTexParams();
1421 GrGLTexture::TexParams newTexParams;
bsalomon@google.com316f99232011-01-13 21:28:12 +00001422
1423 newTexParams.fFilter = sampler.isFilter() ? GL_LINEAR :
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001424 GL_NEAREST;
bsalomon@google.com316f99232011-01-13 21:28:12 +00001425 newTexParams.fWrapS =
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001426 GrGLTexture::gWrapMode2GLWrap[sampler.getWrapX()];
bsalomon@google.com316f99232011-01-13 21:28:12 +00001427 newTexParams.fWrapT =
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001428 GrGLTexture::gWrapMode2GLWrap[sampler.getWrapY()];
reed@google.comac10a2d2010-12-22 21:39:39 +00001429
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001430 if (newTexParams.fFilter != oldTexParams.fFilter) {
1431 setTextureUnit(s);
bsalomon@google.com316f99232011-01-13 21:28:12 +00001432 GR_GL(TexParameteri(GL_TEXTURE_2D,
1433 GL_TEXTURE_MAG_FILTER,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001434 newTexParams.fFilter));
bsalomon@google.com316f99232011-01-13 21:28:12 +00001435 GR_GL(TexParameteri(GL_TEXTURE_2D,
1436 GL_TEXTURE_MIN_FILTER,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001437 newTexParams.fFilter));
1438 }
1439 if (newTexParams.fWrapS != oldTexParams.fWrapS) {
1440 setTextureUnit(s);
bsalomon@google.com316f99232011-01-13 21:28:12 +00001441 GR_GL(TexParameteri(GL_TEXTURE_2D,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001442 GL_TEXTURE_WRAP_S,
1443 newTexParams.fWrapS));
1444 }
1445 if (newTexParams.fWrapT != oldTexParams.fWrapT) {
1446 setTextureUnit(s);
bsalomon@google.com316f99232011-01-13 21:28:12 +00001447 GR_GL(TexParameteri(GL_TEXTURE_2D,
1448 GL_TEXTURE_WRAP_T,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001449 newTexParams.fWrapT));
1450 }
1451 nextTexture->setTexParams(newTexParams);
1452 } else {
1453 GrAssert(!"Rendering with texture vert flag set but no texture");
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001454 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +00001455 }
1456 }
1457 }
1458
1459 flushRenderTarget();
1460
1461 if ((fCurrDrawState.fFlagBits & kDither_StateBit) !=
1462 (fHWDrawState.fFlagBits & kDither_StateBit)) {
1463 if (fCurrDrawState.fFlagBits & kDither_StateBit) {
1464 GR_GL(Enable(GL_DITHER));
1465 } else {
1466 GR_GL(Disable(GL_DITHER));
1467 }
1468 }
1469
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001470#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +00001471 // ES doesn't support toggling GL_MULTISAMPLE and doesn't have
1472 // smooth lines.
1473 if (fRenderTargetChanged ||
1474 (fCurrDrawState.fFlagBits & kAntialias_StateBit) !=
1475 (fHWDrawState.fFlagBits & kAntialias_StateBit)) {
1476 GLint msaa = 0;
1477 // only perform query if we know MSAA is supported.
1478 // calling on non-MSAA target caused a crash in one environment,
1479 // though I don't think it should.
1480 if (!fAASamples[kHigh_AALevel]) {
reed@google.comac20fb92011-01-12 17:14:53 +00001481 GR_GL_GetIntegerv(GL_SAMPLE_BUFFERS, &msaa);
reed@google.comac10a2d2010-12-22 21:39:39 +00001482 }
1483 if (fCurrDrawState.fFlagBits & kAntialias_StateBit) {
1484 if (msaa) {
1485 GR_GL(Enable(GL_MULTISAMPLE));
1486 } else {
1487 GR_GL(Enable(GL_LINE_SMOOTH));
1488 }
1489 } else {
1490 if (msaa) {
1491 GR_GL(Disable(GL_MULTISAMPLE));
1492 }
1493 GR_GL(Disable(GL_LINE_SMOOTH));
1494 }
1495 }
1496#endif
1497
1498 bool blendOff = canDisableBlend();
1499 if (fHWBlendDisabled != blendOff) {
1500 if (blendOff) {
1501 GR_GL(Disable(GL_BLEND));
1502 } else {
1503 GR_GL(Enable(GL_BLEND));
1504 }
1505 fHWBlendDisabled = blendOff;
1506 }
1507
1508 if (!blendOff) {
1509 if (fHWDrawState.fSrcBlend != fCurrDrawState.fSrcBlend ||
1510 fHWDrawState.fDstBlend != fCurrDrawState.fDstBlend) {
1511 GR_GL(BlendFunc(gXfermodeCoeff2Blend[fCurrDrawState.fSrcBlend],
1512 gXfermodeCoeff2Blend[fCurrDrawState.fDstBlend]));
1513 fHWDrawState.fSrcBlend = fCurrDrawState.fSrcBlend;
1514 fHWDrawState.fDstBlend = fCurrDrawState.fDstBlend;
1515 }
1516 }
bsalomon@google.com316f99232011-01-13 21:28:12 +00001517
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001518#if GR_DEBUG
reed@google.comac10a2d2010-12-22 21:39:39 +00001519 // check for circular rendering
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001520 for (int s = 0; s < kNumStages; ++s) {
1521 GrAssert(!VertexUsesStage(s, fGeometrySrc.fVertexLayout) ||
1522 NULL == fCurrDrawState.fRenderTarget ||
1523 NULL == fCurrDrawState.fTextures[s] ||
bsalomon@google.com316f99232011-01-13 21:28:12 +00001524 fCurrDrawState.fTextures[s]->asRenderTarget() !=
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001525 fCurrDrawState.fRenderTarget);
1526 }
1527#endif
bsalomon@google.com316f99232011-01-13 21:28:12 +00001528
reed@google.comac10a2d2010-12-22 21:39:39 +00001529 flushStencil();
1530
1531 fHWDrawState.fFlagBits = fCurrDrawState.fFlagBits;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001532 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +00001533}
1534
1535void GrGpuGL::notifyVertexBufferBind(const GrGLVertexBuffer* buffer) {
1536 fHWGeometryState.fVertexBuffer = buffer;
1537}
1538
1539void GrGpuGL::notifyVertexBufferDelete(const GrGLVertexBuffer* buffer) {
1540 GrAssert(!(kBuffer_GeometrySrcType == fGeometrySrc.fVertexSrc &&
1541 buffer == fGeometrySrc.fVertexBuffer));
1542
1543 if (fHWGeometryState.fVertexBuffer == buffer) {
1544 // deleting bound buffer does implied bind to 0
1545 fHWGeometryState.fVertexBuffer = NULL;
1546 }
1547}
1548
1549void GrGpuGL::notifyIndexBufferBind(const GrGLIndexBuffer* buffer) {
1550 fGeometrySrc.fIndexBuffer = buffer;
1551}
1552
1553void GrGpuGL::notifyIndexBufferDelete(const GrGLIndexBuffer* buffer) {
1554 GrAssert(!(kBuffer_GeometrySrcType == fGeometrySrc.fIndexSrc &&
1555 buffer == fGeometrySrc.fIndexBuffer));
1556
1557 if (fHWGeometryState.fIndexBuffer == buffer) {
1558 // deleting bound buffer does implied bind to 0
1559 fHWGeometryState.fIndexBuffer = NULL;
1560 }
1561}
1562
reed@google.comac10a2d2010-12-22 21:39:39 +00001563void GrGpuGL::notifyRenderTargetDelete(GrRenderTarget* renderTarget) {
1564 GrAssert(NULL != renderTarget);
1565
1566 // if the bound FBO is destroyed we can't rely on the implicit bind to 0
1567 // a) we want the default RT which may not be FBO 0
1568 // b) we set more state than just FBO based on the RT
1569 // So trash the HW state to force an RT flush next time
1570 if (fCurrDrawState.fRenderTarget == renderTarget) {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001571 fCurrDrawState.fRenderTarget = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +00001572 }
1573 if (fHWDrawState.fRenderTarget == renderTarget) {
1574 fHWDrawState.fRenderTarget = NULL;
1575 }
1576 if (fClipState.fStencilClipTarget == renderTarget) {
1577 fClipState.fStencilClipTarget = NULL;
1578 }
1579}
1580
1581void GrGpuGL::notifyTextureDelete(GrGLTexture* texture) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001582 for (int s = 0; s < kNumStages; ++s) {
1583 if (fCurrDrawState.fTextures[s] == texture) {
1584 fCurrDrawState.fTextures[s] = NULL;
1585 }
1586 if (fHWDrawState.fTextures[s] == texture) {
1587 // deleting bound texture does implied bind to 0
1588 fHWDrawState.fTextures[s] = NULL;
1589 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001590 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001591}
1592
1593void GrGpuGL::notifyTextureRemoveRenderTarget(GrGLTexture* texture) {
1594 GrAssert(NULL != texture->asRenderTarget());
1595
1596 // if there is a pending resolve, perform it.
1597 resolveTextureRenderTarget(texture);
1598}
1599
1600bool GrGpuGL::canBeTexture(GrTexture::PixelConfig config,
1601 GLenum* internalFormat,
1602 GLenum* format,
1603 GLenum* type) {
1604 switch (config) {
1605 case GrTexture::kRGBA_8888_PixelConfig:
1606 case GrTexture::kRGBX_8888_PixelConfig: // todo: can we tell it our X?
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +00001607 *format = GR_GL_32BPP_COLOR_FORMAT;
reed@google.com63100f92011-01-18 21:32:14 +00001608#if GR_SUPPORT_GLES
1609 // according to GL_EXT_texture_format_BGRA8888 the *internal*
1610 // format for a BGRA is BGRA not RGBA (as on desktop)
1611 *internalFormat = GR_GL_32BPP_COLOR_FORMAT;
1612#else
1613 *internalFormat = GL_RGBA;
bsalomon@google.comed3a0682011-01-18 16:54:04 +00001614#endif
reed@google.comac10a2d2010-12-22 21:39:39 +00001615 *type = GL_UNSIGNED_BYTE;
1616 break;
1617 case GrTexture::kRGB_565_PixelConfig:
1618 *format = GL_RGB;
1619 *internalFormat = GL_RGB;
1620 *type = GL_UNSIGNED_SHORT_5_6_5;
1621 break;
1622 case GrTexture::kRGBA_4444_PixelConfig:
1623 *format = GL_RGBA;
1624 *internalFormat = GL_RGBA;
1625 *type = GL_UNSIGNED_SHORT_4_4_4_4;
1626 break;
1627 case GrTexture::kIndex_8_PixelConfig:
1628 if (this->supports8BitPalette()) {
1629 *format = GR_PALETTE8_RGBA8;
1630 *internalFormat = GR_PALETTE8_RGBA8;
1631 *type = GL_UNSIGNED_BYTE; // unused I think
1632 } else {
1633 return false;
1634 }
1635 break;
1636 case GrTexture::kAlpha_8_PixelConfig:
1637 *format = GL_ALPHA;
1638 *internalFormat = GL_ALPHA;
1639 *type = GL_UNSIGNED_BYTE;
1640 break;
1641 default:
1642 return false;
1643 }
1644 return true;
1645}
1646
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001647void GrGpuGL::setTextureUnit(int unit) {
1648 GrAssert(unit >= 0 && unit < kNumStages);
1649 if (fActiveTextureUnitIdx != unit) {
1650 GR_GL(ActiveTexture(GL_TEXTURE0 + unit));
1651 fActiveTextureUnitIdx = unit;
1652 }
1653}
bsalomon@google.com316f99232011-01-13 21:28:12 +00001654
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001655void GrGpuGL::setSpareTextureUnit() {
1656 if (fActiveTextureUnitIdx != (GL_TEXTURE0 + SPARE_TEX_UNIT)) {
1657 GR_GL(ActiveTexture(GL_TEXTURE0 + SPARE_TEX_UNIT));
1658 fActiveTextureUnitIdx = SPARE_TEX_UNIT;
1659 }
1660}
1661
reed@google.comac10a2d2010-12-22 21:39:39 +00001662/* On ES the internalFormat and format must match for TexImage and we use
1663 GL_RGB, GL_RGBA for color formats. We also generally like having the driver
1664 decide the internalFormat. However, on ES internalFormat for
1665 RenderBufferStorage* has to be a specific format (not a base format like
1666 GL_RGBA).
1667 */
1668bool GrGpuGL::fboInternalFormat(GrTexture::PixelConfig config, GLenum* format) {
1669 switch (config) {
1670 case GrTexture::kRGBA_8888_PixelConfig:
1671 case GrTexture::kRGBX_8888_PixelConfig:
1672 if (fRGBA8Renderbuffer) {
1673 *format = GR_RGBA8;
1674 return true;
1675 } else {
1676 return false;
1677 }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001678#if GR_SUPPORT_GLES // ES2 supports 565. ES1 supports it with FBO extension
1679 // desktop GL has no such internal format
reed@google.comac10a2d2010-12-22 21:39:39 +00001680 case GrTexture::kRGB_565_PixelConfig:
1681 *format = GR_RGB565;
1682 return true;
1683#endif
1684 case GrTexture::kRGBA_4444_PixelConfig:
1685 *format = GL_RGBA4;
1686 return true;
1687 default:
1688 return false;
1689 }
1690}