blob: 23636d1a926d80f423a085c523c796b42648fdc1 [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
155 GrGLRenderTarget::GLRenderTargetIDs defaultRTIDs;
reed@google.comac20fb92011-01-12 17:14:53 +0000156 GR_GL_GetIntegerv(GR_FRAMEBUFFER_BINDING, (GLint*)&defaultRTIDs.fRTFBOID);
reed@google.comac10a2d2010-12-22 21:39:39 +0000157 defaultRTIDs.fTexFBOID = defaultRTIDs.fRTFBOID;
158 defaultRTIDs.fMSColorRenderbufferID = 0;
159 defaultRTIDs.fStencilRenderbufferID = 0;
160 GLint vp[4];
reed@google.comac20fb92011-01-12 17:14:53 +0000161 GR_GL_GetIntegerv(GL_VIEWPORT, vp);
reed@google.comac10a2d2010-12-22 21:39:39 +0000162 fHWBounds.fViewportRect.setLTRB(vp[0],
163 vp[1] + vp[3],
164 vp[0] + vp[2],
165 vp[1]);
166 defaultRTIDs.fOwnIDs = false;
167
168 fDefaultRenderTarget = new GrGLRenderTarget(defaultRTIDs,
169 fHWBounds.fViewportRect,
170 NULL,
171 this);
172 fHWDrawState.fRenderTarget = fDefaultRenderTarget;
173 fRenderTargetChanged = true;
bsalomon@google.com316f99232011-01-13 21:28:12 +0000174
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000175 GLint maxTextureUnits;
176 // check FS and fixed-function texture unit limits
177 // we only use textures in the fragment stage currently.
178 // checks are > to make sure we have a spare unit.
179#if GR_SUPPORT_GLDESKTOP || GR_SUPPORT_GLES2
180 GR_GL(GetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextureUnits));
181 GrAssert(maxTextureUnits > kNumStages);
182#endif
183#if GR_SUPPORT_GLDESKTOP || GR_SUPPORT_GLES1
184 GR_GL(GetIntegerv(GL_MAX_TEXTURE_UNITS, &maxTextureUnits));
185 GrAssert(maxTextureUnits > kNumStages);
186#endif
bsalomon@google.com316f99232011-01-13 21:28:12 +0000187
reed@google.comac10a2d2010-12-22 21:39:39 +0000188 fCurrDrawState = fHWDrawState;
189
190 ////////////////////////////////////////////////////////////////////////////
191 // Check for supported features.
192
193 int major, minor;
194 gl_version(&major, &minor);
195
196 GLint numFormats;
reed@google.comac20fb92011-01-12 17:14:53 +0000197 GR_GL_GetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &numFormats);
reed@google.comac10a2d2010-12-22 21:39:39 +0000198 GrAutoSTMalloc<10, GLint> formats(numFormats);
reed@google.comac20fb92011-01-12 17:14:53 +0000199 GR_GL_GetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, formats);
reed@google.comac10a2d2010-12-22 21:39:39 +0000200 for (int i = 0; i < numFormats; ++i) {
201 if (formats[i] == GR_PALETTE8_RGBA8) {
202 f8bitPaletteSupport = true;
203 break;
204 }
205 }
reed@google.comeeeb5a02010-12-23 15:12:59 +0000206
207 if (gPrintStartupSpew) {
208 GrPrintf("Palette8 support: %s\n", (f8bitPaletteSupport ? "YES" : "NO"));
209 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000210
211 GR_STATIC_ASSERT(0 == kNone_AALevel);
212 GR_STATIC_ASSERT(1 == kLow_AALevel);
213 GR_STATIC_ASSERT(2 == kMed_AALevel);
214 GR_STATIC_ASSERT(3 == kHigh_AALevel);
215
216 memset(fAASamples, 0, sizeof(fAASamples));
217 fMSFBOType = kNone_MSFBO;
218 if (has_gl_extension("GL_IMG_multisampled_render_to_texture")) {
219 fMSFBOType = kIMG_MSFBO;
reed@google.comeeeb5a02010-12-23 15:12:59 +0000220 if (gPrintStartupSpew) {
221 GrPrintf("MSAA Support: IMG ES EXT.\n");
222 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000223 }
224 else if (has_gl_extension("GL_APPLE_framebuffer_multisample")) {
225 fMSFBOType = kApple_MSFBO;
reed@google.comeeeb5a02010-12-23 15:12:59 +0000226 if (gPrintStartupSpew) {
227 GrPrintf("MSAA Support: APPLE ES EXT.\n");
228 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000229 }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000230#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000231 else if ((major >= 3) ||
232 has_gl_extension("GL_ARB_framebuffer_object") ||
233 (has_gl_extension("GL_EXT_framebuffer_multisample") &&
234 has_gl_extension("GL_EXT_framebuffer_blit"))) {
235 fMSFBOType = kDesktop_MSFBO;
reed@google.comeeeb5a02010-12-23 15:12:59 +0000236 if (gPrintStartupSpew) {
237 GrPrintf("MSAA Support: DESKTOP\n");
238 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000239 }
240#endif
241 else {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000242 if (gPrintStartupSpew) {
243 GrPrintf("MSAA Support: NONE\n");
244 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000245 }
246
247 if (kNone_MSFBO != fMSFBOType) {
248 GLint maxSamples;
249 GLenum maxSampleGetter = (kIMG_MSFBO == fMSFBOType) ?
250 GR_MAX_SAMPLES_IMG :
251 GR_MAX_SAMPLES;
reed@google.comac20fb92011-01-12 17:14:53 +0000252 GR_GL_GetIntegerv(maxSampleGetter, &maxSamples);
reed@google.comac10a2d2010-12-22 21:39:39 +0000253 if (maxSamples > 1 ) {
254 fAASamples[kNone_AALevel] = 0;
255 fAASamples[kLow_AALevel] = GrMax(2,
256 GrFixedFloorToInt((GR_FixedHalf) *
257 maxSamples));
258 fAASamples[kMed_AALevel] = GrMax(2,
259 GrFixedFloorToInt(((GR_Fixed1*3)/4) *
260 maxSamples));
261 fAASamples[kHigh_AALevel] = maxSamples;
262 }
reed@google.comeeeb5a02010-12-23 15:12:59 +0000263 if (gPrintStartupSpew) {
264 GrPrintf("\tMax Samples: %d\n", maxSamples);
265 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000266 }
267
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000268#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000269 fHasStencilWrap = (major >= 2 || (major == 1 && minor >= 4)) ||
270 has_gl_extension("GL_EXT_stencil_wrap");
271#else
272 fHasStencilWrap = (major >= 2) || has_gl_extension("GL_OES_stencil_wrap");
273#endif
reed@google.comeeeb5a02010-12-23 15:12:59 +0000274 if (gPrintStartupSpew) {
275 GrPrintf("Stencil Wrap: %s\n", (fHasStencilWrap ? "YES" : "NO"));
276 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000277
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000278#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000279 // we could also look for GL_ATI_separate_stencil extension or
280 // GL_EXT_stencil_two_side but they use different function signatures
281 // than GL2.0+ (and than each other).
282 fSingleStencilPassForWinding = (major >= 2);
283#else
284 // ES 2 has two sided stencil but 1.1 doesn't. There doesn't seem to be
285 // an ES1 extension.
286 fSingleStencilPassForWinding = (major >= 2);
287#endif
reed@google.comeeeb5a02010-12-23 15:12:59 +0000288 if (gPrintStartupSpew) {
289 GrPrintf("Single Stencil Pass For Winding: %s\n", (fSingleStencilPassForWinding ? "YES" : "NO"));
290 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000291
292
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000293#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000294 fRGBA8Renderbuffer = true;
295#else
296 fRGBA8Renderbuffer = has_gl_extension("GL_OES_rgb8_rgba8");
297#endif
reed@google.comeeeb5a02010-12-23 15:12:59 +0000298 if (gPrintStartupSpew) {
299 GrPrintf("RGBA Renderbuffer: %s\n", (fRGBA8Renderbuffer ? "YES" : "NO"));
300 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000301
bsalomon@google.comed3a0682011-01-18 16:54:04 +0000302#if GR_SUPPORT_GLES
303 if (GR_GL_32BPP_COLOR_FORMAT == GR_BGRA) {
304 GrAssert(has_gl_extension("GL_EXT_texture_format_BGRA8888"));
305 }
306#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000307
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000308#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000309 fBufferLockSupport = true; // we require VBO support and the desktop VBO
310 // extension includes glMapBuffer.
311#else
312 fBufferLockSupport = has_gl_extension("GL_OES_mapbuffer");
313#endif
reed@google.comeeeb5a02010-12-23 15:12:59 +0000314 if (gPrintStartupSpew) {
315 GrPrintf("Map Buffer: %s\n", (fBufferLockSupport ? "YES" : "NO"));
316 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000317
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000318#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000319 fNPOTTextureSupport =
320 (major >= 2 || has_gl_extension("GL_ARB_texture_non_power_of_two")) ?
321 kFull_NPOTTextureType :
322 kNone_NPOTTextureType;
323#else
324 if (has_gl_extension("GL_OES_texture_npot")) {
325 fNPOTTextureSupport = kFull_NPOTTextureType;
326 } else if (major >= 2 ||
327 has_gl_extension("GL_APPLE_texture_2D_limited_npot")) {
328 fNPOTTextureSupport = kNoRepeat_NPOTTextureType;
329 } else {
330 fNPOTTextureSupport = kNone_NPOTTextureType;
331 }
332#endif
333 ////////////////////////////////////////////////////////////////////////////
334 // Experiments to determine limitations that can't be queried. TODO: Make
335 // these a preprocess that generate some compile time constants.
336
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000337 // sanity check to make sure we can at least create an FBO from a POT texture
338 if (fNPOTTextureSupport < kFull_NPOTTextureType) {
339 bool npotFBOSuccess = fbo_test(fExts, 128, 128);
340 if (gPrintStartupSpew) {
341 if (!npotFBOSuccess) {
342 GrPrintf("FBO Sanity Test: FAILED\n");
343 } else {
344 GrPrintf("FBO Sanity Test: PASSED\n");
345 }
346 }
347 }
reed@google.comac20fb92011-01-12 17:14:53 +0000348
reed@google.comac10a2d2010-12-22 21:39:39 +0000349 /* Experimentation has found that some GLs that support NPOT textures
350 do not support FBOs with a NPOT texture. They report "unsupported" FBO
351 status. I don't know how to explicitly query for this. Do an
352 experiment. Note they may support NPOT with a renderbuffer but not a
353 texture. Presumably, the implementation bloats the renderbuffer
354 internally to the next POT.
355 */
356 if (fNPOTTextureSupport == kFull_NPOTTextureType) {
357 bool npotFBOSuccess = fbo_test(fExts, 200, 200);
358 if (!npotFBOSuccess) {
359 fNPOTTextureSupport = kNonRendertarget_NPOTTextureType;
reed@google.comeeeb5a02010-12-23 15:12:59 +0000360 if (gPrintStartupSpew) {
361 GrPrintf("NPOT Renderbuffer Test: FAILED\n");
362 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000363 } else {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000364 if (gPrintStartupSpew) {
365 GrPrintf("NPOT Renderbuffer Test: PASSED\n");
366 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000367 }
368 }
reed@google.comeeeb5a02010-12-23 15:12:59 +0000369
370 if (gPrintStartupSpew) {
371 switch (fNPOTTextureSupport) {
372 case kNone_NPOTTextureType:
373 GrPrintf("NPOT Support: NONE\n");
374 break;
375 case kNoRepeat_NPOTTextureType:
376 GrPrintf("NPOT Support: NO REPEAT\n");
377 break;
378 case kNonRendertarget_NPOTTextureType:
379 GrPrintf("NPOT Support: NO FBOTEX\n");
380 break;
381 case kFull_NPOTTextureType:
382 GrPrintf("NPOT Support: FULL\n");
383 break;
384 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000385 }
386
reed@google.comac10a2d2010-12-22 21:39:39 +0000387 /* The iPhone 4 has a restriction that for an FBO with texture color
388 attachment with height <= 8 then the width must be <= height. Here
389 we look for such a limitation.
390 */
391 fMinRenderTargetHeight = GR_INVAL_GLINT;
392 GLint maxRenderSize;
reed@google.comac20fb92011-01-12 17:14:53 +0000393 GR_GL_GetIntegerv(GR_MAX_RENDERBUFFER_SIZE, &maxRenderSize);
reed@google.comac10a2d2010-12-22 21:39:39 +0000394
reed@google.comeeeb5a02010-12-23 15:12:59 +0000395 if (gPrintStartupSpew) {
396 GrPrintf("Small height FBO texture experiments\n");
397 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000398 for (GLuint i = 1; i <= 256;
399 (kFull_NPOTTextureType != fNPOTTextureSupport) ? i *= 2 : ++i) {
400 GLuint w = maxRenderSize;
401 GLuint h = i;
402 if (fbo_test(fExts, w, h)) {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000403 if (gPrintStartupSpew) {
404 GrPrintf("\t[%d, %d]: PASSED\n", w, h);
405 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000406 fMinRenderTargetHeight = i;
407 break;
408 } else {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000409 if (gPrintStartupSpew) {
410 GrPrintf("\t[%d, %d]: FAILED\n", w, h);
411 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000412 }
413 }
414 GrAssert(GR_INVAL_GLINT != fMinRenderTargetHeight);
415
reed@google.comeeeb5a02010-12-23 15:12:59 +0000416 if (gPrintStartupSpew) {
417 GrPrintf("Small width FBO texture experiments\n");
418 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000419 fMinRenderTargetWidth = GR_MAX_GLUINT;
420 for (GLuint i = 1; i <= 256;
421 (kFull_NPOTTextureType != fNPOTTextureSupport) ? i *= 2 : ++i) {
422 GLuint w = i;
423 GLuint h = maxRenderSize;
424 if (fbo_test(fExts, w, h)) {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000425 if (gPrintStartupSpew) {
426 GrPrintf("\t[%d, %d]: PASSED\n", w, h);
427 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000428 fMinRenderTargetWidth = i;
429 break;
430 } else {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000431 if (gPrintStartupSpew) {
432 GrPrintf("\t[%d, %d]: FAILED\n", w, h);
433 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000434 }
435 }
436 GrAssert(GR_INVAL_GLINT != fMinRenderTargetWidth);
437
438#if GR_IOS_BUILD
439 /*
440 The iPad seems to fail, at least sometimes, if the height is < 16,
441 so we pin the values here for now. A better fix might be to
442 conditionalize this based on known that its an iPad (or some other
443 check).
444 */
445 fMinRenderTargetWidth = GrMax<GLuint>(fMinRenderTargetWidth, 16);
446 fMinRenderTargetHeight = GrMax<GLuint>(fMinRenderTargetHeight, 16);
447#endif
448 // bind back to original FBO
449 GR_GLEXT(fExts, BindFramebuffer(GR_FRAMEBUFFER, defaultRTIDs.fRTFBOID));
450#if GR_COLLECT_STATS
451 ++fStats.fRenderTargetChngCnt;
452#endif
453 eraseStencil(0, ~0);
454}
455
456GrGpuGL::~GrGpuGL() {
457 fDefaultRenderTarget->abandon();
458 fDefaultRenderTarget->unref();
459}
460
461void GrGpuGL::resetContextHelper() {
462// We detect cases when blending is effectively off
463 fHWBlendDisabled = false;
464 GR_GL(Enable(GL_BLEND));
465
466 // this is always disabled
467 GR_GL(Disable(GL_CULL_FACE));
468
469 GR_GL(Disable(GL_DITHER));
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000470#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000471 GR_GL(Disable(GL_LINE_SMOOTH));
472 GR_GL(Disable(GL_POINT_SMOOTH));
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000473 GR_GL(Disable(GL_MULTISAMPLE));
reed@google.comac10a2d2010-12-22 21:39:39 +0000474#endif
475
476 // we only ever use lines in hairline mode
477 GR_GL(LineWidth(1));
478
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000479 // invalid
480 fActiveTextureUnitIdx = -1;
reed@google.comac10a2d2010-12-22 21:39:39 +0000481
482 fHWDrawState.fFlagBits = 0;
483
484 // illegal values
485 fHWDrawState.fSrcBlend = (BlendCoeff)-1;
486 fHWDrawState.fDstBlend = (BlendCoeff)-1;
487 fHWDrawState.fColor = GrColor_ILLEGAL;
488 fHWDrawState.fPointSize = -1;
bsalomon@google.com316f99232011-01-13 21:28:12 +0000489
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000490 fHWDrawState.fViewMatrix.setScale(GR_ScalarMax, GR_ScalarMax); // illegal
bsalomon@google.com316f99232011-01-13 21:28:12 +0000491
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000492 for (int s = 0; s < kNumStages; ++s) {
493 fHWDrawState.fTextures[s] = NULL;
494 fHWDrawState.fSamplerStates[s].setRadial2Params(-GR_ScalarMax,
495 -GR_ScalarMax,
496 true);
bsalomon@google.com316f99232011-01-13 21:28:12 +0000497 fHWDrawState.fTextureMatrices[s].setScale(GR_ScalarMax, GR_ScalarMax);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000498 }
bsalomon@google.com316f99232011-01-13 21:28:12 +0000499
reed@google.comac10a2d2010-12-22 21:39:39 +0000500 GR_GL(Scissor(0,0,0,0));
501 fHWBounds.fScissorRect.setLTRB(0,0,0,0);
502 fHWBounds.fScissorEnabled = false;
503 GR_GL(Disable(GL_SCISSOR_TEST));
504
reed@google.comac10a2d2010-12-22 21:39:39 +0000505 // disabling the stencil test also disables
506 // stencil buffer writes
507 GR_GL(Disable(GL_STENCIL_TEST));
508 GR_GL(StencilMask(0xffffffff));
509 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
510 fHWDrawState.fReverseFill = false;
511 fHWDrawState.fStencilPass = kNone_StencilPass;
512 fHWStencilClip = false;
513
514 fHWGeometryState.fIndexBuffer = NULL;
515 fHWGeometryState.fVertexBuffer = NULL;
516 GR_GL(BindBuffer(GL_ARRAY_BUFFER, 0));
517 GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
518
519 fHWDrawState.fRenderTarget = NULL;
520}
521
522void GrGpuGL::resetContext() {
523 INHERITED::resetContext();
524 resetContextHelper();
525}
526
reed@google.comac10a2d2010-12-22 21:39:39 +0000527GrRenderTarget* GrGpuGL::createPlatformRenderTarget(
528 intptr_t platformRenderTarget,
529 int width, int height) {
530 GrGLRenderTarget::GLRenderTargetIDs rtIDs;
531 rtIDs.fStencilRenderbufferID = 0;
532 rtIDs.fMSColorRenderbufferID = 0;
533 rtIDs.fTexFBOID = 0;
534 rtIDs.fOwnIDs = false;
535
536 GrIRect viewport;
537
538 // viewport is in GL coords (top >= bottom)
539 viewport.setLTRB(0, height, width, 0);
540
541 rtIDs.fRTFBOID = (GLuint)platformRenderTarget;
542 rtIDs.fTexFBOID = (GLuint)platformRenderTarget;
543
544 GrGLRenderTarget* rt = new GrGLRenderTarget(rtIDs, viewport, NULL, this);
545
546 return rt;
547}
548
bsalomon@google.com3f3ffd62011-01-18 17:14:52 +0000549// defines stencil formats from more to less preferred
550GLenum GR_GL_STENCIL_FORMAT_ARRAY[] = {
551 GR_STENCIL_INDEX8,
552
553#if GR_SUPPORT_GLDESKTOP
554 GR_STENCIL_INDEX16,
555#endif
556
557 GR_DEPTH24_STENCIL8,
558 GR_STENCIL_INDEX4,
559
560#if GR_SUPPORT_GLDESKTOP
561 GL_STENCIL_INDEX,
562 GR_DEPTH_STENCIL,
563#endif
564};
565
566// good to set a break-point here to know when createTexture fails
567static GrTexture* return_null_texture() {
568// GrAssert(!"null texture");
569 return NULL;
570}
571
572#if GR_DEBUG
573static size_t as_size_t(int x) {
574 return x;
575}
576#endif
577
reed@google.comac10a2d2010-12-22 21:39:39 +0000578GrTexture* GrGpuGL::createTexture(const TextureDesc& desc,
579 const void* srcData, size_t rowBytes) {
580
581#if GR_COLLECT_STATS
582 ++fStats.fTextureCreateCnt;
583#endif
reed@google.com1fcd51e2011-01-05 15:50:27 +0000584
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000585 setSpareTextureUnit();
bsalomon@google.com316f99232011-01-13 21:28:12 +0000586
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000587 static const GrGLTexture::TexParams DEFAULT_PARAMS = {
588 GL_NEAREST,
589 GL_CLAMP_TO_EDGE,
590 GL_CLAMP_TO_EDGE
591 };
reed@google.com1fcd51e2011-01-05 15:50:27 +0000592
reed@google.comac10a2d2010-12-22 21:39:39 +0000593 GrGLTexture::GLTextureDesc glDesc;
594 GLenum internalFormat;
595
596 glDesc.fContentWidth = desc.fWidth;
597 glDesc.fContentHeight = desc.fHeight;
598 glDesc.fAllocWidth = desc.fWidth;
599 glDesc.fAllocHeight = desc.fHeight;
600 glDesc.fFormat = desc.fFormat;
601
602 bool renderTarget = 0 != (desc.fFlags & kRenderTarget_TextureFlag);
603 if (!canBeTexture(desc.fFormat,
604 &internalFormat,
605 &glDesc.fUploadFormat,
606 &glDesc.fUploadType)) {
607 return return_null_texture();
608 }
609
610 GrAssert(as_size_t(desc.fAALevel) < GR_ARRAY_COUNT(fAASamples));
611 GLint samples = fAASamples[desc.fAALevel];
612 if (kNone_MSFBO == fMSFBOType && desc.fAALevel != kNone_AALevel) {
613 GrPrintf("AA RT requested but not supported on this platform.");
614 }
615
616 GR_GL(GenTextures(1, &glDesc.fTextureID));
617 if (!glDesc.fTextureID) {
618 return return_null_texture();
619 }
620
621 glDesc.fUploadByteCount = GrTexture::BytesPerPixel(desc.fFormat);
622
623 /*
624 * check if our srcData has extra bytes past each row. If so, we need
625 * to trim those off here, since GL doesn't let us pass the rowBytes as
626 * a parameter to glTexImage2D
627 */
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000628#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000629 if (srcData) {
630 GR_GL(PixelStorei(GL_UNPACK_ROW_LENGTH,
631 rowBytes / glDesc.fUploadByteCount));
632 }
633#else
634 GrAutoSMalloc<128 * 128> trimStorage;
635 size_t trimRowBytes = desc.fWidth * glDesc.fUploadByteCount;
636 if (srcData && (trimRowBytes < rowBytes)) {
637 size_t trimSize = desc.fHeight * trimRowBytes;
638 trimStorage.realloc(trimSize);
639 // now copy the data into our new storage, skipping the trailing bytes
640 const char* src = (const char*)srcData;
641 char* dst = (char*)trimStorage.get();
642 for (uint32_t y = 0; y < desc.fHeight; y++) {
643 memcpy(dst, src, trimRowBytes);
644 src += rowBytes;
645 dst += trimRowBytes;
646 }
647 // now point srcData to our trimmed version
648 srcData = trimStorage.get();
649 }
650#endif
651
652 if (fNPOTTextureSupport < kNonRendertarget_NPOTTextureType ||
653 (fNPOTTextureSupport == kNonRendertarget_NPOTTextureType &&
654 renderTarget)) {
655 glDesc.fAllocWidth = GrNextPow2(desc.fWidth);
656 glDesc.fAllocHeight = GrNextPow2(desc.fHeight);
657 }
658
659 if (renderTarget) {
660 glDesc.fAllocWidth = GrMax<int>(fMinRenderTargetWidth,
661 glDesc.fAllocWidth);
662 glDesc.fAllocHeight = GrMax<int>(fMinRenderTargetHeight,
663 glDesc.fAllocHeight);
664 }
665
666 GR_GL(BindTexture(GL_TEXTURE_2D, glDesc.fTextureID));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000667 GR_GL(TexParameteri(GL_TEXTURE_2D,
668 GL_TEXTURE_MAG_FILTER,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000669 DEFAULT_PARAMS.fFilter));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000670 GR_GL(TexParameteri(GL_TEXTURE_2D,
671 GL_TEXTURE_MIN_FILTER,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000672 DEFAULT_PARAMS.fFilter));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000673 GR_GL(TexParameteri(GL_TEXTURE_2D,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000674 GL_TEXTURE_WRAP_S,
675 DEFAULT_PARAMS.fWrapS));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000676 GR_GL(TexParameteri(GL_TEXTURE_2D,
677 GL_TEXTURE_WRAP_T,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000678 DEFAULT_PARAMS.fWrapT));
reed@google.comac10a2d2010-12-22 21:39:39 +0000679
680 GR_GL(PixelStorei(GL_UNPACK_ALIGNMENT, glDesc.fUploadByteCount));
681 if (GrTexture::kIndex_8_PixelConfig == desc.fFormat &&
682 supports8BitPalette()) {
683 // ES only supports CompressedTexImage2D, not CompressedTexSubimage2D
684 GrAssert(desc.fWidth == glDesc.fAllocWidth);
685 GrAssert(desc.fHeight == glDesc.fAllocHeight);
686 GLsizei imageSize = glDesc.fAllocWidth * glDesc.fAllocHeight +
687 kColorTableSize;
688 GR_GL(CompressedTexImage2D(GL_TEXTURE_2D, 0, glDesc.fUploadFormat,
689 glDesc.fAllocWidth, glDesc.fAllocHeight,
690 0, imageSize, srcData));
691 GrGL_RestoreResetRowLength();
692 } else {
693 if (NULL != srcData && (glDesc.fAllocWidth != desc.fWidth ||
694 glDesc.fAllocHeight != desc.fHeight)) {
695 GR_GL(TexImage2D(GL_TEXTURE_2D, 0, internalFormat,
696 glDesc.fAllocWidth, glDesc.fAllocHeight,
697 0, glDesc.fUploadFormat, glDesc.fUploadType, NULL));
698 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, desc.fWidth,
699 desc.fHeight, glDesc.fUploadFormat,
700 glDesc.fUploadType, srcData));
701 GrGL_RestoreResetRowLength();
702
703 uint32_t extraW = glDesc.fAllocWidth - desc.fWidth;
704 uint32_t extraH = glDesc.fAllocHeight - desc.fHeight;
705 uint32_t maxTexels = extraW * extraH;
706 maxTexels = GrMax(extraW * desc.fHeight, maxTexels);
707 maxTexels = GrMax(desc.fWidth * extraH, maxTexels);
708
709 GrAutoSMalloc<128*128> texels(glDesc.fUploadByteCount * maxTexels);
710
711 uint32_t rowSize = desc.fWidth * glDesc.fUploadByteCount;
712 if (extraH) {
713 uint8_t* lastRowStart = (uint8_t*) srcData +
714 (desc.fHeight - 1) * rowSize;
715 uint8_t* extraRowStart = (uint8_t*)texels.get();
716
717 for (uint32_t i = 0; i < extraH; ++i) {
718 memcpy(extraRowStart, lastRowStart, rowSize);
719 extraRowStart += rowSize;
720 }
721 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, 0, desc.fHeight, desc.fWidth,
722 extraH, glDesc.fUploadFormat, glDesc.fUploadType,
723 texels.get()));
724 }
725 if (extraW) {
726 uint8_t* edgeTexel = (uint8_t*)srcData + rowSize - glDesc.fUploadByteCount;
727 uint8_t* extraTexel = (uint8_t*)texels.get();
728 for (uint32_t j = 0; j < desc.fHeight; ++j) {
729 for (uint32_t i = 0; i < extraW; ++i) {
730 memcpy(extraTexel, edgeTexel, glDesc.fUploadByteCount);
731 extraTexel += glDesc.fUploadByteCount;
732 }
733 edgeTexel += rowSize;
734 }
735 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, desc.fWidth, 0, extraW,
736 desc.fHeight, glDesc.fUploadFormat,
737 glDesc.fUploadType, texels.get()));
738 }
739 if (extraW && extraH) {
740 uint8_t* cornerTexel = (uint8_t*)srcData + desc.fHeight * rowSize
741 - glDesc.fUploadByteCount;
742 uint8_t* extraTexel = (uint8_t*)texels.get();
743 for (uint32_t i = 0; i < extraW*extraH; ++i) {
744 memcpy(extraTexel, cornerTexel, glDesc.fUploadByteCount);
745 extraTexel += glDesc.fUploadByteCount;
746 }
747 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, desc.fWidth, desc.fHeight,
748 extraW, extraH, glDesc.fUploadFormat,
749 glDesc.fUploadType, texels.get()));
750 }
751
752 } else {
753 GR_GL(TexImage2D(GL_TEXTURE_2D, 0, internalFormat, glDesc.fAllocWidth,
754 glDesc.fAllocHeight, 0, glDesc.fUploadFormat,
755 glDesc.fUploadType, srcData));
756 GrGL_RestoreResetRowLength();
757 }
758 }
759
760 glDesc.fOrientation = GrGLTexture::kTopDown_Orientation;
761
762 GrGLRenderTarget::GLRenderTargetIDs rtIDs;
763 rtIDs.fStencilRenderbufferID = 0;
764 rtIDs.fMSColorRenderbufferID = 0;
765 rtIDs.fRTFBOID = 0;
766 rtIDs.fTexFBOID = 0;
767 rtIDs.fOwnIDs = true;
768 GLenum msColorRenderbufferFormat = -1;
769
770 if (renderTarget) {
771#if GR_COLLECT_STATS
772 ++fStats.fRenderTargetCreateCnt;
773#endif
774 bool failed = true;
775 GLenum status;
776 GLint err;
777
778 // If need have both RT flag and srcData we have
779 // to invert the data before uploading because FBO
780 // will be rendered bottom up
781 GrAssert(NULL == srcData);
782 glDesc.fOrientation = GrGLTexture::kBottomUp_Orientation;
783
784 GR_GLEXT(fExts, GenFramebuffers(1, &rtIDs.fTexFBOID));
785 GrAssert(rtIDs.fTexFBOID);
786
787 // If we are using multisampling and any extension other than the IMG
788 // one we will create two FBOs. We render to one and then resolve to
789 // the texture bound to the other. The IMG extension does an implicit
790 // resolve.
791 if (samples > 1 && kIMG_MSFBO != fMSFBOType && kNone_MSFBO != fMSFBOType) {
792 GR_GLEXT(fExts, GenFramebuffers(1, &rtIDs.fRTFBOID));
793 GrAssert(0 != rtIDs.fRTFBOID);
794 GR_GLEXT(fExts, GenRenderbuffers(1, &rtIDs.fMSColorRenderbufferID));
795 GrAssert(0 != rtIDs.fMSColorRenderbufferID);
796 if (!fboInternalFormat(desc.fFormat, &msColorRenderbufferFormat)) {
797 GR_GLEXT(fExts,
798 DeleteRenderbuffers(1, &rtIDs.fMSColorRenderbufferID));
799 GR_GL(DeleteTextures(1, &glDesc.fTextureID));
800 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fTexFBOID));
801 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fRTFBOID));
reed@google.comac10a2d2010-12-22 21:39:39 +0000802 return return_null_texture();
803 }
804 } else {
805 rtIDs.fRTFBOID = rtIDs.fTexFBOID;
806 }
807 int attempts = 1;
808 if (!(kNoPathRendering_TextureFlag & desc.fFlags)) {
809 GR_GLEXT(fExts, GenRenderbuffers(1, &rtIDs.fStencilRenderbufferID));
810 GrAssert(0 != rtIDs.fStencilRenderbufferID);
811 attempts = GR_ARRAY_COUNT(GR_GL_STENCIL_FORMAT_ARRAY);
812 }
813
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000814 // someone suggested that some systems might require
bsalomon@google.com316f99232011-01-13 21:28:12 +0000815 // unbinding the texture before we call FramebufferTexture2D
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000816 // (seems unlikely)
reed@google.comac10a2d2010-12-22 21:39:39 +0000817 GR_GL(BindTexture(GL_TEXTURE_2D, 0));
reed@google.comac10a2d2010-12-22 21:39:39 +0000818
819 err = ~GL_NO_ERROR;
820 for (int i = 0; i < attempts; ++i) {
821 if (rtIDs.fStencilRenderbufferID) {
822 GR_GLEXT(fExts, BindRenderbuffer(GR_RENDERBUFFER,
823 rtIDs.fStencilRenderbufferID));
824 if (samples > 1) {
825 GR_GLEXT_NO_ERR(fExts, RenderbufferStorageMultisample(
826 GR_RENDERBUFFER,
827 samples,
828 GR_GL_STENCIL_FORMAT_ARRAY[i],
829 glDesc.fAllocWidth,
830 glDesc.fAllocHeight));
831 } else {
832 GR_GLEXT_NO_ERR(fExts, RenderbufferStorage(
833 GR_RENDERBUFFER,
834 GR_GL_STENCIL_FORMAT_ARRAY[i],
835 glDesc.fAllocWidth,
836 glDesc.fAllocHeight));
837 }
838 err = glGetError();
839 if (err != GL_NO_ERROR) {
840 continue;
841 }
842 }
843 if (rtIDs.fRTFBOID != rtIDs.fTexFBOID) {
844 GrAssert(samples > 1);
845 GR_GLEXT(fExts, BindRenderbuffer(GR_RENDERBUFFER,
846 rtIDs.fMSColorRenderbufferID));
847 GR_GLEXT_NO_ERR(fExts, RenderbufferStorageMultisample(
848 GR_RENDERBUFFER,
849 samples,
850 msColorRenderbufferFormat,
851 glDesc.fAllocWidth,
852 glDesc.fAllocHeight));
853 err = glGetError();
854 if (err != GL_NO_ERROR) {
855 continue;
856 }
857 }
858 GR_GLEXT(fExts, BindFramebuffer(GR_FRAMEBUFFER, rtIDs.fTexFBOID));
859
860#if GR_COLLECT_STATS
861 ++fStats.fRenderTargetChngCnt;
862#endif
863 if (kIMG_MSFBO == fMSFBOType && samples > 1) {
864 GR_GLEXT(fExts, FramebufferTexture2DMultisample(
865 GR_FRAMEBUFFER,
866 GR_COLOR_ATTACHMENT0,
867 GL_TEXTURE_2D,
868 glDesc.fTextureID,
869 0,
870 samples));
871
872 } else {
873 GR_GLEXT(fExts, FramebufferTexture2D(GR_FRAMEBUFFER,
874 GR_COLOR_ATTACHMENT0,
875 GL_TEXTURE_2D,
876 glDesc.fTextureID, 0));
877 }
878 if (rtIDs.fRTFBOID != rtIDs.fTexFBOID) {
879 GLenum status = GR_GLEXT(fExts,
880 CheckFramebufferStatus(GR_FRAMEBUFFER));
881 if (status != GR_FRAMEBUFFER_COMPLETE) {
882 GrPrintf("-- glCheckFramebufferStatus %x %d %d\n",
883 status, desc.fWidth, desc.fHeight);
884 continue;
885 }
886 GR_GLEXT(fExts, BindFramebuffer(GR_FRAMEBUFFER, rtIDs.fRTFBOID));
887 #if GR_COLLECT_STATS
888 ++fStats.fRenderTargetChngCnt;
889 #endif
890 GR_GLEXT(fExts, FramebufferRenderbuffer(GR_FRAMEBUFFER,
891 GR_COLOR_ATTACHMENT0,
892 GR_RENDERBUFFER,
893 rtIDs.fMSColorRenderbufferID));
894
895 }
896 if (rtIDs.fStencilRenderbufferID) {
897 // bind the stencil to rt fbo if present, othewise the tex fbo
898 GR_GLEXT(fExts, FramebufferRenderbuffer(GR_FRAMEBUFFER,
899 GR_STENCIL_ATTACHMENT,
bsalomon@google.com316f99232011-01-13 21:28:12 +0000900 GR_RENDERBUFFER,
reed@google.comac10a2d2010-12-22 21:39:39 +0000901 rtIDs.fStencilRenderbufferID));
902 }
903 status = GR_GLEXT(fExts, CheckFramebufferStatus(GR_FRAMEBUFFER));
904
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000905#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000906 // On some implementations you have to be bound as DEPTH_STENCIL.
907 // (Even binding to DEPTH and STENCIL separately with the same
908 // buffer doesn't work.)
909 if (rtIDs.fStencilRenderbufferID &&
910 status != GR_FRAMEBUFFER_COMPLETE) {
911 GR_GLEXT(fExts, FramebufferRenderbuffer(GR_FRAMEBUFFER,
912 GR_STENCIL_ATTACHMENT,
913 GR_RENDERBUFFER,
914 0));
915 GR_GLEXT(fExts,
916 FramebufferRenderbuffer(GR_FRAMEBUFFER,
917 GR_DEPTH_STENCIL_ATTACHMENT,
918 GR_RENDERBUFFER,
919 rtIDs.fStencilRenderbufferID));
920 status = GR_GLEXT(fExts, CheckFramebufferStatus(GR_FRAMEBUFFER));
921 }
922#endif
923 if (status != GR_FRAMEBUFFER_COMPLETE) {
924 GrPrintf("-- glCheckFramebufferStatus %x %d %d\n",
925 status, desc.fWidth, desc.fHeight);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000926#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000927 if (rtIDs.fStencilRenderbufferID) {
928 GR_GLEXT(fExts, FramebufferRenderbuffer(GR_FRAMEBUFFER,
929 GR_DEPTH_STENCIL_ATTACHMENT,
930 GR_RENDERBUFFER,
931 0));
932 }
933#endif
934 continue;
935 }
936 // we're successful!
937 failed = false;
938 break;
939 }
940 if (failed) {
941 if (rtIDs.fStencilRenderbufferID) {
942 GR_GLEXT(fExts,
943 DeleteRenderbuffers(1, &rtIDs.fStencilRenderbufferID));
944 }
945 if (rtIDs.fMSColorRenderbufferID) {
946 GR_GLEXT(fExts,
947 DeleteRenderbuffers(1, &rtIDs.fMSColorRenderbufferID));
948 }
949 if (rtIDs.fRTFBOID != rtIDs.fTexFBOID) {
950 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fRTFBOID));
951 }
952 if (rtIDs.fTexFBOID) {
953 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fTexFBOID));
954 }
955 GR_GL(DeleteTextures(1, &glDesc.fTextureID));
956 return return_null_texture();
957 }
958 }
959#ifdef TRACE_TEXTURE_CREATION
960 GrPrintf("--- new texture [%d] size=(%d %d) bpp=%d\n",
961 tex->fTextureID, width, height, tex->fUploadByteCount);
962#endif
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000963 GrGLTexture* tex = new GrGLTexture(glDesc, rtIDs, DEFAULT_PARAMS, this);
reed@google.comac10a2d2010-12-22 21:39:39 +0000964
965 if (0 != rtIDs.fTexFBOID) {
966 GrRenderTarget* rt = tex->asRenderTarget();
967 // We've messed with FBO state but may not have set the correct viewport
968 // so just dirty the rendertarget state to force a resend.
969 fHWDrawState.fRenderTarget = NULL;
970
971 // clear the new stencil buffer if we have one
972 if (!(desc.fFlags & kNoPathRendering_TextureFlag)) {
973 GrRenderTarget* rtSave = fCurrDrawState.fRenderTarget;
974 fCurrDrawState.fRenderTarget = rt;
975 eraseStencil(0, ~0);
976 fCurrDrawState.fRenderTarget = rtSave;
977 }
978 }
979 return tex;
980}
981
982GrRenderTarget* GrGpuGL::defaultRenderTarget() {
983 return fDefaultRenderTarget;
984}
985
986GrVertexBuffer* 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
1032void GrGpuGL::setDefaultRenderTargetSize(uint32_t width, uint32_t height) {
1033 GrIRect viewport(0, height, width, 0);
1034 if (viewport != fDefaultRenderTarget->viewport()) {
1035 fDefaultRenderTarget->setViewport(viewport);
1036 if (fHWDrawState.fRenderTarget == fDefaultRenderTarget) {
1037 fHWDrawState.fRenderTarget = NULL;
1038 }
1039 }
1040}
1041
1042void GrGpuGL::flushScissor(const GrIRect* rect) {
1043 GrAssert(NULL != fCurrDrawState.fRenderTarget);
1044 const GrIRect& vp =
1045 ((GrGLRenderTarget*)fCurrDrawState.fRenderTarget)->viewport();
1046
1047 if (NULL != rect &&
1048 rect->contains(vp)) {
1049 rect = NULL;
1050 }
1051
1052 if (NULL != rect) {
1053 GrIRect scissor;
1054 // viewport is already in GL coords
1055 // create a scissor in GL coords (top > bottom)
1056 scissor.setLTRB(vp.fLeft + rect->fLeft,
1057 vp.fTop - rect->fTop,
1058 vp.fLeft + rect->fRight,
1059 vp.fTop - rect->fBottom);
1060
1061 if (fHWBounds.fScissorRect != scissor) {
1062 GR_GL(Scissor(scissor.fLeft, scissor.fBottom,
1063 scissor.width(), -scissor.height()));
1064 fHWBounds.fScissorRect = scissor;
1065 }
1066
1067 if (!fHWBounds.fScissorEnabled) {
1068 GR_GL(Enable(GL_SCISSOR_TEST));
1069 fHWBounds.fScissorEnabled = true;
1070 }
1071 } else {
1072 if (fHWBounds.fScissorEnabled) {
1073 GR_GL(Disable(GL_SCISSOR_TEST));
1074 fHWBounds.fScissorEnabled = false;
1075 }
1076 }
1077}
1078
reed@google.comac10a2d2010-12-22 21:39:39 +00001079void GrGpuGL::eraseColor(GrColor color) {
1080 flushRenderTarget();
1081 if (fHWBounds.fScissorEnabled) {
1082 GR_GL(Disable(GL_SCISSOR_TEST));
1083 }
1084 GR_GL(ColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE));
1085 GR_GL(ClearColor(GrColorUnpackR(color)/255.f,
1086 GrColorUnpackG(color)/255.f,
1087 GrColorUnpackB(color)/255.f,
1088 GrColorUnpackA(color)/255.f));
1089 GR_GL(Clear(GL_COLOR_BUFFER_BIT));
1090 fHWBounds.fScissorEnabled = false;
1091 fWriteMaskChanged = true;
1092}
1093
1094void GrGpuGL::eraseStencil(uint32_t value, uint32_t mask) {
1095 flushRenderTarget();
1096 if (fHWBounds.fScissorEnabled) {
1097 GR_GL(Disable(GL_SCISSOR_TEST));
1098 }
1099 GR_GL(StencilMask(mask));
1100 GR_GL(ClearStencil(value));
1101 GR_GL(Clear(GL_STENCIL_BUFFER_BIT));
1102 fHWBounds.fScissorEnabled = false;
1103 fWriteMaskChanged = true;
1104}
1105
1106void GrGpuGL::eraseStencilClip() {
1107 GLint stencilBitCount;
reed@google.comac20fb92011-01-12 17:14:53 +00001108 GR_GL_GetIntegerv(GL_STENCIL_BITS, &stencilBitCount);
reed@google.comac10a2d2010-12-22 21:39:39 +00001109 GrAssert(stencilBitCount > 0);
1110 GLint clipStencilMask = (1 << (stencilBitCount - 1));
1111 eraseStencil(0, clipStencilMask);
1112}
1113
1114void GrGpuGL::forceRenderTargetFlush() {
1115 flushRenderTarget();
1116}
1117
1118bool GrGpuGL::readPixels(int left, int top, int width, int height,
1119 GrTexture::PixelConfig config, void* buffer) {
1120 GLenum internalFormat; // we don't use this for glReadPixels
1121 GLenum format;
1122 GLenum type;
1123 if (!this->canBeTexture(config, &internalFormat, &format, &type)) {
1124 return false;
1125 }
1126
1127 GrAssert(NULL != fCurrDrawState.fRenderTarget);
1128 const GrIRect& vp = ((GrGLRenderTarget*)fCurrDrawState.fRenderTarget)->viewport();
1129
1130 // Brian says that viewport rects are already upside down (grrrrr)
bsalomon@google.com316f99232011-01-13 21:28:12 +00001131 GR_GL(ReadPixels(left, -vp.height() - top - height, width, height,
1132 format, type, buffer));
reed@google.comac10a2d2010-12-22 21:39:39 +00001133
1134 // now reverse the order of the rows, since GL's are bottom-to-top, but our
1135 // API presents top-to-bottom
1136 {
1137 size_t stride = width * GrTexture::BytesPerPixel(config);
1138 GrAutoMalloc rowStorage(stride);
1139 void* tmp = rowStorage.get();
1140
1141 const int halfY = height >> 1;
1142 char* top = reinterpret_cast<char*>(buffer);
1143 char* bottom = top + (height - 1) * stride;
1144 for (int y = 0; y < halfY; y++) {
1145 memcpy(tmp, top, stride);
1146 memcpy(top, bottom, stride);
1147 memcpy(bottom, tmp, stride);
1148 top += stride;
1149 bottom -= stride;
1150 }
1151 }
1152 return true;
1153}
1154
1155void GrGpuGL::flushRenderTarget() {
1156 if (fHWDrawState.fRenderTarget != fCurrDrawState.fRenderTarget) {
1157 GrGLRenderTarget* rt = (GrGLRenderTarget*)fCurrDrawState.fRenderTarget;
1158 GR_GLEXT(fExts, BindFramebuffer(GR_FRAMEBUFFER, rt->renderFBOID()));
1159 #if GR_COLLECT_STATS
1160 ++fStats.fRenderTargetChngCnt;
1161 #endif
1162 rt->setDirty(true);
1163 #if GR_DEBUG
1164 GLenum status = GR_GLEXT(fExts, CheckFramebufferStatus(GR_FRAMEBUFFER));
1165 if (status != GR_FRAMEBUFFER_COMPLETE) {
1166 GrPrintf("-- glCheckFramebufferStatus %x\n", status);
1167 }
1168 #endif
1169 fHWDrawState.fRenderTarget = fCurrDrawState.fRenderTarget;
1170 const GrIRect& vp = rt->viewport();
1171 fRenderTargetChanged = true;
1172 if (fHWBounds.fViewportRect != vp) {
1173 GR_GL(Viewport(vp.fLeft,
1174 vp.fBottom,
1175 vp.width(),
1176 -vp.height()));
1177 fHWBounds.fViewportRect = vp;
1178 }
1179 }
1180}
1181
1182GLenum gPrimitiveType2GLMode[] = {
1183 GL_TRIANGLES,
1184 GL_TRIANGLE_STRIP,
1185 GL_TRIANGLE_FAN,
1186 GL_POINTS,
1187 GL_LINES,
1188 GL_LINE_STRIP
1189};
1190
1191void GrGpuGL::drawIndexedHelper(PrimitiveType type,
1192 uint32_t startVertex,
1193 uint32_t startIndex,
1194 uint32_t vertexCount,
1195 uint32_t indexCount) {
1196 GrAssert((size_t)type < GR_ARRAY_COUNT(gPrimitiveType2GLMode));
1197
1198 GLvoid* indices = (GLvoid*)(sizeof(uint16_t) * startIndex);
1199 if (kReserved_GeometrySrcType == fGeometrySrc.fIndexSrc) {
1200 indices = (GLvoid*)((intptr_t)indices + (intptr_t)fIndices.get());
1201 } else if (kArray_GeometrySrcType == fGeometrySrc.fIndexSrc) {
1202 indices = (GLvoid*)((intptr_t)indices +
1203 (intptr_t)fGeometrySrc.fIndexArray);
1204 }
1205
1206 GR_GL(DrawElements(gPrimitiveType2GLMode[type], indexCount,
1207 GL_UNSIGNED_SHORT, indices));
1208}
1209
1210void GrGpuGL::drawNonIndexedHelper(PrimitiveType type,
1211 uint32_t startVertex,
1212 uint32_t vertexCount) {
1213 GrAssert((size_t)type < GR_ARRAY_COUNT(gPrimitiveType2GLMode));
1214
1215 GR_GL(DrawArrays(gPrimitiveType2GLMode[type], 0, vertexCount));
1216}
1217
1218#if !defined(SK_GL_HAS_COLOR4UB)
1219static inline GrFixed byte2fixed(unsigned value) {
1220 return (value + (value >> 7)) << 8;
1221}
1222#endif
1223
1224void GrGpuGL::resolveTextureRenderTarget(GrGLTexture* texture) {
1225 GrGLRenderTarget* rt = (GrGLRenderTarget*) texture->asRenderTarget();
1226
1227 if (NULL != rt && rt->needsResolve()) {
1228 GrAssert(kNone_MSFBO != fMSFBOType);
1229 GrAssert(rt->textureFBOID() != rt->renderFBOID());
1230 GR_GLEXT(fExts, BindFramebuffer(GR_READ_FRAMEBUFFER,
1231 rt->renderFBOID()));
1232 GR_GLEXT(fExts, BindFramebuffer(GR_DRAW_FRAMEBUFFER,
1233 rt->textureFBOID()));
1234 #if GR_COLLECT_STATS
1235 ++fStats.fRenderTargetChngCnt;
1236 #endif
1237 // make sure we go through set render target
1238 fHWDrawState.fRenderTarget = NULL;
1239
1240 GLint left = 0;
1241 GLint right = texture->contentWidth();
1242 // we will have rendered to the top of the FBO.
1243 GLint top = texture->allocHeight();
1244 GLint bottom = texture->allocHeight() - texture->contentHeight();
1245 if (kApple_MSFBO == fMSFBOType) {
1246 GR_GL(Enable(GL_SCISSOR_TEST));
1247 GR_GL(Scissor(left, bottom, right-left, top-bottom));
1248 GR_GLEXT(fExts, ResolveMultisampleFramebuffer());
1249 fHWBounds.fScissorRect.setEmpty();
1250 fHWBounds.fScissorEnabled = true;
1251 } else {
1252 GR_GLEXT(fExts, BlitFramebuffer(left, bottom, right, top,
1253 left, bottom, right, top,
1254 GL_COLOR_BUFFER_BIT, GL_NEAREST));
1255 }
1256 rt->setDirty(false);
1257
1258 }
1259}
1260
1261void GrGpuGL::flushStencil() {
1262
1263 // use stencil for clipping if clipping is enabled and the clip
1264 // has been written into the stencil.
1265 bool stencilClip = fClipState.fClipInStencil &&
1266 (kClip_StateBit & fCurrDrawState.fFlagBits);
1267 bool stencilChange =
1268 fWriteMaskChanged ||
1269 fHWStencilClip != stencilClip ||
1270 fHWDrawState.fStencilPass != fCurrDrawState.fStencilPass ||
1271 (kNone_StencilPass != fCurrDrawState.fStencilPass &&
1272 (StencilPass)kSetClip_StencilPass != fCurrDrawState.fStencilPass &&
1273 fHWDrawState.fReverseFill != fCurrDrawState.fReverseFill);
1274
1275 if (stencilChange) {
1276 GLint stencilBitCount;
1277 GLint clipStencilMask;
1278 GLint pathStencilMask;
reed@google.comac20fb92011-01-12 17:14:53 +00001279 GR_GL_GetIntegerv(GL_STENCIL_BITS, &stencilBitCount);
reed@google.comac10a2d2010-12-22 21:39:39 +00001280 GrAssert(stencilBitCount > 0 ||
1281 kNone_StencilPass == fCurrDrawState.fStencilPass);
1282 clipStencilMask = (1 << (stencilBitCount - 1));
1283 pathStencilMask = clipStencilMask - 1;
1284 switch (fCurrDrawState.fStencilPass) {
1285 case kNone_StencilPass:
1286 if (stencilClip) {
1287 GR_GL(Enable(GL_STENCIL_TEST));
1288 GR_GL(StencilFunc(GL_EQUAL,
1289 clipStencilMask,
1290 clipStencilMask));
1291 GR_GL(StencilOp(GL_KEEP, GL_KEEP, GL_KEEP));
1292 } else {
1293 GR_GL(Disable(GL_STENCIL_TEST));
1294 }
1295 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
1296 if (!fSingleStencilPassForWinding) {
1297 GR_GL(Disable(GL_CULL_FACE));
1298 }
1299 break;
1300 case kEvenOddStencil_StencilPass:
1301 GR_GL(Enable(GL_STENCIL_TEST));
1302 if (stencilClip) {
1303 GR_GL(StencilFunc(GL_EQUAL, clipStencilMask, clipStencilMask));
1304 } else {
1305 GR_GL(StencilFunc(GL_ALWAYS, 0x0, 0x0));
1306 }
1307 GR_GL(StencilMask(pathStencilMask));
1308 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
1309 GR_GL(StencilOp(GL_KEEP, GL_INVERT, GL_INVERT));
1310 GR_GL(ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE));
1311 if (!fSingleStencilPassForWinding) {
1312 GR_GL(Disable(GL_CULL_FACE));
1313 }
1314 break;
1315 case kEvenOddColor_StencilPass: {
1316 GR_GL(Enable(GL_STENCIL_TEST));
1317 GLint funcRef = 0;
1318 GLuint funcMask = pathStencilMask;
1319 if (stencilClip) {
1320 funcRef |= clipStencilMask;
1321 funcMask |= clipStencilMask;
1322 }
1323 if (!fCurrDrawState.fReverseFill) {
1324 funcRef |= pathStencilMask;
1325 }
bsalomon@google.com316f99232011-01-13 21:28:12 +00001326 GR_GL(StencilFunc(GL_EQUAL, funcRef, funcMask));
1327 GR_GL(StencilMask(pathStencilMask));
reed@google.comac10a2d2010-12-22 21:39:39 +00001328 GR_GL(StencilOp(GL_ZERO, GL_ZERO, GL_ZERO));
1329 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
1330 if (!fSingleStencilPassForWinding) {
1331 GR_GL(Disable(GL_CULL_FACE));
1332 }
1333 } break;
1334 case kWindingStencil1_StencilPass:
1335 GR_GL(Enable(GL_STENCIL_TEST));
1336 if (fHasStencilWrap) {
1337 if (stencilClip) {
1338 GR_GL(StencilFunc(GL_EQUAL,
1339 clipStencilMask,
1340 clipStencilMask));
1341 } else {
1342 GR_GL(StencilFunc(GL_ALWAYS, 0x0, 0x0));
1343 }
1344 if (fSingleStencilPassForWinding) {
1345 GR_GL(StencilOpSeparate(GL_FRONT, GL_KEEP,
1346 GL_INCR_WRAP, GL_INCR_WRAP));
1347 GR_GL(StencilOpSeparate(GL_BACK, GL_KEEP,
1348 GL_DECR_WRAP, GL_DECR_WRAP));
1349 } else {
1350 GR_GL(StencilOp(GL_KEEP, GL_INCR_WRAP, GL_INCR_WRAP));
1351 GR_GL(Enable(GL_CULL_FACE));
1352 GR_GL(CullFace(GL_BACK));
1353 }
1354 } else {
1355 // If we don't have wrap then we use the Func to detect
1356 // values that would wrap (0 on decr and mask on incr). We
1357 // make the func fail on these values and use the sfail op
1358 // to effectively wrap by inverting.
1359 // This applies whether we are doing a two-pass (front faces
1360 // followed by back faces) or a single pass (separate func/op)
1361
1362 // Note that in the case where we are also using stencil to
1363 // clip this means we will write into the path bits in clipped
1364 // out pixels. We still apply the clip bit in the color pass
1365 // stencil func so we don't draw color outside the clip.
1366 // We also will clear the stencil bits in clipped pixels by
1367 // using zero in the sfail op with write mask set to the
1368 // path mask.
1369 GR_GL(Enable(GL_STENCIL_TEST));
1370 if (fSingleStencilPassForWinding) {
1371 GR_GL(StencilFuncSeparate(GL_FRONT,
1372 GL_NOTEQUAL,
1373 pathStencilMask,
1374 pathStencilMask));
1375 GR_GL(StencilFuncSeparate(GL_BACK,
1376 GL_NOTEQUAL,
1377 0x0,
1378 pathStencilMask));
1379 GR_GL(StencilOpSeparate(GL_FRONT, GL_INVERT,
1380 GL_INCR, GL_INCR));
1381 GR_GL(StencilOpSeparate(GL_BACK, GL_INVERT,
1382 GL_DECR, GL_DECR));
1383 } else {
1384 GR_GL(StencilFunc(GL_NOTEQUAL,
1385 pathStencilMask,
1386 pathStencilMask));
1387 GR_GL(StencilOp(GL_INVERT, GL_INCR, GL_INCR));
1388 GR_GL(Enable(GL_CULL_FACE));
1389 GR_GL(CullFace(GL_BACK));
1390 }
1391 }
1392 GR_GL(StencilMask(pathStencilMask));
1393 GR_GL(ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE));
1394 break;
1395 case kWindingStencil2_StencilPass:
1396 GrAssert(!fSingleStencilPassForWinding);
1397 GR_GL(Enable(GL_STENCIL_TEST));
1398 if (fHasStencilWrap) {
1399 if (stencilClip) {
1400 GR_GL(StencilFunc(GL_EQUAL,
1401 clipStencilMask,
1402 clipStencilMask));
1403 } else {
1404 GR_GL(StencilFunc(GL_ALWAYS, 0x0, 0x0));
1405 }
1406 GR_GL(StencilOp(GL_DECR_WRAP, GL_DECR_WRAP, GL_DECR_WRAP));
1407 } else {
1408 GR_GL(StencilFunc(GL_NOTEQUAL, 0x0, pathStencilMask));
1409 GR_GL(StencilOp(GL_INVERT, GL_DECR, GL_DECR));
1410 }
1411 GR_GL(StencilMask(pathStencilMask));
1412 GR_GL(Enable(GL_CULL_FACE));
1413 GR_GL(CullFace(GL_FRONT));
1414 GR_GL(ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE));
1415 break;
1416 case kWindingColor_StencilPass: {
1417 GR_GL(Enable(GL_STENCIL_TEST));
1418 GLint funcRef = 0;
1419 GLuint funcMask = pathStencilMask;
1420 GLenum funcFunc;
1421 if (stencilClip) {
1422 funcRef |= clipStencilMask;
1423 funcMask |= clipStencilMask;
1424 }
1425 if (fCurrDrawState.fReverseFill) {
1426 funcFunc = GL_EQUAL;
1427 } else {
1428 funcFunc = GL_LESS;
1429 }
1430 GR_GL(StencilFunc(funcFunc, funcRef, funcMask));
1431 GR_GL(StencilMask(pathStencilMask));
1432 // must zero in sfail because winding w/o wrap will write
1433 // path stencil bits in clipped out pixels
1434 GR_GL(StencilOp(GL_ZERO, GL_ZERO, GL_ZERO));
1435 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
1436 if (!fSingleStencilPassForWinding) {
1437 GR_GL(Disable(GL_CULL_FACE));
1438 }
1439 } break;
1440 case kSetClip_StencilPass:
1441 GR_GL(Enable(GL_STENCIL_TEST));
1442 GR_GL(StencilFunc(GL_ALWAYS, clipStencilMask, clipStencilMask));
1443 GR_GL(StencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE));
1444 GR_GL(StencilMask(clipStencilMask));
1445 GR_GL(ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE));
1446 if (!fSingleStencilPassForWinding) {
1447 GR_GL(Disable(GL_CULL_FACE));
1448 }
1449 break;
1450 default:
1451 GrAssert(!"Unexpected stencil pass.");
1452 break;
1453
1454 }
1455 fHWDrawState.fStencilPass = fCurrDrawState.fStencilPass;
1456 fHWDrawState.fReverseFill = fCurrDrawState.fReverseFill;
1457 fWriteMaskChanged = false;
1458 fHWStencilClip = stencilClip;
1459 }
1460}
1461
1462void GrGpuGL::flushGLStateCommon(PrimitiveType type) {
1463
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001464 for (int s = 0; s < kNumStages; ++s) {
1465 bool usingTexture = VertexUsesStage(s, fGeometrySrc.fVertexLayout);
reed@google.comac10a2d2010-12-22 21:39:39 +00001466
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001467 // bind texture and set sampler state
1468 if (usingTexture) {
1469 GrGLTexture* nextTexture = (GrGLTexture*)fCurrDrawState.fTextures[s];
reed@google.comac10a2d2010-12-22 21:39:39 +00001470
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001471 if (NULL != nextTexture) {
bsalomon@google.com316f99232011-01-13 21:28:12 +00001472 // if we created a rt/tex and rendered to it without using a
1473 // texture and now we're texuring from the rt it will still be
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001474 // the last bound texture, but it needs resolving. So keep this
1475 // out of the "last != next" check.
1476 resolveTextureRenderTarget(nextTexture);
reed@google.comac10a2d2010-12-22 21:39:39 +00001477
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001478 if (fHWDrawState.fTextures[s] != nextTexture) {
1479 setTextureUnit(s);
1480 GR_GL(BindTexture(GL_TEXTURE_2D, nextTexture->textureID()));
1481 #if GR_COLLECT_STATS
1482 ++fStats.fTextureChngCnt;
1483 #endif
1484 //GrPrintf("---- bindtexture %d\n", nextTexture->textureID());
1485 fHWDrawState.fTextures[s] = nextTexture;
1486 }
bsalomon@google.com316f99232011-01-13 21:28:12 +00001487
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001488 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
bsalomon@google.com316f99232011-01-13 21:28:12 +00001489 const GrGLTexture::TexParams& oldTexParams =
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001490 nextTexture->getTexParams();
1491 GrGLTexture::TexParams newTexParams;
bsalomon@google.com316f99232011-01-13 21:28:12 +00001492
1493 newTexParams.fFilter = sampler.isFilter() ? GL_LINEAR :
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001494 GL_NEAREST;
bsalomon@google.com316f99232011-01-13 21:28:12 +00001495 newTexParams.fWrapS =
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001496 GrGLTexture::gWrapMode2GLWrap[sampler.getWrapX()];
bsalomon@google.com316f99232011-01-13 21:28:12 +00001497 newTexParams.fWrapT =
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001498 GrGLTexture::gWrapMode2GLWrap[sampler.getWrapY()];
reed@google.comac10a2d2010-12-22 21:39:39 +00001499
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001500 if (newTexParams.fFilter != oldTexParams.fFilter) {
1501 setTextureUnit(s);
bsalomon@google.com316f99232011-01-13 21:28:12 +00001502 GR_GL(TexParameteri(GL_TEXTURE_2D,
1503 GL_TEXTURE_MAG_FILTER,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001504 newTexParams.fFilter));
bsalomon@google.com316f99232011-01-13 21:28:12 +00001505 GR_GL(TexParameteri(GL_TEXTURE_2D,
1506 GL_TEXTURE_MIN_FILTER,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001507 newTexParams.fFilter));
1508 }
1509 if (newTexParams.fWrapS != oldTexParams.fWrapS) {
1510 setTextureUnit(s);
bsalomon@google.com316f99232011-01-13 21:28:12 +00001511 GR_GL(TexParameteri(GL_TEXTURE_2D,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001512 GL_TEXTURE_WRAP_S,
1513 newTexParams.fWrapS));
1514 }
1515 if (newTexParams.fWrapT != oldTexParams.fWrapT) {
1516 setTextureUnit(s);
bsalomon@google.com316f99232011-01-13 21:28:12 +00001517 GR_GL(TexParameteri(GL_TEXTURE_2D,
1518 GL_TEXTURE_WRAP_T,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001519 newTexParams.fWrapT));
1520 }
1521 nextTexture->setTexParams(newTexParams);
1522 } else {
1523 GrAssert(!"Rendering with texture vert flag set but no texture");
1524 if (NULL != fHWDrawState.fTextures[s]) {
1525 setTextureUnit(s);
1526 GR_GL(BindTexture(GL_TEXTURE_2D, 0));
1527 // GrPrintf("---- bindtexture 0\n");
1528 #if GR_COLLECT_STATS
1529 ++fStats.fTextureChngCnt;
1530 #endif
1531 fHWDrawState.fTextures[s] = NULL;
1532 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001533 }
1534 }
1535 }
1536
1537 flushRenderTarget();
1538
1539 if ((fCurrDrawState.fFlagBits & kDither_StateBit) !=
1540 (fHWDrawState.fFlagBits & kDither_StateBit)) {
1541 if (fCurrDrawState.fFlagBits & kDither_StateBit) {
1542 GR_GL(Enable(GL_DITHER));
1543 } else {
1544 GR_GL(Disable(GL_DITHER));
1545 }
1546 }
1547
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001548#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +00001549 // ES doesn't support toggling GL_MULTISAMPLE and doesn't have
1550 // smooth lines.
1551 if (fRenderTargetChanged ||
1552 (fCurrDrawState.fFlagBits & kAntialias_StateBit) !=
1553 (fHWDrawState.fFlagBits & kAntialias_StateBit)) {
1554 GLint msaa = 0;
1555 // only perform query if we know MSAA is supported.
1556 // calling on non-MSAA target caused a crash in one environment,
1557 // though I don't think it should.
1558 if (!fAASamples[kHigh_AALevel]) {
reed@google.comac20fb92011-01-12 17:14:53 +00001559 GR_GL_GetIntegerv(GL_SAMPLE_BUFFERS, &msaa);
reed@google.comac10a2d2010-12-22 21:39:39 +00001560 }
1561 if (fCurrDrawState.fFlagBits & kAntialias_StateBit) {
1562 if (msaa) {
1563 GR_GL(Enable(GL_MULTISAMPLE));
1564 } else {
1565 GR_GL(Enable(GL_LINE_SMOOTH));
1566 }
1567 } else {
1568 if (msaa) {
1569 GR_GL(Disable(GL_MULTISAMPLE));
1570 }
1571 GR_GL(Disable(GL_LINE_SMOOTH));
1572 }
1573 }
1574#endif
1575
1576 bool blendOff = canDisableBlend();
1577 if (fHWBlendDisabled != blendOff) {
1578 if (blendOff) {
1579 GR_GL(Disable(GL_BLEND));
1580 } else {
1581 GR_GL(Enable(GL_BLEND));
1582 }
1583 fHWBlendDisabled = blendOff;
1584 }
1585
1586 if (!blendOff) {
1587 if (fHWDrawState.fSrcBlend != fCurrDrawState.fSrcBlend ||
1588 fHWDrawState.fDstBlend != fCurrDrawState.fDstBlend) {
1589 GR_GL(BlendFunc(gXfermodeCoeff2Blend[fCurrDrawState.fSrcBlend],
1590 gXfermodeCoeff2Blend[fCurrDrawState.fDstBlend]));
1591 fHWDrawState.fSrcBlend = fCurrDrawState.fSrcBlend;
1592 fHWDrawState.fDstBlend = fCurrDrawState.fDstBlend;
1593 }
1594 }
bsalomon@google.com316f99232011-01-13 21:28:12 +00001595
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001596#if GR_DEBUG
reed@google.comac10a2d2010-12-22 21:39:39 +00001597 // check for circular rendering
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001598 for (int s = 0; s < kNumStages; ++s) {
1599 GrAssert(!VertexUsesStage(s, fGeometrySrc.fVertexLayout) ||
1600 NULL == fCurrDrawState.fRenderTarget ||
1601 NULL == fCurrDrawState.fTextures[s] ||
bsalomon@google.com316f99232011-01-13 21:28:12 +00001602 fCurrDrawState.fTextures[s]->asRenderTarget() !=
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001603 fCurrDrawState.fRenderTarget);
1604 }
1605#endif
bsalomon@google.com316f99232011-01-13 21:28:12 +00001606
reed@google.comac10a2d2010-12-22 21:39:39 +00001607 flushStencil();
1608
1609 fHWDrawState.fFlagBits = fCurrDrawState.fFlagBits;
1610}
1611
1612void GrGpuGL::notifyVertexBufferBind(const GrGLVertexBuffer* buffer) {
1613 fHWGeometryState.fVertexBuffer = buffer;
1614}
1615
1616void GrGpuGL::notifyVertexBufferDelete(const GrGLVertexBuffer* buffer) {
1617 GrAssert(!(kBuffer_GeometrySrcType == fGeometrySrc.fVertexSrc &&
1618 buffer == fGeometrySrc.fVertexBuffer));
1619
1620 if (fHWGeometryState.fVertexBuffer == buffer) {
1621 // deleting bound buffer does implied bind to 0
1622 fHWGeometryState.fVertexBuffer = NULL;
1623 }
1624}
1625
1626void GrGpuGL::notifyIndexBufferBind(const GrGLIndexBuffer* buffer) {
1627 fGeometrySrc.fIndexBuffer = buffer;
1628}
1629
1630void GrGpuGL::notifyIndexBufferDelete(const GrGLIndexBuffer* buffer) {
1631 GrAssert(!(kBuffer_GeometrySrcType == fGeometrySrc.fIndexSrc &&
1632 buffer == fGeometrySrc.fIndexBuffer));
1633
1634 if (fHWGeometryState.fIndexBuffer == buffer) {
1635 // deleting bound buffer does implied bind to 0
1636 fHWGeometryState.fIndexBuffer = NULL;
1637 }
1638}
1639
reed@google.comac10a2d2010-12-22 21:39:39 +00001640void GrGpuGL::notifyRenderTargetDelete(GrRenderTarget* renderTarget) {
1641 GrAssert(NULL != renderTarget);
1642
1643 // if the bound FBO is destroyed we can't rely on the implicit bind to 0
1644 // a) we want the default RT which may not be FBO 0
1645 // b) we set more state than just FBO based on the RT
1646 // So trash the HW state to force an RT flush next time
1647 if (fCurrDrawState.fRenderTarget == renderTarget) {
reed@google.com1fcd51e2011-01-05 15:50:27 +00001648 fCurrDrawState.fRenderTarget = fDefaultRenderTarget;
reed@google.comac10a2d2010-12-22 21:39:39 +00001649 }
1650 if (fHWDrawState.fRenderTarget == renderTarget) {
1651 fHWDrawState.fRenderTarget = NULL;
1652 }
1653 if (fClipState.fStencilClipTarget == renderTarget) {
1654 fClipState.fStencilClipTarget = NULL;
1655 }
1656}
1657
1658void GrGpuGL::notifyTextureDelete(GrGLTexture* texture) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001659 for (int s = 0; s < kNumStages; ++s) {
1660 if (fCurrDrawState.fTextures[s] == texture) {
1661 fCurrDrawState.fTextures[s] = NULL;
1662 }
1663 if (fHWDrawState.fTextures[s] == texture) {
1664 // deleting bound texture does implied bind to 0
1665 fHWDrawState.fTextures[s] = NULL;
1666 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001667 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001668}
1669
1670void GrGpuGL::notifyTextureRemoveRenderTarget(GrGLTexture* texture) {
1671 GrAssert(NULL != texture->asRenderTarget());
1672
1673 // if there is a pending resolve, perform it.
1674 resolveTextureRenderTarget(texture);
1675}
1676
1677bool GrGpuGL::canBeTexture(GrTexture::PixelConfig config,
1678 GLenum* internalFormat,
1679 GLenum* format,
1680 GLenum* type) {
1681 switch (config) {
1682 case GrTexture::kRGBA_8888_PixelConfig:
1683 case GrTexture::kRGBX_8888_PixelConfig: // todo: can we tell it our X?
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +00001684 *format = GR_GL_32BPP_COLOR_FORMAT;
bsalomon@google.comed3a0682011-01-18 16:54:04 +00001685#if GR_SUPPORT_GLES
1686 // according to GL_EXT_texture_format_BGRA8888 the *internal*
1687 // format for a BGRA is BGRA not RGBA (as on desktop)
1688 *internalFormat = GR_GL_32BPP_COLOR_FORMAT;
1689#else
1690 *internalFormat = GL_RGBA;
1691#endif
reed@google.comac10a2d2010-12-22 21:39:39 +00001692 *type = GL_UNSIGNED_BYTE;
1693 break;
1694 case GrTexture::kRGB_565_PixelConfig:
1695 *format = GL_RGB;
1696 *internalFormat = GL_RGB;
1697 *type = GL_UNSIGNED_SHORT_5_6_5;
1698 break;
1699 case GrTexture::kRGBA_4444_PixelConfig:
1700 *format = GL_RGBA;
1701 *internalFormat = GL_RGBA;
1702 *type = GL_UNSIGNED_SHORT_4_4_4_4;
1703 break;
1704 case GrTexture::kIndex_8_PixelConfig:
1705 if (this->supports8BitPalette()) {
1706 *format = GR_PALETTE8_RGBA8;
1707 *internalFormat = GR_PALETTE8_RGBA8;
1708 *type = GL_UNSIGNED_BYTE; // unused I think
1709 } else {
1710 return false;
1711 }
1712 break;
1713 case GrTexture::kAlpha_8_PixelConfig:
1714 *format = GL_ALPHA;
1715 *internalFormat = GL_ALPHA;
1716 *type = GL_UNSIGNED_BYTE;
1717 break;
1718 default:
1719 return false;
1720 }
1721 return true;
1722}
1723
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001724void GrGpuGL::setTextureUnit(int unit) {
1725 GrAssert(unit >= 0 && unit < kNumStages);
1726 if (fActiveTextureUnitIdx != unit) {
1727 GR_GL(ActiveTexture(GL_TEXTURE0 + unit));
1728 fActiveTextureUnitIdx = unit;
1729 }
1730}
bsalomon@google.com316f99232011-01-13 21:28:12 +00001731
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001732void GrGpuGL::setSpareTextureUnit() {
1733 if (fActiveTextureUnitIdx != (GL_TEXTURE0 + SPARE_TEX_UNIT)) {
1734 GR_GL(ActiveTexture(GL_TEXTURE0 + SPARE_TEX_UNIT));
1735 fActiveTextureUnitIdx = SPARE_TEX_UNIT;
1736 }
1737}
1738
reed@google.comac10a2d2010-12-22 21:39:39 +00001739/* On ES the internalFormat and format must match for TexImage and we use
1740 GL_RGB, GL_RGBA for color formats. We also generally like having the driver
1741 decide the internalFormat. However, on ES internalFormat for
1742 RenderBufferStorage* has to be a specific format (not a base format like
1743 GL_RGBA).
1744 */
1745bool GrGpuGL::fboInternalFormat(GrTexture::PixelConfig config, GLenum* format) {
1746 switch (config) {
1747 case GrTexture::kRGBA_8888_PixelConfig:
1748 case GrTexture::kRGBX_8888_PixelConfig:
1749 if (fRGBA8Renderbuffer) {
1750 *format = GR_RGBA8;
1751 return true;
1752 } else {
1753 return false;
1754 }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001755#if GR_SUPPORT_GLES // ES2 supports 565. ES1 supports it with FBO extension
1756 // desktop GL has no such internal format
reed@google.comac10a2d2010-12-22 21:39:39 +00001757 case GrTexture::kRGB_565_PixelConfig:
1758 *format = GR_RGB565;
1759 return true;
1760#endif
1761 case GrTexture::kRGBA_4444_PixelConfig:
1762 *format = GL_RGBA4;
1763 return true;
1764 default:
1765 return false;
1766 }
1767}
1768
1769///////////////////////////////////////////////////////////////////////////////
1770
1771void GrGLCheckErr(const char* location, const char* call) {
1772 uint32_t err = glGetError();
1773 if (GL_NO_ERROR != err) {
1774 GrPrintf("---- glGetError %x", err);
1775 if (NULL != location) {
1776 GrPrintf(" at\n\t%s", location);
1777 }
1778 if (NULL != call) {
1779 GrPrintf("\n\t\t%s", call);
1780 }
1781 GrPrintf("\n");
1782 }
1783}
1784
1785///////////////////////////////////////////////////////////////////////////////
1786
1787typedef void (*glProc)(void);
1788
1789void get_gl_proc(const char procName[], glProc *address) {
1790#if GR_WIN32_BUILD
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +00001791 *address = (glProc)wglGetProcAddress(procName);
reed@google.comac10a2d2010-12-22 21:39:39 +00001792 GrAssert(NULL != *address);
1793#elif GR_MAC_BUILD || GR_IOS_BUILD
1794 GrAssert(!"Extensions don't need to be initialized!");
1795#elif GR_ANDROID_BUILD
1796 *address = eglGetProcAddress(procName);
1797 GrAssert(NULL != *address);
1798#elif GR_LINUX_BUILD
reed@google.com37df17d2010-12-23 20:20:51 +00001799// GR_STATIC_ASSERT(!"Add environment-dependent implementation here");
reed@google.comac10a2d2010-12-22 21:39:39 +00001800 //*address = glXGetProcAddressARB(procName);
reed@google.com37df17d2010-12-23 20:20:51 +00001801 *address = NULL;//eglGetProcAddress(procName);
reed@google.comac10a2d2010-12-22 21:39:39 +00001802#elif GR_QNX_BUILD
1803 *address = eglGetProcAddress(procName);
1804 GrAssert(NULL != *address);
1805#else
1806 // hopefully we're on a system with EGL
1807 *address = eglGetProcAddress(procName);
1808 GrAssert(NULL != *address);
1809#endif
1810}
1811
1812#define GET_PROC(EXT_STRUCT, PROC_NAME, EXT_TAG) \
1813 get_gl_proc("gl" #PROC_NAME #EXT_TAG, (glProc*)&EXT_STRUCT-> PROC_NAME);
1814
1815extern void GrGLInitExtensions(GrGLExts* exts) {
1816 exts->GenFramebuffers = NULL;
1817 exts->BindFramebuffer = NULL;
1818 exts->FramebufferTexture2D = NULL;
1819 exts->CheckFramebufferStatus = NULL;
1820 exts->DeleteFramebuffers = NULL;
1821 exts->RenderbufferStorage = NULL;
1822 exts->GenRenderbuffers = NULL;
1823 exts->DeleteRenderbuffers = NULL;
1824 exts->FramebufferRenderbuffer = NULL;
1825 exts->BindRenderbuffer = NULL;
1826 exts->RenderbufferStorageMultisample = NULL;
1827 exts->BlitFramebuffer = NULL;
1828 exts->ResolveMultisampleFramebuffer = NULL;
1829 exts->FramebufferTexture2DMultisample = NULL;
1830 exts->MapBuffer = NULL;
1831 exts->UnmapBuffer = NULL;
1832
1833#if GR_MAC_BUILD
1834 exts->GenFramebuffers = glGenFramebuffers;
1835 exts->BindFramebuffer = glBindFramebuffer;
1836 exts->FramebufferTexture2D = glFramebufferTexture2D;
1837 exts->CheckFramebufferStatus = glCheckFramebufferStatus;
1838 exts->DeleteFramebuffers = glDeleteFramebuffers;
1839 exts->RenderbufferStorage = glRenderbufferStorage;
1840 exts->GenRenderbuffers = glGenRenderbuffers;
1841 exts->DeleteRenderbuffers = glDeleteRenderbuffers;
1842 exts->FramebufferRenderbuffer = glFramebufferRenderbuffer;
1843 exts->BindRenderbuffer = glBindRenderbuffer;
1844 exts->RenderbufferStorageMultisample = glRenderbufferStorageMultisample;
1845 exts->BlitFramebuffer = glBlitFramebuffer;
1846 exts->MapBuffer = glMapBuffer;
1847 exts->UnmapBuffer = glUnmapBuffer;
1848#elif GR_IOS_BUILD
1849 exts->GenFramebuffers = glGenFramebuffers;
1850 exts->BindFramebuffer = glBindFramebuffer;
1851 exts->FramebufferTexture2D = glFramebufferTexture2D;
1852 exts->CheckFramebufferStatus = glCheckFramebufferStatus;
1853 exts->DeleteFramebuffers = glDeleteFramebuffers;
1854 exts->RenderbufferStorage = glRenderbufferStorage;
1855 exts->GenRenderbuffers = glGenRenderbuffers;
1856 exts->DeleteRenderbuffers = glDeleteRenderbuffers;
1857 exts->FramebufferRenderbuffer = glFramebufferRenderbuffer;
1858 exts->BindRenderbuffer = glBindRenderbuffer;
1859 exts->RenderbufferStorageMultisample = glRenderbufferStorageMultisampleAPPLE;
1860 exts->ResolveMultisampleFramebuffer = glResolveMultisampleFramebufferAPPLE;
1861 exts->MapBuffer = glMapBufferOES;
1862 exts->UnmapBuffer = glUnmapBufferOES;
1863#else
1864 GLint major, minor;
1865 gl_version(&major, &minor);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001866 #if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +00001867 if (major >= 3) {// FBO, FBOMS, and FBOBLIT part of 3.0
1868 exts->GenFramebuffers = glGenFramebuffers;
1869 exts->BindFramebuffer = glBindFramebuffer;
1870 exts->FramebufferTexture2D = glFramebufferTexture2D;
1871 exts->CheckFramebufferStatus = glCheckFramebufferStatus;
1872 exts->DeleteFramebuffers = glDeleteFramebuffers;
1873 exts->RenderbufferStorage = glRenderbufferStorage;
1874 exts->GenRenderbuffers = glGenRenderbuffers;
1875 exts->DeleteRenderbuffers = glDeleteRenderbuffers;
1876 exts->FramebufferRenderbuffer = glFramebufferRenderbuffer;
1877 exts->BindRenderbuffer = glBindRenderbuffer;
1878 exts->RenderbufferStorageMultisample = glRenderbufferStorageMultisample;
1879 exts->BlitFramebuffer = glBlitFramebuffer;
1880 } else if (has_gl_extension("GL_ARB_framebuffer_object")) {
1881 GET_PROC(exts, GenFramebuffers, ARB);
1882 GET_PROC(exts, BindFramebuffer, ARB);
1883 GET_PROC(exts, FramebufferTexture2D, ARB);
1884 GET_PROC(exts, CheckFramebufferStatus, ARB);
1885 GET_PROC(exts, DeleteFramebuffers, ARB);
1886 GET_PROC(exts, RenderbufferStorage, ARB);
1887 GET_PROC(exts, GenRenderbuffers, ARB);
1888 GET_PROC(exts, DeleteRenderbuffers, ARB);
1889 GET_PROC(exts, FramebufferRenderbuffer, ARB);
1890 GET_PROC(exts, BindRenderbuffer, ARB);
1891 GET_PROC(exts, RenderbufferStorageMultisample, ARB);
1892 GET_PROC(exts, BlitFramebuffer, ARB);
1893 } else {
1894 // we require some form of FBO
1895 GrAssert(has_gl_extension("GL_EXT_framebuffer_object"));
1896 GET_PROC(exts, GenFramebuffers, EXT);
1897 GET_PROC(exts, BindFramebuffer, EXT);
1898 GET_PROC(exts, FramebufferTexture2D, EXT);
1899 GET_PROC(exts, CheckFramebufferStatus, EXT);
1900 GET_PROC(exts, DeleteFramebuffers, EXT);
1901 GET_PROC(exts, RenderbufferStorage, EXT);
1902 GET_PROC(exts, GenRenderbuffers, EXT);
1903 GET_PROC(exts, DeleteRenderbuffers, EXT);
1904 GET_PROC(exts, FramebufferRenderbuffer, EXT);
1905 GET_PROC(exts, BindRenderbuffer, EXT);
1906 if (has_gl_extension("GL_EXT_framebuffer_multisample")) {
1907 GET_PROC(exts, RenderbufferStorageMultisample, EXT);
1908 }
1909 if (has_gl_extension("GL_EXT_framebuffer_blit")) {
1910 GET_PROC(exts, BlitFramebuffer, EXT);
1911 }
1912 }
1913 // we assume we have at least GL 1.5 or higher (VBOs introduced in 1.5)
1914 exts->MapBuffer = glMapBuffer;
1915 exts->UnmapBuffer = glUnmapBuffer;
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001916 #else // !GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +00001917 if (major >= 2) {// ES 2.0 supports FBO
1918 exts->GenFramebuffers = glGenFramebuffers;
1919 exts->BindFramebuffer = glBindFramebuffer;
1920 exts->FramebufferTexture2D = glFramebufferTexture2D;
1921 exts->CheckFramebufferStatus = glCheckFramebufferStatus;
1922 exts->DeleteFramebuffers = glDeleteFramebuffers;
1923 exts->RenderbufferStorage = glRenderbufferStorage;
1924 exts->GenRenderbuffers = glGenRenderbuffers;
1925 exts->DeleteRenderbuffers = glDeleteRenderbuffers;
1926 exts->FramebufferRenderbuffer = glFramebufferRenderbuffer;
1927 exts->BindRenderbuffer = glBindRenderbuffer;
1928 } else {
1929 // we require some form of FBO
1930 GrAssert(has_gl_extension("GL_OES_framebuffer_object"));
1931
1932 GET_PROC(exts, GenFramebuffers, OES);
1933 GET_PROC(exts, BindFramebuffer, OES);
1934 GET_PROC(exts, FramebufferTexture2D, OES);
1935 GET_PROC(exts, CheckFramebufferStatus, OES);
1936 GET_PROC(exts, DeleteFramebuffers, OES);
1937 GET_PROC(exts, RenderbufferStorage, OES);
1938 GET_PROC(exts, GenRenderbuffers, OES);
1939 GET_PROC(exts, DeleteRenderbuffers, OES);
1940 GET_PROC(exts, FramebufferRenderbuffer, OES);
1941 GET_PROC(exts, BindRenderbuffer, OES);
1942 }
1943 if (has_gl_extension("GL_APPLE_framebuffer_multisample")) {
1944 GET_PROC(exts, ResolveMultisampleFramebuffer, APPLE);
1945 }
1946 if (has_gl_extension("GL_IMG_multisampled_render_to_texture")) {
1947 GET_PROC(exts, FramebufferTexture2DMultisample, IMG);
1948 }
1949 if (has_gl_extension("GL_OES_mapbuffer")) {
1950 GET_PROC(exts, MapBuffer, OES);
1951 GET_PROC(exts, UnmapBuffer, OES);
1952 }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001953 #endif // !GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +00001954#endif // BUILD
1955}
1956
1957bool gPrintGL = true;
1958