blob: ff3519389fc57de6bc4b182a0353445a80d66e2e [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
527
528// defines stencil formats from more to less preferred
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000529#if GR_SUPPORT_GLES
reed@google.comac10a2d2010-12-22 21:39:39 +0000530 GLenum GR_GL_STENCIL_FORMAT_ARRAY[] = {
531 GR_STENCIL_INDEX8,
532 };
533#else
534 GLenum GR_GL_STENCIL_FORMAT_ARRAY[] = {
535 GR_STENCIL_INDEX8,
536 GR_STENCIL_INDEX16,
537 GR_UNSIGNED_INT_24_8,
538 GR_DEPTH_STENCIL,
539 };
540#endif
541
542// good to set a break-point here to know when createTexture fails
543static GrTexture* return_null_texture() {
544// GrAssert(!"null texture");
545 return NULL;
546}
547
548#if GR_DEBUG
549static size_t as_size_t(int x) {
550 return x;
551}
552#endif
553
554GrRenderTarget* GrGpuGL::createPlatformRenderTarget(
555 intptr_t platformRenderTarget,
556 int width, int height) {
557 GrGLRenderTarget::GLRenderTargetIDs rtIDs;
558 rtIDs.fStencilRenderbufferID = 0;
559 rtIDs.fMSColorRenderbufferID = 0;
560 rtIDs.fTexFBOID = 0;
561 rtIDs.fOwnIDs = false;
562
563 GrIRect viewport;
564
565 // viewport is in GL coords (top >= bottom)
566 viewport.setLTRB(0, height, width, 0);
567
568 rtIDs.fRTFBOID = (GLuint)platformRenderTarget;
569 rtIDs.fTexFBOID = (GLuint)platformRenderTarget;
570
571 GrGLRenderTarget* rt = new GrGLRenderTarget(rtIDs, viewport, NULL, this);
572
573 return rt;
574}
575
576GrTexture* GrGpuGL::createTexture(const TextureDesc& desc,
577 const void* srcData, size_t rowBytes) {
578
579#if GR_COLLECT_STATS
580 ++fStats.fTextureCreateCnt;
581#endif
reed@google.com1fcd51e2011-01-05 15:50:27 +0000582
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000583 setSpareTextureUnit();
bsalomon@google.com316f99232011-01-13 21:28:12 +0000584
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000585 static const GrGLTexture::TexParams DEFAULT_PARAMS = {
586 GL_NEAREST,
587 GL_CLAMP_TO_EDGE,
588 GL_CLAMP_TO_EDGE
589 };
reed@google.com1fcd51e2011-01-05 15:50:27 +0000590
reed@google.comac10a2d2010-12-22 21:39:39 +0000591 GrGLTexture::GLTextureDesc glDesc;
592 GLenum internalFormat;
593
594 glDesc.fContentWidth = desc.fWidth;
595 glDesc.fContentHeight = desc.fHeight;
596 glDesc.fAllocWidth = desc.fWidth;
597 glDesc.fAllocHeight = desc.fHeight;
598 glDesc.fFormat = desc.fFormat;
599
600 bool renderTarget = 0 != (desc.fFlags & kRenderTarget_TextureFlag);
601 if (!canBeTexture(desc.fFormat,
602 &internalFormat,
603 &glDesc.fUploadFormat,
604 &glDesc.fUploadType)) {
605 return return_null_texture();
606 }
607
608 GrAssert(as_size_t(desc.fAALevel) < GR_ARRAY_COUNT(fAASamples));
609 GLint samples = fAASamples[desc.fAALevel];
610 if (kNone_MSFBO == fMSFBOType && desc.fAALevel != kNone_AALevel) {
611 GrPrintf("AA RT requested but not supported on this platform.");
612 }
613
614 GR_GL(GenTextures(1, &glDesc.fTextureID));
615 if (!glDesc.fTextureID) {
616 return return_null_texture();
617 }
618
619 glDesc.fUploadByteCount = GrTexture::BytesPerPixel(desc.fFormat);
620
621 /*
622 * check if our srcData has extra bytes past each row. If so, we need
623 * to trim those off here, since GL doesn't let us pass the rowBytes as
624 * a parameter to glTexImage2D
625 */
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000626#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000627 if (srcData) {
628 GR_GL(PixelStorei(GL_UNPACK_ROW_LENGTH,
629 rowBytes / glDesc.fUploadByteCount));
630 }
631#else
632 GrAutoSMalloc<128 * 128> trimStorage;
633 size_t trimRowBytes = desc.fWidth * glDesc.fUploadByteCount;
634 if (srcData && (trimRowBytes < rowBytes)) {
635 size_t trimSize = desc.fHeight * trimRowBytes;
636 trimStorage.realloc(trimSize);
637 // now copy the data into our new storage, skipping the trailing bytes
638 const char* src = (const char*)srcData;
639 char* dst = (char*)trimStorage.get();
640 for (uint32_t y = 0; y < desc.fHeight; y++) {
641 memcpy(dst, src, trimRowBytes);
642 src += rowBytes;
643 dst += trimRowBytes;
644 }
645 // now point srcData to our trimmed version
646 srcData = trimStorage.get();
647 }
648#endif
649
650 if (fNPOTTextureSupport < kNonRendertarget_NPOTTextureType ||
651 (fNPOTTextureSupport == kNonRendertarget_NPOTTextureType &&
652 renderTarget)) {
653 glDesc.fAllocWidth = GrNextPow2(desc.fWidth);
654 glDesc.fAllocHeight = GrNextPow2(desc.fHeight);
655 }
656
657 if (renderTarget) {
658 glDesc.fAllocWidth = GrMax<int>(fMinRenderTargetWidth,
659 glDesc.fAllocWidth);
660 glDesc.fAllocHeight = GrMax<int>(fMinRenderTargetHeight,
661 glDesc.fAllocHeight);
662 }
663
664 GR_GL(BindTexture(GL_TEXTURE_2D, glDesc.fTextureID));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000665 GR_GL(TexParameteri(GL_TEXTURE_2D,
666 GL_TEXTURE_MAG_FILTER,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000667 DEFAULT_PARAMS.fFilter));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000668 GR_GL(TexParameteri(GL_TEXTURE_2D,
669 GL_TEXTURE_MIN_FILTER,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000670 DEFAULT_PARAMS.fFilter));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000671 GR_GL(TexParameteri(GL_TEXTURE_2D,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000672 GL_TEXTURE_WRAP_S,
673 DEFAULT_PARAMS.fWrapS));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000674 GR_GL(TexParameteri(GL_TEXTURE_2D,
675 GL_TEXTURE_WRAP_T,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000676 DEFAULT_PARAMS.fWrapT));
reed@google.comac10a2d2010-12-22 21:39:39 +0000677
678 GR_GL(PixelStorei(GL_UNPACK_ALIGNMENT, glDesc.fUploadByteCount));
679 if (GrTexture::kIndex_8_PixelConfig == desc.fFormat &&
680 supports8BitPalette()) {
681 // ES only supports CompressedTexImage2D, not CompressedTexSubimage2D
682 GrAssert(desc.fWidth == glDesc.fAllocWidth);
683 GrAssert(desc.fHeight == glDesc.fAllocHeight);
684 GLsizei imageSize = glDesc.fAllocWidth * glDesc.fAllocHeight +
685 kColorTableSize;
686 GR_GL(CompressedTexImage2D(GL_TEXTURE_2D, 0, glDesc.fUploadFormat,
687 glDesc.fAllocWidth, glDesc.fAllocHeight,
688 0, imageSize, srcData));
689 GrGL_RestoreResetRowLength();
690 } else {
691 if (NULL != srcData && (glDesc.fAllocWidth != desc.fWidth ||
692 glDesc.fAllocHeight != desc.fHeight)) {
693 GR_GL(TexImage2D(GL_TEXTURE_2D, 0, internalFormat,
694 glDesc.fAllocWidth, glDesc.fAllocHeight,
695 0, glDesc.fUploadFormat, glDesc.fUploadType, NULL));
696 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, desc.fWidth,
697 desc.fHeight, glDesc.fUploadFormat,
698 glDesc.fUploadType, srcData));
699 GrGL_RestoreResetRowLength();
700
701 uint32_t extraW = glDesc.fAllocWidth - desc.fWidth;
702 uint32_t extraH = glDesc.fAllocHeight - desc.fHeight;
703 uint32_t maxTexels = extraW * extraH;
704 maxTexels = GrMax(extraW * desc.fHeight, maxTexels);
705 maxTexels = GrMax(desc.fWidth * extraH, maxTexels);
706
707 GrAutoSMalloc<128*128> texels(glDesc.fUploadByteCount * maxTexels);
708
709 uint32_t rowSize = desc.fWidth * glDesc.fUploadByteCount;
710 if (extraH) {
711 uint8_t* lastRowStart = (uint8_t*) srcData +
712 (desc.fHeight - 1) * rowSize;
713 uint8_t* extraRowStart = (uint8_t*)texels.get();
714
715 for (uint32_t i = 0; i < extraH; ++i) {
716 memcpy(extraRowStart, lastRowStart, rowSize);
717 extraRowStart += rowSize;
718 }
719 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, 0, desc.fHeight, desc.fWidth,
720 extraH, glDesc.fUploadFormat, glDesc.fUploadType,
721 texels.get()));
722 }
723 if (extraW) {
724 uint8_t* edgeTexel = (uint8_t*)srcData + rowSize - glDesc.fUploadByteCount;
725 uint8_t* extraTexel = (uint8_t*)texels.get();
726 for (uint32_t j = 0; j < desc.fHeight; ++j) {
727 for (uint32_t i = 0; i < extraW; ++i) {
728 memcpy(extraTexel, edgeTexel, glDesc.fUploadByteCount);
729 extraTexel += glDesc.fUploadByteCount;
730 }
731 edgeTexel += rowSize;
732 }
733 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, desc.fWidth, 0, extraW,
734 desc.fHeight, glDesc.fUploadFormat,
735 glDesc.fUploadType, texels.get()));
736 }
737 if (extraW && extraH) {
738 uint8_t* cornerTexel = (uint8_t*)srcData + desc.fHeight * rowSize
739 - glDesc.fUploadByteCount;
740 uint8_t* extraTexel = (uint8_t*)texels.get();
741 for (uint32_t i = 0; i < extraW*extraH; ++i) {
742 memcpy(extraTexel, cornerTexel, glDesc.fUploadByteCount);
743 extraTexel += glDesc.fUploadByteCount;
744 }
745 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, desc.fWidth, desc.fHeight,
746 extraW, extraH, glDesc.fUploadFormat,
747 glDesc.fUploadType, texels.get()));
748 }
749
750 } else {
751 GR_GL(TexImage2D(GL_TEXTURE_2D, 0, internalFormat, glDesc.fAllocWidth,
752 glDesc.fAllocHeight, 0, glDesc.fUploadFormat,
753 glDesc.fUploadType, srcData));
754 GrGL_RestoreResetRowLength();
755 }
756 }
757
758 glDesc.fOrientation = GrGLTexture::kTopDown_Orientation;
759
760 GrGLRenderTarget::GLRenderTargetIDs rtIDs;
761 rtIDs.fStencilRenderbufferID = 0;
762 rtIDs.fMSColorRenderbufferID = 0;
763 rtIDs.fRTFBOID = 0;
764 rtIDs.fTexFBOID = 0;
765 rtIDs.fOwnIDs = true;
766 GLenum msColorRenderbufferFormat = -1;
767
768 if (renderTarget) {
769#if GR_COLLECT_STATS
770 ++fStats.fRenderTargetCreateCnt;
771#endif
772 bool failed = true;
773 GLenum status;
774 GLint err;
775
776 // If need have both RT flag and srcData we have
777 // to invert the data before uploading because FBO
778 // will be rendered bottom up
779 GrAssert(NULL == srcData);
780 glDesc.fOrientation = GrGLTexture::kBottomUp_Orientation;
781
782 GR_GLEXT(fExts, GenFramebuffers(1, &rtIDs.fTexFBOID));
783 GrAssert(rtIDs.fTexFBOID);
784
785 // If we are using multisampling and any extension other than the IMG
786 // one we will create two FBOs. We render to one and then resolve to
787 // the texture bound to the other. The IMG extension does an implicit
788 // resolve.
789 if (samples > 1 && kIMG_MSFBO != fMSFBOType && kNone_MSFBO != fMSFBOType) {
790 GR_GLEXT(fExts, GenFramebuffers(1, &rtIDs.fRTFBOID));
791 GrAssert(0 != rtIDs.fRTFBOID);
792 GR_GLEXT(fExts, GenRenderbuffers(1, &rtIDs.fMSColorRenderbufferID));
793 GrAssert(0 != rtIDs.fMSColorRenderbufferID);
794 if (!fboInternalFormat(desc.fFormat, &msColorRenderbufferFormat)) {
795 GR_GLEXT(fExts,
796 DeleteRenderbuffers(1, &rtIDs.fMSColorRenderbufferID));
797 GR_GL(DeleteTextures(1, &glDesc.fTextureID));
798 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fTexFBOID));
799 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fRTFBOID));
reed@google.comac10a2d2010-12-22 21:39:39 +0000800 return return_null_texture();
801 }
802 } else {
803 rtIDs.fRTFBOID = rtIDs.fTexFBOID;
804 }
805 int attempts = 1;
806 if (!(kNoPathRendering_TextureFlag & desc.fFlags)) {
807 GR_GLEXT(fExts, GenRenderbuffers(1, &rtIDs.fStencilRenderbufferID));
808 GrAssert(0 != rtIDs.fStencilRenderbufferID);
809 attempts = GR_ARRAY_COUNT(GR_GL_STENCIL_FORMAT_ARRAY);
810 }
811
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000812 // someone suggested that some systems might require
bsalomon@google.com316f99232011-01-13 21:28:12 +0000813 // unbinding the texture before we call FramebufferTexture2D
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000814 // (seems unlikely)
reed@google.comac10a2d2010-12-22 21:39:39 +0000815 GR_GL(BindTexture(GL_TEXTURE_2D, 0));
reed@google.comac10a2d2010-12-22 21:39:39 +0000816
817 err = ~GL_NO_ERROR;
818 for (int i = 0; i < attempts; ++i) {
819 if (rtIDs.fStencilRenderbufferID) {
820 GR_GLEXT(fExts, BindRenderbuffer(GR_RENDERBUFFER,
821 rtIDs.fStencilRenderbufferID));
822 if (samples > 1) {
823 GR_GLEXT_NO_ERR(fExts, RenderbufferStorageMultisample(
824 GR_RENDERBUFFER,
825 samples,
826 GR_GL_STENCIL_FORMAT_ARRAY[i],
827 glDesc.fAllocWidth,
828 glDesc.fAllocHeight));
829 } else {
830 GR_GLEXT_NO_ERR(fExts, RenderbufferStorage(
831 GR_RENDERBUFFER,
832 GR_GL_STENCIL_FORMAT_ARRAY[i],
833 glDesc.fAllocWidth,
834 glDesc.fAllocHeight));
835 }
836 err = glGetError();
837 if (err != GL_NO_ERROR) {
838 continue;
839 }
840 }
841 if (rtIDs.fRTFBOID != rtIDs.fTexFBOID) {
842 GrAssert(samples > 1);
843 GR_GLEXT(fExts, BindRenderbuffer(GR_RENDERBUFFER,
844 rtIDs.fMSColorRenderbufferID));
845 GR_GLEXT_NO_ERR(fExts, RenderbufferStorageMultisample(
846 GR_RENDERBUFFER,
847 samples,
848 msColorRenderbufferFormat,
849 glDesc.fAllocWidth,
850 glDesc.fAllocHeight));
851 err = glGetError();
852 if (err != GL_NO_ERROR) {
853 continue;
854 }
855 }
856 GR_GLEXT(fExts, BindFramebuffer(GR_FRAMEBUFFER, rtIDs.fTexFBOID));
857
858#if GR_COLLECT_STATS
859 ++fStats.fRenderTargetChngCnt;
860#endif
861 if (kIMG_MSFBO == fMSFBOType && samples > 1) {
862 GR_GLEXT(fExts, FramebufferTexture2DMultisample(
863 GR_FRAMEBUFFER,
864 GR_COLOR_ATTACHMENT0,
865 GL_TEXTURE_2D,
866 glDesc.fTextureID,
867 0,
868 samples));
869
870 } else {
871 GR_GLEXT(fExts, FramebufferTexture2D(GR_FRAMEBUFFER,
872 GR_COLOR_ATTACHMENT0,
873 GL_TEXTURE_2D,
874 glDesc.fTextureID, 0));
875 }
876 if (rtIDs.fRTFBOID != rtIDs.fTexFBOID) {
877 GLenum status = GR_GLEXT(fExts,
878 CheckFramebufferStatus(GR_FRAMEBUFFER));
879 if (status != GR_FRAMEBUFFER_COMPLETE) {
880 GrPrintf("-- glCheckFramebufferStatus %x %d %d\n",
881 status, desc.fWidth, desc.fHeight);
882 continue;
883 }
884 GR_GLEXT(fExts, BindFramebuffer(GR_FRAMEBUFFER, rtIDs.fRTFBOID));
885 #if GR_COLLECT_STATS
886 ++fStats.fRenderTargetChngCnt;
887 #endif
888 GR_GLEXT(fExts, FramebufferRenderbuffer(GR_FRAMEBUFFER,
889 GR_COLOR_ATTACHMENT0,
890 GR_RENDERBUFFER,
891 rtIDs.fMSColorRenderbufferID));
892
893 }
894 if (rtIDs.fStencilRenderbufferID) {
895 // bind the stencil to rt fbo if present, othewise the tex fbo
896 GR_GLEXT(fExts, FramebufferRenderbuffer(GR_FRAMEBUFFER,
897 GR_STENCIL_ATTACHMENT,
bsalomon@google.com316f99232011-01-13 21:28:12 +0000898 GR_RENDERBUFFER,
reed@google.comac10a2d2010-12-22 21:39:39 +0000899 rtIDs.fStencilRenderbufferID));
900 }
901 status = GR_GLEXT(fExts, CheckFramebufferStatus(GR_FRAMEBUFFER));
902
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000903#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000904 // On some implementations you have to be bound as DEPTH_STENCIL.
905 // (Even binding to DEPTH and STENCIL separately with the same
906 // buffer doesn't work.)
907 if (rtIDs.fStencilRenderbufferID &&
908 status != GR_FRAMEBUFFER_COMPLETE) {
909 GR_GLEXT(fExts, FramebufferRenderbuffer(GR_FRAMEBUFFER,
910 GR_STENCIL_ATTACHMENT,
911 GR_RENDERBUFFER,
912 0));
913 GR_GLEXT(fExts,
914 FramebufferRenderbuffer(GR_FRAMEBUFFER,
915 GR_DEPTH_STENCIL_ATTACHMENT,
916 GR_RENDERBUFFER,
917 rtIDs.fStencilRenderbufferID));
918 status = GR_GLEXT(fExts, CheckFramebufferStatus(GR_FRAMEBUFFER));
919 }
920#endif
921 if (status != GR_FRAMEBUFFER_COMPLETE) {
922 GrPrintf("-- glCheckFramebufferStatus %x %d %d\n",
923 status, desc.fWidth, desc.fHeight);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000924#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000925 if (rtIDs.fStencilRenderbufferID) {
926 GR_GLEXT(fExts, FramebufferRenderbuffer(GR_FRAMEBUFFER,
927 GR_DEPTH_STENCIL_ATTACHMENT,
928 GR_RENDERBUFFER,
929 0));
930 }
931#endif
932 continue;
933 }
934 // we're successful!
935 failed = false;
936 break;
937 }
938 if (failed) {
939 if (rtIDs.fStencilRenderbufferID) {
940 GR_GLEXT(fExts,
941 DeleteRenderbuffers(1, &rtIDs.fStencilRenderbufferID));
942 }
943 if (rtIDs.fMSColorRenderbufferID) {
944 GR_GLEXT(fExts,
945 DeleteRenderbuffers(1, &rtIDs.fMSColorRenderbufferID));
946 }
947 if (rtIDs.fRTFBOID != rtIDs.fTexFBOID) {
948 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fRTFBOID));
949 }
950 if (rtIDs.fTexFBOID) {
951 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fTexFBOID));
952 }
953 GR_GL(DeleteTextures(1, &glDesc.fTextureID));
954 return return_null_texture();
955 }
956 }
957#ifdef TRACE_TEXTURE_CREATION
958 GrPrintf("--- new texture [%d] size=(%d %d) bpp=%d\n",
959 tex->fTextureID, width, height, tex->fUploadByteCount);
960#endif
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000961 GrGLTexture* tex = new GrGLTexture(glDesc, rtIDs, DEFAULT_PARAMS, this);
reed@google.comac10a2d2010-12-22 21:39:39 +0000962
963 if (0 != rtIDs.fTexFBOID) {
964 GrRenderTarget* rt = tex->asRenderTarget();
965 // We've messed with FBO state but may not have set the correct viewport
966 // so just dirty the rendertarget state to force a resend.
967 fHWDrawState.fRenderTarget = NULL;
968
969 // clear the new stencil buffer if we have one
970 if (!(desc.fFlags & kNoPathRendering_TextureFlag)) {
971 GrRenderTarget* rtSave = fCurrDrawState.fRenderTarget;
972 fCurrDrawState.fRenderTarget = rt;
973 eraseStencil(0, ~0);
974 fCurrDrawState.fRenderTarget = rtSave;
975 }
976 }
977 return tex;
978}
979
980GrRenderTarget* GrGpuGL::defaultRenderTarget() {
981 return fDefaultRenderTarget;
982}
983
984GrVertexBuffer* GrGpuGL::createVertexBuffer(uint32_t size, bool dynamic) {
985 GLuint id;
986 GR_GL(GenBuffers(1, &id));
987 if (id) {
988 GR_GL(BindBuffer(GL_ARRAY_BUFFER, id));
989 GrGLClearErr();
990 // make sure driver can allocate memory for this buffer
991 GR_GL_NO_ERR(BufferData(GL_ARRAY_BUFFER, size, NULL,
992 dynamic ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW));
993 if (glGetError() != GL_NO_ERROR) {
994 GR_GL(DeleteBuffers(1, &id));
995 // deleting bound buffer does implicit bind to 0
996 fHWGeometryState.fVertexBuffer = NULL;
997 return NULL;
998 }
999 GrGLVertexBuffer* vertexBuffer = new GrGLVertexBuffer(id, this,
1000 size, dynamic);
1001 fHWGeometryState.fVertexBuffer = vertexBuffer;
1002 return vertexBuffer;
1003 }
1004 return NULL;
1005}
1006
1007GrIndexBuffer* GrGpuGL::createIndexBuffer(uint32_t size, bool dynamic) {
1008 GLuint id;
1009 GR_GL(GenBuffers(1, &id));
1010 if (id) {
1011 GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, id));
1012 GrGLClearErr();
1013 // make sure driver can allocate memory for this buffer
1014 GR_GL_NO_ERR(BufferData(GL_ELEMENT_ARRAY_BUFFER, size, NULL,
1015 dynamic ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW));
1016 if (glGetError() != GL_NO_ERROR) {
1017 GR_GL(DeleteBuffers(1, &id));
1018 // deleting bound buffer does implicit bind to 0
1019 fHWGeometryState.fIndexBuffer = NULL;
1020 return NULL;
1021 }
1022 GrIndexBuffer* indexBuffer = new GrGLIndexBuffer(id, this,
1023 size, dynamic);
1024 fHWGeometryState.fIndexBuffer = indexBuffer;
1025 return indexBuffer;
1026 }
1027 return NULL;
1028}
1029
1030void GrGpuGL::setDefaultRenderTargetSize(uint32_t width, uint32_t height) {
1031 GrIRect viewport(0, height, width, 0);
1032 if (viewport != fDefaultRenderTarget->viewport()) {
1033 fDefaultRenderTarget->setViewport(viewport);
1034 if (fHWDrawState.fRenderTarget == fDefaultRenderTarget) {
1035 fHWDrawState.fRenderTarget = NULL;
1036 }
1037 }
1038}
1039
1040void GrGpuGL::flushScissor(const GrIRect* rect) {
1041 GrAssert(NULL != fCurrDrawState.fRenderTarget);
1042 const GrIRect& vp =
1043 ((GrGLRenderTarget*)fCurrDrawState.fRenderTarget)->viewport();
1044
1045 if (NULL != rect &&
1046 rect->contains(vp)) {
1047 rect = NULL;
1048 }
1049
1050 if (NULL != rect) {
1051 GrIRect scissor;
1052 // viewport is already in GL coords
1053 // create a scissor in GL coords (top > bottom)
1054 scissor.setLTRB(vp.fLeft + rect->fLeft,
1055 vp.fTop - rect->fTop,
1056 vp.fLeft + rect->fRight,
1057 vp.fTop - rect->fBottom);
1058
1059 if (fHWBounds.fScissorRect != scissor) {
1060 GR_GL(Scissor(scissor.fLeft, scissor.fBottom,
1061 scissor.width(), -scissor.height()));
1062 fHWBounds.fScissorRect = scissor;
1063 }
1064
1065 if (!fHWBounds.fScissorEnabled) {
1066 GR_GL(Enable(GL_SCISSOR_TEST));
1067 fHWBounds.fScissorEnabled = true;
1068 }
1069 } else {
1070 if (fHWBounds.fScissorEnabled) {
1071 GR_GL(Disable(GL_SCISSOR_TEST));
1072 fHWBounds.fScissorEnabled = false;
1073 }
1074 }
1075}
1076
reed@google.comac10a2d2010-12-22 21:39:39 +00001077void GrGpuGL::eraseColor(GrColor color) {
1078 flushRenderTarget();
1079 if (fHWBounds.fScissorEnabled) {
1080 GR_GL(Disable(GL_SCISSOR_TEST));
1081 }
1082 GR_GL(ColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE));
1083 GR_GL(ClearColor(GrColorUnpackR(color)/255.f,
1084 GrColorUnpackG(color)/255.f,
1085 GrColorUnpackB(color)/255.f,
1086 GrColorUnpackA(color)/255.f));
1087 GR_GL(Clear(GL_COLOR_BUFFER_BIT));
1088 fHWBounds.fScissorEnabled = false;
1089 fWriteMaskChanged = true;
1090}
1091
1092void GrGpuGL::eraseStencil(uint32_t value, uint32_t mask) {
1093 flushRenderTarget();
1094 if (fHWBounds.fScissorEnabled) {
1095 GR_GL(Disable(GL_SCISSOR_TEST));
1096 }
1097 GR_GL(StencilMask(mask));
1098 GR_GL(ClearStencil(value));
1099 GR_GL(Clear(GL_STENCIL_BUFFER_BIT));
1100 fHWBounds.fScissorEnabled = false;
1101 fWriteMaskChanged = true;
1102}
1103
1104void GrGpuGL::eraseStencilClip() {
1105 GLint stencilBitCount;
reed@google.comac20fb92011-01-12 17:14:53 +00001106 GR_GL_GetIntegerv(GL_STENCIL_BITS, &stencilBitCount);
reed@google.comac10a2d2010-12-22 21:39:39 +00001107 GrAssert(stencilBitCount > 0);
1108 GLint clipStencilMask = (1 << (stencilBitCount - 1));
1109 eraseStencil(0, clipStencilMask);
1110}
1111
1112void GrGpuGL::forceRenderTargetFlush() {
1113 flushRenderTarget();
1114}
1115
1116bool GrGpuGL::readPixels(int left, int top, int width, int height,
1117 GrTexture::PixelConfig config, void* buffer) {
1118 GLenum internalFormat; // we don't use this for glReadPixels
1119 GLenum format;
1120 GLenum type;
1121 if (!this->canBeTexture(config, &internalFormat, &format, &type)) {
1122 return false;
1123 }
1124
1125 GrAssert(NULL != fCurrDrawState.fRenderTarget);
1126 const GrIRect& vp = ((GrGLRenderTarget*)fCurrDrawState.fRenderTarget)->viewport();
1127
1128 // Brian says that viewport rects are already upside down (grrrrr)
bsalomon@google.com316f99232011-01-13 21:28:12 +00001129 GR_GL(ReadPixels(left, -vp.height() - top - height, width, height,
1130 format, type, buffer));
reed@google.comac10a2d2010-12-22 21:39:39 +00001131
1132 // now reverse the order of the rows, since GL's are bottom-to-top, but our
1133 // API presents top-to-bottom
1134 {
1135 size_t stride = width * GrTexture::BytesPerPixel(config);
1136 GrAutoMalloc rowStorage(stride);
1137 void* tmp = rowStorage.get();
1138
1139 const int halfY = height >> 1;
1140 char* top = reinterpret_cast<char*>(buffer);
1141 char* bottom = top + (height - 1) * stride;
1142 for (int y = 0; y < halfY; y++) {
1143 memcpy(tmp, top, stride);
1144 memcpy(top, bottom, stride);
1145 memcpy(bottom, tmp, stride);
1146 top += stride;
1147 bottom -= stride;
1148 }
1149 }
1150 return true;
1151}
1152
1153void GrGpuGL::flushRenderTarget() {
1154 if (fHWDrawState.fRenderTarget != fCurrDrawState.fRenderTarget) {
1155 GrGLRenderTarget* rt = (GrGLRenderTarget*)fCurrDrawState.fRenderTarget;
1156 GR_GLEXT(fExts, BindFramebuffer(GR_FRAMEBUFFER, rt->renderFBOID()));
1157 #if GR_COLLECT_STATS
1158 ++fStats.fRenderTargetChngCnt;
1159 #endif
1160 rt->setDirty(true);
1161 #if GR_DEBUG
1162 GLenum status = GR_GLEXT(fExts, CheckFramebufferStatus(GR_FRAMEBUFFER));
1163 if (status != GR_FRAMEBUFFER_COMPLETE) {
1164 GrPrintf("-- glCheckFramebufferStatus %x\n", status);
1165 }
1166 #endif
1167 fHWDrawState.fRenderTarget = fCurrDrawState.fRenderTarget;
1168 const GrIRect& vp = rt->viewport();
1169 fRenderTargetChanged = true;
1170 if (fHWBounds.fViewportRect != vp) {
1171 GR_GL(Viewport(vp.fLeft,
1172 vp.fBottom,
1173 vp.width(),
1174 -vp.height()));
1175 fHWBounds.fViewportRect = vp;
1176 }
1177 }
1178}
1179
1180GLenum gPrimitiveType2GLMode[] = {
1181 GL_TRIANGLES,
1182 GL_TRIANGLE_STRIP,
1183 GL_TRIANGLE_FAN,
1184 GL_POINTS,
1185 GL_LINES,
1186 GL_LINE_STRIP
1187};
1188
1189void GrGpuGL::drawIndexedHelper(PrimitiveType type,
1190 uint32_t startVertex,
1191 uint32_t startIndex,
1192 uint32_t vertexCount,
1193 uint32_t indexCount) {
1194 GrAssert((size_t)type < GR_ARRAY_COUNT(gPrimitiveType2GLMode));
1195
1196 GLvoid* indices = (GLvoid*)(sizeof(uint16_t) * startIndex);
1197 if (kReserved_GeometrySrcType == fGeometrySrc.fIndexSrc) {
1198 indices = (GLvoid*)((intptr_t)indices + (intptr_t)fIndices.get());
1199 } else if (kArray_GeometrySrcType == fGeometrySrc.fIndexSrc) {
1200 indices = (GLvoid*)((intptr_t)indices +
1201 (intptr_t)fGeometrySrc.fIndexArray);
1202 }
1203
1204 GR_GL(DrawElements(gPrimitiveType2GLMode[type], indexCount,
1205 GL_UNSIGNED_SHORT, indices));
1206}
1207
1208void GrGpuGL::drawNonIndexedHelper(PrimitiveType type,
1209 uint32_t startVertex,
1210 uint32_t vertexCount) {
1211 GrAssert((size_t)type < GR_ARRAY_COUNT(gPrimitiveType2GLMode));
1212
1213 GR_GL(DrawArrays(gPrimitiveType2GLMode[type], 0, vertexCount));
1214}
1215
1216#if !defined(SK_GL_HAS_COLOR4UB)
1217static inline GrFixed byte2fixed(unsigned value) {
1218 return (value + (value >> 7)) << 8;
1219}
1220#endif
1221
1222void GrGpuGL::resolveTextureRenderTarget(GrGLTexture* texture) {
1223 GrGLRenderTarget* rt = (GrGLRenderTarget*) texture->asRenderTarget();
1224
1225 if (NULL != rt && rt->needsResolve()) {
1226 GrAssert(kNone_MSFBO != fMSFBOType);
1227 GrAssert(rt->textureFBOID() != rt->renderFBOID());
1228 GR_GLEXT(fExts, BindFramebuffer(GR_READ_FRAMEBUFFER,
1229 rt->renderFBOID()));
1230 GR_GLEXT(fExts, BindFramebuffer(GR_DRAW_FRAMEBUFFER,
1231 rt->textureFBOID()));
1232 #if GR_COLLECT_STATS
1233 ++fStats.fRenderTargetChngCnt;
1234 #endif
1235 // make sure we go through set render target
1236 fHWDrawState.fRenderTarget = NULL;
1237
1238 GLint left = 0;
1239 GLint right = texture->contentWidth();
1240 // we will have rendered to the top of the FBO.
1241 GLint top = texture->allocHeight();
1242 GLint bottom = texture->allocHeight() - texture->contentHeight();
1243 if (kApple_MSFBO == fMSFBOType) {
1244 GR_GL(Enable(GL_SCISSOR_TEST));
1245 GR_GL(Scissor(left, bottom, right-left, top-bottom));
1246 GR_GLEXT(fExts, ResolveMultisampleFramebuffer());
1247 fHWBounds.fScissorRect.setEmpty();
1248 fHWBounds.fScissorEnabled = true;
1249 } else {
1250 GR_GLEXT(fExts, BlitFramebuffer(left, bottom, right, top,
1251 left, bottom, right, top,
1252 GL_COLOR_BUFFER_BIT, GL_NEAREST));
1253 }
1254 rt->setDirty(false);
1255
1256 }
1257}
1258
1259void GrGpuGL::flushStencil() {
1260
1261 // use stencil for clipping if clipping is enabled and the clip
1262 // has been written into the stencil.
1263 bool stencilClip = fClipState.fClipInStencil &&
1264 (kClip_StateBit & fCurrDrawState.fFlagBits);
1265 bool stencilChange =
1266 fWriteMaskChanged ||
1267 fHWStencilClip != stencilClip ||
1268 fHWDrawState.fStencilPass != fCurrDrawState.fStencilPass ||
1269 (kNone_StencilPass != fCurrDrawState.fStencilPass &&
1270 (StencilPass)kSetClip_StencilPass != fCurrDrawState.fStencilPass &&
1271 fHWDrawState.fReverseFill != fCurrDrawState.fReverseFill);
1272
1273 if (stencilChange) {
1274 GLint stencilBitCount;
1275 GLint clipStencilMask;
1276 GLint pathStencilMask;
reed@google.comac20fb92011-01-12 17:14:53 +00001277 GR_GL_GetIntegerv(GL_STENCIL_BITS, &stencilBitCount);
reed@google.comac10a2d2010-12-22 21:39:39 +00001278 GrAssert(stencilBitCount > 0 ||
1279 kNone_StencilPass == fCurrDrawState.fStencilPass);
1280 clipStencilMask = (1 << (stencilBitCount - 1));
1281 pathStencilMask = clipStencilMask - 1;
1282 switch (fCurrDrawState.fStencilPass) {
1283 case kNone_StencilPass:
1284 if (stencilClip) {
1285 GR_GL(Enable(GL_STENCIL_TEST));
1286 GR_GL(StencilFunc(GL_EQUAL,
1287 clipStencilMask,
1288 clipStencilMask));
1289 GR_GL(StencilOp(GL_KEEP, GL_KEEP, GL_KEEP));
1290 } else {
1291 GR_GL(Disable(GL_STENCIL_TEST));
1292 }
1293 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
1294 if (!fSingleStencilPassForWinding) {
1295 GR_GL(Disable(GL_CULL_FACE));
1296 }
1297 break;
1298 case kEvenOddStencil_StencilPass:
1299 GR_GL(Enable(GL_STENCIL_TEST));
1300 if (stencilClip) {
1301 GR_GL(StencilFunc(GL_EQUAL, clipStencilMask, clipStencilMask));
1302 } else {
1303 GR_GL(StencilFunc(GL_ALWAYS, 0x0, 0x0));
1304 }
1305 GR_GL(StencilMask(pathStencilMask));
1306 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
1307 GR_GL(StencilOp(GL_KEEP, GL_INVERT, GL_INVERT));
1308 GR_GL(ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE));
1309 if (!fSingleStencilPassForWinding) {
1310 GR_GL(Disable(GL_CULL_FACE));
1311 }
1312 break;
1313 case kEvenOddColor_StencilPass: {
1314 GR_GL(Enable(GL_STENCIL_TEST));
1315 GLint funcRef = 0;
1316 GLuint funcMask = pathStencilMask;
1317 if (stencilClip) {
1318 funcRef |= clipStencilMask;
1319 funcMask |= clipStencilMask;
1320 }
1321 if (!fCurrDrawState.fReverseFill) {
1322 funcRef |= pathStencilMask;
1323 }
bsalomon@google.com316f99232011-01-13 21:28:12 +00001324 GR_GL(StencilFunc(GL_EQUAL, funcRef, funcMask));
1325 GR_GL(StencilMask(pathStencilMask));
reed@google.comac10a2d2010-12-22 21:39:39 +00001326 GR_GL(StencilOp(GL_ZERO, GL_ZERO, GL_ZERO));
1327 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
1328 if (!fSingleStencilPassForWinding) {
1329 GR_GL(Disable(GL_CULL_FACE));
1330 }
1331 } break;
1332 case kWindingStencil1_StencilPass:
1333 GR_GL(Enable(GL_STENCIL_TEST));
1334 if (fHasStencilWrap) {
1335 if (stencilClip) {
1336 GR_GL(StencilFunc(GL_EQUAL,
1337 clipStencilMask,
1338 clipStencilMask));
1339 } else {
1340 GR_GL(StencilFunc(GL_ALWAYS, 0x0, 0x0));
1341 }
1342 if (fSingleStencilPassForWinding) {
1343 GR_GL(StencilOpSeparate(GL_FRONT, GL_KEEP,
1344 GL_INCR_WRAP, GL_INCR_WRAP));
1345 GR_GL(StencilOpSeparate(GL_BACK, GL_KEEP,
1346 GL_DECR_WRAP, GL_DECR_WRAP));
1347 } else {
1348 GR_GL(StencilOp(GL_KEEP, GL_INCR_WRAP, GL_INCR_WRAP));
1349 GR_GL(Enable(GL_CULL_FACE));
1350 GR_GL(CullFace(GL_BACK));
1351 }
1352 } else {
1353 // If we don't have wrap then we use the Func to detect
1354 // values that would wrap (0 on decr and mask on incr). We
1355 // make the func fail on these values and use the sfail op
1356 // to effectively wrap by inverting.
1357 // This applies whether we are doing a two-pass (front faces
1358 // followed by back faces) or a single pass (separate func/op)
1359
1360 // Note that in the case where we are also using stencil to
1361 // clip this means we will write into the path bits in clipped
1362 // out pixels. We still apply the clip bit in the color pass
1363 // stencil func so we don't draw color outside the clip.
1364 // We also will clear the stencil bits in clipped pixels by
1365 // using zero in the sfail op with write mask set to the
1366 // path mask.
1367 GR_GL(Enable(GL_STENCIL_TEST));
1368 if (fSingleStencilPassForWinding) {
1369 GR_GL(StencilFuncSeparate(GL_FRONT,
1370 GL_NOTEQUAL,
1371 pathStencilMask,
1372 pathStencilMask));
1373 GR_GL(StencilFuncSeparate(GL_BACK,
1374 GL_NOTEQUAL,
1375 0x0,
1376 pathStencilMask));
1377 GR_GL(StencilOpSeparate(GL_FRONT, GL_INVERT,
1378 GL_INCR, GL_INCR));
1379 GR_GL(StencilOpSeparate(GL_BACK, GL_INVERT,
1380 GL_DECR, GL_DECR));
1381 } else {
1382 GR_GL(StencilFunc(GL_NOTEQUAL,
1383 pathStencilMask,
1384 pathStencilMask));
1385 GR_GL(StencilOp(GL_INVERT, GL_INCR, GL_INCR));
1386 GR_GL(Enable(GL_CULL_FACE));
1387 GR_GL(CullFace(GL_BACK));
1388 }
1389 }
1390 GR_GL(StencilMask(pathStencilMask));
1391 GR_GL(ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE));
1392 break;
1393 case kWindingStencil2_StencilPass:
1394 GrAssert(!fSingleStencilPassForWinding);
1395 GR_GL(Enable(GL_STENCIL_TEST));
1396 if (fHasStencilWrap) {
1397 if (stencilClip) {
1398 GR_GL(StencilFunc(GL_EQUAL,
1399 clipStencilMask,
1400 clipStencilMask));
1401 } else {
1402 GR_GL(StencilFunc(GL_ALWAYS, 0x0, 0x0));
1403 }
1404 GR_GL(StencilOp(GL_DECR_WRAP, GL_DECR_WRAP, GL_DECR_WRAP));
1405 } else {
1406 GR_GL(StencilFunc(GL_NOTEQUAL, 0x0, pathStencilMask));
1407 GR_GL(StencilOp(GL_INVERT, GL_DECR, GL_DECR));
1408 }
1409 GR_GL(StencilMask(pathStencilMask));
1410 GR_GL(Enable(GL_CULL_FACE));
1411 GR_GL(CullFace(GL_FRONT));
1412 GR_GL(ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE));
1413 break;
1414 case kWindingColor_StencilPass: {
1415 GR_GL(Enable(GL_STENCIL_TEST));
1416 GLint funcRef = 0;
1417 GLuint funcMask = pathStencilMask;
1418 GLenum funcFunc;
1419 if (stencilClip) {
1420 funcRef |= clipStencilMask;
1421 funcMask |= clipStencilMask;
1422 }
1423 if (fCurrDrawState.fReverseFill) {
1424 funcFunc = GL_EQUAL;
1425 } else {
1426 funcFunc = GL_LESS;
1427 }
1428 GR_GL(StencilFunc(funcFunc, funcRef, funcMask));
1429 GR_GL(StencilMask(pathStencilMask));
1430 // must zero in sfail because winding w/o wrap will write
1431 // path stencil bits in clipped out pixels
1432 GR_GL(StencilOp(GL_ZERO, GL_ZERO, GL_ZERO));
1433 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
1434 if (!fSingleStencilPassForWinding) {
1435 GR_GL(Disable(GL_CULL_FACE));
1436 }
1437 } break;
1438 case kSetClip_StencilPass:
1439 GR_GL(Enable(GL_STENCIL_TEST));
1440 GR_GL(StencilFunc(GL_ALWAYS, clipStencilMask, clipStencilMask));
1441 GR_GL(StencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE));
1442 GR_GL(StencilMask(clipStencilMask));
1443 GR_GL(ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE));
1444 if (!fSingleStencilPassForWinding) {
1445 GR_GL(Disable(GL_CULL_FACE));
1446 }
1447 break;
1448 default:
1449 GrAssert(!"Unexpected stencil pass.");
1450 break;
1451
1452 }
1453 fHWDrawState.fStencilPass = fCurrDrawState.fStencilPass;
1454 fHWDrawState.fReverseFill = fCurrDrawState.fReverseFill;
1455 fWriteMaskChanged = false;
1456 fHWStencilClip = stencilClip;
1457 }
1458}
1459
1460void GrGpuGL::flushGLStateCommon(PrimitiveType type) {
1461
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001462 for (int s = 0; s < kNumStages; ++s) {
1463 bool usingTexture = VertexUsesStage(s, fGeometrySrc.fVertexLayout);
reed@google.comac10a2d2010-12-22 21:39:39 +00001464
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001465 // bind texture and set sampler state
1466 if (usingTexture) {
1467 GrGLTexture* nextTexture = (GrGLTexture*)fCurrDrawState.fTextures[s];
reed@google.comac10a2d2010-12-22 21:39:39 +00001468
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001469 if (NULL != nextTexture) {
bsalomon@google.com316f99232011-01-13 21:28:12 +00001470 // if we created a rt/tex and rendered to it without using a
1471 // texture and now we're texuring from the rt it will still be
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001472 // the last bound texture, but it needs resolving. So keep this
1473 // out of the "last != next" check.
1474 resolveTextureRenderTarget(nextTexture);
reed@google.comac10a2d2010-12-22 21:39:39 +00001475
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001476 if (fHWDrawState.fTextures[s] != nextTexture) {
1477 setTextureUnit(s);
1478 GR_GL(BindTexture(GL_TEXTURE_2D, nextTexture->textureID()));
1479 #if GR_COLLECT_STATS
1480 ++fStats.fTextureChngCnt;
1481 #endif
1482 //GrPrintf("---- bindtexture %d\n", nextTexture->textureID());
1483 fHWDrawState.fTextures[s] = nextTexture;
1484 }
bsalomon@google.com316f99232011-01-13 21:28:12 +00001485
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001486 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
bsalomon@google.com316f99232011-01-13 21:28:12 +00001487 const GrGLTexture::TexParams& oldTexParams =
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001488 nextTexture->getTexParams();
1489 GrGLTexture::TexParams newTexParams;
bsalomon@google.com316f99232011-01-13 21:28:12 +00001490
1491 newTexParams.fFilter = sampler.isFilter() ? GL_LINEAR :
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001492 GL_NEAREST;
bsalomon@google.com316f99232011-01-13 21:28:12 +00001493 newTexParams.fWrapS =
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001494 GrGLTexture::gWrapMode2GLWrap[sampler.getWrapX()];
bsalomon@google.com316f99232011-01-13 21:28:12 +00001495 newTexParams.fWrapT =
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001496 GrGLTexture::gWrapMode2GLWrap[sampler.getWrapY()];
reed@google.comac10a2d2010-12-22 21:39:39 +00001497
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001498 if (newTexParams.fFilter != oldTexParams.fFilter) {
1499 setTextureUnit(s);
bsalomon@google.com316f99232011-01-13 21:28:12 +00001500 GR_GL(TexParameteri(GL_TEXTURE_2D,
1501 GL_TEXTURE_MAG_FILTER,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001502 newTexParams.fFilter));
bsalomon@google.com316f99232011-01-13 21:28:12 +00001503 GR_GL(TexParameteri(GL_TEXTURE_2D,
1504 GL_TEXTURE_MIN_FILTER,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001505 newTexParams.fFilter));
1506 }
1507 if (newTexParams.fWrapS != oldTexParams.fWrapS) {
1508 setTextureUnit(s);
bsalomon@google.com316f99232011-01-13 21:28:12 +00001509 GR_GL(TexParameteri(GL_TEXTURE_2D,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001510 GL_TEXTURE_WRAP_S,
1511 newTexParams.fWrapS));
1512 }
1513 if (newTexParams.fWrapT != oldTexParams.fWrapT) {
1514 setTextureUnit(s);
bsalomon@google.com316f99232011-01-13 21:28:12 +00001515 GR_GL(TexParameteri(GL_TEXTURE_2D,
1516 GL_TEXTURE_WRAP_T,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001517 newTexParams.fWrapT));
1518 }
1519 nextTexture->setTexParams(newTexParams);
1520 } else {
1521 GrAssert(!"Rendering with texture vert flag set but no texture");
1522 if (NULL != fHWDrawState.fTextures[s]) {
1523 setTextureUnit(s);
1524 GR_GL(BindTexture(GL_TEXTURE_2D, 0));
1525 // GrPrintf("---- bindtexture 0\n");
1526 #if GR_COLLECT_STATS
1527 ++fStats.fTextureChngCnt;
1528 #endif
1529 fHWDrawState.fTextures[s] = NULL;
1530 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001531 }
1532 }
1533 }
1534
1535 flushRenderTarget();
1536
1537 if ((fCurrDrawState.fFlagBits & kDither_StateBit) !=
1538 (fHWDrawState.fFlagBits & kDither_StateBit)) {
1539 if (fCurrDrawState.fFlagBits & kDither_StateBit) {
1540 GR_GL(Enable(GL_DITHER));
1541 } else {
1542 GR_GL(Disable(GL_DITHER));
1543 }
1544 }
1545
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001546#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +00001547 // ES doesn't support toggling GL_MULTISAMPLE and doesn't have
1548 // smooth lines.
1549 if (fRenderTargetChanged ||
1550 (fCurrDrawState.fFlagBits & kAntialias_StateBit) !=
1551 (fHWDrawState.fFlagBits & kAntialias_StateBit)) {
1552 GLint msaa = 0;
1553 // only perform query if we know MSAA is supported.
1554 // calling on non-MSAA target caused a crash in one environment,
1555 // though I don't think it should.
1556 if (!fAASamples[kHigh_AALevel]) {
reed@google.comac20fb92011-01-12 17:14:53 +00001557 GR_GL_GetIntegerv(GL_SAMPLE_BUFFERS, &msaa);
reed@google.comac10a2d2010-12-22 21:39:39 +00001558 }
1559 if (fCurrDrawState.fFlagBits & kAntialias_StateBit) {
1560 if (msaa) {
1561 GR_GL(Enable(GL_MULTISAMPLE));
1562 } else {
1563 GR_GL(Enable(GL_LINE_SMOOTH));
1564 }
1565 } else {
1566 if (msaa) {
1567 GR_GL(Disable(GL_MULTISAMPLE));
1568 }
1569 GR_GL(Disable(GL_LINE_SMOOTH));
1570 }
1571 }
1572#endif
1573
1574 bool blendOff = canDisableBlend();
1575 if (fHWBlendDisabled != blendOff) {
1576 if (blendOff) {
1577 GR_GL(Disable(GL_BLEND));
1578 } else {
1579 GR_GL(Enable(GL_BLEND));
1580 }
1581 fHWBlendDisabled = blendOff;
1582 }
1583
1584 if (!blendOff) {
1585 if (fHWDrawState.fSrcBlend != fCurrDrawState.fSrcBlend ||
1586 fHWDrawState.fDstBlend != fCurrDrawState.fDstBlend) {
1587 GR_GL(BlendFunc(gXfermodeCoeff2Blend[fCurrDrawState.fSrcBlend],
1588 gXfermodeCoeff2Blend[fCurrDrawState.fDstBlend]));
1589 fHWDrawState.fSrcBlend = fCurrDrawState.fSrcBlend;
1590 fHWDrawState.fDstBlend = fCurrDrawState.fDstBlend;
1591 }
1592 }
bsalomon@google.com316f99232011-01-13 21:28:12 +00001593
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001594#if GR_DEBUG
reed@google.comac10a2d2010-12-22 21:39:39 +00001595 // check for circular rendering
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001596 for (int s = 0; s < kNumStages; ++s) {
1597 GrAssert(!VertexUsesStage(s, fGeometrySrc.fVertexLayout) ||
1598 NULL == fCurrDrawState.fRenderTarget ||
1599 NULL == fCurrDrawState.fTextures[s] ||
bsalomon@google.com316f99232011-01-13 21:28:12 +00001600 fCurrDrawState.fTextures[s]->asRenderTarget() !=
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001601 fCurrDrawState.fRenderTarget);
1602 }
1603#endif
bsalomon@google.com316f99232011-01-13 21:28:12 +00001604
reed@google.comac10a2d2010-12-22 21:39:39 +00001605 flushStencil();
1606
1607 fHWDrawState.fFlagBits = fCurrDrawState.fFlagBits;
1608}
1609
1610void GrGpuGL::notifyVertexBufferBind(const GrGLVertexBuffer* buffer) {
1611 fHWGeometryState.fVertexBuffer = buffer;
1612}
1613
1614void GrGpuGL::notifyVertexBufferDelete(const GrGLVertexBuffer* buffer) {
1615 GrAssert(!(kBuffer_GeometrySrcType == fGeometrySrc.fVertexSrc &&
1616 buffer == fGeometrySrc.fVertexBuffer));
1617
1618 if (fHWGeometryState.fVertexBuffer == buffer) {
1619 // deleting bound buffer does implied bind to 0
1620 fHWGeometryState.fVertexBuffer = NULL;
1621 }
1622}
1623
1624void GrGpuGL::notifyIndexBufferBind(const GrGLIndexBuffer* buffer) {
1625 fGeometrySrc.fIndexBuffer = buffer;
1626}
1627
1628void GrGpuGL::notifyIndexBufferDelete(const GrGLIndexBuffer* buffer) {
1629 GrAssert(!(kBuffer_GeometrySrcType == fGeometrySrc.fIndexSrc &&
1630 buffer == fGeometrySrc.fIndexBuffer));
1631
1632 if (fHWGeometryState.fIndexBuffer == buffer) {
1633 // deleting bound buffer does implied bind to 0
1634 fHWGeometryState.fIndexBuffer = NULL;
1635 }
1636}
1637
reed@google.comac10a2d2010-12-22 21:39:39 +00001638void GrGpuGL::notifyRenderTargetDelete(GrRenderTarget* renderTarget) {
1639 GrAssert(NULL != renderTarget);
1640
1641 // if the bound FBO is destroyed we can't rely on the implicit bind to 0
1642 // a) we want the default RT which may not be FBO 0
1643 // b) we set more state than just FBO based on the RT
1644 // So trash the HW state to force an RT flush next time
1645 if (fCurrDrawState.fRenderTarget == renderTarget) {
reed@google.com1fcd51e2011-01-05 15:50:27 +00001646 fCurrDrawState.fRenderTarget = fDefaultRenderTarget;
reed@google.comac10a2d2010-12-22 21:39:39 +00001647 }
1648 if (fHWDrawState.fRenderTarget == renderTarget) {
1649 fHWDrawState.fRenderTarget = NULL;
1650 }
1651 if (fClipState.fStencilClipTarget == renderTarget) {
1652 fClipState.fStencilClipTarget = NULL;
1653 }
1654}
1655
1656void GrGpuGL::notifyTextureDelete(GrGLTexture* texture) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001657 for (int s = 0; s < kNumStages; ++s) {
1658 if (fCurrDrawState.fTextures[s] == texture) {
1659 fCurrDrawState.fTextures[s] = NULL;
1660 }
1661 if (fHWDrawState.fTextures[s] == texture) {
1662 // deleting bound texture does implied bind to 0
1663 fHWDrawState.fTextures[s] = NULL;
1664 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001665 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001666}
1667
1668void GrGpuGL::notifyTextureRemoveRenderTarget(GrGLTexture* texture) {
1669 GrAssert(NULL != texture->asRenderTarget());
1670
1671 // if there is a pending resolve, perform it.
1672 resolveTextureRenderTarget(texture);
1673}
1674
1675bool GrGpuGL::canBeTexture(GrTexture::PixelConfig config,
1676 GLenum* internalFormat,
1677 GLenum* format,
1678 GLenum* type) {
1679 switch (config) {
1680 case GrTexture::kRGBA_8888_PixelConfig:
1681 case GrTexture::kRGBX_8888_PixelConfig: // todo: can we tell it our X?
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +00001682 *format = GR_GL_32BPP_COLOR_FORMAT;
bsalomon@google.comed3a0682011-01-18 16:54:04 +00001683#if GR_SUPPORT_GLES
1684 // according to GL_EXT_texture_format_BGRA8888 the *internal*
1685 // format for a BGRA is BGRA not RGBA (as on desktop)
1686 *internalFormat = GR_GL_32BPP_COLOR_FORMAT;
1687#else
1688 *internalFormat = GL_RGBA;
1689#endif
reed@google.comac10a2d2010-12-22 21:39:39 +00001690 *type = GL_UNSIGNED_BYTE;
1691 break;
1692 case GrTexture::kRGB_565_PixelConfig:
1693 *format = GL_RGB;
1694 *internalFormat = GL_RGB;
1695 *type = GL_UNSIGNED_SHORT_5_6_5;
1696 break;
1697 case GrTexture::kRGBA_4444_PixelConfig:
1698 *format = GL_RGBA;
1699 *internalFormat = GL_RGBA;
1700 *type = GL_UNSIGNED_SHORT_4_4_4_4;
1701 break;
1702 case GrTexture::kIndex_8_PixelConfig:
1703 if (this->supports8BitPalette()) {
1704 *format = GR_PALETTE8_RGBA8;
1705 *internalFormat = GR_PALETTE8_RGBA8;
1706 *type = GL_UNSIGNED_BYTE; // unused I think
1707 } else {
1708 return false;
1709 }
1710 break;
1711 case GrTexture::kAlpha_8_PixelConfig:
1712 *format = GL_ALPHA;
1713 *internalFormat = GL_ALPHA;
1714 *type = GL_UNSIGNED_BYTE;
1715 break;
1716 default:
1717 return false;
1718 }
1719 return true;
1720}
1721
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001722void GrGpuGL::setTextureUnit(int unit) {
1723 GrAssert(unit >= 0 && unit < kNumStages);
1724 if (fActiveTextureUnitIdx != unit) {
1725 GR_GL(ActiveTexture(GL_TEXTURE0 + unit));
1726 fActiveTextureUnitIdx = unit;
1727 }
1728}
bsalomon@google.com316f99232011-01-13 21:28:12 +00001729
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001730void GrGpuGL::setSpareTextureUnit() {
1731 if (fActiveTextureUnitIdx != (GL_TEXTURE0 + SPARE_TEX_UNIT)) {
1732 GR_GL(ActiveTexture(GL_TEXTURE0 + SPARE_TEX_UNIT));
1733 fActiveTextureUnitIdx = SPARE_TEX_UNIT;
1734 }
1735}
1736
reed@google.comac10a2d2010-12-22 21:39:39 +00001737/* On ES the internalFormat and format must match for TexImage and we use
1738 GL_RGB, GL_RGBA for color formats. We also generally like having the driver
1739 decide the internalFormat. However, on ES internalFormat for
1740 RenderBufferStorage* has to be a specific format (not a base format like
1741 GL_RGBA).
1742 */
1743bool GrGpuGL::fboInternalFormat(GrTexture::PixelConfig config, GLenum* format) {
1744 switch (config) {
1745 case GrTexture::kRGBA_8888_PixelConfig:
1746 case GrTexture::kRGBX_8888_PixelConfig:
1747 if (fRGBA8Renderbuffer) {
1748 *format = GR_RGBA8;
1749 return true;
1750 } else {
1751 return false;
1752 }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001753#if GR_SUPPORT_GLES // ES2 supports 565. ES1 supports it with FBO extension
1754 // desktop GL has no such internal format
reed@google.comac10a2d2010-12-22 21:39:39 +00001755 case GrTexture::kRGB_565_PixelConfig:
1756 *format = GR_RGB565;
1757 return true;
1758#endif
1759 case GrTexture::kRGBA_4444_PixelConfig:
1760 *format = GL_RGBA4;
1761 return true;
1762 default:
1763 return false;
1764 }
1765}
1766
1767///////////////////////////////////////////////////////////////////////////////
1768
1769void GrGLCheckErr(const char* location, const char* call) {
1770 uint32_t err = glGetError();
1771 if (GL_NO_ERROR != err) {
1772 GrPrintf("---- glGetError %x", err);
1773 if (NULL != location) {
1774 GrPrintf(" at\n\t%s", location);
1775 }
1776 if (NULL != call) {
1777 GrPrintf("\n\t\t%s", call);
1778 }
1779 GrPrintf("\n");
1780 }
1781}
1782
1783///////////////////////////////////////////////////////////////////////////////
1784
1785typedef void (*glProc)(void);
1786
1787void get_gl_proc(const char procName[], glProc *address) {
1788#if GR_WIN32_BUILD
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +00001789 *address = (glProc)wglGetProcAddress(procName);
reed@google.comac10a2d2010-12-22 21:39:39 +00001790 GrAssert(NULL != *address);
1791#elif GR_MAC_BUILD || GR_IOS_BUILD
1792 GrAssert(!"Extensions don't need to be initialized!");
1793#elif GR_ANDROID_BUILD
1794 *address = eglGetProcAddress(procName);
1795 GrAssert(NULL != *address);
1796#elif GR_LINUX_BUILD
reed@google.com37df17d2010-12-23 20:20:51 +00001797// GR_STATIC_ASSERT(!"Add environment-dependent implementation here");
reed@google.comac10a2d2010-12-22 21:39:39 +00001798 //*address = glXGetProcAddressARB(procName);
reed@google.com37df17d2010-12-23 20:20:51 +00001799 *address = NULL;//eglGetProcAddress(procName);
reed@google.comac10a2d2010-12-22 21:39:39 +00001800#elif GR_QNX_BUILD
1801 *address = eglGetProcAddress(procName);
1802 GrAssert(NULL != *address);
1803#else
1804 // hopefully we're on a system with EGL
1805 *address = eglGetProcAddress(procName);
1806 GrAssert(NULL != *address);
1807#endif
1808}
1809
1810#define GET_PROC(EXT_STRUCT, PROC_NAME, EXT_TAG) \
1811 get_gl_proc("gl" #PROC_NAME #EXT_TAG, (glProc*)&EXT_STRUCT-> PROC_NAME);
1812
1813extern void GrGLInitExtensions(GrGLExts* exts) {
1814 exts->GenFramebuffers = NULL;
1815 exts->BindFramebuffer = NULL;
1816 exts->FramebufferTexture2D = NULL;
1817 exts->CheckFramebufferStatus = NULL;
1818 exts->DeleteFramebuffers = NULL;
1819 exts->RenderbufferStorage = NULL;
1820 exts->GenRenderbuffers = NULL;
1821 exts->DeleteRenderbuffers = NULL;
1822 exts->FramebufferRenderbuffer = NULL;
1823 exts->BindRenderbuffer = NULL;
1824 exts->RenderbufferStorageMultisample = NULL;
1825 exts->BlitFramebuffer = NULL;
1826 exts->ResolveMultisampleFramebuffer = NULL;
1827 exts->FramebufferTexture2DMultisample = NULL;
1828 exts->MapBuffer = NULL;
1829 exts->UnmapBuffer = NULL;
1830
1831#if GR_MAC_BUILD
1832 exts->GenFramebuffers = glGenFramebuffers;
1833 exts->BindFramebuffer = glBindFramebuffer;
1834 exts->FramebufferTexture2D = glFramebufferTexture2D;
1835 exts->CheckFramebufferStatus = glCheckFramebufferStatus;
1836 exts->DeleteFramebuffers = glDeleteFramebuffers;
1837 exts->RenderbufferStorage = glRenderbufferStorage;
1838 exts->GenRenderbuffers = glGenRenderbuffers;
1839 exts->DeleteRenderbuffers = glDeleteRenderbuffers;
1840 exts->FramebufferRenderbuffer = glFramebufferRenderbuffer;
1841 exts->BindRenderbuffer = glBindRenderbuffer;
1842 exts->RenderbufferStorageMultisample = glRenderbufferStorageMultisample;
1843 exts->BlitFramebuffer = glBlitFramebuffer;
1844 exts->MapBuffer = glMapBuffer;
1845 exts->UnmapBuffer = glUnmapBuffer;
1846#elif GR_IOS_BUILD
1847 exts->GenFramebuffers = glGenFramebuffers;
1848 exts->BindFramebuffer = glBindFramebuffer;
1849 exts->FramebufferTexture2D = glFramebufferTexture2D;
1850 exts->CheckFramebufferStatus = glCheckFramebufferStatus;
1851 exts->DeleteFramebuffers = glDeleteFramebuffers;
1852 exts->RenderbufferStorage = glRenderbufferStorage;
1853 exts->GenRenderbuffers = glGenRenderbuffers;
1854 exts->DeleteRenderbuffers = glDeleteRenderbuffers;
1855 exts->FramebufferRenderbuffer = glFramebufferRenderbuffer;
1856 exts->BindRenderbuffer = glBindRenderbuffer;
1857 exts->RenderbufferStorageMultisample = glRenderbufferStorageMultisampleAPPLE;
1858 exts->ResolveMultisampleFramebuffer = glResolveMultisampleFramebufferAPPLE;
1859 exts->MapBuffer = glMapBufferOES;
1860 exts->UnmapBuffer = glUnmapBufferOES;
1861#else
1862 GLint major, minor;
1863 gl_version(&major, &minor);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001864 #if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +00001865 if (major >= 3) {// FBO, FBOMS, and FBOBLIT part of 3.0
1866 exts->GenFramebuffers = glGenFramebuffers;
1867 exts->BindFramebuffer = glBindFramebuffer;
1868 exts->FramebufferTexture2D = glFramebufferTexture2D;
1869 exts->CheckFramebufferStatus = glCheckFramebufferStatus;
1870 exts->DeleteFramebuffers = glDeleteFramebuffers;
1871 exts->RenderbufferStorage = glRenderbufferStorage;
1872 exts->GenRenderbuffers = glGenRenderbuffers;
1873 exts->DeleteRenderbuffers = glDeleteRenderbuffers;
1874 exts->FramebufferRenderbuffer = glFramebufferRenderbuffer;
1875 exts->BindRenderbuffer = glBindRenderbuffer;
1876 exts->RenderbufferStorageMultisample = glRenderbufferStorageMultisample;
1877 exts->BlitFramebuffer = glBlitFramebuffer;
1878 } else if (has_gl_extension("GL_ARB_framebuffer_object")) {
1879 GET_PROC(exts, GenFramebuffers, ARB);
1880 GET_PROC(exts, BindFramebuffer, ARB);
1881 GET_PROC(exts, FramebufferTexture2D, ARB);
1882 GET_PROC(exts, CheckFramebufferStatus, ARB);
1883 GET_PROC(exts, DeleteFramebuffers, ARB);
1884 GET_PROC(exts, RenderbufferStorage, ARB);
1885 GET_PROC(exts, GenRenderbuffers, ARB);
1886 GET_PROC(exts, DeleteRenderbuffers, ARB);
1887 GET_PROC(exts, FramebufferRenderbuffer, ARB);
1888 GET_PROC(exts, BindRenderbuffer, ARB);
1889 GET_PROC(exts, RenderbufferStorageMultisample, ARB);
1890 GET_PROC(exts, BlitFramebuffer, ARB);
1891 } else {
1892 // we require some form of FBO
1893 GrAssert(has_gl_extension("GL_EXT_framebuffer_object"));
1894 GET_PROC(exts, GenFramebuffers, EXT);
1895 GET_PROC(exts, BindFramebuffer, EXT);
1896 GET_PROC(exts, FramebufferTexture2D, EXT);
1897 GET_PROC(exts, CheckFramebufferStatus, EXT);
1898 GET_PROC(exts, DeleteFramebuffers, EXT);
1899 GET_PROC(exts, RenderbufferStorage, EXT);
1900 GET_PROC(exts, GenRenderbuffers, EXT);
1901 GET_PROC(exts, DeleteRenderbuffers, EXT);
1902 GET_PROC(exts, FramebufferRenderbuffer, EXT);
1903 GET_PROC(exts, BindRenderbuffer, EXT);
1904 if (has_gl_extension("GL_EXT_framebuffer_multisample")) {
1905 GET_PROC(exts, RenderbufferStorageMultisample, EXT);
1906 }
1907 if (has_gl_extension("GL_EXT_framebuffer_blit")) {
1908 GET_PROC(exts, BlitFramebuffer, EXT);
1909 }
1910 }
1911 // we assume we have at least GL 1.5 or higher (VBOs introduced in 1.5)
1912 exts->MapBuffer = glMapBuffer;
1913 exts->UnmapBuffer = glUnmapBuffer;
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001914 #else // !GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +00001915 if (major >= 2) {// ES 2.0 supports FBO
1916 exts->GenFramebuffers = glGenFramebuffers;
1917 exts->BindFramebuffer = glBindFramebuffer;
1918 exts->FramebufferTexture2D = glFramebufferTexture2D;
1919 exts->CheckFramebufferStatus = glCheckFramebufferStatus;
1920 exts->DeleteFramebuffers = glDeleteFramebuffers;
1921 exts->RenderbufferStorage = glRenderbufferStorage;
1922 exts->GenRenderbuffers = glGenRenderbuffers;
1923 exts->DeleteRenderbuffers = glDeleteRenderbuffers;
1924 exts->FramebufferRenderbuffer = glFramebufferRenderbuffer;
1925 exts->BindRenderbuffer = glBindRenderbuffer;
1926 } else {
1927 // we require some form of FBO
1928 GrAssert(has_gl_extension("GL_OES_framebuffer_object"));
1929
1930 GET_PROC(exts, GenFramebuffers, OES);
1931 GET_PROC(exts, BindFramebuffer, OES);
1932 GET_PROC(exts, FramebufferTexture2D, OES);
1933 GET_PROC(exts, CheckFramebufferStatus, OES);
1934 GET_PROC(exts, DeleteFramebuffers, OES);
1935 GET_PROC(exts, RenderbufferStorage, OES);
1936 GET_PROC(exts, GenRenderbuffers, OES);
1937 GET_PROC(exts, DeleteRenderbuffers, OES);
1938 GET_PROC(exts, FramebufferRenderbuffer, OES);
1939 GET_PROC(exts, BindRenderbuffer, OES);
1940 }
1941 if (has_gl_extension("GL_APPLE_framebuffer_multisample")) {
1942 GET_PROC(exts, ResolveMultisampleFramebuffer, APPLE);
1943 }
1944 if (has_gl_extension("GL_IMG_multisampled_render_to_texture")) {
1945 GET_PROC(exts, FramebufferTexture2DMultisample, IMG);
1946 }
1947 if (has_gl_extension("GL_OES_mapbuffer")) {
1948 GET_PROC(exts, MapBuffer, OES);
1949 GET_PROC(exts, UnmapBuffer, OES);
1950 }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001951 #endif // !GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +00001952#endif // BUILD
1953}
1954
1955bool gPrintGL = true;
1956