blob: 6de6db38c190d5bb119a38245f624e29f8ac781d [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.com8531c1c2011-01-13 19:52:45 +000032// we use a spare texture unit to avoid
33// mucking with the state of any of the stages.
34static const int SPARE_TEX_UNIT = GrGpuGL::kNumStages;
35
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));
108
109 GR_GL(ActiveTexture(GL_TEXTURE0 + SPARE_TEX_UNIT));
110
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.com8531c1c2011-01-13 19:52:45 +0000128
129 GR_GL(ActiveTexture(savedTexUnit));
130 GR_GLEXT(exts, BindFramebuffer(GR_FRAMEBUFFER, savedFBO));
131
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.com8531c1c2011-01-13 19:52:45 +0000174
175 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
187
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
302
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000303#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000304 fBufferLockSupport = true; // we require VBO support and the desktop VBO
305 // extension includes glMapBuffer.
306#else
307 fBufferLockSupport = has_gl_extension("GL_OES_mapbuffer");
308#endif
reed@google.comeeeb5a02010-12-23 15:12:59 +0000309 if (gPrintStartupSpew) {
310 GrPrintf("Map Buffer: %s\n", (fBufferLockSupport ? "YES" : "NO"));
311 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000312
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000313#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000314 fNPOTTextureSupport =
315 (major >= 2 || has_gl_extension("GL_ARB_texture_non_power_of_two")) ?
316 kFull_NPOTTextureType :
317 kNone_NPOTTextureType;
318#else
319 if (has_gl_extension("GL_OES_texture_npot")) {
320 fNPOTTextureSupport = kFull_NPOTTextureType;
321 } else if (major >= 2 ||
322 has_gl_extension("GL_APPLE_texture_2D_limited_npot")) {
323 fNPOTTextureSupport = kNoRepeat_NPOTTextureType;
324 } else {
325 fNPOTTextureSupport = kNone_NPOTTextureType;
326 }
327#endif
328 ////////////////////////////////////////////////////////////////////////////
329 // Experiments to determine limitations that can't be queried. TODO: Make
330 // these a preprocess that generate some compile time constants.
331
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000332 // sanity check to make sure we can at least create an FBO from a POT texture
333 if (fNPOTTextureSupport < kFull_NPOTTextureType) {
334 bool npotFBOSuccess = fbo_test(fExts, 128, 128);
335 if (gPrintStartupSpew) {
336 if (!npotFBOSuccess) {
337 GrPrintf("FBO Sanity Test: FAILED\n");
338 } else {
339 GrPrintf("FBO Sanity Test: PASSED\n");
340 }
341 }
342 }
reed@google.comac20fb92011-01-12 17:14:53 +0000343
reed@google.comac10a2d2010-12-22 21:39:39 +0000344 /* Experimentation has found that some GLs that support NPOT textures
345 do not support FBOs with a NPOT texture. They report "unsupported" FBO
346 status. I don't know how to explicitly query for this. Do an
347 experiment. Note they may support NPOT with a renderbuffer but not a
348 texture. Presumably, the implementation bloats the renderbuffer
349 internally to the next POT.
350 */
351 if (fNPOTTextureSupport == kFull_NPOTTextureType) {
352 bool npotFBOSuccess = fbo_test(fExts, 200, 200);
353 if (!npotFBOSuccess) {
354 fNPOTTextureSupport = kNonRendertarget_NPOTTextureType;
reed@google.comeeeb5a02010-12-23 15:12:59 +0000355 if (gPrintStartupSpew) {
356 GrPrintf("NPOT Renderbuffer Test: FAILED\n");
357 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000358 } else {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000359 if (gPrintStartupSpew) {
360 GrPrintf("NPOT Renderbuffer Test: PASSED\n");
361 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000362 }
363 }
reed@google.comeeeb5a02010-12-23 15:12:59 +0000364
365 if (gPrintStartupSpew) {
366 switch (fNPOTTextureSupport) {
367 case kNone_NPOTTextureType:
368 GrPrintf("NPOT Support: NONE\n");
369 break;
370 case kNoRepeat_NPOTTextureType:
371 GrPrintf("NPOT Support: NO REPEAT\n");
372 break;
373 case kNonRendertarget_NPOTTextureType:
374 GrPrintf("NPOT Support: NO FBOTEX\n");
375 break;
376 case kFull_NPOTTextureType:
377 GrPrintf("NPOT Support: FULL\n");
378 break;
379 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000380 }
381
reed@google.comac10a2d2010-12-22 21:39:39 +0000382 /* The iPhone 4 has a restriction that for an FBO with texture color
383 attachment with height <= 8 then the width must be <= height. Here
384 we look for such a limitation.
385 */
386 fMinRenderTargetHeight = GR_INVAL_GLINT;
387 GLint maxRenderSize;
reed@google.comac20fb92011-01-12 17:14:53 +0000388 GR_GL_GetIntegerv(GR_MAX_RENDERBUFFER_SIZE, &maxRenderSize);
reed@google.comac10a2d2010-12-22 21:39:39 +0000389
reed@google.comeeeb5a02010-12-23 15:12:59 +0000390 if (gPrintStartupSpew) {
391 GrPrintf("Small height FBO texture experiments\n");
392 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000393 for (GLuint i = 1; i <= 256;
394 (kFull_NPOTTextureType != fNPOTTextureSupport) ? i *= 2 : ++i) {
395 GLuint w = maxRenderSize;
396 GLuint h = i;
397 if (fbo_test(fExts, w, h)) {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000398 if (gPrintStartupSpew) {
399 GrPrintf("\t[%d, %d]: PASSED\n", w, h);
400 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000401 fMinRenderTargetHeight = i;
402 break;
403 } else {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000404 if (gPrintStartupSpew) {
405 GrPrintf("\t[%d, %d]: FAILED\n", w, h);
406 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000407 }
408 }
409 GrAssert(GR_INVAL_GLINT != fMinRenderTargetHeight);
410
reed@google.comeeeb5a02010-12-23 15:12:59 +0000411 if (gPrintStartupSpew) {
412 GrPrintf("Small width FBO texture experiments\n");
413 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000414 fMinRenderTargetWidth = GR_MAX_GLUINT;
415 for (GLuint i = 1; i <= 256;
416 (kFull_NPOTTextureType != fNPOTTextureSupport) ? i *= 2 : ++i) {
417 GLuint w = i;
418 GLuint h = maxRenderSize;
419 if (fbo_test(fExts, w, h)) {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000420 if (gPrintStartupSpew) {
421 GrPrintf("\t[%d, %d]: PASSED\n", w, h);
422 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000423 fMinRenderTargetWidth = i;
424 break;
425 } else {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000426 if (gPrintStartupSpew) {
427 GrPrintf("\t[%d, %d]: FAILED\n", w, h);
428 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000429 }
430 }
431 GrAssert(GR_INVAL_GLINT != fMinRenderTargetWidth);
432
433#if GR_IOS_BUILD
434 /*
435 The iPad seems to fail, at least sometimes, if the height is < 16,
436 so we pin the values here for now. A better fix might be to
437 conditionalize this based on known that its an iPad (or some other
438 check).
439 */
440 fMinRenderTargetWidth = GrMax<GLuint>(fMinRenderTargetWidth, 16);
441 fMinRenderTargetHeight = GrMax<GLuint>(fMinRenderTargetHeight, 16);
442#endif
443 // bind back to original FBO
444 GR_GLEXT(fExts, BindFramebuffer(GR_FRAMEBUFFER, defaultRTIDs.fRTFBOID));
445#if GR_COLLECT_STATS
446 ++fStats.fRenderTargetChngCnt;
447#endif
448 eraseStencil(0, ~0);
449}
450
451GrGpuGL::~GrGpuGL() {
452 fDefaultRenderTarget->abandon();
453 fDefaultRenderTarget->unref();
454}
455
456void GrGpuGL::resetContextHelper() {
457// We detect cases when blending is effectively off
458 fHWBlendDisabled = false;
459 GR_GL(Enable(GL_BLEND));
460
461 // this is always disabled
462 GR_GL(Disable(GL_CULL_FACE));
463
464 GR_GL(Disable(GL_DITHER));
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000465#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000466 GR_GL(Disable(GL_LINE_SMOOTH));
467 GR_GL(Disable(GL_POINT_SMOOTH));
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000468 GR_GL(Disable(GL_MULTISAMPLE));
reed@google.comac10a2d2010-12-22 21:39:39 +0000469#endif
470
471 // we only ever use lines in hairline mode
472 GR_GL(LineWidth(1));
473
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000474 // invalid
475 fActiveTextureUnitIdx = -1;
reed@google.comac10a2d2010-12-22 21:39:39 +0000476
477 fHWDrawState.fFlagBits = 0;
478
479 // illegal values
480 fHWDrawState.fSrcBlend = (BlendCoeff)-1;
481 fHWDrawState.fDstBlend = (BlendCoeff)-1;
482 fHWDrawState.fColor = GrColor_ILLEGAL;
483 fHWDrawState.fPointSize = -1;
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000484
485 fHWDrawState.fViewMatrix.setScale(GR_ScalarMax, GR_ScalarMax); // illegal
486
487 for (int s = 0; s < kNumStages; ++s) {
488 fHWDrawState.fTextures[s] = NULL;
489 fHWDrawState.fSamplerStates[s].setRadial2Params(-GR_ScalarMax,
490 -GR_ScalarMax,
491 true);
492 fHWDrawState.fTextureMatrices[s].setScale(GR_ScalarMax, GR_ScalarMax);
493 }
494
reed@google.comac10a2d2010-12-22 21:39:39 +0000495 GR_GL(Scissor(0,0,0,0));
496 fHWBounds.fScissorRect.setLTRB(0,0,0,0);
497 fHWBounds.fScissorEnabled = false;
498 GR_GL(Disable(GL_SCISSOR_TEST));
499
reed@google.comac10a2d2010-12-22 21:39:39 +0000500 // disabling the stencil test also disables
501 // stencil buffer writes
502 GR_GL(Disable(GL_STENCIL_TEST));
503 GR_GL(StencilMask(0xffffffff));
504 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
505 fHWDrawState.fReverseFill = false;
506 fHWDrawState.fStencilPass = kNone_StencilPass;
507 fHWStencilClip = false;
508
509 fHWGeometryState.fIndexBuffer = NULL;
510 fHWGeometryState.fVertexBuffer = NULL;
511 GR_GL(BindBuffer(GL_ARRAY_BUFFER, 0));
512 GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
513
514 fHWDrawState.fRenderTarget = NULL;
515}
516
517void GrGpuGL::resetContext() {
518 INHERITED::resetContext();
519 resetContextHelper();
520}
521
522
523// defines stencil formats from more to less preferred
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000524#if GR_SUPPORT_GLES
reed@google.comac10a2d2010-12-22 21:39:39 +0000525 GLenum GR_GL_STENCIL_FORMAT_ARRAY[] = {
526 GR_STENCIL_INDEX8,
527 };
528#else
529 GLenum GR_GL_STENCIL_FORMAT_ARRAY[] = {
530 GR_STENCIL_INDEX8,
531 GR_STENCIL_INDEX16,
532 GR_UNSIGNED_INT_24_8,
533 GR_DEPTH_STENCIL,
534 };
535#endif
536
537// good to set a break-point here to know when createTexture fails
538static GrTexture* return_null_texture() {
539// GrAssert(!"null texture");
540 return NULL;
541}
542
543#if GR_DEBUG
544static size_t as_size_t(int x) {
545 return x;
546}
547#endif
548
549GrRenderTarget* GrGpuGL::createPlatformRenderTarget(
550 intptr_t platformRenderTarget,
551 int width, int height) {
552 GrGLRenderTarget::GLRenderTargetIDs rtIDs;
553 rtIDs.fStencilRenderbufferID = 0;
554 rtIDs.fMSColorRenderbufferID = 0;
555 rtIDs.fTexFBOID = 0;
556 rtIDs.fOwnIDs = false;
557
558 GrIRect viewport;
559
560 // viewport is in GL coords (top >= bottom)
561 viewport.setLTRB(0, height, width, 0);
562
563 rtIDs.fRTFBOID = (GLuint)platformRenderTarget;
564 rtIDs.fTexFBOID = (GLuint)platformRenderTarget;
565
566 GrGLRenderTarget* rt = new GrGLRenderTarget(rtIDs, viewport, NULL, this);
567
568 return rt;
569}
570
571GrTexture* GrGpuGL::createTexture(const TextureDesc& desc,
572 const void* srcData, size_t rowBytes) {
573
574#if GR_COLLECT_STATS
575 ++fStats.fTextureCreateCnt;
576#endif
reed@google.com1fcd51e2011-01-05 15:50:27 +0000577
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000578 setSpareTextureUnit();
579
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000580 static const GrGLTexture::TexParams DEFAULT_PARAMS = {
581 GL_NEAREST,
582 GL_CLAMP_TO_EDGE,
583 GL_CLAMP_TO_EDGE
584 };
reed@google.com1fcd51e2011-01-05 15:50:27 +0000585
reed@google.comac10a2d2010-12-22 21:39:39 +0000586 GrGLTexture::GLTextureDesc glDesc;
587 GLenum internalFormat;
588
589 glDesc.fContentWidth = desc.fWidth;
590 glDesc.fContentHeight = desc.fHeight;
591 glDesc.fAllocWidth = desc.fWidth;
592 glDesc.fAllocHeight = desc.fHeight;
593 glDesc.fFormat = desc.fFormat;
594
595 bool renderTarget = 0 != (desc.fFlags & kRenderTarget_TextureFlag);
596 if (!canBeTexture(desc.fFormat,
597 &internalFormat,
598 &glDesc.fUploadFormat,
599 &glDesc.fUploadType)) {
600 return return_null_texture();
601 }
602
603 GrAssert(as_size_t(desc.fAALevel) < GR_ARRAY_COUNT(fAASamples));
604 GLint samples = fAASamples[desc.fAALevel];
605 if (kNone_MSFBO == fMSFBOType && desc.fAALevel != kNone_AALevel) {
606 GrPrintf("AA RT requested but not supported on this platform.");
607 }
608
609 GR_GL(GenTextures(1, &glDesc.fTextureID));
610 if (!glDesc.fTextureID) {
611 return return_null_texture();
612 }
613
614 glDesc.fUploadByteCount = GrTexture::BytesPerPixel(desc.fFormat);
615
616 /*
617 * check if our srcData has extra bytes past each row. If so, we need
618 * to trim those off here, since GL doesn't let us pass the rowBytes as
619 * a parameter to glTexImage2D
620 */
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000621#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000622 if (srcData) {
623 GR_GL(PixelStorei(GL_UNPACK_ROW_LENGTH,
624 rowBytes / glDesc.fUploadByteCount));
625 }
626#else
627 GrAutoSMalloc<128 * 128> trimStorage;
628 size_t trimRowBytes = desc.fWidth * glDesc.fUploadByteCount;
629 if (srcData && (trimRowBytes < rowBytes)) {
630 size_t trimSize = desc.fHeight * trimRowBytes;
631 trimStorage.realloc(trimSize);
632 // now copy the data into our new storage, skipping the trailing bytes
633 const char* src = (const char*)srcData;
634 char* dst = (char*)trimStorage.get();
635 for (uint32_t y = 0; y < desc.fHeight; y++) {
636 memcpy(dst, src, trimRowBytes);
637 src += rowBytes;
638 dst += trimRowBytes;
639 }
640 // now point srcData to our trimmed version
641 srcData = trimStorage.get();
642 }
643#endif
644
645 if (fNPOTTextureSupport < kNonRendertarget_NPOTTextureType ||
646 (fNPOTTextureSupport == kNonRendertarget_NPOTTextureType &&
647 renderTarget)) {
648 glDesc.fAllocWidth = GrNextPow2(desc.fWidth);
649 glDesc.fAllocHeight = GrNextPow2(desc.fHeight);
650 }
651
652 if (renderTarget) {
653 glDesc.fAllocWidth = GrMax<int>(fMinRenderTargetWidth,
654 glDesc.fAllocWidth);
655 glDesc.fAllocHeight = GrMax<int>(fMinRenderTargetHeight,
656 glDesc.fAllocHeight);
657 }
658
659 GR_GL(BindTexture(GL_TEXTURE_2D, glDesc.fTextureID));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000660 GR_GL(TexParameteri(GL_TEXTURE_2D,
661 GL_TEXTURE_MAG_FILTER,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000662 DEFAULT_PARAMS.fFilter));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000663 GR_GL(TexParameteri(GL_TEXTURE_2D,
664 GL_TEXTURE_MIN_FILTER,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000665 DEFAULT_PARAMS.fFilter));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000666 GR_GL(TexParameteri(GL_TEXTURE_2D,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000667 GL_TEXTURE_WRAP_S,
668 DEFAULT_PARAMS.fWrapS));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000669 GR_GL(TexParameteri(GL_TEXTURE_2D,
670 GL_TEXTURE_WRAP_T,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000671 DEFAULT_PARAMS.fWrapT));
reed@google.comac10a2d2010-12-22 21:39:39 +0000672
673 GR_GL(PixelStorei(GL_UNPACK_ALIGNMENT, glDesc.fUploadByteCount));
674 if (GrTexture::kIndex_8_PixelConfig == desc.fFormat &&
675 supports8BitPalette()) {
676 // ES only supports CompressedTexImage2D, not CompressedTexSubimage2D
677 GrAssert(desc.fWidth == glDesc.fAllocWidth);
678 GrAssert(desc.fHeight == glDesc.fAllocHeight);
679 GLsizei imageSize = glDesc.fAllocWidth * glDesc.fAllocHeight +
680 kColorTableSize;
681 GR_GL(CompressedTexImage2D(GL_TEXTURE_2D, 0, glDesc.fUploadFormat,
682 glDesc.fAllocWidth, glDesc.fAllocHeight,
683 0, imageSize, srcData));
684 GrGL_RestoreResetRowLength();
685 } else {
686 if (NULL != srcData && (glDesc.fAllocWidth != desc.fWidth ||
687 glDesc.fAllocHeight != desc.fHeight)) {
688 GR_GL(TexImage2D(GL_TEXTURE_2D, 0, internalFormat,
689 glDesc.fAllocWidth, glDesc.fAllocHeight,
690 0, glDesc.fUploadFormat, glDesc.fUploadType, NULL));
691 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, desc.fWidth,
692 desc.fHeight, glDesc.fUploadFormat,
693 glDesc.fUploadType, srcData));
694 GrGL_RestoreResetRowLength();
695
696 uint32_t extraW = glDesc.fAllocWidth - desc.fWidth;
697 uint32_t extraH = glDesc.fAllocHeight - desc.fHeight;
698 uint32_t maxTexels = extraW * extraH;
699 maxTexels = GrMax(extraW * desc.fHeight, maxTexels);
700 maxTexels = GrMax(desc.fWidth * extraH, maxTexels);
701
702 GrAutoSMalloc<128*128> texels(glDesc.fUploadByteCount * maxTexels);
703
704 uint32_t rowSize = desc.fWidth * glDesc.fUploadByteCount;
705 if (extraH) {
706 uint8_t* lastRowStart = (uint8_t*) srcData +
707 (desc.fHeight - 1) * rowSize;
708 uint8_t* extraRowStart = (uint8_t*)texels.get();
709
710 for (uint32_t i = 0; i < extraH; ++i) {
711 memcpy(extraRowStart, lastRowStart, rowSize);
712 extraRowStart += rowSize;
713 }
714 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, 0, desc.fHeight, desc.fWidth,
715 extraH, glDesc.fUploadFormat, glDesc.fUploadType,
716 texels.get()));
717 }
718 if (extraW) {
719 uint8_t* edgeTexel = (uint8_t*)srcData + rowSize - glDesc.fUploadByteCount;
720 uint8_t* extraTexel = (uint8_t*)texels.get();
721 for (uint32_t j = 0; j < desc.fHeight; ++j) {
722 for (uint32_t i = 0; i < extraW; ++i) {
723 memcpy(extraTexel, edgeTexel, glDesc.fUploadByteCount);
724 extraTexel += glDesc.fUploadByteCount;
725 }
726 edgeTexel += rowSize;
727 }
728 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, desc.fWidth, 0, extraW,
729 desc.fHeight, glDesc.fUploadFormat,
730 glDesc.fUploadType, texels.get()));
731 }
732 if (extraW && extraH) {
733 uint8_t* cornerTexel = (uint8_t*)srcData + desc.fHeight * rowSize
734 - glDesc.fUploadByteCount;
735 uint8_t* extraTexel = (uint8_t*)texels.get();
736 for (uint32_t i = 0; i < extraW*extraH; ++i) {
737 memcpy(extraTexel, cornerTexel, glDesc.fUploadByteCount);
738 extraTexel += glDesc.fUploadByteCount;
739 }
740 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, desc.fWidth, desc.fHeight,
741 extraW, extraH, glDesc.fUploadFormat,
742 glDesc.fUploadType, texels.get()));
743 }
744
745 } else {
746 GR_GL(TexImage2D(GL_TEXTURE_2D, 0, internalFormat, glDesc.fAllocWidth,
747 glDesc.fAllocHeight, 0, glDesc.fUploadFormat,
748 glDesc.fUploadType, srcData));
749 GrGL_RestoreResetRowLength();
750 }
751 }
752
753 glDesc.fOrientation = GrGLTexture::kTopDown_Orientation;
754
755 GrGLRenderTarget::GLRenderTargetIDs rtIDs;
756 rtIDs.fStencilRenderbufferID = 0;
757 rtIDs.fMSColorRenderbufferID = 0;
758 rtIDs.fRTFBOID = 0;
759 rtIDs.fTexFBOID = 0;
760 rtIDs.fOwnIDs = true;
761 GLenum msColorRenderbufferFormat = -1;
762
763 if (renderTarget) {
764#if GR_COLLECT_STATS
765 ++fStats.fRenderTargetCreateCnt;
766#endif
767 bool failed = true;
768 GLenum status;
769 GLint err;
770
771 // If need have both RT flag and srcData we have
772 // to invert the data before uploading because FBO
773 // will be rendered bottom up
774 GrAssert(NULL == srcData);
775 glDesc.fOrientation = GrGLTexture::kBottomUp_Orientation;
776
777 GR_GLEXT(fExts, GenFramebuffers(1, &rtIDs.fTexFBOID));
778 GrAssert(rtIDs.fTexFBOID);
779
780 // If we are using multisampling and any extension other than the IMG
781 // one we will create two FBOs. We render to one and then resolve to
782 // the texture bound to the other. The IMG extension does an implicit
783 // resolve.
784 if (samples > 1 && kIMG_MSFBO != fMSFBOType && kNone_MSFBO != fMSFBOType) {
785 GR_GLEXT(fExts, GenFramebuffers(1, &rtIDs.fRTFBOID));
786 GrAssert(0 != rtIDs.fRTFBOID);
787 GR_GLEXT(fExts, GenRenderbuffers(1, &rtIDs.fMSColorRenderbufferID));
788 GrAssert(0 != rtIDs.fMSColorRenderbufferID);
789 if (!fboInternalFormat(desc.fFormat, &msColorRenderbufferFormat)) {
790 GR_GLEXT(fExts,
791 DeleteRenderbuffers(1, &rtIDs.fMSColorRenderbufferID));
792 GR_GL(DeleteTextures(1, &glDesc.fTextureID));
793 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fTexFBOID));
794 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fRTFBOID));
reed@google.comac10a2d2010-12-22 21:39:39 +0000795 return return_null_texture();
796 }
797 } else {
798 rtIDs.fRTFBOID = rtIDs.fTexFBOID;
799 }
800 int attempts = 1;
801 if (!(kNoPathRendering_TextureFlag & desc.fFlags)) {
802 GR_GLEXT(fExts, GenRenderbuffers(1, &rtIDs.fStencilRenderbufferID));
803 GrAssert(0 != rtIDs.fStencilRenderbufferID);
804 attempts = GR_ARRAY_COUNT(GR_GL_STENCIL_FORMAT_ARRAY);
805 }
806
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000807 // someone suggested that some systems might require
808 // unbinding the texture before we call FramebufferTexture2D
809 // (seems unlikely)
reed@google.comac10a2d2010-12-22 21:39:39 +0000810 GR_GL(BindTexture(GL_TEXTURE_2D, 0));
reed@google.comac10a2d2010-12-22 21:39:39 +0000811
812 err = ~GL_NO_ERROR;
813 for (int i = 0; i < attempts; ++i) {
814 if (rtIDs.fStencilRenderbufferID) {
815 GR_GLEXT(fExts, BindRenderbuffer(GR_RENDERBUFFER,
816 rtIDs.fStencilRenderbufferID));
817 if (samples > 1) {
818 GR_GLEXT_NO_ERR(fExts, RenderbufferStorageMultisample(
819 GR_RENDERBUFFER,
820 samples,
821 GR_GL_STENCIL_FORMAT_ARRAY[i],
822 glDesc.fAllocWidth,
823 glDesc.fAllocHeight));
824 } else {
825 GR_GLEXT_NO_ERR(fExts, RenderbufferStorage(
826 GR_RENDERBUFFER,
827 GR_GL_STENCIL_FORMAT_ARRAY[i],
828 glDesc.fAllocWidth,
829 glDesc.fAllocHeight));
830 }
831 err = glGetError();
832 if (err != GL_NO_ERROR) {
833 continue;
834 }
835 }
836 if (rtIDs.fRTFBOID != rtIDs.fTexFBOID) {
837 GrAssert(samples > 1);
838 GR_GLEXT(fExts, BindRenderbuffer(GR_RENDERBUFFER,
839 rtIDs.fMSColorRenderbufferID));
840 GR_GLEXT_NO_ERR(fExts, RenderbufferStorageMultisample(
841 GR_RENDERBUFFER,
842 samples,
843 msColorRenderbufferFormat,
844 glDesc.fAllocWidth,
845 glDesc.fAllocHeight));
846 err = glGetError();
847 if (err != GL_NO_ERROR) {
848 continue;
849 }
850 }
851 GR_GLEXT(fExts, BindFramebuffer(GR_FRAMEBUFFER, rtIDs.fTexFBOID));
852
853#if GR_COLLECT_STATS
854 ++fStats.fRenderTargetChngCnt;
855#endif
856 if (kIMG_MSFBO == fMSFBOType && samples > 1) {
857 GR_GLEXT(fExts, FramebufferTexture2DMultisample(
858 GR_FRAMEBUFFER,
859 GR_COLOR_ATTACHMENT0,
860 GL_TEXTURE_2D,
861 glDesc.fTextureID,
862 0,
863 samples));
864
865 } else {
866 GR_GLEXT(fExts, FramebufferTexture2D(GR_FRAMEBUFFER,
867 GR_COLOR_ATTACHMENT0,
868 GL_TEXTURE_2D,
869 glDesc.fTextureID, 0));
870 }
871 if (rtIDs.fRTFBOID != rtIDs.fTexFBOID) {
872 GLenum status = GR_GLEXT(fExts,
873 CheckFramebufferStatus(GR_FRAMEBUFFER));
874 if (status != GR_FRAMEBUFFER_COMPLETE) {
875 GrPrintf("-- glCheckFramebufferStatus %x %d %d\n",
876 status, desc.fWidth, desc.fHeight);
877 continue;
878 }
879 GR_GLEXT(fExts, BindFramebuffer(GR_FRAMEBUFFER, rtIDs.fRTFBOID));
880 #if GR_COLLECT_STATS
881 ++fStats.fRenderTargetChngCnt;
882 #endif
883 GR_GLEXT(fExts, FramebufferRenderbuffer(GR_FRAMEBUFFER,
884 GR_COLOR_ATTACHMENT0,
885 GR_RENDERBUFFER,
886 rtIDs.fMSColorRenderbufferID));
887
888 }
889 if (rtIDs.fStencilRenderbufferID) {
890 // bind the stencil to rt fbo if present, othewise the tex fbo
891 GR_GLEXT(fExts, FramebufferRenderbuffer(GR_FRAMEBUFFER,
892 GR_STENCIL_ATTACHMENT,
893 GR_RENDERBUFFER,
894 rtIDs.fStencilRenderbufferID));
895 }
896 status = GR_GLEXT(fExts, CheckFramebufferStatus(GR_FRAMEBUFFER));
897
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000898#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000899 // On some implementations you have to be bound as DEPTH_STENCIL.
900 // (Even binding to DEPTH and STENCIL separately with the same
901 // buffer doesn't work.)
902 if (rtIDs.fStencilRenderbufferID &&
903 status != GR_FRAMEBUFFER_COMPLETE) {
904 GR_GLEXT(fExts, FramebufferRenderbuffer(GR_FRAMEBUFFER,
905 GR_STENCIL_ATTACHMENT,
906 GR_RENDERBUFFER,
907 0));
908 GR_GLEXT(fExts,
909 FramebufferRenderbuffer(GR_FRAMEBUFFER,
910 GR_DEPTH_STENCIL_ATTACHMENT,
911 GR_RENDERBUFFER,
912 rtIDs.fStencilRenderbufferID));
913 status = GR_GLEXT(fExts, CheckFramebufferStatus(GR_FRAMEBUFFER));
914 }
915#endif
916 if (status != GR_FRAMEBUFFER_COMPLETE) {
917 GrPrintf("-- glCheckFramebufferStatus %x %d %d\n",
918 status, desc.fWidth, desc.fHeight);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000919#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000920 if (rtIDs.fStencilRenderbufferID) {
921 GR_GLEXT(fExts, FramebufferRenderbuffer(GR_FRAMEBUFFER,
922 GR_DEPTH_STENCIL_ATTACHMENT,
923 GR_RENDERBUFFER,
924 0));
925 }
926#endif
927 continue;
928 }
929 // we're successful!
930 failed = false;
931 break;
932 }
933 if (failed) {
934 if (rtIDs.fStencilRenderbufferID) {
935 GR_GLEXT(fExts,
936 DeleteRenderbuffers(1, &rtIDs.fStencilRenderbufferID));
937 }
938 if (rtIDs.fMSColorRenderbufferID) {
939 GR_GLEXT(fExts,
940 DeleteRenderbuffers(1, &rtIDs.fMSColorRenderbufferID));
941 }
942 if (rtIDs.fRTFBOID != rtIDs.fTexFBOID) {
943 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fRTFBOID));
944 }
945 if (rtIDs.fTexFBOID) {
946 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fTexFBOID));
947 }
948 GR_GL(DeleteTextures(1, &glDesc.fTextureID));
949 return return_null_texture();
950 }
951 }
952#ifdef TRACE_TEXTURE_CREATION
953 GrPrintf("--- new texture [%d] size=(%d %d) bpp=%d\n",
954 tex->fTextureID, width, height, tex->fUploadByteCount);
955#endif
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000956 GrGLTexture* tex = new GrGLTexture(glDesc, rtIDs, DEFAULT_PARAMS, this);
reed@google.comac10a2d2010-12-22 21:39:39 +0000957
958 if (0 != rtIDs.fTexFBOID) {
959 GrRenderTarget* rt = tex->asRenderTarget();
960 // We've messed with FBO state but may not have set the correct viewport
961 // so just dirty the rendertarget state to force a resend.
962 fHWDrawState.fRenderTarget = NULL;
963
964 // clear the new stencil buffer if we have one
965 if (!(desc.fFlags & kNoPathRendering_TextureFlag)) {
966 GrRenderTarget* rtSave = fCurrDrawState.fRenderTarget;
967 fCurrDrawState.fRenderTarget = rt;
968 eraseStencil(0, ~0);
969 fCurrDrawState.fRenderTarget = rtSave;
970 }
971 }
972 return tex;
973}
974
975GrRenderTarget* GrGpuGL::defaultRenderTarget() {
976 return fDefaultRenderTarget;
977}
978
979GrVertexBuffer* GrGpuGL::createVertexBuffer(uint32_t size, bool dynamic) {
980 GLuint id;
981 GR_GL(GenBuffers(1, &id));
982 if (id) {
983 GR_GL(BindBuffer(GL_ARRAY_BUFFER, id));
984 GrGLClearErr();
985 // make sure driver can allocate memory for this buffer
986 GR_GL_NO_ERR(BufferData(GL_ARRAY_BUFFER, size, NULL,
987 dynamic ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW));
988 if (glGetError() != GL_NO_ERROR) {
989 GR_GL(DeleteBuffers(1, &id));
990 // deleting bound buffer does implicit bind to 0
991 fHWGeometryState.fVertexBuffer = NULL;
992 return NULL;
993 }
994 GrGLVertexBuffer* vertexBuffer = new GrGLVertexBuffer(id, this,
995 size, dynamic);
996 fHWGeometryState.fVertexBuffer = vertexBuffer;
997 return vertexBuffer;
998 }
999 return NULL;
1000}
1001
1002GrIndexBuffer* GrGpuGL::createIndexBuffer(uint32_t size, bool dynamic) {
1003 GLuint id;
1004 GR_GL(GenBuffers(1, &id));
1005 if (id) {
1006 GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, id));
1007 GrGLClearErr();
1008 // make sure driver can allocate memory for this buffer
1009 GR_GL_NO_ERR(BufferData(GL_ELEMENT_ARRAY_BUFFER, size, NULL,
1010 dynamic ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW));
1011 if (glGetError() != GL_NO_ERROR) {
1012 GR_GL(DeleteBuffers(1, &id));
1013 // deleting bound buffer does implicit bind to 0
1014 fHWGeometryState.fIndexBuffer = NULL;
1015 return NULL;
1016 }
1017 GrIndexBuffer* indexBuffer = new GrGLIndexBuffer(id, this,
1018 size, dynamic);
1019 fHWGeometryState.fIndexBuffer = indexBuffer;
1020 return indexBuffer;
1021 }
1022 return NULL;
1023}
1024
1025void GrGpuGL::setDefaultRenderTargetSize(uint32_t width, uint32_t height) {
1026 GrIRect viewport(0, height, width, 0);
1027 if (viewport != fDefaultRenderTarget->viewport()) {
1028 fDefaultRenderTarget->setViewport(viewport);
1029 if (fHWDrawState.fRenderTarget == fDefaultRenderTarget) {
1030 fHWDrawState.fRenderTarget = NULL;
1031 }
1032 }
1033}
1034
1035void GrGpuGL::flushScissor(const GrIRect* rect) {
1036 GrAssert(NULL != fCurrDrawState.fRenderTarget);
1037 const GrIRect& vp =
1038 ((GrGLRenderTarget*)fCurrDrawState.fRenderTarget)->viewport();
1039
1040 if (NULL != rect &&
1041 rect->contains(vp)) {
1042 rect = NULL;
1043 }
1044
1045 if (NULL != rect) {
1046 GrIRect scissor;
1047 // viewport is already in GL coords
1048 // create a scissor in GL coords (top > bottom)
1049 scissor.setLTRB(vp.fLeft + rect->fLeft,
1050 vp.fTop - rect->fTop,
1051 vp.fLeft + rect->fRight,
1052 vp.fTop - rect->fBottom);
1053
1054 if (fHWBounds.fScissorRect != scissor) {
1055 GR_GL(Scissor(scissor.fLeft, scissor.fBottom,
1056 scissor.width(), -scissor.height()));
1057 fHWBounds.fScissorRect = scissor;
1058 }
1059
1060 if (!fHWBounds.fScissorEnabled) {
1061 GR_GL(Enable(GL_SCISSOR_TEST));
1062 fHWBounds.fScissorEnabled = true;
1063 }
1064 } else {
1065 if (fHWBounds.fScissorEnabled) {
1066 GR_GL(Disable(GL_SCISSOR_TEST));
1067 fHWBounds.fScissorEnabled = false;
1068 }
1069 }
1070}
1071
reed@google.comac10a2d2010-12-22 21:39:39 +00001072void GrGpuGL::eraseColor(GrColor color) {
1073 flushRenderTarget();
1074 if (fHWBounds.fScissorEnabled) {
1075 GR_GL(Disable(GL_SCISSOR_TEST));
1076 }
1077 GR_GL(ColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE));
1078 GR_GL(ClearColor(GrColorUnpackR(color)/255.f,
1079 GrColorUnpackG(color)/255.f,
1080 GrColorUnpackB(color)/255.f,
1081 GrColorUnpackA(color)/255.f));
1082 GR_GL(Clear(GL_COLOR_BUFFER_BIT));
1083 fHWBounds.fScissorEnabled = false;
1084 fWriteMaskChanged = true;
1085}
1086
1087void GrGpuGL::eraseStencil(uint32_t value, uint32_t mask) {
1088 flushRenderTarget();
1089 if (fHWBounds.fScissorEnabled) {
1090 GR_GL(Disable(GL_SCISSOR_TEST));
1091 }
1092 GR_GL(StencilMask(mask));
1093 GR_GL(ClearStencil(value));
1094 GR_GL(Clear(GL_STENCIL_BUFFER_BIT));
1095 fHWBounds.fScissorEnabled = false;
1096 fWriteMaskChanged = true;
1097}
1098
1099void GrGpuGL::eraseStencilClip() {
1100 GLint stencilBitCount;
reed@google.comac20fb92011-01-12 17:14:53 +00001101 GR_GL_GetIntegerv(GL_STENCIL_BITS, &stencilBitCount);
reed@google.comac10a2d2010-12-22 21:39:39 +00001102 GrAssert(stencilBitCount > 0);
1103 GLint clipStencilMask = (1 << (stencilBitCount - 1));
1104 eraseStencil(0, clipStencilMask);
1105}
1106
1107void GrGpuGL::forceRenderTargetFlush() {
1108 flushRenderTarget();
1109}
1110
1111bool GrGpuGL::readPixels(int left, int top, int width, int height,
1112 GrTexture::PixelConfig config, void* buffer) {
1113 GLenum internalFormat; // we don't use this for glReadPixels
1114 GLenum format;
1115 GLenum type;
1116 if (!this->canBeTexture(config, &internalFormat, &format, &type)) {
1117 return false;
1118 }
1119
1120 GrAssert(NULL != fCurrDrawState.fRenderTarget);
1121 const GrIRect& vp = ((GrGLRenderTarget*)fCurrDrawState.fRenderTarget)->viewport();
1122
1123 // Brian says that viewport rects are already upside down (grrrrr)
1124 glReadPixels(left, -vp.height() - top - height, width, height,
1125 format, type, buffer);
1126
1127 // now reverse the order of the rows, since GL's are bottom-to-top, but our
1128 // API presents top-to-bottom
1129 {
1130 size_t stride = width * GrTexture::BytesPerPixel(config);
1131 GrAutoMalloc rowStorage(stride);
1132 void* tmp = rowStorage.get();
1133
1134 const int halfY = height >> 1;
1135 char* top = reinterpret_cast<char*>(buffer);
1136 char* bottom = top + (height - 1) * stride;
1137 for (int y = 0; y < halfY; y++) {
1138 memcpy(tmp, top, stride);
1139 memcpy(top, bottom, stride);
1140 memcpy(bottom, tmp, stride);
1141 top += stride;
1142 bottom -= stride;
1143 }
1144 }
1145 return true;
1146}
1147
1148void GrGpuGL::flushRenderTarget() {
1149 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 }
1319 glStencilFunc(GL_EQUAL, funcRef, funcMask);
1320 glStencilMask(pathStencilMask);
1321 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
1455void GrGpuGL::flushGLStateCommon(PrimitiveType type) {
1456
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001457 for (int s = 0; s < kNumStages; ++s) {
1458 bool usingTexture = VertexUsesStage(s, fGeometrySrc.fVertexLayout);
reed@google.comac10a2d2010-12-22 21:39:39 +00001459
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001460 // bind texture and set sampler state
1461 if (usingTexture) {
1462 GrGLTexture* nextTexture = (GrGLTexture*)fCurrDrawState.fTextures[s];
reed@google.comac10a2d2010-12-22 21:39:39 +00001463
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001464 if (NULL != nextTexture) {
1465 // if we created a rt/tex and rendered to it without using a
1466 // texture and now we're texuring from the rt it will still be
1467 // the last bound texture, but it needs resolving. So keep this
1468 // out of the "last != next" check.
1469 resolveTextureRenderTarget(nextTexture);
reed@google.comac10a2d2010-12-22 21:39:39 +00001470
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001471 if (fHWDrawState.fTextures[s] != nextTexture) {
1472 setTextureUnit(s);
1473 GR_GL(BindTexture(GL_TEXTURE_2D, nextTexture->textureID()));
1474 #if GR_COLLECT_STATS
1475 ++fStats.fTextureChngCnt;
1476 #endif
1477 //GrPrintf("---- bindtexture %d\n", nextTexture->textureID());
1478 fHWDrawState.fTextures[s] = nextTexture;
1479 }
1480
1481 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
1482 const GrGLTexture::TexParams& oldTexParams =
1483 nextTexture->getTexParams();
1484 GrGLTexture::TexParams newTexParams;
1485
1486 newTexParams.fFilter = sampler.isFilter() ? GL_LINEAR :
1487 GL_NEAREST;
1488 newTexParams.fWrapS =
1489 GrGLTexture::gWrapMode2GLWrap[sampler.getWrapX()];
1490 newTexParams.fWrapT =
1491 GrGLTexture::gWrapMode2GLWrap[sampler.getWrapY()];
reed@google.comac10a2d2010-12-22 21:39:39 +00001492
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001493 if (newTexParams.fFilter != oldTexParams.fFilter) {
1494 setTextureUnit(s);
1495 GR_GL(TexParameteri(GL_TEXTURE_2D,
1496 GL_TEXTURE_MAG_FILTER,
1497 newTexParams.fFilter));
1498 GR_GL(TexParameteri(GL_TEXTURE_2D,
1499 GL_TEXTURE_MIN_FILTER,
1500 newTexParams.fFilter));
1501 }
1502 if (newTexParams.fWrapS != oldTexParams.fWrapS) {
1503 setTextureUnit(s);
1504 GR_GL(TexParameteri(GL_TEXTURE_2D,
1505 GL_TEXTURE_WRAP_S,
1506 newTexParams.fWrapS));
1507 }
1508 if (newTexParams.fWrapT != oldTexParams.fWrapT) {
1509 setTextureUnit(s);
1510 GR_GL(TexParameteri(GL_TEXTURE_2D,
1511 GL_TEXTURE_WRAP_T,
1512 newTexParams.fWrapT));
1513 }
1514 nextTexture->setTexParams(newTexParams);
1515 } else {
1516 GrAssert(!"Rendering with texture vert flag set but no texture");
1517 if (NULL != fHWDrawState.fTextures[s]) {
1518 setTextureUnit(s);
1519 GR_GL(BindTexture(GL_TEXTURE_2D, 0));
1520 // GrPrintf("---- bindtexture 0\n");
1521 #if GR_COLLECT_STATS
1522 ++fStats.fTextureChngCnt;
1523 #endif
1524 fHWDrawState.fTextures[s] = NULL;
1525 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001526 }
1527 }
1528 }
1529
1530 flushRenderTarget();
1531
1532 if ((fCurrDrawState.fFlagBits & kDither_StateBit) !=
1533 (fHWDrawState.fFlagBits & kDither_StateBit)) {
1534 if (fCurrDrawState.fFlagBits & kDither_StateBit) {
1535 GR_GL(Enable(GL_DITHER));
1536 } else {
1537 GR_GL(Disable(GL_DITHER));
1538 }
1539 }
1540
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001541#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +00001542 // ES doesn't support toggling GL_MULTISAMPLE and doesn't have
1543 // smooth lines.
1544 if (fRenderTargetChanged ||
1545 (fCurrDrawState.fFlagBits & kAntialias_StateBit) !=
1546 (fHWDrawState.fFlagBits & kAntialias_StateBit)) {
1547 GLint msaa = 0;
1548 // only perform query if we know MSAA is supported.
1549 // calling on non-MSAA target caused a crash in one environment,
1550 // though I don't think it should.
1551 if (!fAASamples[kHigh_AALevel]) {
reed@google.comac20fb92011-01-12 17:14:53 +00001552 GR_GL_GetIntegerv(GL_SAMPLE_BUFFERS, &msaa);
reed@google.comac10a2d2010-12-22 21:39:39 +00001553 }
1554 if (fCurrDrawState.fFlagBits & kAntialias_StateBit) {
1555 if (msaa) {
1556 GR_GL(Enable(GL_MULTISAMPLE));
1557 } else {
1558 GR_GL(Enable(GL_LINE_SMOOTH));
1559 }
1560 } else {
1561 if (msaa) {
1562 GR_GL(Disable(GL_MULTISAMPLE));
1563 }
1564 GR_GL(Disable(GL_LINE_SMOOTH));
1565 }
1566 }
1567#endif
1568
1569 bool blendOff = canDisableBlend();
1570 if (fHWBlendDisabled != blendOff) {
1571 if (blendOff) {
1572 GR_GL(Disable(GL_BLEND));
1573 } else {
1574 GR_GL(Enable(GL_BLEND));
1575 }
1576 fHWBlendDisabled = blendOff;
1577 }
1578
1579 if (!blendOff) {
1580 if (fHWDrawState.fSrcBlend != fCurrDrawState.fSrcBlend ||
1581 fHWDrawState.fDstBlend != fCurrDrawState.fDstBlend) {
1582 GR_GL(BlendFunc(gXfermodeCoeff2Blend[fCurrDrawState.fSrcBlend],
1583 gXfermodeCoeff2Blend[fCurrDrawState.fDstBlend]));
1584 fHWDrawState.fSrcBlend = fCurrDrawState.fSrcBlend;
1585 fHWDrawState.fDstBlend = fCurrDrawState.fDstBlend;
1586 }
1587 }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001588
1589#if GR_DEBUG
reed@google.comac10a2d2010-12-22 21:39:39 +00001590 // check for circular rendering
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001591 for (int s = 0; s < kNumStages; ++s) {
1592 GrAssert(!VertexUsesStage(s, fGeometrySrc.fVertexLayout) ||
1593 NULL == fCurrDrawState.fRenderTarget ||
1594 NULL == fCurrDrawState.fTextures[s] ||
1595 fCurrDrawState.fTextures[s]->asRenderTarget() !=
1596 fCurrDrawState.fRenderTarget);
1597 }
1598#endif
1599
reed@google.comac10a2d2010-12-22 21:39:39 +00001600 flushStencil();
1601
1602 fHWDrawState.fFlagBits = fCurrDrawState.fFlagBits;
1603}
1604
1605void GrGpuGL::notifyVertexBufferBind(const GrGLVertexBuffer* buffer) {
1606 fHWGeometryState.fVertexBuffer = buffer;
1607}
1608
1609void GrGpuGL::notifyVertexBufferDelete(const GrGLVertexBuffer* buffer) {
1610 GrAssert(!(kBuffer_GeometrySrcType == fGeometrySrc.fVertexSrc &&
1611 buffer == fGeometrySrc.fVertexBuffer));
1612
1613 if (fHWGeometryState.fVertexBuffer == buffer) {
1614 // deleting bound buffer does implied bind to 0
1615 fHWGeometryState.fVertexBuffer = NULL;
1616 }
1617}
1618
1619void GrGpuGL::notifyIndexBufferBind(const GrGLIndexBuffer* buffer) {
1620 fGeometrySrc.fIndexBuffer = buffer;
1621}
1622
1623void GrGpuGL::notifyIndexBufferDelete(const GrGLIndexBuffer* buffer) {
1624 GrAssert(!(kBuffer_GeometrySrcType == fGeometrySrc.fIndexSrc &&
1625 buffer == fGeometrySrc.fIndexBuffer));
1626
1627 if (fHWGeometryState.fIndexBuffer == buffer) {
1628 // deleting bound buffer does implied bind to 0
1629 fHWGeometryState.fIndexBuffer = NULL;
1630 }
1631}
1632
reed@google.comac10a2d2010-12-22 21:39:39 +00001633void GrGpuGL::notifyRenderTargetDelete(GrRenderTarget* renderTarget) {
1634 GrAssert(NULL != renderTarget);
1635
1636 // if the bound FBO is destroyed we can't rely on the implicit bind to 0
1637 // a) we want the default RT which may not be FBO 0
1638 // b) we set more state than just FBO based on the RT
1639 // So trash the HW state to force an RT flush next time
1640 if (fCurrDrawState.fRenderTarget == renderTarget) {
reed@google.com1fcd51e2011-01-05 15:50:27 +00001641 fCurrDrawState.fRenderTarget = fDefaultRenderTarget;
reed@google.comac10a2d2010-12-22 21:39:39 +00001642 }
1643 if (fHWDrawState.fRenderTarget == renderTarget) {
1644 fHWDrawState.fRenderTarget = NULL;
1645 }
1646 if (fClipState.fStencilClipTarget == renderTarget) {
1647 fClipState.fStencilClipTarget = NULL;
1648 }
1649}
1650
1651void GrGpuGL::notifyTextureDelete(GrGLTexture* texture) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001652 for (int s = 0; s < kNumStages; ++s) {
1653 if (fCurrDrawState.fTextures[s] == texture) {
1654 fCurrDrawState.fTextures[s] = NULL;
1655 }
1656 if (fHWDrawState.fTextures[s] == texture) {
1657 // deleting bound texture does implied bind to 0
1658 fHWDrawState.fTextures[s] = NULL;
1659 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001660 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001661}
1662
1663void GrGpuGL::notifyTextureRemoveRenderTarget(GrGLTexture* texture) {
1664 GrAssert(NULL != texture->asRenderTarget());
1665
1666 // if there is a pending resolve, perform it.
1667 resolveTextureRenderTarget(texture);
1668}
1669
1670bool GrGpuGL::canBeTexture(GrTexture::PixelConfig config,
1671 GLenum* internalFormat,
1672 GLenum* format,
1673 GLenum* type) {
1674 switch (config) {
1675 case GrTexture::kRGBA_8888_PixelConfig:
1676 case GrTexture::kRGBX_8888_PixelConfig: // todo: can we tell it our X?
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +00001677 *format = GR_GL_32BPP_COLOR_FORMAT;
reed@google.comac10a2d2010-12-22 21:39:39 +00001678 *internalFormat = GL_RGBA;
1679 *type = GL_UNSIGNED_BYTE;
1680 break;
1681 case GrTexture::kRGB_565_PixelConfig:
1682 *format = GL_RGB;
1683 *internalFormat = GL_RGB;
1684 *type = GL_UNSIGNED_SHORT_5_6_5;
1685 break;
1686 case GrTexture::kRGBA_4444_PixelConfig:
1687 *format = GL_RGBA;
1688 *internalFormat = GL_RGBA;
1689 *type = GL_UNSIGNED_SHORT_4_4_4_4;
1690 break;
1691 case GrTexture::kIndex_8_PixelConfig:
1692 if (this->supports8BitPalette()) {
1693 *format = GR_PALETTE8_RGBA8;
1694 *internalFormat = GR_PALETTE8_RGBA8;
1695 *type = GL_UNSIGNED_BYTE; // unused I think
1696 } else {
1697 return false;
1698 }
1699 break;
1700 case GrTexture::kAlpha_8_PixelConfig:
1701 *format = GL_ALPHA;
1702 *internalFormat = GL_ALPHA;
1703 *type = GL_UNSIGNED_BYTE;
1704 break;
1705 default:
1706 return false;
1707 }
1708 return true;
1709}
1710
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001711void GrGpuGL::setTextureUnit(int unit) {
1712 GrAssert(unit >= 0 && unit < kNumStages);
1713 if (fActiveTextureUnitIdx != unit) {
1714 GR_GL(ActiveTexture(GL_TEXTURE0 + unit));
1715 fActiveTextureUnitIdx = unit;
1716 }
1717}
1718
1719void GrGpuGL::setSpareTextureUnit() {
1720 if (fActiveTextureUnitIdx != (GL_TEXTURE0 + SPARE_TEX_UNIT)) {
1721 GR_GL(ActiveTexture(GL_TEXTURE0 + SPARE_TEX_UNIT));
1722 fActiveTextureUnitIdx = SPARE_TEX_UNIT;
1723 }
1724}
1725
reed@google.comac10a2d2010-12-22 21:39:39 +00001726/* On ES the internalFormat and format must match for TexImage and we use
1727 GL_RGB, GL_RGBA for color formats. We also generally like having the driver
1728 decide the internalFormat. However, on ES internalFormat for
1729 RenderBufferStorage* has to be a specific format (not a base format like
1730 GL_RGBA).
1731 */
1732bool GrGpuGL::fboInternalFormat(GrTexture::PixelConfig config, GLenum* format) {
1733 switch (config) {
1734 case GrTexture::kRGBA_8888_PixelConfig:
1735 case GrTexture::kRGBX_8888_PixelConfig:
1736 if (fRGBA8Renderbuffer) {
1737 *format = GR_RGBA8;
1738 return true;
1739 } else {
1740 return false;
1741 }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001742#if GR_SUPPORT_GLES // ES2 supports 565. ES1 supports it with FBO extension
1743 // desktop GL has no such internal format
reed@google.comac10a2d2010-12-22 21:39:39 +00001744 case GrTexture::kRGB_565_PixelConfig:
1745 *format = GR_RGB565;
1746 return true;
1747#endif
1748 case GrTexture::kRGBA_4444_PixelConfig:
1749 *format = GL_RGBA4;
1750 return true;
1751 default:
1752 return false;
1753 }
1754}
1755
1756///////////////////////////////////////////////////////////////////////////////
1757
1758void GrGLCheckErr(const char* location, const char* call) {
1759 uint32_t err = glGetError();
1760 if (GL_NO_ERROR != err) {
1761 GrPrintf("---- glGetError %x", err);
1762 if (NULL != location) {
1763 GrPrintf(" at\n\t%s", location);
1764 }
1765 if (NULL != call) {
1766 GrPrintf("\n\t\t%s", call);
1767 }
1768 GrPrintf("\n");
1769 }
1770}
1771
1772///////////////////////////////////////////////////////////////////////////////
1773
1774typedef void (*glProc)(void);
1775
1776void get_gl_proc(const char procName[], glProc *address) {
1777#if GR_WIN32_BUILD
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +00001778 *address = (glProc)wglGetProcAddress(procName);
reed@google.comac10a2d2010-12-22 21:39:39 +00001779 GrAssert(NULL != *address);
1780#elif GR_MAC_BUILD || GR_IOS_BUILD
1781 GrAssert(!"Extensions don't need to be initialized!");
1782#elif GR_ANDROID_BUILD
1783 *address = eglGetProcAddress(procName);
1784 GrAssert(NULL != *address);
1785#elif GR_LINUX_BUILD
reed@google.com37df17d2010-12-23 20:20:51 +00001786// GR_STATIC_ASSERT(!"Add environment-dependent implementation here");
reed@google.comac10a2d2010-12-22 21:39:39 +00001787 //*address = glXGetProcAddressARB(procName);
reed@google.com37df17d2010-12-23 20:20:51 +00001788 *address = NULL;//eglGetProcAddress(procName);
reed@google.comac10a2d2010-12-22 21:39:39 +00001789#elif GR_QNX_BUILD
1790 *address = eglGetProcAddress(procName);
1791 GrAssert(NULL != *address);
1792#else
1793 // hopefully we're on a system with EGL
1794 *address = eglGetProcAddress(procName);
1795 GrAssert(NULL != *address);
1796#endif
1797}
1798
1799#define GET_PROC(EXT_STRUCT, PROC_NAME, EXT_TAG) \
1800 get_gl_proc("gl" #PROC_NAME #EXT_TAG, (glProc*)&EXT_STRUCT-> PROC_NAME);
1801
1802extern void GrGLInitExtensions(GrGLExts* exts) {
1803 exts->GenFramebuffers = NULL;
1804 exts->BindFramebuffer = NULL;
1805 exts->FramebufferTexture2D = NULL;
1806 exts->CheckFramebufferStatus = NULL;
1807 exts->DeleteFramebuffers = NULL;
1808 exts->RenderbufferStorage = NULL;
1809 exts->GenRenderbuffers = NULL;
1810 exts->DeleteRenderbuffers = NULL;
1811 exts->FramebufferRenderbuffer = NULL;
1812 exts->BindRenderbuffer = NULL;
1813 exts->RenderbufferStorageMultisample = NULL;
1814 exts->BlitFramebuffer = NULL;
1815 exts->ResolveMultisampleFramebuffer = NULL;
1816 exts->FramebufferTexture2DMultisample = NULL;
1817 exts->MapBuffer = NULL;
1818 exts->UnmapBuffer = NULL;
1819
1820#if GR_MAC_BUILD
1821 exts->GenFramebuffers = glGenFramebuffers;
1822 exts->BindFramebuffer = glBindFramebuffer;
1823 exts->FramebufferTexture2D = glFramebufferTexture2D;
1824 exts->CheckFramebufferStatus = glCheckFramebufferStatus;
1825 exts->DeleteFramebuffers = glDeleteFramebuffers;
1826 exts->RenderbufferStorage = glRenderbufferStorage;
1827 exts->GenRenderbuffers = glGenRenderbuffers;
1828 exts->DeleteRenderbuffers = glDeleteRenderbuffers;
1829 exts->FramebufferRenderbuffer = glFramebufferRenderbuffer;
1830 exts->BindRenderbuffer = glBindRenderbuffer;
1831 exts->RenderbufferStorageMultisample = glRenderbufferStorageMultisample;
1832 exts->BlitFramebuffer = glBlitFramebuffer;
1833 exts->MapBuffer = glMapBuffer;
1834 exts->UnmapBuffer = glUnmapBuffer;
1835#elif GR_IOS_BUILD
1836 exts->GenFramebuffers = glGenFramebuffers;
1837 exts->BindFramebuffer = glBindFramebuffer;
1838 exts->FramebufferTexture2D = glFramebufferTexture2D;
1839 exts->CheckFramebufferStatus = glCheckFramebufferStatus;
1840 exts->DeleteFramebuffers = glDeleteFramebuffers;
1841 exts->RenderbufferStorage = glRenderbufferStorage;
1842 exts->GenRenderbuffers = glGenRenderbuffers;
1843 exts->DeleteRenderbuffers = glDeleteRenderbuffers;
1844 exts->FramebufferRenderbuffer = glFramebufferRenderbuffer;
1845 exts->BindRenderbuffer = glBindRenderbuffer;
1846 exts->RenderbufferStorageMultisample = glRenderbufferStorageMultisampleAPPLE;
1847 exts->ResolveMultisampleFramebuffer = glResolveMultisampleFramebufferAPPLE;
1848 exts->MapBuffer = glMapBufferOES;
1849 exts->UnmapBuffer = glUnmapBufferOES;
1850#else
1851 GLint major, minor;
1852 gl_version(&major, &minor);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001853 #if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +00001854 if (major >= 3) {// FBO, FBOMS, and FBOBLIT part of 3.0
1855 exts->GenFramebuffers = glGenFramebuffers;
1856 exts->BindFramebuffer = glBindFramebuffer;
1857 exts->FramebufferTexture2D = glFramebufferTexture2D;
1858 exts->CheckFramebufferStatus = glCheckFramebufferStatus;
1859 exts->DeleteFramebuffers = glDeleteFramebuffers;
1860 exts->RenderbufferStorage = glRenderbufferStorage;
1861 exts->GenRenderbuffers = glGenRenderbuffers;
1862 exts->DeleteRenderbuffers = glDeleteRenderbuffers;
1863 exts->FramebufferRenderbuffer = glFramebufferRenderbuffer;
1864 exts->BindRenderbuffer = glBindRenderbuffer;
1865 exts->RenderbufferStorageMultisample = glRenderbufferStorageMultisample;
1866 exts->BlitFramebuffer = glBlitFramebuffer;
1867 } else if (has_gl_extension("GL_ARB_framebuffer_object")) {
1868 GET_PROC(exts, GenFramebuffers, ARB);
1869 GET_PROC(exts, BindFramebuffer, ARB);
1870 GET_PROC(exts, FramebufferTexture2D, ARB);
1871 GET_PROC(exts, CheckFramebufferStatus, ARB);
1872 GET_PROC(exts, DeleteFramebuffers, ARB);
1873 GET_PROC(exts, RenderbufferStorage, ARB);
1874 GET_PROC(exts, GenRenderbuffers, ARB);
1875 GET_PROC(exts, DeleteRenderbuffers, ARB);
1876 GET_PROC(exts, FramebufferRenderbuffer, ARB);
1877 GET_PROC(exts, BindRenderbuffer, ARB);
1878 GET_PROC(exts, RenderbufferStorageMultisample, ARB);
1879 GET_PROC(exts, BlitFramebuffer, ARB);
1880 } else {
1881 // we require some form of FBO
1882 GrAssert(has_gl_extension("GL_EXT_framebuffer_object"));
1883 GET_PROC(exts, GenFramebuffers, EXT);
1884 GET_PROC(exts, BindFramebuffer, EXT);
1885 GET_PROC(exts, FramebufferTexture2D, EXT);
1886 GET_PROC(exts, CheckFramebufferStatus, EXT);
1887 GET_PROC(exts, DeleteFramebuffers, EXT);
1888 GET_PROC(exts, RenderbufferStorage, EXT);
1889 GET_PROC(exts, GenRenderbuffers, EXT);
1890 GET_PROC(exts, DeleteRenderbuffers, EXT);
1891 GET_PROC(exts, FramebufferRenderbuffer, EXT);
1892 GET_PROC(exts, BindRenderbuffer, EXT);
1893 if (has_gl_extension("GL_EXT_framebuffer_multisample")) {
1894 GET_PROC(exts, RenderbufferStorageMultisample, EXT);
1895 }
1896 if (has_gl_extension("GL_EXT_framebuffer_blit")) {
1897 GET_PROC(exts, BlitFramebuffer, EXT);
1898 }
1899 }
1900 // we assume we have at least GL 1.5 or higher (VBOs introduced in 1.5)
1901 exts->MapBuffer = glMapBuffer;
1902 exts->UnmapBuffer = glUnmapBuffer;
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001903 #else // !GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +00001904 if (major >= 2) {// ES 2.0 supports FBO
1905 exts->GenFramebuffers = glGenFramebuffers;
1906 exts->BindFramebuffer = glBindFramebuffer;
1907 exts->FramebufferTexture2D = glFramebufferTexture2D;
1908 exts->CheckFramebufferStatus = glCheckFramebufferStatus;
1909 exts->DeleteFramebuffers = glDeleteFramebuffers;
1910 exts->RenderbufferStorage = glRenderbufferStorage;
1911 exts->GenRenderbuffers = glGenRenderbuffers;
1912 exts->DeleteRenderbuffers = glDeleteRenderbuffers;
1913 exts->FramebufferRenderbuffer = glFramebufferRenderbuffer;
1914 exts->BindRenderbuffer = glBindRenderbuffer;
1915 } else {
1916 // we require some form of FBO
1917 GrAssert(has_gl_extension("GL_OES_framebuffer_object"));
1918
1919 GET_PROC(exts, GenFramebuffers, OES);
1920 GET_PROC(exts, BindFramebuffer, OES);
1921 GET_PROC(exts, FramebufferTexture2D, OES);
1922 GET_PROC(exts, CheckFramebufferStatus, OES);
1923 GET_PROC(exts, DeleteFramebuffers, OES);
1924 GET_PROC(exts, RenderbufferStorage, OES);
1925 GET_PROC(exts, GenRenderbuffers, OES);
1926 GET_PROC(exts, DeleteRenderbuffers, OES);
1927 GET_PROC(exts, FramebufferRenderbuffer, OES);
1928 GET_PROC(exts, BindRenderbuffer, OES);
1929 }
1930 if (has_gl_extension("GL_APPLE_framebuffer_multisample")) {
1931 GET_PROC(exts, ResolveMultisampleFramebuffer, APPLE);
1932 }
1933 if (has_gl_extension("GL_IMG_multisampled_render_to_texture")) {
1934 GET_PROC(exts, FramebufferTexture2DMultisample, IMG);
1935 }
1936 if (has_gl_extension("GL_OES_mapbuffer")) {
1937 GET_PROC(exts, MapBuffer, OES);
1938 GET_PROC(exts, UnmapBuffer, OES);
1939 }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001940 #endif // !GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +00001941#endif // BUILD
1942}
1943
1944bool gPrintGL = true;
1945