blob: 2951895df8665f1b4f6a9e1e0f965c375d057814 [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"
19#include <stdio.h>
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +000020#if GR_WIN32_BUILD
21 // need to get wglGetProcAddress
22 #undef WIN32_LEAN_AND_MEAN
23 #define WIN32_LEAN_AND_MEAN 1
24 #include <windows.h>
25 #undef WIN32_LEAN_AND_MEAN
26#endif
27
reed@google.comac10a2d2010-12-22 21:39:39 +000028
29static const GLuint GR_MAX_GLUINT = ~0;
30static const GLint GR_INVAL_GLINT = ~0;
31
bsalomon@google.com316f99232011-01-13 21:28:12 +000032// we use a spare texture unit to avoid
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000033// mucking with the state of any of the stages.
bsalomon@google.com316f99232011-01-13 21:28:12 +000034static const int SPARE_TEX_UNIT = GrGpuGL::kNumStages;
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000035
reed@google.comac10a2d2010-12-22 21:39:39 +000036#define SKIP_CACHE_CHECK true
37
38static const GLenum gXfermodeCoeff2Blend[] = {
39 GL_ZERO,
40 GL_ONE,
41 GL_SRC_COLOR,
42 GL_ONE_MINUS_SRC_COLOR,
43 GL_DST_COLOR,
44 GL_ONE_MINUS_DST_COLOR,
45 GL_SRC_ALPHA,
46 GL_ONE_MINUS_SRC_ALPHA,
47 GL_DST_ALPHA,
48 GL_ONE_MINUS_DST_ALPHA,
49};
50
51bool has_gl_extension(const char* ext) {
52 const char* glstr = (const char*) glGetString(GL_EXTENSIONS);
53
54 int extLength = strlen(ext);
55
56 while (true) {
57 int n = strcspn(glstr, " ");
58 if (n == extLength && 0 == strncmp(ext, glstr, n)) {
59 return true;
60 }
61 if (0 == glstr[n]) {
62 return false;
63 }
64 glstr += n+1;
65 }
66}
67
68void gl_version(int* major, int* minor) {
69 const char* v = (const char*) glGetString(GL_VERSION);
70 if (NULL == v) {
71 GrAssert(0);
72 *major = 0;
73 *minor = 0;
74 return;
75 }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000076#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +000077 int n = sscanf(v, "%d.%d", major, minor);
78 if (n != 2) {
79 GrAssert(0);
80 *major = 0;
81 *minor = 0;
82 return;
83 }
84#else
85 char profile[2];
86 int n = sscanf(v, "OpenGL ES-%c%c %d.%d", profile, profile+1, major, minor);
87 bool ok = 4 == n;
88 if (!ok) {
89 int n = sscanf(v, "OpenGL ES %d.%d", major, minor);
90 ok = 2 == n;
91 }
92 if (!ok) {
93 GrAssert(0);
94 *major = 0;
95 *minor = 0;
96 return;
97 }
98#endif
99}
100///////////////////////////////////////////////////////////////////////////////
101
102bool fbo_test(GrGLExts exts, int w, int h) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000103
104 GLint savedFBO;
105 GLint savedTexUnit;
106 GR_GL(GetIntegerv(GL_ACTIVE_TEXTURE, &savedTexUnit));
107 GR_GL(GetIntegerv(GR_FRAMEBUFFER_BINDING, &savedFBO));
bsalomon@google.com316f99232011-01-13 21:28:12 +0000108
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000109 GR_GL(ActiveTexture(GL_TEXTURE0 + SPARE_TEX_UNIT));
bsalomon@google.com316f99232011-01-13 21:28:12 +0000110
reed@google.comac10a2d2010-12-22 21:39:39 +0000111 GLuint testFBO;
112 GR_GLEXT(exts, GenFramebuffers(1, &testFBO));
113 GR_GLEXT(exts, BindFramebuffer(GR_FRAMEBUFFER, testFBO));
114 GLuint testRTTex;
115 GR_GL(GenTextures(1, &testRTTex));
116 GR_GL(BindTexture(GL_TEXTURE_2D, testRTTex));
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000117 // some implementations require texture to be mip-map complete before
118 // FBO with level 0 bound as color attachment will be framebuffer complete.
119 GR_GL(TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
reed@google.comac10a2d2010-12-22 21:39:39 +0000120 GR_GL(TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h,
121 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL));
122 GR_GL(BindTexture(GL_TEXTURE_2D, 0));
123 GR_GLEXT(exts, FramebufferTexture2D(GR_FRAMEBUFFER, GR_COLOR_ATTACHMENT0,
124 GL_TEXTURE_2D, testRTTex, 0));
125 GLenum status = GR_GLEXT(exts, CheckFramebufferStatus(GR_FRAMEBUFFER));
126 GR_GLEXT(exts, DeleteFramebuffers(1, &testFBO));
127 GR_GL(DeleteTextures(1, &testRTTex));
bsalomon@google.com316f99232011-01-13 21:28:12 +0000128
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000129 GR_GL(ActiveTexture(savedTexUnit));
130 GR_GLEXT(exts, BindFramebuffer(GR_FRAMEBUFFER, savedFBO));
bsalomon@google.com316f99232011-01-13 21:28:12 +0000131
reed@google.comac10a2d2010-12-22 21:39:39 +0000132 return status == GR_FRAMEBUFFER_COMPLETE;
133}
134
135///////////////////////////////////////////////////////////////////////////////
136
reed@google.comeeeb5a02010-12-23 15:12:59 +0000137static bool gPrintStartupSpew;
138
reed@google.comac10a2d2010-12-22 21:39:39 +0000139GrGpuGL::GrGpuGL() {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000140 if (gPrintStartupSpew) {
141 GrPrintf("------------------------- create GrGpuGL %p --------------\n",
142 this);
143 GrPrintf("------ VENDOR %s\n", glGetString(GL_VENDOR));
144 GrPrintf("------ RENDERER %s\n", glGetString(GL_RENDERER));
145 GrPrintf("------ VERSION %s\n", glGetString(GL_VERSION));
146 GrPrintf("------ EXTENSIONS\n %s \n", glGetString(GL_EXTENSIONS));
147 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000148
149 GrGLClearErr();
150
151 GrGLInitExtensions(&fExts);
152
153 resetContextHelper();
154
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000155 fHWDrawState.fRenderTarget = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +0000156 fRenderTargetChanged = true;
bsalomon@google.com316f99232011-01-13 21:28:12 +0000157
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000158 GLint maxTextureUnits;
159 // check FS and fixed-function texture unit limits
160 // we only use textures in the fragment stage currently.
161 // checks are > to make sure we have a spare unit.
162#if GR_SUPPORT_GLDESKTOP || GR_SUPPORT_GLES2
163 GR_GL(GetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextureUnits));
164 GrAssert(maxTextureUnits > kNumStages);
165#endif
166#if GR_SUPPORT_GLDESKTOP || GR_SUPPORT_GLES1
167 GR_GL(GetIntegerv(GL_MAX_TEXTURE_UNITS, &maxTextureUnits));
168 GrAssert(maxTextureUnits > kNumStages);
169#endif
bsalomon@google.com316f99232011-01-13 21:28:12 +0000170
reed@google.comac10a2d2010-12-22 21:39:39 +0000171 fCurrDrawState = fHWDrawState;
172
173 ////////////////////////////////////////////////////////////////////////////
174 // Check for supported features.
175
176 int major, minor;
177 gl_version(&major, &minor);
178
179 GLint numFormats;
reed@google.comac20fb92011-01-12 17:14:53 +0000180 GR_GL_GetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &numFormats);
reed@google.comac10a2d2010-12-22 21:39:39 +0000181 GrAutoSTMalloc<10, GLint> formats(numFormats);
reed@google.comac20fb92011-01-12 17:14:53 +0000182 GR_GL_GetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, formats);
reed@google.comac10a2d2010-12-22 21:39:39 +0000183 for (int i = 0; i < numFormats; ++i) {
184 if (formats[i] == GR_PALETTE8_RGBA8) {
185 f8bitPaletteSupport = true;
186 break;
187 }
188 }
reed@google.comeeeb5a02010-12-23 15:12:59 +0000189
190 if (gPrintStartupSpew) {
191 GrPrintf("Palette8 support: %s\n", (f8bitPaletteSupport ? "YES" : "NO"));
192 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000193
194 GR_STATIC_ASSERT(0 == kNone_AALevel);
195 GR_STATIC_ASSERT(1 == kLow_AALevel);
196 GR_STATIC_ASSERT(2 == kMed_AALevel);
197 GR_STATIC_ASSERT(3 == kHigh_AALevel);
198
199 memset(fAASamples, 0, sizeof(fAASamples));
200 fMSFBOType = kNone_MSFBO;
201 if (has_gl_extension("GL_IMG_multisampled_render_to_texture")) {
202 fMSFBOType = kIMG_MSFBO;
reed@google.comeeeb5a02010-12-23 15:12:59 +0000203 if (gPrintStartupSpew) {
204 GrPrintf("MSAA Support: IMG ES EXT.\n");
205 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000206 }
207 else if (has_gl_extension("GL_APPLE_framebuffer_multisample")) {
208 fMSFBOType = kApple_MSFBO;
reed@google.comeeeb5a02010-12-23 15:12:59 +0000209 if (gPrintStartupSpew) {
210 GrPrintf("MSAA Support: APPLE ES EXT.\n");
211 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000212 }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000213#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000214 else if ((major >= 3) ||
215 has_gl_extension("GL_ARB_framebuffer_object") ||
216 (has_gl_extension("GL_EXT_framebuffer_multisample") &&
217 has_gl_extension("GL_EXT_framebuffer_blit"))) {
218 fMSFBOType = kDesktop_MSFBO;
reed@google.comeeeb5a02010-12-23 15:12:59 +0000219 if (gPrintStartupSpew) {
220 GrPrintf("MSAA Support: DESKTOP\n");
221 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000222 }
223#endif
224 else {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000225 if (gPrintStartupSpew) {
226 GrPrintf("MSAA Support: NONE\n");
227 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000228 }
229
230 if (kNone_MSFBO != fMSFBOType) {
231 GLint maxSamples;
232 GLenum maxSampleGetter = (kIMG_MSFBO == fMSFBOType) ?
233 GR_MAX_SAMPLES_IMG :
234 GR_MAX_SAMPLES;
reed@google.comac20fb92011-01-12 17:14:53 +0000235 GR_GL_GetIntegerv(maxSampleGetter, &maxSamples);
reed@google.comac10a2d2010-12-22 21:39:39 +0000236 if (maxSamples > 1 ) {
237 fAASamples[kNone_AALevel] = 0;
238 fAASamples[kLow_AALevel] = GrMax(2,
239 GrFixedFloorToInt((GR_FixedHalf) *
240 maxSamples));
241 fAASamples[kMed_AALevel] = GrMax(2,
242 GrFixedFloorToInt(((GR_Fixed1*3)/4) *
243 maxSamples));
244 fAASamples[kHigh_AALevel] = maxSamples;
245 }
reed@google.comeeeb5a02010-12-23 15:12:59 +0000246 if (gPrintStartupSpew) {
247 GrPrintf("\tMax Samples: %d\n", maxSamples);
248 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000249 }
250
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000251#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000252 fHasStencilWrap = (major >= 2 || (major == 1 && minor >= 4)) ||
253 has_gl_extension("GL_EXT_stencil_wrap");
254#else
255 fHasStencilWrap = (major >= 2) || has_gl_extension("GL_OES_stencil_wrap");
256#endif
reed@google.comeeeb5a02010-12-23 15:12:59 +0000257 if (gPrintStartupSpew) {
258 GrPrintf("Stencil Wrap: %s\n", (fHasStencilWrap ? "YES" : "NO"));
259 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000260
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000261#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000262 // we could also look for GL_ATI_separate_stencil extension or
263 // GL_EXT_stencil_two_side but they use different function signatures
264 // than GL2.0+ (and than each other).
265 fSingleStencilPassForWinding = (major >= 2);
266#else
267 // ES 2 has two sided stencil but 1.1 doesn't. There doesn't seem to be
268 // an ES1 extension.
269 fSingleStencilPassForWinding = (major >= 2);
270#endif
reed@google.comeeeb5a02010-12-23 15:12:59 +0000271 if (gPrintStartupSpew) {
272 GrPrintf("Single Stencil Pass For Winding: %s\n", (fSingleStencilPassForWinding ? "YES" : "NO"));
273 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000274
275
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000276#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000277 fRGBA8Renderbuffer = true;
278#else
279 fRGBA8Renderbuffer = has_gl_extension("GL_OES_rgb8_rgba8");
280#endif
reed@google.comeeeb5a02010-12-23 15:12:59 +0000281 if (gPrintStartupSpew) {
282 GrPrintf("RGBA Renderbuffer: %s\n", (fRGBA8Renderbuffer ? "YES" : "NO"));
283 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000284
bsalomon@google.comed3a0682011-01-18 16:54:04 +0000285#if GR_SUPPORT_GLES
286 if (GR_GL_32BPP_COLOR_FORMAT == GR_BGRA) {
287 GrAssert(has_gl_extension("GL_EXT_texture_format_BGRA8888"));
288 }
289#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000290
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000291#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000292 fBufferLockSupport = true; // we require VBO support and the desktop VBO
293 // extension includes glMapBuffer.
294#else
295 fBufferLockSupport = has_gl_extension("GL_OES_mapbuffer");
296#endif
reed@google.comeeeb5a02010-12-23 15:12:59 +0000297 if (gPrintStartupSpew) {
298 GrPrintf("Map Buffer: %s\n", (fBufferLockSupport ? "YES" : "NO"));
299 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000300
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000301#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000302 fNPOTTextureSupport =
303 (major >= 2 || has_gl_extension("GL_ARB_texture_non_power_of_two")) ?
304 kFull_NPOTTextureType :
305 kNone_NPOTTextureType;
306#else
307 if (has_gl_extension("GL_OES_texture_npot")) {
308 fNPOTTextureSupport = kFull_NPOTTextureType;
309 } else if (major >= 2 ||
310 has_gl_extension("GL_APPLE_texture_2D_limited_npot")) {
311 fNPOTTextureSupport = kNoRepeat_NPOTTextureType;
312 } else {
313 fNPOTTextureSupport = kNone_NPOTTextureType;
314 }
315#endif
316 ////////////////////////////////////////////////////////////////////////////
317 // Experiments to determine limitations that can't be queried. TODO: Make
318 // these a preprocess that generate some compile time constants.
319
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000320 // sanity check to make sure we can at least create an FBO from a POT texture
321 if (fNPOTTextureSupport < kFull_NPOTTextureType) {
322 bool npotFBOSuccess = fbo_test(fExts, 128, 128);
323 if (gPrintStartupSpew) {
324 if (!npotFBOSuccess) {
325 GrPrintf("FBO Sanity Test: FAILED\n");
326 } else {
327 GrPrintf("FBO Sanity Test: PASSED\n");
328 }
329 }
330 }
reed@google.comac20fb92011-01-12 17:14:53 +0000331
reed@google.comac10a2d2010-12-22 21:39:39 +0000332 /* Experimentation has found that some GLs that support NPOT textures
333 do not support FBOs with a NPOT texture. They report "unsupported" FBO
334 status. I don't know how to explicitly query for this. Do an
335 experiment. Note they may support NPOT with a renderbuffer but not a
336 texture. Presumably, the implementation bloats the renderbuffer
337 internally to the next POT.
338 */
339 if (fNPOTTextureSupport == kFull_NPOTTextureType) {
340 bool npotFBOSuccess = fbo_test(fExts, 200, 200);
341 if (!npotFBOSuccess) {
342 fNPOTTextureSupport = kNonRendertarget_NPOTTextureType;
reed@google.comeeeb5a02010-12-23 15:12:59 +0000343 if (gPrintStartupSpew) {
344 GrPrintf("NPOT Renderbuffer Test: FAILED\n");
345 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000346 } else {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000347 if (gPrintStartupSpew) {
348 GrPrintf("NPOT Renderbuffer Test: PASSED\n");
349 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000350 }
351 }
reed@google.comeeeb5a02010-12-23 15:12:59 +0000352
353 if (gPrintStartupSpew) {
354 switch (fNPOTTextureSupport) {
355 case kNone_NPOTTextureType:
356 GrPrintf("NPOT Support: NONE\n");
357 break;
358 case kNoRepeat_NPOTTextureType:
359 GrPrintf("NPOT Support: NO REPEAT\n");
360 break;
361 case kNonRendertarget_NPOTTextureType:
362 GrPrintf("NPOT Support: NO FBOTEX\n");
363 break;
364 case kFull_NPOTTextureType:
365 GrPrintf("NPOT Support: FULL\n");
366 break;
367 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000368 }
369
reed@google.comac10a2d2010-12-22 21:39:39 +0000370 /* The iPhone 4 has a restriction that for an FBO with texture color
371 attachment with height <= 8 then the width must be <= height. Here
372 we look for such a limitation.
373 */
374 fMinRenderTargetHeight = GR_INVAL_GLINT;
375 GLint maxRenderSize;
reed@google.comac20fb92011-01-12 17:14:53 +0000376 GR_GL_GetIntegerv(GR_MAX_RENDERBUFFER_SIZE, &maxRenderSize);
reed@google.comac10a2d2010-12-22 21:39:39 +0000377
reed@google.comeeeb5a02010-12-23 15:12:59 +0000378 if (gPrintStartupSpew) {
379 GrPrintf("Small height FBO texture experiments\n");
380 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000381 for (GLuint i = 1; i <= 256;
382 (kFull_NPOTTextureType != fNPOTTextureSupport) ? i *= 2 : ++i) {
383 GLuint w = maxRenderSize;
384 GLuint h = i;
385 if (fbo_test(fExts, w, h)) {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000386 if (gPrintStartupSpew) {
387 GrPrintf("\t[%d, %d]: PASSED\n", w, h);
388 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000389 fMinRenderTargetHeight = i;
390 break;
391 } else {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000392 if (gPrintStartupSpew) {
393 GrPrintf("\t[%d, %d]: FAILED\n", w, h);
394 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000395 }
396 }
397 GrAssert(GR_INVAL_GLINT != fMinRenderTargetHeight);
398
reed@google.comeeeb5a02010-12-23 15:12:59 +0000399 if (gPrintStartupSpew) {
400 GrPrintf("Small width FBO texture experiments\n");
401 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000402 fMinRenderTargetWidth = GR_MAX_GLUINT;
403 for (GLuint i = 1; i <= 256;
404 (kFull_NPOTTextureType != fNPOTTextureSupport) ? i *= 2 : ++i) {
405 GLuint w = i;
406 GLuint h = maxRenderSize;
407 if (fbo_test(fExts, w, h)) {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000408 if (gPrintStartupSpew) {
409 GrPrintf("\t[%d, %d]: PASSED\n", w, h);
410 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000411 fMinRenderTargetWidth = i;
412 break;
413 } else {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000414 if (gPrintStartupSpew) {
415 GrPrintf("\t[%d, %d]: FAILED\n", w, h);
416 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000417 }
418 }
419 GrAssert(GR_INVAL_GLINT != fMinRenderTargetWidth);
420
421#if GR_IOS_BUILD
422 /*
423 The iPad seems to fail, at least sometimes, if the height is < 16,
424 so we pin the values here for now. A better fix might be to
425 conditionalize this based on known that its an iPad (or some other
426 check).
427 */
428 fMinRenderTargetWidth = GrMax<GLuint>(fMinRenderTargetWidth, 16);
429 fMinRenderTargetHeight = GrMax<GLuint>(fMinRenderTargetHeight, 16);
430#endif
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000431
reed@google.comac10a2d2010-12-22 21:39:39 +0000432#if GR_COLLECT_STATS
433 ++fStats.fRenderTargetChngCnt;
434#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000435}
436
437GrGpuGL::~GrGpuGL() {
reed@google.comac10a2d2010-12-22 21:39:39 +0000438}
439
440void GrGpuGL::resetContextHelper() {
441// We detect cases when blending is effectively off
442 fHWBlendDisabled = false;
443 GR_GL(Enable(GL_BLEND));
444
445 // this is always disabled
446 GR_GL(Disable(GL_CULL_FACE));
447
448 GR_GL(Disable(GL_DITHER));
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000449#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000450 GR_GL(Disable(GL_LINE_SMOOTH));
451 GR_GL(Disable(GL_POINT_SMOOTH));
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000452 GR_GL(Disable(GL_MULTISAMPLE));
reed@google.comac10a2d2010-12-22 21:39:39 +0000453#endif
454
455 // we only ever use lines in hairline mode
456 GR_GL(LineWidth(1));
457
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000458 // invalid
459 fActiveTextureUnitIdx = -1;
reed@google.comac10a2d2010-12-22 21:39:39 +0000460
461 fHWDrawState.fFlagBits = 0;
462
463 // illegal values
464 fHWDrawState.fSrcBlend = (BlendCoeff)-1;
465 fHWDrawState.fDstBlend = (BlendCoeff)-1;
466 fHWDrawState.fColor = GrColor_ILLEGAL;
467 fHWDrawState.fPointSize = -1;
bsalomon@google.com316f99232011-01-13 21:28:12 +0000468
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000469 fHWDrawState.fViewMatrix.setScale(GR_ScalarMax, GR_ScalarMax); // illegal
bsalomon@google.com316f99232011-01-13 21:28:12 +0000470
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000471 for (int s = 0; s < kNumStages; ++s) {
472 fHWDrawState.fTextures[s] = NULL;
473 fHWDrawState.fSamplerStates[s].setRadial2Params(-GR_ScalarMax,
474 -GR_ScalarMax,
475 true);
bsalomon@google.com316f99232011-01-13 21:28:12 +0000476 fHWDrawState.fTextureMatrices[s].setScale(GR_ScalarMax, GR_ScalarMax);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000477 }
bsalomon@google.com316f99232011-01-13 21:28:12 +0000478
reed@google.comac10a2d2010-12-22 21:39:39 +0000479 GR_GL(Scissor(0,0,0,0));
480 fHWBounds.fScissorRect.setLTRB(0,0,0,0);
481 fHWBounds.fScissorEnabled = false;
482 GR_GL(Disable(GL_SCISSOR_TEST));
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000483 fHWBounds.fViewportRect.setLTRB(-1,-1,-1,-1);
reed@google.comac10a2d2010-12-22 21:39:39 +0000484
reed@google.comac10a2d2010-12-22 21:39:39 +0000485 // disabling the stencil test also disables
486 // stencil buffer writes
487 GR_GL(Disable(GL_STENCIL_TEST));
488 GR_GL(StencilMask(0xffffffff));
489 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
490 fHWDrawState.fReverseFill = false;
491 fHWDrawState.fStencilPass = kNone_StencilPass;
492 fHWStencilClip = false;
493
494 fHWGeometryState.fIndexBuffer = NULL;
495 fHWGeometryState.fVertexBuffer = NULL;
496 GR_GL(BindBuffer(GL_ARRAY_BUFFER, 0));
497 GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
498
499 fHWDrawState.fRenderTarget = NULL;
500}
501
502void GrGpuGL::resetContext() {
503 INHERITED::resetContext();
504 resetContextHelper();
505}
506
reed@google.comac10a2d2010-12-22 21:39:39 +0000507GrRenderTarget* GrGpuGL::createPlatformRenderTarget(
508 intptr_t platformRenderTarget,
509 int width, int height) {
510 GrGLRenderTarget::GLRenderTargetIDs rtIDs;
511 rtIDs.fStencilRenderbufferID = 0;
512 rtIDs.fMSColorRenderbufferID = 0;
513 rtIDs.fTexFBOID = 0;
514 rtIDs.fOwnIDs = false;
515
516 GrIRect viewport;
517
518 // viewport is in GL coords (top >= bottom)
519 viewport.setLTRB(0, height, width, 0);
520
521 rtIDs.fRTFBOID = (GLuint)platformRenderTarget;
522 rtIDs.fTexFBOID = (GLuint)platformRenderTarget;
523
524 GrGLRenderTarget* rt = new GrGLRenderTarget(rtIDs, viewport, NULL, this);
525
526 return rt;
527}
528
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000529GrRenderTarget* GrGpuGL::createRenderTargetFrom3DApiState() {
530
531 GrGLRenderTarget::GLRenderTargetIDs rtIDs;
532
533 GR_GL_GetIntegerv(GR_FRAMEBUFFER_BINDING, (GLint*)&rtIDs.fRTFBOID);
534 rtIDs.fTexFBOID = rtIDs.fRTFBOID;
535 rtIDs.fMSColorRenderbufferID = 0;
536 rtIDs.fStencilRenderbufferID = 0;
537
538 GLint vp[4];
539 GR_GL_GetIntegerv(GL_VIEWPORT, vp);
540 GrIRect viewportRect;
541 viewportRect.setLTRB(vp[0],
542 vp[1] + vp[3],
543 vp[0] + vp[2],
544 vp[1]);
545 rtIDs.fOwnIDs = false;
546
547 return new GrGLRenderTarget(rtIDs,
548 viewportRect,
549 NULL,
550 this);
551}
552
bsalomon@google.com3f3ffd62011-01-18 17:14:52 +0000553// defines stencil formats from more to less preferred
reed@google.com63100f92011-01-18 21:32:14 +0000554GLenum GR_GL_STENCIL_FORMAT_ARRAY[] = {
555 GR_STENCIL_INDEX8,
556
557#if GR_SUPPORT_GLDESKTOP
558 GR_STENCIL_INDEX16,
559#endif
560
561 GR_DEPTH24_STENCIL8,
562 GR_STENCIL_INDEX4,
563
564#if GR_SUPPORT_GLDESKTOP
bsalomon@google.com3f3ffd62011-01-18 17:14:52 +0000565 GL_STENCIL_INDEX,
566 GR_DEPTH_STENCIL,
567#endif
568};
569
570// good to set a break-point here to know when createTexture fails
571static GrTexture* return_null_texture() {
572// GrAssert(!"null texture");
573 return NULL;
574}
575
576#if GR_DEBUG
577static size_t as_size_t(int x) {
578 return x;
579}
580#endif
581
reed@google.comac10a2d2010-12-22 21:39:39 +0000582GrTexture* GrGpuGL::createTexture(const TextureDesc& desc,
583 const void* srcData, size_t rowBytes) {
584
585#if GR_COLLECT_STATS
586 ++fStats.fTextureCreateCnt;
587#endif
reed@google.com1fcd51e2011-01-05 15:50:27 +0000588
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000589 setSpareTextureUnit();
bsalomon@google.com316f99232011-01-13 21:28:12 +0000590
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000591 static const GrGLTexture::TexParams DEFAULT_PARAMS = {
592 GL_NEAREST,
593 GL_CLAMP_TO_EDGE,
594 GL_CLAMP_TO_EDGE
595 };
reed@google.com1fcd51e2011-01-05 15:50:27 +0000596
reed@google.comac10a2d2010-12-22 21:39:39 +0000597 GrGLTexture::GLTextureDesc glDesc;
598 GLenum internalFormat;
599
600 glDesc.fContentWidth = desc.fWidth;
601 glDesc.fContentHeight = desc.fHeight;
602 glDesc.fAllocWidth = desc.fWidth;
603 glDesc.fAllocHeight = desc.fHeight;
604 glDesc.fFormat = desc.fFormat;
605
606 bool renderTarget = 0 != (desc.fFlags & kRenderTarget_TextureFlag);
607 if (!canBeTexture(desc.fFormat,
608 &internalFormat,
609 &glDesc.fUploadFormat,
610 &glDesc.fUploadType)) {
611 return return_null_texture();
612 }
613
614 GrAssert(as_size_t(desc.fAALevel) < GR_ARRAY_COUNT(fAASamples));
615 GLint samples = fAASamples[desc.fAALevel];
616 if (kNone_MSFBO == fMSFBOType && desc.fAALevel != kNone_AALevel) {
617 GrPrintf("AA RT requested but not supported on this platform.");
618 }
619
620 GR_GL(GenTextures(1, &glDesc.fTextureID));
621 if (!glDesc.fTextureID) {
622 return return_null_texture();
623 }
624
625 glDesc.fUploadByteCount = GrTexture::BytesPerPixel(desc.fFormat);
626
627 /*
628 * check if our srcData has extra bytes past each row. If so, we need
629 * to trim those off here, since GL doesn't let us pass the rowBytes as
630 * a parameter to glTexImage2D
631 */
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000632#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000633 if (srcData) {
634 GR_GL(PixelStorei(GL_UNPACK_ROW_LENGTH,
635 rowBytes / glDesc.fUploadByteCount));
636 }
637#else
638 GrAutoSMalloc<128 * 128> trimStorage;
639 size_t trimRowBytes = desc.fWidth * glDesc.fUploadByteCount;
640 if (srcData && (trimRowBytes < rowBytes)) {
641 size_t trimSize = desc.fHeight * trimRowBytes;
642 trimStorage.realloc(trimSize);
643 // now copy the data into our new storage, skipping the trailing bytes
644 const char* src = (const char*)srcData;
645 char* dst = (char*)trimStorage.get();
646 for (uint32_t y = 0; y < desc.fHeight; y++) {
647 memcpy(dst, src, trimRowBytes);
648 src += rowBytes;
649 dst += trimRowBytes;
650 }
651 // now point srcData to our trimmed version
652 srcData = trimStorage.get();
653 }
654#endif
655
656 if (fNPOTTextureSupport < kNonRendertarget_NPOTTextureType ||
657 (fNPOTTextureSupport == kNonRendertarget_NPOTTextureType &&
658 renderTarget)) {
659 glDesc.fAllocWidth = GrNextPow2(desc.fWidth);
660 glDesc.fAllocHeight = GrNextPow2(desc.fHeight);
661 }
662
663 if (renderTarget) {
664 glDesc.fAllocWidth = GrMax<int>(fMinRenderTargetWidth,
665 glDesc.fAllocWidth);
666 glDesc.fAllocHeight = GrMax<int>(fMinRenderTargetHeight,
667 glDesc.fAllocHeight);
668 }
669
670 GR_GL(BindTexture(GL_TEXTURE_2D, glDesc.fTextureID));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000671 GR_GL(TexParameteri(GL_TEXTURE_2D,
672 GL_TEXTURE_MAG_FILTER,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000673 DEFAULT_PARAMS.fFilter));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000674 GR_GL(TexParameteri(GL_TEXTURE_2D,
675 GL_TEXTURE_MIN_FILTER,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000676 DEFAULT_PARAMS.fFilter));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000677 GR_GL(TexParameteri(GL_TEXTURE_2D,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000678 GL_TEXTURE_WRAP_S,
679 DEFAULT_PARAMS.fWrapS));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000680 GR_GL(TexParameteri(GL_TEXTURE_2D,
681 GL_TEXTURE_WRAP_T,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000682 DEFAULT_PARAMS.fWrapT));
reed@google.comac10a2d2010-12-22 21:39:39 +0000683
684 GR_GL(PixelStorei(GL_UNPACK_ALIGNMENT, glDesc.fUploadByteCount));
685 if (GrTexture::kIndex_8_PixelConfig == desc.fFormat &&
686 supports8BitPalette()) {
687 // ES only supports CompressedTexImage2D, not CompressedTexSubimage2D
688 GrAssert(desc.fWidth == glDesc.fAllocWidth);
689 GrAssert(desc.fHeight == glDesc.fAllocHeight);
690 GLsizei imageSize = glDesc.fAllocWidth * glDesc.fAllocHeight +
691 kColorTableSize;
692 GR_GL(CompressedTexImage2D(GL_TEXTURE_2D, 0, glDesc.fUploadFormat,
693 glDesc.fAllocWidth, glDesc.fAllocHeight,
694 0, imageSize, srcData));
695 GrGL_RestoreResetRowLength();
696 } else {
697 if (NULL != srcData && (glDesc.fAllocWidth != desc.fWidth ||
698 glDesc.fAllocHeight != desc.fHeight)) {
699 GR_GL(TexImage2D(GL_TEXTURE_2D, 0, internalFormat,
700 glDesc.fAllocWidth, glDesc.fAllocHeight,
701 0, glDesc.fUploadFormat, glDesc.fUploadType, NULL));
702 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, desc.fWidth,
703 desc.fHeight, glDesc.fUploadFormat,
704 glDesc.fUploadType, srcData));
705 GrGL_RestoreResetRowLength();
706
707 uint32_t extraW = glDesc.fAllocWidth - desc.fWidth;
708 uint32_t extraH = glDesc.fAllocHeight - desc.fHeight;
709 uint32_t maxTexels = extraW * extraH;
710 maxTexels = GrMax(extraW * desc.fHeight, maxTexels);
711 maxTexels = GrMax(desc.fWidth * extraH, maxTexels);
712
713 GrAutoSMalloc<128*128> texels(glDesc.fUploadByteCount * maxTexels);
714
715 uint32_t rowSize = desc.fWidth * glDesc.fUploadByteCount;
716 if (extraH) {
717 uint8_t* lastRowStart = (uint8_t*) srcData +
718 (desc.fHeight - 1) * rowSize;
719 uint8_t* extraRowStart = (uint8_t*)texels.get();
720
721 for (uint32_t i = 0; i < extraH; ++i) {
722 memcpy(extraRowStart, lastRowStart, rowSize);
723 extraRowStart += rowSize;
724 }
725 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, 0, desc.fHeight, desc.fWidth,
726 extraH, glDesc.fUploadFormat, glDesc.fUploadType,
727 texels.get()));
728 }
729 if (extraW) {
730 uint8_t* edgeTexel = (uint8_t*)srcData + rowSize - glDesc.fUploadByteCount;
731 uint8_t* extraTexel = (uint8_t*)texels.get();
732 for (uint32_t j = 0; j < desc.fHeight; ++j) {
733 for (uint32_t i = 0; i < extraW; ++i) {
734 memcpy(extraTexel, edgeTexel, glDesc.fUploadByteCount);
735 extraTexel += glDesc.fUploadByteCount;
736 }
737 edgeTexel += rowSize;
738 }
739 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, desc.fWidth, 0, extraW,
740 desc.fHeight, glDesc.fUploadFormat,
741 glDesc.fUploadType, texels.get()));
742 }
743 if (extraW && extraH) {
744 uint8_t* cornerTexel = (uint8_t*)srcData + desc.fHeight * rowSize
745 - glDesc.fUploadByteCount;
746 uint8_t* extraTexel = (uint8_t*)texels.get();
747 for (uint32_t i = 0; i < extraW*extraH; ++i) {
748 memcpy(extraTexel, cornerTexel, glDesc.fUploadByteCount);
749 extraTexel += glDesc.fUploadByteCount;
750 }
751 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, desc.fWidth, desc.fHeight,
752 extraW, extraH, glDesc.fUploadFormat,
753 glDesc.fUploadType, texels.get()));
754 }
755
756 } else {
757 GR_GL(TexImage2D(GL_TEXTURE_2D, 0, internalFormat, glDesc.fAllocWidth,
758 glDesc.fAllocHeight, 0, glDesc.fUploadFormat,
759 glDesc.fUploadType, srcData));
760 GrGL_RestoreResetRowLength();
761 }
762 }
763
764 glDesc.fOrientation = GrGLTexture::kTopDown_Orientation;
765
766 GrGLRenderTarget::GLRenderTargetIDs rtIDs;
767 rtIDs.fStencilRenderbufferID = 0;
768 rtIDs.fMSColorRenderbufferID = 0;
769 rtIDs.fRTFBOID = 0;
770 rtIDs.fTexFBOID = 0;
771 rtIDs.fOwnIDs = true;
772 GLenum msColorRenderbufferFormat = -1;
773
774 if (renderTarget) {
775#if GR_COLLECT_STATS
776 ++fStats.fRenderTargetCreateCnt;
777#endif
778 bool failed = true;
779 GLenum status;
780 GLint err;
781
782 // If need have both RT flag and srcData we have
783 // to invert the data before uploading because FBO
784 // will be rendered bottom up
785 GrAssert(NULL == srcData);
786 glDesc.fOrientation = GrGLTexture::kBottomUp_Orientation;
787
788 GR_GLEXT(fExts, GenFramebuffers(1, &rtIDs.fTexFBOID));
789 GrAssert(rtIDs.fTexFBOID);
790
791 // If we are using multisampling and any extension other than the IMG
792 // one we will create two FBOs. We render to one and then resolve to
793 // the texture bound to the other. The IMG extension does an implicit
794 // resolve.
795 if (samples > 1 && kIMG_MSFBO != fMSFBOType && kNone_MSFBO != fMSFBOType) {
796 GR_GLEXT(fExts, GenFramebuffers(1, &rtIDs.fRTFBOID));
797 GrAssert(0 != rtIDs.fRTFBOID);
798 GR_GLEXT(fExts, GenRenderbuffers(1, &rtIDs.fMSColorRenderbufferID));
799 GrAssert(0 != rtIDs.fMSColorRenderbufferID);
800 if (!fboInternalFormat(desc.fFormat, &msColorRenderbufferFormat)) {
801 GR_GLEXT(fExts,
802 DeleteRenderbuffers(1, &rtIDs.fMSColorRenderbufferID));
803 GR_GL(DeleteTextures(1, &glDesc.fTextureID));
804 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fTexFBOID));
805 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fRTFBOID));
reed@google.comac10a2d2010-12-22 21:39:39 +0000806 return return_null_texture();
807 }
808 } else {
809 rtIDs.fRTFBOID = rtIDs.fTexFBOID;
810 }
811 int attempts = 1;
812 if (!(kNoPathRendering_TextureFlag & desc.fFlags)) {
813 GR_GLEXT(fExts, GenRenderbuffers(1, &rtIDs.fStencilRenderbufferID));
814 GrAssert(0 != rtIDs.fStencilRenderbufferID);
815 attempts = GR_ARRAY_COUNT(GR_GL_STENCIL_FORMAT_ARRAY);
816 }
817
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000818 // someone suggested that some systems might require
bsalomon@google.com316f99232011-01-13 21:28:12 +0000819 // unbinding the texture before we call FramebufferTexture2D
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000820 // (seems unlikely)
reed@google.comac10a2d2010-12-22 21:39:39 +0000821 GR_GL(BindTexture(GL_TEXTURE_2D, 0));
reed@google.comac10a2d2010-12-22 21:39:39 +0000822
823 err = ~GL_NO_ERROR;
824 for (int i = 0; i < attempts; ++i) {
825 if (rtIDs.fStencilRenderbufferID) {
826 GR_GLEXT(fExts, BindRenderbuffer(GR_RENDERBUFFER,
827 rtIDs.fStencilRenderbufferID));
828 if (samples > 1) {
829 GR_GLEXT_NO_ERR(fExts, RenderbufferStorageMultisample(
830 GR_RENDERBUFFER,
831 samples,
832 GR_GL_STENCIL_FORMAT_ARRAY[i],
833 glDesc.fAllocWidth,
834 glDesc.fAllocHeight));
835 } else {
836 GR_GLEXT_NO_ERR(fExts, RenderbufferStorage(
837 GR_RENDERBUFFER,
838 GR_GL_STENCIL_FORMAT_ARRAY[i],
839 glDesc.fAllocWidth,
840 glDesc.fAllocHeight));
841 }
842 err = glGetError();
843 if (err != GL_NO_ERROR) {
844 continue;
845 }
846 }
847 if (rtIDs.fRTFBOID != rtIDs.fTexFBOID) {
848 GrAssert(samples > 1);
849 GR_GLEXT(fExts, BindRenderbuffer(GR_RENDERBUFFER,
850 rtIDs.fMSColorRenderbufferID));
851 GR_GLEXT_NO_ERR(fExts, RenderbufferStorageMultisample(
852 GR_RENDERBUFFER,
853 samples,
854 msColorRenderbufferFormat,
855 glDesc.fAllocWidth,
856 glDesc.fAllocHeight));
857 err = glGetError();
858 if (err != GL_NO_ERROR) {
859 continue;
860 }
861 }
862 GR_GLEXT(fExts, BindFramebuffer(GR_FRAMEBUFFER, rtIDs.fTexFBOID));
863
864#if GR_COLLECT_STATS
865 ++fStats.fRenderTargetChngCnt;
866#endif
867 if (kIMG_MSFBO == fMSFBOType && samples > 1) {
868 GR_GLEXT(fExts, FramebufferTexture2DMultisample(
869 GR_FRAMEBUFFER,
870 GR_COLOR_ATTACHMENT0,
871 GL_TEXTURE_2D,
872 glDesc.fTextureID,
873 0,
874 samples));
875
876 } else {
877 GR_GLEXT(fExts, FramebufferTexture2D(GR_FRAMEBUFFER,
878 GR_COLOR_ATTACHMENT0,
879 GL_TEXTURE_2D,
880 glDesc.fTextureID, 0));
881 }
882 if (rtIDs.fRTFBOID != rtIDs.fTexFBOID) {
883 GLenum status = GR_GLEXT(fExts,
884 CheckFramebufferStatus(GR_FRAMEBUFFER));
885 if (status != GR_FRAMEBUFFER_COMPLETE) {
886 GrPrintf("-- glCheckFramebufferStatus %x %d %d\n",
887 status, desc.fWidth, desc.fHeight);
888 continue;
889 }
890 GR_GLEXT(fExts, BindFramebuffer(GR_FRAMEBUFFER, rtIDs.fRTFBOID));
891 #if GR_COLLECT_STATS
892 ++fStats.fRenderTargetChngCnt;
893 #endif
894 GR_GLEXT(fExts, FramebufferRenderbuffer(GR_FRAMEBUFFER,
895 GR_COLOR_ATTACHMENT0,
896 GR_RENDERBUFFER,
897 rtIDs.fMSColorRenderbufferID));
898
899 }
900 if (rtIDs.fStencilRenderbufferID) {
901 // bind the stencil to rt fbo if present, othewise the tex fbo
902 GR_GLEXT(fExts, FramebufferRenderbuffer(GR_FRAMEBUFFER,
903 GR_STENCIL_ATTACHMENT,
bsalomon@google.com316f99232011-01-13 21:28:12 +0000904 GR_RENDERBUFFER,
reed@google.comac10a2d2010-12-22 21:39:39 +0000905 rtIDs.fStencilRenderbufferID));
906 }
907 status = GR_GLEXT(fExts, CheckFramebufferStatus(GR_FRAMEBUFFER));
908
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000909#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000910 // On some implementations you have to be bound as DEPTH_STENCIL.
911 // (Even binding to DEPTH and STENCIL separately with the same
912 // buffer doesn't work.)
913 if (rtIDs.fStencilRenderbufferID &&
914 status != GR_FRAMEBUFFER_COMPLETE) {
915 GR_GLEXT(fExts, FramebufferRenderbuffer(GR_FRAMEBUFFER,
916 GR_STENCIL_ATTACHMENT,
917 GR_RENDERBUFFER,
918 0));
919 GR_GLEXT(fExts,
920 FramebufferRenderbuffer(GR_FRAMEBUFFER,
921 GR_DEPTH_STENCIL_ATTACHMENT,
922 GR_RENDERBUFFER,
923 rtIDs.fStencilRenderbufferID));
924 status = GR_GLEXT(fExts, CheckFramebufferStatus(GR_FRAMEBUFFER));
925 }
926#endif
927 if (status != GR_FRAMEBUFFER_COMPLETE) {
928 GrPrintf("-- glCheckFramebufferStatus %x %d %d\n",
929 status, desc.fWidth, desc.fHeight);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000930#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000931 if (rtIDs.fStencilRenderbufferID) {
932 GR_GLEXT(fExts, FramebufferRenderbuffer(GR_FRAMEBUFFER,
933 GR_DEPTH_STENCIL_ATTACHMENT,
934 GR_RENDERBUFFER,
935 0));
936 }
937#endif
938 continue;
939 }
940 // we're successful!
941 failed = false;
942 break;
943 }
944 if (failed) {
945 if (rtIDs.fStencilRenderbufferID) {
946 GR_GLEXT(fExts,
947 DeleteRenderbuffers(1, &rtIDs.fStencilRenderbufferID));
948 }
949 if (rtIDs.fMSColorRenderbufferID) {
950 GR_GLEXT(fExts,
951 DeleteRenderbuffers(1, &rtIDs.fMSColorRenderbufferID));
952 }
953 if (rtIDs.fRTFBOID != rtIDs.fTexFBOID) {
954 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fRTFBOID));
955 }
956 if (rtIDs.fTexFBOID) {
957 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fTexFBOID));
958 }
959 GR_GL(DeleteTextures(1, &glDesc.fTextureID));
960 return return_null_texture();
961 }
962 }
963#ifdef TRACE_TEXTURE_CREATION
964 GrPrintf("--- new texture [%d] size=(%d %d) bpp=%d\n",
965 tex->fTextureID, width, height, tex->fUploadByteCount);
966#endif
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000967 GrGLTexture* tex = new GrGLTexture(glDesc, rtIDs, DEFAULT_PARAMS, this);
reed@google.comac10a2d2010-12-22 21:39:39 +0000968
969 if (0 != rtIDs.fTexFBOID) {
970 GrRenderTarget* rt = tex->asRenderTarget();
971 // We've messed with FBO state but may not have set the correct viewport
972 // so just dirty the rendertarget state to force a resend.
973 fHWDrawState.fRenderTarget = NULL;
974
975 // clear the new stencil buffer if we have one
976 if (!(desc.fFlags & kNoPathRendering_TextureFlag)) {
977 GrRenderTarget* rtSave = fCurrDrawState.fRenderTarget;
978 fCurrDrawState.fRenderTarget = rt;
979 eraseStencil(0, ~0);
980 fCurrDrawState.fRenderTarget = rtSave;
981 }
982 }
983 return tex;
984}
985
reed@google.comac10a2d2010-12-22 21:39:39 +0000986GrVertexBuffer* GrGpuGL::createVertexBuffer(uint32_t size, bool dynamic) {
987 GLuint id;
988 GR_GL(GenBuffers(1, &id));
989 if (id) {
990 GR_GL(BindBuffer(GL_ARRAY_BUFFER, id));
991 GrGLClearErr();
992 // make sure driver can allocate memory for this buffer
993 GR_GL_NO_ERR(BufferData(GL_ARRAY_BUFFER, size, NULL,
994 dynamic ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW));
995 if (glGetError() != GL_NO_ERROR) {
996 GR_GL(DeleteBuffers(1, &id));
997 // deleting bound buffer does implicit bind to 0
998 fHWGeometryState.fVertexBuffer = NULL;
999 return NULL;
1000 }
1001 GrGLVertexBuffer* vertexBuffer = new GrGLVertexBuffer(id, this,
1002 size, dynamic);
1003 fHWGeometryState.fVertexBuffer = vertexBuffer;
1004 return vertexBuffer;
1005 }
1006 return NULL;
1007}
1008
1009GrIndexBuffer* GrGpuGL::createIndexBuffer(uint32_t size, bool dynamic) {
1010 GLuint id;
1011 GR_GL(GenBuffers(1, &id));
1012 if (id) {
1013 GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, id));
1014 GrGLClearErr();
1015 // make sure driver can allocate memory for this buffer
1016 GR_GL_NO_ERR(BufferData(GL_ELEMENT_ARRAY_BUFFER, size, NULL,
1017 dynamic ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW));
1018 if (glGetError() != GL_NO_ERROR) {
1019 GR_GL(DeleteBuffers(1, &id));
1020 // deleting bound buffer does implicit bind to 0
1021 fHWGeometryState.fIndexBuffer = NULL;
1022 return NULL;
1023 }
1024 GrIndexBuffer* indexBuffer = new GrGLIndexBuffer(id, this,
1025 size, dynamic);
1026 fHWGeometryState.fIndexBuffer = indexBuffer;
1027 return indexBuffer;
1028 }
1029 return NULL;
1030}
1031
reed@google.comac10a2d2010-12-22 21:39:39 +00001032void GrGpuGL::flushScissor(const GrIRect* rect) {
1033 GrAssert(NULL != fCurrDrawState.fRenderTarget);
1034 const GrIRect& vp =
1035 ((GrGLRenderTarget*)fCurrDrawState.fRenderTarget)->viewport();
1036
1037 if (NULL != rect &&
1038 rect->contains(vp)) {
1039 rect = NULL;
1040 }
1041
1042 if (NULL != rect) {
1043 GrIRect scissor;
1044 // viewport is already in GL coords
1045 // create a scissor in GL coords (top > bottom)
1046 scissor.setLTRB(vp.fLeft + rect->fLeft,
1047 vp.fTop - rect->fTop,
1048 vp.fLeft + rect->fRight,
1049 vp.fTop - rect->fBottom);
1050
1051 if (fHWBounds.fScissorRect != scissor) {
1052 GR_GL(Scissor(scissor.fLeft, scissor.fBottom,
1053 scissor.width(), -scissor.height()));
1054 fHWBounds.fScissorRect = scissor;
1055 }
1056
1057 if (!fHWBounds.fScissorEnabled) {
1058 GR_GL(Enable(GL_SCISSOR_TEST));
1059 fHWBounds.fScissorEnabled = true;
1060 }
1061 } else {
1062 if (fHWBounds.fScissorEnabled) {
1063 GR_GL(Disable(GL_SCISSOR_TEST));
1064 fHWBounds.fScissorEnabled = false;
1065 }
1066 }
1067}
1068
reed@google.comac10a2d2010-12-22 21:39:39 +00001069void GrGpuGL::eraseColor(GrColor color) {
1070 flushRenderTarget();
1071 if (fHWBounds.fScissorEnabled) {
1072 GR_GL(Disable(GL_SCISSOR_TEST));
1073 }
1074 GR_GL(ColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE));
1075 GR_GL(ClearColor(GrColorUnpackR(color)/255.f,
1076 GrColorUnpackG(color)/255.f,
1077 GrColorUnpackB(color)/255.f,
1078 GrColorUnpackA(color)/255.f));
1079 GR_GL(Clear(GL_COLOR_BUFFER_BIT));
1080 fHWBounds.fScissorEnabled = false;
1081 fWriteMaskChanged = true;
1082}
1083
1084void GrGpuGL::eraseStencil(uint32_t value, uint32_t mask) {
1085 flushRenderTarget();
1086 if (fHWBounds.fScissorEnabled) {
1087 GR_GL(Disable(GL_SCISSOR_TEST));
1088 }
1089 GR_GL(StencilMask(mask));
1090 GR_GL(ClearStencil(value));
1091 GR_GL(Clear(GL_STENCIL_BUFFER_BIT));
1092 fHWBounds.fScissorEnabled = false;
1093 fWriteMaskChanged = true;
1094}
1095
1096void GrGpuGL::eraseStencilClip() {
1097 GLint stencilBitCount;
reed@google.comac20fb92011-01-12 17:14:53 +00001098 GR_GL_GetIntegerv(GL_STENCIL_BITS, &stencilBitCount);
reed@google.comac10a2d2010-12-22 21:39:39 +00001099 GrAssert(stencilBitCount > 0);
1100 GLint clipStencilMask = (1 << (stencilBitCount - 1));
1101 eraseStencil(0, clipStencilMask);
1102}
1103
1104void GrGpuGL::forceRenderTargetFlush() {
1105 flushRenderTarget();
1106}
1107
1108bool GrGpuGL::readPixels(int left, int top, int width, int height,
1109 GrTexture::PixelConfig config, void* buffer) {
1110 GLenum internalFormat; // we don't use this for glReadPixels
1111 GLenum format;
1112 GLenum type;
1113 if (!this->canBeTexture(config, &internalFormat, &format, &type)) {
1114 return false;
1115 }
1116
1117 GrAssert(NULL != fCurrDrawState.fRenderTarget);
1118 const GrIRect& vp = ((GrGLRenderTarget*)fCurrDrawState.fRenderTarget)->viewport();
1119
1120 // Brian says that viewport rects are already upside down (grrrrr)
bsalomon@google.com316f99232011-01-13 21:28:12 +00001121 GR_GL(ReadPixels(left, -vp.height() - top - height, width, height,
1122 format, type, buffer));
reed@google.comac10a2d2010-12-22 21:39:39 +00001123
1124 // now reverse the order of the rows, since GL's are bottom-to-top, but our
1125 // API presents top-to-bottom
1126 {
1127 size_t stride = width * GrTexture::BytesPerPixel(config);
1128 GrAutoMalloc rowStorage(stride);
1129 void* tmp = rowStorage.get();
1130
1131 const int halfY = height >> 1;
1132 char* top = reinterpret_cast<char*>(buffer);
1133 char* bottom = top + (height - 1) * stride;
1134 for (int y = 0; y < halfY; y++) {
1135 memcpy(tmp, top, stride);
1136 memcpy(top, bottom, stride);
1137 memcpy(bottom, tmp, stride);
1138 top += stride;
1139 bottom -= stride;
1140 }
1141 }
1142 return true;
1143}
1144
1145void GrGpuGL::flushRenderTarget() {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001146
1147 GrAssert(NULL != fCurrDrawState.fRenderTarget);
1148
reed@google.comac10a2d2010-12-22 21:39:39 +00001149 if (fHWDrawState.fRenderTarget != fCurrDrawState.fRenderTarget) {
1150 GrGLRenderTarget* rt = (GrGLRenderTarget*)fCurrDrawState.fRenderTarget;
1151 GR_GLEXT(fExts, BindFramebuffer(GR_FRAMEBUFFER, rt->renderFBOID()));
1152 #if GR_COLLECT_STATS
1153 ++fStats.fRenderTargetChngCnt;
1154 #endif
1155 rt->setDirty(true);
1156 #if GR_DEBUG
1157 GLenum status = GR_GLEXT(fExts, CheckFramebufferStatus(GR_FRAMEBUFFER));
1158 if (status != GR_FRAMEBUFFER_COMPLETE) {
1159 GrPrintf("-- glCheckFramebufferStatus %x\n", status);
1160 }
1161 #endif
1162 fHWDrawState.fRenderTarget = fCurrDrawState.fRenderTarget;
1163 const GrIRect& vp = rt->viewport();
1164 fRenderTargetChanged = true;
1165 if (fHWBounds.fViewportRect != vp) {
1166 GR_GL(Viewport(vp.fLeft,
1167 vp.fBottom,
1168 vp.width(),
1169 -vp.height()));
1170 fHWBounds.fViewportRect = vp;
1171 }
1172 }
1173}
1174
1175GLenum gPrimitiveType2GLMode[] = {
1176 GL_TRIANGLES,
1177 GL_TRIANGLE_STRIP,
1178 GL_TRIANGLE_FAN,
1179 GL_POINTS,
1180 GL_LINES,
1181 GL_LINE_STRIP
1182};
1183
1184void GrGpuGL::drawIndexedHelper(PrimitiveType type,
1185 uint32_t startVertex,
1186 uint32_t startIndex,
1187 uint32_t vertexCount,
1188 uint32_t indexCount) {
1189 GrAssert((size_t)type < GR_ARRAY_COUNT(gPrimitiveType2GLMode));
1190
1191 GLvoid* indices = (GLvoid*)(sizeof(uint16_t) * startIndex);
1192 if (kReserved_GeometrySrcType == fGeometrySrc.fIndexSrc) {
1193 indices = (GLvoid*)((intptr_t)indices + (intptr_t)fIndices.get());
1194 } else if (kArray_GeometrySrcType == fGeometrySrc.fIndexSrc) {
1195 indices = (GLvoid*)((intptr_t)indices +
1196 (intptr_t)fGeometrySrc.fIndexArray);
1197 }
1198
1199 GR_GL(DrawElements(gPrimitiveType2GLMode[type], indexCount,
1200 GL_UNSIGNED_SHORT, indices));
1201}
1202
1203void GrGpuGL::drawNonIndexedHelper(PrimitiveType type,
1204 uint32_t startVertex,
1205 uint32_t vertexCount) {
1206 GrAssert((size_t)type < GR_ARRAY_COUNT(gPrimitiveType2GLMode));
1207
1208 GR_GL(DrawArrays(gPrimitiveType2GLMode[type], 0, vertexCount));
1209}
1210
1211#if !defined(SK_GL_HAS_COLOR4UB)
1212static inline GrFixed byte2fixed(unsigned value) {
1213 return (value + (value >> 7)) << 8;
1214}
1215#endif
1216
1217void GrGpuGL::resolveTextureRenderTarget(GrGLTexture* texture) {
1218 GrGLRenderTarget* rt = (GrGLRenderTarget*) texture->asRenderTarget();
1219
1220 if (NULL != rt && rt->needsResolve()) {
1221 GrAssert(kNone_MSFBO != fMSFBOType);
1222 GrAssert(rt->textureFBOID() != rt->renderFBOID());
1223 GR_GLEXT(fExts, BindFramebuffer(GR_READ_FRAMEBUFFER,
1224 rt->renderFBOID()));
1225 GR_GLEXT(fExts, BindFramebuffer(GR_DRAW_FRAMEBUFFER,
1226 rt->textureFBOID()));
1227 #if GR_COLLECT_STATS
1228 ++fStats.fRenderTargetChngCnt;
1229 #endif
1230 // make sure we go through set render target
1231 fHWDrawState.fRenderTarget = NULL;
1232
1233 GLint left = 0;
1234 GLint right = texture->contentWidth();
1235 // we will have rendered to the top of the FBO.
1236 GLint top = texture->allocHeight();
1237 GLint bottom = texture->allocHeight() - texture->contentHeight();
1238 if (kApple_MSFBO == fMSFBOType) {
1239 GR_GL(Enable(GL_SCISSOR_TEST));
1240 GR_GL(Scissor(left, bottom, right-left, top-bottom));
1241 GR_GLEXT(fExts, ResolveMultisampleFramebuffer());
1242 fHWBounds.fScissorRect.setEmpty();
1243 fHWBounds.fScissorEnabled = true;
1244 } else {
1245 GR_GLEXT(fExts, BlitFramebuffer(left, bottom, right, top,
1246 left, bottom, right, top,
1247 GL_COLOR_BUFFER_BIT, GL_NEAREST));
1248 }
1249 rt->setDirty(false);
1250
1251 }
1252}
1253
1254void GrGpuGL::flushStencil() {
1255
1256 // use stencil for clipping if clipping is enabled and the clip
1257 // has been written into the stencil.
1258 bool stencilClip = fClipState.fClipInStencil &&
1259 (kClip_StateBit & fCurrDrawState.fFlagBits);
1260 bool stencilChange =
1261 fWriteMaskChanged ||
1262 fHWStencilClip != stencilClip ||
1263 fHWDrawState.fStencilPass != fCurrDrawState.fStencilPass ||
1264 (kNone_StencilPass != fCurrDrawState.fStencilPass &&
1265 (StencilPass)kSetClip_StencilPass != fCurrDrawState.fStencilPass &&
1266 fHWDrawState.fReverseFill != fCurrDrawState.fReverseFill);
1267
1268 if (stencilChange) {
1269 GLint stencilBitCount;
1270 GLint clipStencilMask;
1271 GLint pathStencilMask;
reed@google.comac20fb92011-01-12 17:14:53 +00001272 GR_GL_GetIntegerv(GL_STENCIL_BITS, &stencilBitCount);
reed@google.comac10a2d2010-12-22 21:39:39 +00001273 GrAssert(stencilBitCount > 0 ||
1274 kNone_StencilPass == fCurrDrawState.fStencilPass);
1275 clipStencilMask = (1 << (stencilBitCount - 1));
1276 pathStencilMask = clipStencilMask - 1;
1277 switch (fCurrDrawState.fStencilPass) {
1278 case kNone_StencilPass:
1279 if (stencilClip) {
1280 GR_GL(Enable(GL_STENCIL_TEST));
1281 GR_GL(StencilFunc(GL_EQUAL,
1282 clipStencilMask,
1283 clipStencilMask));
1284 GR_GL(StencilOp(GL_KEEP, GL_KEEP, GL_KEEP));
1285 } else {
1286 GR_GL(Disable(GL_STENCIL_TEST));
1287 }
1288 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
1289 if (!fSingleStencilPassForWinding) {
1290 GR_GL(Disable(GL_CULL_FACE));
1291 }
1292 break;
1293 case kEvenOddStencil_StencilPass:
1294 GR_GL(Enable(GL_STENCIL_TEST));
1295 if (stencilClip) {
1296 GR_GL(StencilFunc(GL_EQUAL, clipStencilMask, clipStencilMask));
1297 } else {
1298 GR_GL(StencilFunc(GL_ALWAYS, 0x0, 0x0));
1299 }
1300 GR_GL(StencilMask(pathStencilMask));
1301 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
1302 GR_GL(StencilOp(GL_KEEP, GL_INVERT, GL_INVERT));
1303 GR_GL(ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE));
1304 if (!fSingleStencilPassForWinding) {
1305 GR_GL(Disable(GL_CULL_FACE));
1306 }
1307 break;
1308 case kEvenOddColor_StencilPass: {
1309 GR_GL(Enable(GL_STENCIL_TEST));
1310 GLint funcRef = 0;
1311 GLuint funcMask = pathStencilMask;
1312 if (stencilClip) {
1313 funcRef |= clipStencilMask;
1314 funcMask |= clipStencilMask;
1315 }
1316 if (!fCurrDrawState.fReverseFill) {
1317 funcRef |= pathStencilMask;
1318 }
bsalomon@google.com316f99232011-01-13 21:28:12 +00001319 GR_GL(StencilFunc(GL_EQUAL, funcRef, funcMask));
1320 GR_GL(StencilMask(pathStencilMask));
reed@google.comac10a2d2010-12-22 21:39:39 +00001321 GR_GL(StencilOp(GL_ZERO, GL_ZERO, GL_ZERO));
1322 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
1323 if (!fSingleStencilPassForWinding) {
1324 GR_GL(Disable(GL_CULL_FACE));
1325 }
1326 } break;
1327 case kWindingStencil1_StencilPass:
1328 GR_GL(Enable(GL_STENCIL_TEST));
1329 if (fHasStencilWrap) {
1330 if (stencilClip) {
1331 GR_GL(StencilFunc(GL_EQUAL,
1332 clipStencilMask,
1333 clipStencilMask));
1334 } else {
1335 GR_GL(StencilFunc(GL_ALWAYS, 0x0, 0x0));
1336 }
1337 if (fSingleStencilPassForWinding) {
1338 GR_GL(StencilOpSeparate(GL_FRONT, GL_KEEP,
1339 GL_INCR_WRAP, GL_INCR_WRAP));
1340 GR_GL(StencilOpSeparate(GL_BACK, GL_KEEP,
1341 GL_DECR_WRAP, GL_DECR_WRAP));
1342 } else {
1343 GR_GL(StencilOp(GL_KEEP, GL_INCR_WRAP, GL_INCR_WRAP));
1344 GR_GL(Enable(GL_CULL_FACE));
1345 GR_GL(CullFace(GL_BACK));
1346 }
1347 } else {
1348 // If we don't have wrap then we use the Func to detect
1349 // values that would wrap (0 on decr and mask on incr). We
1350 // make the func fail on these values and use the sfail op
1351 // to effectively wrap by inverting.
1352 // This applies whether we are doing a two-pass (front faces
1353 // followed by back faces) or a single pass (separate func/op)
1354
1355 // Note that in the case where we are also using stencil to
1356 // clip this means we will write into the path bits in clipped
1357 // out pixels. We still apply the clip bit in the color pass
1358 // stencil func so we don't draw color outside the clip.
1359 // We also will clear the stencil bits in clipped pixels by
1360 // using zero in the sfail op with write mask set to the
1361 // path mask.
1362 GR_GL(Enable(GL_STENCIL_TEST));
1363 if (fSingleStencilPassForWinding) {
1364 GR_GL(StencilFuncSeparate(GL_FRONT,
1365 GL_NOTEQUAL,
1366 pathStencilMask,
1367 pathStencilMask));
1368 GR_GL(StencilFuncSeparate(GL_BACK,
1369 GL_NOTEQUAL,
1370 0x0,
1371 pathStencilMask));
1372 GR_GL(StencilOpSeparate(GL_FRONT, GL_INVERT,
1373 GL_INCR, GL_INCR));
1374 GR_GL(StencilOpSeparate(GL_BACK, GL_INVERT,
1375 GL_DECR, GL_DECR));
1376 } else {
1377 GR_GL(StencilFunc(GL_NOTEQUAL,
1378 pathStencilMask,
1379 pathStencilMask));
1380 GR_GL(StencilOp(GL_INVERT, GL_INCR, GL_INCR));
1381 GR_GL(Enable(GL_CULL_FACE));
1382 GR_GL(CullFace(GL_BACK));
1383 }
1384 }
1385 GR_GL(StencilMask(pathStencilMask));
1386 GR_GL(ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE));
1387 break;
1388 case kWindingStencil2_StencilPass:
1389 GrAssert(!fSingleStencilPassForWinding);
1390 GR_GL(Enable(GL_STENCIL_TEST));
1391 if (fHasStencilWrap) {
1392 if (stencilClip) {
1393 GR_GL(StencilFunc(GL_EQUAL,
1394 clipStencilMask,
1395 clipStencilMask));
1396 } else {
1397 GR_GL(StencilFunc(GL_ALWAYS, 0x0, 0x0));
1398 }
1399 GR_GL(StencilOp(GL_DECR_WRAP, GL_DECR_WRAP, GL_DECR_WRAP));
1400 } else {
1401 GR_GL(StencilFunc(GL_NOTEQUAL, 0x0, pathStencilMask));
1402 GR_GL(StencilOp(GL_INVERT, GL_DECR, GL_DECR));
1403 }
1404 GR_GL(StencilMask(pathStencilMask));
1405 GR_GL(Enable(GL_CULL_FACE));
1406 GR_GL(CullFace(GL_FRONT));
1407 GR_GL(ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE));
1408 break;
1409 case kWindingColor_StencilPass: {
1410 GR_GL(Enable(GL_STENCIL_TEST));
1411 GLint funcRef = 0;
1412 GLuint funcMask = pathStencilMask;
1413 GLenum funcFunc;
1414 if (stencilClip) {
1415 funcRef |= clipStencilMask;
1416 funcMask |= clipStencilMask;
1417 }
1418 if (fCurrDrawState.fReverseFill) {
1419 funcFunc = GL_EQUAL;
1420 } else {
1421 funcFunc = GL_LESS;
1422 }
1423 GR_GL(StencilFunc(funcFunc, funcRef, funcMask));
1424 GR_GL(StencilMask(pathStencilMask));
1425 // must zero in sfail because winding w/o wrap will write
1426 // path stencil bits in clipped out pixels
1427 GR_GL(StencilOp(GL_ZERO, GL_ZERO, GL_ZERO));
1428 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
1429 if (!fSingleStencilPassForWinding) {
1430 GR_GL(Disable(GL_CULL_FACE));
1431 }
1432 } break;
1433 case kSetClip_StencilPass:
1434 GR_GL(Enable(GL_STENCIL_TEST));
1435 GR_GL(StencilFunc(GL_ALWAYS, clipStencilMask, clipStencilMask));
1436 GR_GL(StencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE));
1437 GR_GL(StencilMask(clipStencilMask));
1438 GR_GL(ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE));
1439 if (!fSingleStencilPassForWinding) {
1440 GR_GL(Disable(GL_CULL_FACE));
1441 }
1442 break;
1443 default:
1444 GrAssert(!"Unexpected stencil pass.");
1445 break;
1446
1447 }
1448 fHWDrawState.fStencilPass = fCurrDrawState.fStencilPass;
1449 fHWDrawState.fReverseFill = fCurrDrawState.fReverseFill;
1450 fWriteMaskChanged = false;
1451 fHWStencilClip = stencilClip;
1452 }
1453}
1454
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001455bool GrGpuGL::flushGLStateCommon(PrimitiveType type) {
1456
1457 // GrGpu::setupClipAndFlushState should have already checked this
1458 // and bailed if not true.
1459 GrAssert(NULL != fCurrDrawState.fRenderTarget);
reed@google.comac10a2d2010-12-22 21:39:39 +00001460
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001461 for (int s = 0; s < kNumStages; ++s) {
1462 bool usingTexture = VertexUsesStage(s, fGeometrySrc.fVertexLayout);
reed@google.comac10a2d2010-12-22 21:39:39 +00001463
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001464 // bind texture and set sampler state
1465 if (usingTexture) {
1466 GrGLTexture* nextTexture = (GrGLTexture*)fCurrDrawState.fTextures[s];
reed@google.comac10a2d2010-12-22 21:39:39 +00001467
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001468 if (NULL != nextTexture) {
bsalomon@google.com316f99232011-01-13 21:28:12 +00001469 // if we created a rt/tex and rendered to it without using a
1470 // texture and now we're texuring from the rt it will still be
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001471 // the last bound texture, but it needs resolving. So keep this
1472 // out of the "last != next" check.
1473 resolveTextureRenderTarget(nextTexture);
reed@google.comac10a2d2010-12-22 21:39:39 +00001474
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001475 if (fHWDrawState.fTextures[s] != nextTexture) {
1476 setTextureUnit(s);
1477 GR_GL(BindTexture(GL_TEXTURE_2D, nextTexture->textureID()));
1478 #if GR_COLLECT_STATS
1479 ++fStats.fTextureChngCnt;
1480 #endif
1481 //GrPrintf("---- bindtexture %d\n", nextTexture->textureID());
1482 fHWDrawState.fTextures[s] = nextTexture;
1483 }
bsalomon@google.com316f99232011-01-13 21:28:12 +00001484
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001485 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
bsalomon@google.com316f99232011-01-13 21:28:12 +00001486 const GrGLTexture::TexParams& oldTexParams =
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001487 nextTexture->getTexParams();
1488 GrGLTexture::TexParams newTexParams;
bsalomon@google.com316f99232011-01-13 21:28:12 +00001489
1490 newTexParams.fFilter = sampler.isFilter() ? GL_LINEAR :
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001491 GL_NEAREST;
bsalomon@google.com316f99232011-01-13 21:28:12 +00001492 newTexParams.fWrapS =
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001493 GrGLTexture::gWrapMode2GLWrap[sampler.getWrapX()];
bsalomon@google.com316f99232011-01-13 21:28:12 +00001494 newTexParams.fWrapT =
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001495 GrGLTexture::gWrapMode2GLWrap[sampler.getWrapY()];
reed@google.comac10a2d2010-12-22 21:39:39 +00001496
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001497 if (newTexParams.fFilter != oldTexParams.fFilter) {
1498 setTextureUnit(s);
bsalomon@google.com316f99232011-01-13 21:28:12 +00001499 GR_GL(TexParameteri(GL_TEXTURE_2D,
1500 GL_TEXTURE_MAG_FILTER,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001501 newTexParams.fFilter));
bsalomon@google.com316f99232011-01-13 21:28:12 +00001502 GR_GL(TexParameteri(GL_TEXTURE_2D,
1503 GL_TEXTURE_MIN_FILTER,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001504 newTexParams.fFilter));
1505 }
1506 if (newTexParams.fWrapS != oldTexParams.fWrapS) {
1507 setTextureUnit(s);
bsalomon@google.com316f99232011-01-13 21:28:12 +00001508 GR_GL(TexParameteri(GL_TEXTURE_2D,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001509 GL_TEXTURE_WRAP_S,
1510 newTexParams.fWrapS));
1511 }
1512 if (newTexParams.fWrapT != oldTexParams.fWrapT) {
1513 setTextureUnit(s);
bsalomon@google.com316f99232011-01-13 21:28:12 +00001514 GR_GL(TexParameteri(GL_TEXTURE_2D,
1515 GL_TEXTURE_WRAP_T,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001516 newTexParams.fWrapT));
1517 }
1518 nextTexture->setTexParams(newTexParams);
1519 } else {
1520 GrAssert(!"Rendering with texture vert flag set but no texture");
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001521 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +00001522 }
1523 }
1524 }
1525
1526 flushRenderTarget();
1527
1528 if ((fCurrDrawState.fFlagBits & kDither_StateBit) !=
1529 (fHWDrawState.fFlagBits & kDither_StateBit)) {
1530 if (fCurrDrawState.fFlagBits & kDither_StateBit) {
1531 GR_GL(Enable(GL_DITHER));
1532 } else {
1533 GR_GL(Disable(GL_DITHER));
1534 }
1535 }
1536
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001537#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +00001538 // ES doesn't support toggling GL_MULTISAMPLE and doesn't have
1539 // smooth lines.
1540 if (fRenderTargetChanged ||
1541 (fCurrDrawState.fFlagBits & kAntialias_StateBit) !=
1542 (fHWDrawState.fFlagBits & kAntialias_StateBit)) {
1543 GLint msaa = 0;
1544 // only perform query if we know MSAA is supported.
1545 // calling on non-MSAA target caused a crash in one environment,
1546 // though I don't think it should.
1547 if (!fAASamples[kHigh_AALevel]) {
reed@google.comac20fb92011-01-12 17:14:53 +00001548 GR_GL_GetIntegerv(GL_SAMPLE_BUFFERS, &msaa);
reed@google.comac10a2d2010-12-22 21:39:39 +00001549 }
1550 if (fCurrDrawState.fFlagBits & kAntialias_StateBit) {
1551 if (msaa) {
1552 GR_GL(Enable(GL_MULTISAMPLE));
1553 } else {
1554 GR_GL(Enable(GL_LINE_SMOOTH));
1555 }
1556 } else {
1557 if (msaa) {
1558 GR_GL(Disable(GL_MULTISAMPLE));
1559 }
1560 GR_GL(Disable(GL_LINE_SMOOTH));
1561 }
1562 }
1563#endif
1564
1565 bool blendOff = canDisableBlend();
1566 if (fHWBlendDisabled != blendOff) {
1567 if (blendOff) {
1568 GR_GL(Disable(GL_BLEND));
1569 } else {
1570 GR_GL(Enable(GL_BLEND));
1571 }
1572 fHWBlendDisabled = blendOff;
1573 }
1574
1575 if (!blendOff) {
1576 if (fHWDrawState.fSrcBlend != fCurrDrawState.fSrcBlend ||
1577 fHWDrawState.fDstBlend != fCurrDrawState.fDstBlend) {
1578 GR_GL(BlendFunc(gXfermodeCoeff2Blend[fCurrDrawState.fSrcBlend],
1579 gXfermodeCoeff2Blend[fCurrDrawState.fDstBlend]));
1580 fHWDrawState.fSrcBlend = fCurrDrawState.fSrcBlend;
1581 fHWDrawState.fDstBlend = fCurrDrawState.fDstBlend;
1582 }
1583 }
bsalomon@google.com316f99232011-01-13 21:28:12 +00001584
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001585#if GR_DEBUG
reed@google.comac10a2d2010-12-22 21:39:39 +00001586 // check for circular rendering
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001587 for (int s = 0; s < kNumStages; ++s) {
1588 GrAssert(!VertexUsesStage(s, fGeometrySrc.fVertexLayout) ||
1589 NULL == fCurrDrawState.fRenderTarget ||
1590 NULL == fCurrDrawState.fTextures[s] ||
bsalomon@google.com316f99232011-01-13 21:28:12 +00001591 fCurrDrawState.fTextures[s]->asRenderTarget() !=
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001592 fCurrDrawState.fRenderTarget);
1593 }
1594#endif
bsalomon@google.com316f99232011-01-13 21:28:12 +00001595
reed@google.comac10a2d2010-12-22 21:39:39 +00001596 flushStencil();
1597
1598 fHWDrawState.fFlagBits = fCurrDrawState.fFlagBits;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001599 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +00001600}
1601
1602void GrGpuGL::notifyVertexBufferBind(const GrGLVertexBuffer* buffer) {
1603 fHWGeometryState.fVertexBuffer = buffer;
1604}
1605
1606void GrGpuGL::notifyVertexBufferDelete(const GrGLVertexBuffer* buffer) {
1607 GrAssert(!(kBuffer_GeometrySrcType == fGeometrySrc.fVertexSrc &&
1608 buffer == fGeometrySrc.fVertexBuffer));
1609
1610 if (fHWGeometryState.fVertexBuffer == buffer) {
1611 // deleting bound buffer does implied bind to 0
1612 fHWGeometryState.fVertexBuffer = NULL;
1613 }
1614}
1615
1616void GrGpuGL::notifyIndexBufferBind(const GrGLIndexBuffer* buffer) {
1617 fGeometrySrc.fIndexBuffer = buffer;
1618}
1619
1620void GrGpuGL::notifyIndexBufferDelete(const GrGLIndexBuffer* buffer) {
1621 GrAssert(!(kBuffer_GeometrySrcType == fGeometrySrc.fIndexSrc &&
1622 buffer == fGeometrySrc.fIndexBuffer));
1623
1624 if (fHWGeometryState.fIndexBuffer == buffer) {
1625 // deleting bound buffer does implied bind to 0
1626 fHWGeometryState.fIndexBuffer = NULL;
1627 }
1628}
1629
reed@google.comac10a2d2010-12-22 21:39:39 +00001630void GrGpuGL::notifyRenderTargetDelete(GrRenderTarget* renderTarget) {
1631 GrAssert(NULL != renderTarget);
1632
1633 // if the bound FBO is destroyed we can't rely on the implicit bind to 0
1634 // a) we want the default RT which may not be FBO 0
1635 // b) we set more state than just FBO based on the RT
1636 // So trash the HW state to force an RT flush next time
1637 if (fCurrDrawState.fRenderTarget == renderTarget) {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001638 fCurrDrawState.fRenderTarget = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +00001639 }
1640 if (fHWDrawState.fRenderTarget == renderTarget) {
1641 fHWDrawState.fRenderTarget = NULL;
1642 }
1643 if (fClipState.fStencilClipTarget == renderTarget) {
1644 fClipState.fStencilClipTarget = NULL;
1645 }
1646}
1647
1648void GrGpuGL::notifyTextureDelete(GrGLTexture* texture) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001649 for (int s = 0; s < kNumStages; ++s) {
1650 if (fCurrDrawState.fTextures[s] == texture) {
1651 fCurrDrawState.fTextures[s] = NULL;
1652 }
1653 if (fHWDrawState.fTextures[s] == texture) {
1654 // deleting bound texture does implied bind to 0
1655 fHWDrawState.fTextures[s] = NULL;
1656 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001657 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001658}
1659
1660void GrGpuGL::notifyTextureRemoveRenderTarget(GrGLTexture* texture) {
1661 GrAssert(NULL != texture->asRenderTarget());
1662
1663 // if there is a pending resolve, perform it.
1664 resolveTextureRenderTarget(texture);
1665}
1666
1667bool GrGpuGL::canBeTexture(GrTexture::PixelConfig config,
1668 GLenum* internalFormat,
1669 GLenum* format,
1670 GLenum* type) {
1671 switch (config) {
1672 case GrTexture::kRGBA_8888_PixelConfig:
1673 case GrTexture::kRGBX_8888_PixelConfig: // todo: can we tell it our X?
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +00001674 *format = GR_GL_32BPP_COLOR_FORMAT;
reed@google.com63100f92011-01-18 21:32:14 +00001675#if GR_SUPPORT_GLES
1676 // according to GL_EXT_texture_format_BGRA8888 the *internal*
1677 // format for a BGRA is BGRA not RGBA (as on desktop)
1678 *internalFormat = GR_GL_32BPP_COLOR_FORMAT;
1679#else
1680 *internalFormat = GL_RGBA;
bsalomon@google.comed3a0682011-01-18 16:54:04 +00001681#endif
reed@google.comac10a2d2010-12-22 21:39:39 +00001682 *type = GL_UNSIGNED_BYTE;
1683 break;
1684 case GrTexture::kRGB_565_PixelConfig:
1685 *format = GL_RGB;
1686 *internalFormat = GL_RGB;
1687 *type = GL_UNSIGNED_SHORT_5_6_5;
1688 break;
1689 case GrTexture::kRGBA_4444_PixelConfig:
1690 *format = GL_RGBA;
1691 *internalFormat = GL_RGBA;
1692 *type = GL_UNSIGNED_SHORT_4_4_4_4;
1693 break;
1694 case GrTexture::kIndex_8_PixelConfig:
1695 if (this->supports8BitPalette()) {
1696 *format = GR_PALETTE8_RGBA8;
1697 *internalFormat = GR_PALETTE8_RGBA8;
1698 *type = GL_UNSIGNED_BYTE; // unused I think
1699 } else {
1700 return false;
1701 }
1702 break;
1703 case GrTexture::kAlpha_8_PixelConfig:
1704 *format = GL_ALPHA;
1705 *internalFormat = GL_ALPHA;
1706 *type = GL_UNSIGNED_BYTE;
1707 break;
1708 default:
1709 return false;
1710 }
1711 return true;
1712}
1713
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001714void GrGpuGL::setTextureUnit(int unit) {
1715 GrAssert(unit >= 0 && unit < kNumStages);
1716 if (fActiveTextureUnitIdx != unit) {
1717 GR_GL(ActiveTexture(GL_TEXTURE0 + unit));
1718 fActiveTextureUnitIdx = unit;
1719 }
1720}
bsalomon@google.com316f99232011-01-13 21:28:12 +00001721
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001722void GrGpuGL::setSpareTextureUnit() {
1723 if (fActiveTextureUnitIdx != (GL_TEXTURE0 + SPARE_TEX_UNIT)) {
1724 GR_GL(ActiveTexture(GL_TEXTURE0 + SPARE_TEX_UNIT));
1725 fActiveTextureUnitIdx = SPARE_TEX_UNIT;
1726 }
1727}
1728
reed@google.comac10a2d2010-12-22 21:39:39 +00001729/* On ES the internalFormat and format must match for TexImage and we use
1730 GL_RGB, GL_RGBA for color formats. We also generally like having the driver
1731 decide the internalFormat. However, on ES internalFormat for
1732 RenderBufferStorage* has to be a specific format (not a base format like
1733 GL_RGBA).
1734 */
1735bool GrGpuGL::fboInternalFormat(GrTexture::PixelConfig config, GLenum* format) {
1736 switch (config) {
1737 case GrTexture::kRGBA_8888_PixelConfig:
1738 case GrTexture::kRGBX_8888_PixelConfig:
1739 if (fRGBA8Renderbuffer) {
1740 *format = GR_RGBA8;
1741 return true;
1742 } else {
1743 return false;
1744 }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001745#if GR_SUPPORT_GLES // ES2 supports 565. ES1 supports it with FBO extension
1746 // desktop GL has no such internal format
reed@google.comac10a2d2010-12-22 21:39:39 +00001747 case GrTexture::kRGB_565_PixelConfig:
1748 *format = GR_RGB565;
1749 return true;
1750#endif
1751 case GrTexture::kRGBA_4444_PixelConfig:
1752 *format = GL_RGBA4;
1753 return true;
1754 default:
1755 return false;
1756 }
1757}
1758
1759///////////////////////////////////////////////////////////////////////////////
1760
1761void GrGLCheckErr(const char* location, const char* call) {
1762 uint32_t err = glGetError();
1763 if (GL_NO_ERROR != err) {
1764 GrPrintf("---- glGetError %x", err);
1765 if (NULL != location) {
1766 GrPrintf(" at\n\t%s", location);
1767 }
1768 if (NULL != call) {
1769 GrPrintf("\n\t\t%s", call);
1770 }
1771 GrPrintf("\n");
1772 }
1773}
1774
1775///////////////////////////////////////////////////////////////////////////////
1776
1777typedef void (*glProc)(void);
1778
1779void get_gl_proc(const char procName[], glProc *address) {
reed@google.com63100f92011-01-18 21:32:14 +00001780#if GR_CHROME_BUILD
1781 GrAssert(!"should not get called");
1782#elif GR_WIN32_BUILD
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +00001783 *address = (glProc)wglGetProcAddress(procName);
reed@google.comac10a2d2010-12-22 21:39:39 +00001784 GrAssert(NULL != *address);
1785#elif GR_MAC_BUILD || GR_IOS_BUILD
1786 GrAssert(!"Extensions don't need to be initialized!");
1787#elif GR_ANDROID_BUILD
1788 *address = eglGetProcAddress(procName);
1789 GrAssert(NULL != *address);
1790#elif GR_LINUX_BUILD
reed@google.com37df17d2010-12-23 20:20:51 +00001791// GR_STATIC_ASSERT(!"Add environment-dependent implementation here");
reed@google.comac10a2d2010-12-22 21:39:39 +00001792 //*address = glXGetProcAddressARB(procName);
reed@google.com37df17d2010-12-23 20:20:51 +00001793 *address = NULL;//eglGetProcAddress(procName);
reed@google.comac10a2d2010-12-22 21:39:39 +00001794#elif GR_QNX_BUILD
1795 *address = eglGetProcAddress(procName);
1796 GrAssert(NULL != *address);
1797#else
1798 // hopefully we're on a system with EGL
1799 *address = eglGetProcAddress(procName);
1800 GrAssert(NULL != *address);
1801#endif
1802}
1803
1804#define GET_PROC(EXT_STRUCT, PROC_NAME, EXT_TAG) \
1805 get_gl_proc("gl" #PROC_NAME #EXT_TAG, (glProc*)&EXT_STRUCT-> PROC_NAME);
1806
1807extern void GrGLInitExtensions(GrGLExts* exts) {
1808 exts->GenFramebuffers = NULL;
1809 exts->BindFramebuffer = NULL;
1810 exts->FramebufferTexture2D = NULL;
1811 exts->CheckFramebufferStatus = NULL;
1812 exts->DeleteFramebuffers = NULL;
1813 exts->RenderbufferStorage = NULL;
1814 exts->GenRenderbuffers = NULL;
1815 exts->DeleteRenderbuffers = NULL;
1816 exts->FramebufferRenderbuffer = NULL;
1817 exts->BindRenderbuffer = NULL;
1818 exts->RenderbufferStorageMultisample = NULL;
1819 exts->BlitFramebuffer = NULL;
1820 exts->ResolveMultisampleFramebuffer = NULL;
1821 exts->FramebufferTexture2DMultisample = NULL;
1822 exts->MapBuffer = NULL;
1823 exts->UnmapBuffer = NULL;
1824
1825#if GR_MAC_BUILD
1826 exts->GenFramebuffers = glGenFramebuffers;
1827 exts->BindFramebuffer = glBindFramebuffer;
1828 exts->FramebufferTexture2D = glFramebufferTexture2D;
1829 exts->CheckFramebufferStatus = glCheckFramebufferStatus;
1830 exts->DeleteFramebuffers = glDeleteFramebuffers;
1831 exts->RenderbufferStorage = glRenderbufferStorage;
1832 exts->GenRenderbuffers = glGenRenderbuffers;
1833 exts->DeleteRenderbuffers = glDeleteRenderbuffers;
1834 exts->FramebufferRenderbuffer = glFramebufferRenderbuffer;
1835 exts->BindRenderbuffer = glBindRenderbuffer;
1836 exts->RenderbufferStorageMultisample = glRenderbufferStorageMultisample;
1837 exts->BlitFramebuffer = glBlitFramebuffer;
1838 exts->MapBuffer = glMapBuffer;
1839 exts->UnmapBuffer = glUnmapBuffer;
1840#elif GR_IOS_BUILD
1841 exts->GenFramebuffers = glGenFramebuffers;
1842 exts->BindFramebuffer = glBindFramebuffer;
1843 exts->FramebufferTexture2D = glFramebufferTexture2D;
1844 exts->CheckFramebufferStatus = glCheckFramebufferStatus;
1845 exts->DeleteFramebuffers = glDeleteFramebuffers;
1846 exts->RenderbufferStorage = glRenderbufferStorage;
1847 exts->GenRenderbuffers = glGenRenderbuffers;
1848 exts->DeleteRenderbuffers = glDeleteRenderbuffers;
1849 exts->FramebufferRenderbuffer = glFramebufferRenderbuffer;
1850 exts->BindRenderbuffer = glBindRenderbuffer;
1851 exts->RenderbufferStorageMultisample = glRenderbufferStorageMultisampleAPPLE;
1852 exts->ResolveMultisampleFramebuffer = glResolveMultisampleFramebufferAPPLE;
1853 exts->MapBuffer = glMapBufferOES;
1854 exts->UnmapBuffer = glUnmapBufferOES;
1855#else
1856 GLint major, minor;
1857 gl_version(&major, &minor);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001858 #if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +00001859 if (major >= 3) {// FBO, FBOMS, and FBOBLIT part of 3.0
1860 exts->GenFramebuffers = glGenFramebuffers;
1861 exts->BindFramebuffer = glBindFramebuffer;
1862 exts->FramebufferTexture2D = glFramebufferTexture2D;
1863 exts->CheckFramebufferStatus = glCheckFramebufferStatus;
1864 exts->DeleteFramebuffers = glDeleteFramebuffers;
1865 exts->RenderbufferStorage = glRenderbufferStorage;
1866 exts->GenRenderbuffers = glGenRenderbuffers;
1867 exts->DeleteRenderbuffers = glDeleteRenderbuffers;
1868 exts->FramebufferRenderbuffer = glFramebufferRenderbuffer;
1869 exts->BindRenderbuffer = glBindRenderbuffer;
1870 exts->RenderbufferStorageMultisample = glRenderbufferStorageMultisample;
1871 exts->BlitFramebuffer = glBlitFramebuffer;
1872 } else if (has_gl_extension("GL_ARB_framebuffer_object")) {
1873 GET_PROC(exts, GenFramebuffers, ARB);
1874 GET_PROC(exts, BindFramebuffer, ARB);
1875 GET_PROC(exts, FramebufferTexture2D, ARB);
1876 GET_PROC(exts, CheckFramebufferStatus, ARB);
1877 GET_PROC(exts, DeleteFramebuffers, ARB);
1878 GET_PROC(exts, RenderbufferStorage, ARB);
1879 GET_PROC(exts, GenRenderbuffers, ARB);
1880 GET_PROC(exts, DeleteRenderbuffers, ARB);
1881 GET_PROC(exts, FramebufferRenderbuffer, ARB);
1882 GET_PROC(exts, BindRenderbuffer, ARB);
1883 GET_PROC(exts, RenderbufferStorageMultisample, ARB);
1884 GET_PROC(exts, BlitFramebuffer, ARB);
1885 } else {
1886 // we require some form of FBO
1887 GrAssert(has_gl_extension("GL_EXT_framebuffer_object"));
1888 GET_PROC(exts, GenFramebuffers, EXT);
1889 GET_PROC(exts, BindFramebuffer, EXT);
1890 GET_PROC(exts, FramebufferTexture2D, EXT);
1891 GET_PROC(exts, CheckFramebufferStatus, EXT);
1892 GET_PROC(exts, DeleteFramebuffers, EXT);
1893 GET_PROC(exts, RenderbufferStorage, EXT);
1894 GET_PROC(exts, GenRenderbuffers, EXT);
1895 GET_PROC(exts, DeleteRenderbuffers, EXT);
1896 GET_PROC(exts, FramebufferRenderbuffer, EXT);
1897 GET_PROC(exts, BindRenderbuffer, EXT);
1898 if (has_gl_extension("GL_EXT_framebuffer_multisample")) {
1899 GET_PROC(exts, RenderbufferStorageMultisample, EXT);
1900 }
1901 if (has_gl_extension("GL_EXT_framebuffer_blit")) {
1902 GET_PROC(exts, BlitFramebuffer, EXT);
1903 }
1904 }
1905 // we assume we have at least GL 1.5 or higher (VBOs introduced in 1.5)
1906 exts->MapBuffer = glMapBuffer;
1907 exts->UnmapBuffer = glUnmapBuffer;
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001908 #else // !GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +00001909 if (major >= 2) {// ES 2.0 supports FBO
1910 exts->GenFramebuffers = glGenFramebuffers;
1911 exts->BindFramebuffer = glBindFramebuffer;
1912 exts->FramebufferTexture2D = glFramebufferTexture2D;
1913 exts->CheckFramebufferStatus = glCheckFramebufferStatus;
1914 exts->DeleteFramebuffers = glDeleteFramebuffers;
1915 exts->RenderbufferStorage = glRenderbufferStorage;
1916 exts->GenRenderbuffers = glGenRenderbuffers;
1917 exts->DeleteRenderbuffers = glDeleteRenderbuffers;
1918 exts->FramebufferRenderbuffer = glFramebufferRenderbuffer;
1919 exts->BindRenderbuffer = glBindRenderbuffer;
1920 } else {
1921 // we require some form of FBO
1922 GrAssert(has_gl_extension("GL_OES_framebuffer_object"));
1923
1924 GET_PROC(exts, GenFramebuffers, OES);
1925 GET_PROC(exts, BindFramebuffer, OES);
1926 GET_PROC(exts, FramebufferTexture2D, OES);
1927 GET_PROC(exts, CheckFramebufferStatus, OES);
1928 GET_PROC(exts, DeleteFramebuffers, OES);
1929 GET_PROC(exts, RenderbufferStorage, OES);
1930 GET_PROC(exts, GenRenderbuffers, OES);
1931 GET_PROC(exts, DeleteRenderbuffers, OES);
1932 GET_PROC(exts, FramebufferRenderbuffer, OES);
1933 GET_PROC(exts, BindRenderbuffer, OES);
1934 }
1935 if (has_gl_extension("GL_APPLE_framebuffer_multisample")) {
1936 GET_PROC(exts, ResolveMultisampleFramebuffer, APPLE);
1937 }
1938 if (has_gl_extension("GL_IMG_multisampled_render_to_texture")) {
1939 GET_PROC(exts, FramebufferTexture2DMultisample, IMG);
1940 }
1941 if (has_gl_extension("GL_OES_mapbuffer")) {
1942 GET_PROC(exts, MapBuffer, OES);
1943 GET_PROC(exts, UnmapBuffer, OES);
1944 }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001945 #endif // !GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +00001946#endif // BUILD
1947}
1948
1949bool gPrintGL = true;
1950
reed@google.com63100f92011-01-18 21:32:14 +00001951