blob: 8a1169e4c4fee9a2a1e2a31bf8e6a3957f46ca14 [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>
20
21static const GLuint GR_MAX_GLUINT = ~0;
22static const GLint GR_INVAL_GLINT = ~0;
23
24#define SKIP_CACHE_CHECK true
25
26static const GLenum gXfermodeCoeff2Blend[] = {
27 GL_ZERO,
28 GL_ONE,
29 GL_SRC_COLOR,
30 GL_ONE_MINUS_SRC_COLOR,
31 GL_DST_COLOR,
32 GL_ONE_MINUS_DST_COLOR,
33 GL_SRC_ALPHA,
34 GL_ONE_MINUS_SRC_ALPHA,
35 GL_DST_ALPHA,
36 GL_ONE_MINUS_DST_ALPHA,
37};
38
39bool has_gl_extension(const char* ext) {
40 const char* glstr = (const char*) glGetString(GL_EXTENSIONS);
41
42 int extLength = strlen(ext);
43
44 while (true) {
45 int n = strcspn(glstr, " ");
46 if (n == extLength && 0 == strncmp(ext, glstr, n)) {
47 return true;
48 }
49 if (0 == glstr[n]) {
50 return false;
51 }
52 glstr += n+1;
53 }
54}
55
56void gl_version(int* major, int* minor) {
57 const char* v = (const char*) glGetString(GL_VERSION);
58 if (NULL == v) {
59 GrAssert(0);
60 *major = 0;
61 *minor = 0;
62 return;
63 }
64#if GR_GL_DESKTOP
65 int n = sscanf(v, "%d.%d", major, minor);
66 if (n != 2) {
67 GrAssert(0);
68 *major = 0;
69 *minor = 0;
70 return;
71 }
72#else
73 char profile[2];
74 int n = sscanf(v, "OpenGL ES-%c%c %d.%d", profile, profile+1, major, minor);
75 bool ok = 4 == n;
76 if (!ok) {
77 int n = sscanf(v, "OpenGL ES %d.%d", major, minor);
78 ok = 2 == n;
79 }
80 if (!ok) {
81 GrAssert(0);
82 *major = 0;
83 *minor = 0;
84 return;
85 }
86#endif
87}
88///////////////////////////////////////////////////////////////////////////////
89
90bool fbo_test(GrGLExts exts, int w, int h) {
91 GLuint testFBO;
92 GR_GLEXT(exts, GenFramebuffers(1, &testFBO));
93 GR_GLEXT(exts, BindFramebuffer(GR_FRAMEBUFFER, testFBO));
94 GLuint testRTTex;
95 GR_GL(GenTextures(1, &testRTTex));
96 GR_GL(BindTexture(GL_TEXTURE_2D, testRTTex));
97
98 GR_GL(TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h,
99 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL));
100 GR_GL(BindTexture(GL_TEXTURE_2D, 0));
101 GR_GLEXT(exts, FramebufferTexture2D(GR_FRAMEBUFFER, GR_COLOR_ATTACHMENT0,
102 GL_TEXTURE_2D, testRTTex, 0));
103 GLenum status = GR_GLEXT(exts, CheckFramebufferStatus(GR_FRAMEBUFFER));
104 GR_GLEXT(exts, DeleteFramebuffers(1, &testFBO));
105 GR_GL(DeleteTextures(1, &testRTTex));
106 return status == GR_FRAMEBUFFER_COMPLETE;
107}
108
109///////////////////////////////////////////////////////////////////////////////
110
111GrGpuGL::GrGpuGL() {
112 GrPrintf("------------------------- create GrGpuGL %p --------------\n",
113 this);
114 GrPrintf("------ VENDOR %s\n", glGetString(GL_VENDOR));
115 GrPrintf("------ RENDERER %s\n", glGetString(GL_RENDERER));
116 GrPrintf("------ VERSION %s\n", glGetString(GL_VERSION));
117 GrPrintf("------ EXTENSIONS\n %s \n", glGetString(GL_EXTENSIONS));
118
119 GrGLClearErr();
120
121 GrGLInitExtensions(&fExts);
122
123 resetContextHelper();
124
125 GrGLRenderTarget::GLRenderTargetIDs defaultRTIDs;
126 GR_GL(GetIntegerv(GR_FRAMEBUFFER_BINDING, (GLint*)&defaultRTIDs.fRTFBOID));
127 defaultRTIDs.fTexFBOID = defaultRTIDs.fRTFBOID;
128 defaultRTIDs.fMSColorRenderbufferID = 0;
129 defaultRTIDs.fStencilRenderbufferID = 0;
130 GLint vp[4];
131 GR_GL(GetIntegerv(GL_VIEWPORT, vp));
132 fHWBounds.fViewportRect.setLTRB(vp[0],
133 vp[1] + vp[3],
134 vp[0] + vp[2],
135 vp[1]);
136 defaultRTIDs.fOwnIDs = false;
137
138 fDefaultRenderTarget = new GrGLRenderTarget(defaultRTIDs,
139 fHWBounds.fViewportRect,
140 NULL,
141 this);
142 fHWDrawState.fRenderTarget = fDefaultRenderTarget;
143 fRenderTargetChanged = true;
144
145 fCurrDrawState = fHWDrawState;
146
147 ////////////////////////////////////////////////////////////////////////////
148 // Check for supported features.
149
150 int major, minor;
151 gl_version(&major, &minor);
152
153 GLint numFormats;
154 GR_GL(GetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &numFormats));
155 GrAutoSTMalloc<10, GLint> formats(numFormats);
156 GR_GL(GetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, formats));
157 for (int i = 0; i < numFormats; ++i) {
158 if (formats[i] == GR_PALETTE8_RGBA8) {
159 f8bitPaletteSupport = true;
160 break;
161 }
162 }
163 GrPrintf("Palette8 support: %s\n", (f8bitPaletteSupport ? "YES" : "NO"));
164
165 GR_STATIC_ASSERT(0 == kNone_AALevel);
166 GR_STATIC_ASSERT(1 == kLow_AALevel);
167 GR_STATIC_ASSERT(2 == kMed_AALevel);
168 GR_STATIC_ASSERT(3 == kHigh_AALevel);
169
170 memset(fAASamples, 0, sizeof(fAASamples));
171 fMSFBOType = kNone_MSFBO;
172 if (has_gl_extension("GL_IMG_multisampled_render_to_texture")) {
173 fMSFBOType = kIMG_MSFBO;
174 GrPrintf("MSAA Support: IMG ES EXT.\n");
175 }
176 else if (has_gl_extension("GL_APPLE_framebuffer_multisample")) {
177 fMSFBOType = kApple_MSFBO;
178 GrPrintf("MSAA Support: APPLE ES EXT.\n");
179 }
180#if GR_GL_DESKTOP
181 else if ((major >= 3) ||
182 has_gl_extension("GL_ARB_framebuffer_object") ||
183 (has_gl_extension("GL_EXT_framebuffer_multisample") &&
184 has_gl_extension("GL_EXT_framebuffer_blit"))) {
185 fMSFBOType = kDesktop_MSFBO;
186 GrPrintf("MSAA Support: DESKTOP\n");
187 }
188#endif
189 else {
190 GrPrintf("MSAA Support: NONE\n");
191 }
192
193 if (kNone_MSFBO != fMSFBOType) {
194 GLint maxSamples;
195 GLenum maxSampleGetter = (kIMG_MSFBO == fMSFBOType) ?
196 GR_MAX_SAMPLES_IMG :
197 GR_MAX_SAMPLES;
198 GR_GL(GetIntegerv(maxSampleGetter, &maxSamples));
199 if (maxSamples > 1 ) {
200 fAASamples[kNone_AALevel] = 0;
201 fAASamples[kLow_AALevel] = GrMax(2,
202 GrFixedFloorToInt((GR_FixedHalf) *
203 maxSamples));
204 fAASamples[kMed_AALevel] = GrMax(2,
205 GrFixedFloorToInt(((GR_Fixed1*3)/4) *
206 maxSamples));
207 fAASamples[kHigh_AALevel] = maxSamples;
208 }
209 GrPrintf("\tMax Samples: %d\n", maxSamples);
210 }
211
212#if GR_GL_DESKTOP
213 fHasStencilWrap = (major >= 2 || (major == 1 && minor >= 4)) ||
214 has_gl_extension("GL_EXT_stencil_wrap");
215#else
216 fHasStencilWrap = (major >= 2) || has_gl_extension("GL_OES_stencil_wrap");
217#endif
218 GrPrintf("Stencil Wrap: %s\n", (fHasStencilWrap ? "YES" : "NO"));
219
220#if GR_GL_DESKTOP
221 // we could also look for GL_ATI_separate_stencil extension or
222 // GL_EXT_stencil_two_side but they use different function signatures
223 // than GL2.0+ (and than each other).
224 fSingleStencilPassForWinding = (major >= 2);
225#else
226 // ES 2 has two sided stencil but 1.1 doesn't. There doesn't seem to be
227 // an ES1 extension.
228 fSingleStencilPassForWinding = (major >= 2);
229#endif
230 GrPrintf("Single Stencil Pass For Winding: %s\n", (fSingleStencilPassForWinding ? "YES" : "NO"));
231
232
233#if GR_GL_DESKTOP
234 fRGBA8Renderbuffer = true;
235#else
236 fRGBA8Renderbuffer = has_gl_extension("GL_OES_rgb8_rgba8");
237#endif
238 GrPrintf("RGBA Renderbuffer: %s\n", (fRGBA8Renderbuffer ? "YES" : "NO"));
239
240
241#if GR_GL_DESKTOP
242 fBufferLockSupport = true; // we require VBO support and the desktop VBO
243 // extension includes glMapBuffer.
244#else
245 fBufferLockSupport = has_gl_extension("GL_OES_mapbuffer");
246#endif
247 GrPrintf("Map Buffer: %s\n", (fBufferLockSupport ? "YES" : "NO"));
248
249#if GR_GL_DESKTOP
250 fNPOTTextureSupport =
251 (major >= 2 || has_gl_extension("GL_ARB_texture_non_power_of_two")) ?
252 kFull_NPOTTextureType :
253 kNone_NPOTTextureType;
254#else
255 if (has_gl_extension("GL_OES_texture_npot")) {
256 fNPOTTextureSupport = kFull_NPOTTextureType;
257 } else if (major >= 2 ||
258 has_gl_extension("GL_APPLE_texture_2D_limited_npot")) {
259 fNPOTTextureSupport = kNoRepeat_NPOTTextureType;
260 } else {
261 fNPOTTextureSupport = kNone_NPOTTextureType;
262 }
263#endif
264 ////////////////////////////////////////////////////////////////////////////
265 // Experiments to determine limitations that can't be queried. TODO: Make
266 // these a preprocess that generate some compile time constants.
267
268 /* Experimentation has found that some GLs that support NPOT textures
269 do not support FBOs with a NPOT texture. They report "unsupported" FBO
270 status. I don't know how to explicitly query for this. Do an
271 experiment. Note they may support NPOT with a renderbuffer but not a
272 texture. Presumably, the implementation bloats the renderbuffer
273 internally to the next POT.
274 */
275 if (fNPOTTextureSupport == kFull_NPOTTextureType) {
276 bool npotFBOSuccess = fbo_test(fExts, 200, 200);
277 if (!npotFBOSuccess) {
278 fNPOTTextureSupport = kNonRendertarget_NPOTTextureType;
279 GrPrintf("NPOT Renderbuffer Test: FAILED\n");
280 } else {
281 GrPrintf("NPOT Renderbuffer Test: PASSED\n");
282 }
283 }
284 switch (fNPOTTextureSupport) {
285 case kNone_NPOTTextureType:
286 GrPrintf("NPOT Support: NONE\n");
287 break;
288 case kNoRepeat_NPOTTextureType:
289 GrPrintf("NPOT Support: NO REPEAT\n");
290 break;
291 case kNonRendertarget_NPOTTextureType:
292 GrPrintf("NPOT Support: NO FBOTEX\n");
293 break;
294 case kFull_NPOTTextureType:
295 GrPrintf("NPOT Support: FULL\n");
296 break;
297 }
298
299 // sanity check to make sure we can at least create an FBO from a POT texture
300 if (fNPOTTextureSupport < kFull_NPOTTextureType) {
301 bool npotFBOSuccess = fbo_test(fExts, 128, 128);
302 if (!npotFBOSuccess) {
303 GrPrintf("FBO Sanity Test: FAILED\n");
304 } else {
305 GrPrintf("FBO Sanity Test: PASSED\n");
306 }
307 }
308
309 /* The iPhone 4 has a restriction that for an FBO with texture color
310 attachment with height <= 8 then the width must be <= height. Here
311 we look for such a limitation.
312 */
313 fMinRenderTargetHeight = GR_INVAL_GLINT;
314 GLint maxRenderSize;
315 glGetIntegerv(GR_MAX_RENDERBUFFER_SIZE, &maxRenderSize);
316
317 GrPrintf("Small height FBO texture experiments\n");
318 for (GLuint i = 1; i <= 256;
319 (kFull_NPOTTextureType != fNPOTTextureSupport) ? i *= 2 : ++i) {
320 GLuint w = maxRenderSize;
321 GLuint h = i;
322 if (fbo_test(fExts, w, h)) {
323 GrPrintf("\t[%d, %d]: PASSED\n", w, h);
324 fMinRenderTargetHeight = i;
325 break;
326 } else {
327 GrPrintf("\t[%d, %d]: FAILED\n", w, h);
328 }
329 }
330 GrAssert(GR_INVAL_GLINT != fMinRenderTargetHeight);
331
332 GrPrintf("Small width FBO texture experiments\n");
333 fMinRenderTargetWidth = GR_MAX_GLUINT;
334 for (GLuint i = 1; i <= 256;
335 (kFull_NPOTTextureType != fNPOTTextureSupport) ? i *= 2 : ++i) {
336 GLuint w = i;
337 GLuint h = maxRenderSize;
338 if (fbo_test(fExts, w, h)) {
339 GrPrintf("\t[%d, %d]: PASSED\n", w, h);
340 fMinRenderTargetWidth = i;
341 break;
342 } else {
343 GrPrintf("\t[%d, %d]: FAILED\n", w, h);
344 }
345 }
346 GrAssert(GR_INVAL_GLINT != fMinRenderTargetWidth);
347
348#if GR_IOS_BUILD
349 /*
350 The iPad seems to fail, at least sometimes, if the height is < 16,
351 so we pin the values here for now. A better fix might be to
352 conditionalize this based on known that its an iPad (or some other
353 check).
354 */
355 fMinRenderTargetWidth = GrMax<GLuint>(fMinRenderTargetWidth, 16);
356 fMinRenderTargetHeight = GrMax<GLuint>(fMinRenderTargetHeight, 16);
357#endif
358 // bind back to original FBO
359 GR_GLEXT(fExts, BindFramebuffer(GR_FRAMEBUFFER, defaultRTIDs.fRTFBOID));
360#if GR_COLLECT_STATS
361 ++fStats.fRenderTargetChngCnt;
362#endif
363 eraseStencil(0, ~0);
364}
365
366GrGpuGL::~GrGpuGL() {
367 fDefaultRenderTarget->abandon();
368 fDefaultRenderTarget->unref();
369}
370
371void GrGpuGL::resetContextHelper() {
372// We detect cases when blending is effectively off
373 fHWBlendDisabled = false;
374 GR_GL(Enable(GL_BLEND));
375
376 // this is always disabled
377 GR_GL(Disable(GL_CULL_FACE));
378
379 GR_GL(Disable(GL_DITHER));
380#if GR_GL_DESKTOP
381 GR_GL(Disable(GL_LINE_SMOOTH));
382 GR_GL(Disable(GL_POINT_SMOOTH));
383 GR_GL(Disable(GL_MULTISAMPLE));
384#endif
385
386 // we only ever use lines in hairline mode
387 GR_GL(LineWidth(1));
388
389 GR_GL(ActiveTexture(GL_TEXTURE0));
390
391 fHWDrawState.fFlagBits = 0;
392
393 // illegal values
394 fHWDrawState.fSrcBlend = (BlendCoeff)-1;
395 fHWDrawState.fDstBlend = (BlendCoeff)-1;
396 fHWDrawState.fColor = GrColor_ILLEGAL;
397 fHWDrawState.fPointSize = -1;
398 fHWDrawState.fTexture = NULL;
399
400 GR_GL(Scissor(0,0,0,0));
401 fHWBounds.fScissorRect.setLTRB(0,0,0,0);
402 fHWBounds.fScissorEnabled = false;
403 GR_GL(Disable(GL_SCISSOR_TEST));
404
405 fHWDrawState.fSamplerState.setRadial2Params(-GR_ScalarMax,
406 -GR_ScalarMax,
407 true);
408
409 for (int i = 0; i < kMatrixModeCount; i++) {
410 fHWDrawState.fMatrixModeCache[i].setScale(GR_ScalarMax, GR_ScalarMax); // illegal
411 }
412
413 // disabling the stencil test also disables
414 // stencil buffer writes
415 GR_GL(Disable(GL_STENCIL_TEST));
416 GR_GL(StencilMask(0xffffffff));
417 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
418 fHWDrawState.fReverseFill = false;
419 fHWDrawState.fStencilPass = kNone_StencilPass;
420 fHWStencilClip = false;
421
422 fHWGeometryState.fIndexBuffer = NULL;
423 fHWGeometryState.fVertexBuffer = NULL;
424 GR_GL(BindBuffer(GL_ARRAY_BUFFER, 0));
425 GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
426
427 fHWDrawState.fRenderTarget = NULL;
428}
429
430void GrGpuGL::resetContext() {
431 INHERITED::resetContext();
432 resetContextHelper();
433}
434
435
436// defines stencil formats from more to less preferred
437#if GR_GL_ES
438 GLenum GR_GL_STENCIL_FORMAT_ARRAY[] = {
439 GR_STENCIL_INDEX8,
440 };
441#else
442 GLenum GR_GL_STENCIL_FORMAT_ARRAY[] = {
443 GR_STENCIL_INDEX8,
444 GR_STENCIL_INDEX16,
445 GR_UNSIGNED_INT_24_8,
446 GR_DEPTH_STENCIL,
447 };
448#endif
449
450// good to set a break-point here to know when createTexture fails
451static GrTexture* return_null_texture() {
452// GrAssert(!"null texture");
453 return NULL;
454}
455
456#if GR_DEBUG
457static size_t as_size_t(int x) {
458 return x;
459}
460#endif
461
462GrRenderTarget* GrGpuGL::createPlatformRenderTarget(
463 intptr_t platformRenderTarget,
464 int width, int height) {
465 GrGLRenderTarget::GLRenderTargetIDs rtIDs;
466 rtIDs.fStencilRenderbufferID = 0;
467 rtIDs.fMSColorRenderbufferID = 0;
468 rtIDs.fTexFBOID = 0;
469 rtIDs.fOwnIDs = false;
470
471 GrIRect viewport;
472
473 // viewport is in GL coords (top >= bottom)
474 viewport.setLTRB(0, height, width, 0);
475
476 rtIDs.fRTFBOID = (GLuint)platformRenderTarget;
477 rtIDs.fTexFBOID = (GLuint)platformRenderTarget;
478
479 GrGLRenderTarget* rt = new GrGLRenderTarget(rtIDs, viewport, NULL, this);
480
481 return rt;
482}
483
484GrTexture* GrGpuGL::createTexture(const TextureDesc& desc,
485 const void* srcData, size_t rowBytes) {
486
487#if GR_COLLECT_STATS
488 ++fStats.fTextureCreateCnt;
489#endif
490 GrGLTexture::GLTextureDesc glDesc;
491 GLenum internalFormat;
492
493 glDesc.fContentWidth = desc.fWidth;
494 glDesc.fContentHeight = desc.fHeight;
495 glDesc.fAllocWidth = desc.fWidth;
496 glDesc.fAllocHeight = desc.fHeight;
497 glDesc.fFormat = desc.fFormat;
498
499 bool renderTarget = 0 != (desc.fFlags & kRenderTarget_TextureFlag);
500 if (!canBeTexture(desc.fFormat,
501 &internalFormat,
502 &glDesc.fUploadFormat,
503 &glDesc.fUploadType)) {
504 return return_null_texture();
505 }
506
507 GrAssert(as_size_t(desc.fAALevel) < GR_ARRAY_COUNT(fAASamples));
508 GLint samples = fAASamples[desc.fAALevel];
509 if (kNone_MSFBO == fMSFBOType && desc.fAALevel != kNone_AALevel) {
510 GrPrintf("AA RT requested but not supported on this platform.");
511 }
512
513 GR_GL(GenTextures(1, &glDesc.fTextureID));
514 if (!glDesc.fTextureID) {
515 return return_null_texture();
516 }
517
518 glDesc.fUploadByteCount = GrTexture::BytesPerPixel(desc.fFormat);
519
520 /*
521 * check if our srcData has extra bytes past each row. If so, we need
522 * to trim those off here, since GL doesn't let us pass the rowBytes as
523 * a parameter to glTexImage2D
524 */
525#if GR_GL_DESKTOP
526 if (srcData) {
527 GR_GL(PixelStorei(GL_UNPACK_ROW_LENGTH,
528 rowBytes / glDesc.fUploadByteCount));
529 }
530#else
531 GrAutoSMalloc<128 * 128> trimStorage;
532 size_t trimRowBytes = desc.fWidth * glDesc.fUploadByteCount;
533 if (srcData && (trimRowBytes < rowBytes)) {
534 size_t trimSize = desc.fHeight * trimRowBytes;
535 trimStorage.realloc(trimSize);
536 // now copy the data into our new storage, skipping the trailing bytes
537 const char* src = (const char*)srcData;
538 char* dst = (char*)trimStorage.get();
539 for (uint32_t y = 0; y < desc.fHeight; y++) {
540 memcpy(dst, src, trimRowBytes);
541 src += rowBytes;
542 dst += trimRowBytes;
543 }
544 // now point srcData to our trimmed version
545 srcData = trimStorage.get();
546 }
547#endif
548
549 if (fNPOTTextureSupport < kNonRendertarget_NPOTTextureType ||
550 (fNPOTTextureSupport == kNonRendertarget_NPOTTextureType &&
551 renderTarget)) {
552 glDesc.fAllocWidth = GrNextPow2(desc.fWidth);
553 glDesc.fAllocHeight = GrNextPow2(desc.fHeight);
554 }
555
556 if (renderTarget) {
557 glDesc.fAllocWidth = GrMax<int>(fMinRenderTargetWidth,
558 glDesc.fAllocWidth);
559 glDesc.fAllocHeight = GrMax<int>(fMinRenderTargetHeight,
560 glDesc.fAllocHeight);
561 }
562
563 GR_GL(BindTexture(GL_TEXTURE_2D, glDesc.fTextureID));
564#if GR_COLLECT_STATS
565 ++fStats.fTextureChngCnt;
566#endif
567
568 GR_GL(PixelStorei(GL_UNPACK_ALIGNMENT, glDesc.fUploadByteCount));
569 if (GrTexture::kIndex_8_PixelConfig == desc.fFormat &&
570 supports8BitPalette()) {
571 // ES only supports CompressedTexImage2D, not CompressedTexSubimage2D
572 GrAssert(desc.fWidth == glDesc.fAllocWidth);
573 GrAssert(desc.fHeight == glDesc.fAllocHeight);
574 GLsizei imageSize = glDesc.fAllocWidth * glDesc.fAllocHeight +
575 kColorTableSize;
576 GR_GL(CompressedTexImage2D(GL_TEXTURE_2D, 0, glDesc.fUploadFormat,
577 glDesc.fAllocWidth, glDesc.fAllocHeight,
578 0, imageSize, srcData));
579 GrGL_RestoreResetRowLength();
580 } else {
581 if (NULL != srcData && (glDesc.fAllocWidth != desc.fWidth ||
582 glDesc.fAllocHeight != desc.fHeight)) {
583 GR_GL(TexImage2D(GL_TEXTURE_2D, 0, internalFormat,
584 glDesc.fAllocWidth, glDesc.fAllocHeight,
585 0, glDesc.fUploadFormat, glDesc.fUploadType, NULL));
586 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, desc.fWidth,
587 desc.fHeight, glDesc.fUploadFormat,
588 glDesc.fUploadType, srcData));
589 GrGL_RestoreResetRowLength();
590
591 uint32_t extraW = glDesc.fAllocWidth - desc.fWidth;
592 uint32_t extraH = glDesc.fAllocHeight - desc.fHeight;
593 uint32_t maxTexels = extraW * extraH;
594 maxTexels = GrMax(extraW * desc.fHeight, maxTexels);
595 maxTexels = GrMax(desc.fWidth * extraH, maxTexels);
596
597 GrAutoSMalloc<128*128> texels(glDesc.fUploadByteCount * maxTexels);
598
599 uint32_t rowSize = desc.fWidth * glDesc.fUploadByteCount;
600 if (extraH) {
601 uint8_t* lastRowStart = (uint8_t*) srcData +
602 (desc.fHeight - 1) * rowSize;
603 uint8_t* extraRowStart = (uint8_t*)texels.get();
604
605 for (uint32_t i = 0; i < extraH; ++i) {
606 memcpy(extraRowStart, lastRowStart, rowSize);
607 extraRowStart += rowSize;
608 }
609 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, 0, desc.fHeight, desc.fWidth,
610 extraH, glDesc.fUploadFormat, glDesc.fUploadType,
611 texels.get()));
612 }
613 if (extraW) {
614 uint8_t* edgeTexel = (uint8_t*)srcData + rowSize - glDesc.fUploadByteCount;
615 uint8_t* extraTexel = (uint8_t*)texels.get();
616 for (uint32_t j = 0; j < desc.fHeight; ++j) {
617 for (uint32_t i = 0; i < extraW; ++i) {
618 memcpy(extraTexel, edgeTexel, glDesc.fUploadByteCount);
619 extraTexel += glDesc.fUploadByteCount;
620 }
621 edgeTexel += rowSize;
622 }
623 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, desc.fWidth, 0, extraW,
624 desc.fHeight, glDesc.fUploadFormat,
625 glDesc.fUploadType, texels.get()));
626 }
627 if (extraW && extraH) {
628 uint8_t* cornerTexel = (uint8_t*)srcData + desc.fHeight * rowSize
629 - glDesc.fUploadByteCount;
630 uint8_t* extraTexel = (uint8_t*)texels.get();
631 for (uint32_t i = 0; i < extraW*extraH; ++i) {
632 memcpy(extraTexel, cornerTexel, glDesc.fUploadByteCount);
633 extraTexel += glDesc.fUploadByteCount;
634 }
635 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, desc.fWidth, desc.fHeight,
636 extraW, extraH, glDesc.fUploadFormat,
637 glDesc.fUploadType, texels.get()));
638 }
639
640 } else {
641 GR_GL(TexImage2D(GL_TEXTURE_2D, 0, internalFormat, glDesc.fAllocWidth,
642 glDesc.fAllocHeight, 0, glDesc.fUploadFormat,
643 glDesc.fUploadType, srcData));
644 GrGL_RestoreResetRowLength();
645 }
646 }
647
648 glDesc.fOrientation = GrGLTexture::kTopDown_Orientation;
649
650 GrGLRenderTarget::GLRenderTargetIDs rtIDs;
651 rtIDs.fStencilRenderbufferID = 0;
652 rtIDs.fMSColorRenderbufferID = 0;
653 rtIDs.fRTFBOID = 0;
654 rtIDs.fTexFBOID = 0;
655 rtIDs.fOwnIDs = true;
656 GLenum msColorRenderbufferFormat = -1;
657
658 if (renderTarget) {
659#if GR_COLLECT_STATS
660 ++fStats.fRenderTargetCreateCnt;
661#endif
662 bool failed = true;
663 GLenum status;
664 GLint err;
665
666 // If need have both RT flag and srcData we have
667 // to invert the data before uploading because FBO
668 // will be rendered bottom up
669 GrAssert(NULL == srcData);
670 glDesc.fOrientation = GrGLTexture::kBottomUp_Orientation;
671
672 GR_GLEXT(fExts, GenFramebuffers(1, &rtIDs.fTexFBOID));
673 GrAssert(rtIDs.fTexFBOID);
674
675 // If we are using multisampling and any extension other than the IMG
676 // one we will create two FBOs. We render to one and then resolve to
677 // the texture bound to the other. The IMG extension does an implicit
678 // resolve.
679 if (samples > 1 && kIMG_MSFBO != fMSFBOType && kNone_MSFBO != fMSFBOType) {
680 GR_GLEXT(fExts, GenFramebuffers(1, &rtIDs.fRTFBOID));
681 GrAssert(0 != rtIDs.fRTFBOID);
682 GR_GLEXT(fExts, GenRenderbuffers(1, &rtIDs.fMSColorRenderbufferID));
683 GrAssert(0 != rtIDs.fMSColorRenderbufferID);
684 if (!fboInternalFormat(desc.fFormat, &msColorRenderbufferFormat)) {
685 GR_GLEXT(fExts,
686 DeleteRenderbuffers(1, &rtIDs.fMSColorRenderbufferID));
687 GR_GL(DeleteTextures(1, &glDesc.fTextureID));
688 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fTexFBOID));
689 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fRTFBOID));
690 fHWDrawState.fTexture = NULL;
691 return return_null_texture();
692 }
693 } else {
694 rtIDs.fRTFBOID = rtIDs.fTexFBOID;
695 }
696 int attempts = 1;
697 if (!(kNoPathRendering_TextureFlag & desc.fFlags)) {
698 GR_GLEXT(fExts, GenRenderbuffers(1, &rtIDs.fStencilRenderbufferID));
699 GrAssert(0 != rtIDs.fStencilRenderbufferID);
700 attempts = GR_ARRAY_COUNT(GR_GL_STENCIL_FORMAT_ARRAY);
701 }
702
703 // need to unbind the texture before we call FramebufferTexture2D
704 GR_GL(BindTexture(GL_TEXTURE_2D, 0));
705#if GR_COLLECT_STATS
706 ++fStats.fTextureChngCnt;
707#endif
708
709 fHWDrawState.fTexture = NULL;
710
711 err = ~GL_NO_ERROR;
712 for (int i = 0; i < attempts; ++i) {
713 if (rtIDs.fStencilRenderbufferID) {
714 GR_GLEXT(fExts, BindRenderbuffer(GR_RENDERBUFFER,
715 rtIDs.fStencilRenderbufferID));
716 if (samples > 1) {
717 GR_GLEXT_NO_ERR(fExts, RenderbufferStorageMultisample(
718 GR_RENDERBUFFER,
719 samples,
720 GR_GL_STENCIL_FORMAT_ARRAY[i],
721 glDesc.fAllocWidth,
722 glDesc.fAllocHeight));
723 } else {
724 GR_GLEXT_NO_ERR(fExts, RenderbufferStorage(
725 GR_RENDERBUFFER,
726 GR_GL_STENCIL_FORMAT_ARRAY[i],
727 glDesc.fAllocWidth,
728 glDesc.fAllocHeight));
729 }
730 err = glGetError();
731 if (err != GL_NO_ERROR) {
732 continue;
733 }
734 }
735 if (rtIDs.fRTFBOID != rtIDs.fTexFBOID) {
736 GrAssert(samples > 1);
737 GR_GLEXT(fExts, BindRenderbuffer(GR_RENDERBUFFER,
738 rtIDs.fMSColorRenderbufferID));
739 GR_GLEXT_NO_ERR(fExts, RenderbufferStorageMultisample(
740 GR_RENDERBUFFER,
741 samples,
742 msColorRenderbufferFormat,
743 glDesc.fAllocWidth,
744 glDesc.fAllocHeight));
745 err = glGetError();
746 if (err != GL_NO_ERROR) {
747 continue;
748 }
749 }
750 GR_GLEXT(fExts, BindFramebuffer(GR_FRAMEBUFFER, rtIDs.fTexFBOID));
751
752#if GR_COLLECT_STATS
753 ++fStats.fRenderTargetChngCnt;
754#endif
755 if (kIMG_MSFBO == fMSFBOType && samples > 1) {
756 GR_GLEXT(fExts, FramebufferTexture2DMultisample(
757 GR_FRAMEBUFFER,
758 GR_COLOR_ATTACHMENT0,
759 GL_TEXTURE_2D,
760 glDesc.fTextureID,
761 0,
762 samples));
763
764 } else {
765 GR_GLEXT(fExts, FramebufferTexture2D(GR_FRAMEBUFFER,
766 GR_COLOR_ATTACHMENT0,
767 GL_TEXTURE_2D,
768 glDesc.fTextureID, 0));
769 }
770 if (rtIDs.fRTFBOID != rtIDs.fTexFBOID) {
771 GLenum status = GR_GLEXT(fExts,
772 CheckFramebufferStatus(GR_FRAMEBUFFER));
773 if (status != GR_FRAMEBUFFER_COMPLETE) {
774 GrPrintf("-- glCheckFramebufferStatus %x %d %d\n",
775 status, desc.fWidth, desc.fHeight);
776 continue;
777 }
778 GR_GLEXT(fExts, BindFramebuffer(GR_FRAMEBUFFER, rtIDs.fRTFBOID));
779 #if GR_COLLECT_STATS
780 ++fStats.fRenderTargetChngCnt;
781 #endif
782 GR_GLEXT(fExts, FramebufferRenderbuffer(GR_FRAMEBUFFER,
783 GR_COLOR_ATTACHMENT0,
784 GR_RENDERBUFFER,
785 rtIDs.fMSColorRenderbufferID));
786
787 }
788 if (rtIDs.fStencilRenderbufferID) {
789 // bind the stencil to rt fbo if present, othewise the tex fbo
790 GR_GLEXT(fExts, FramebufferRenderbuffer(GR_FRAMEBUFFER,
791 GR_STENCIL_ATTACHMENT,
792 GR_RENDERBUFFER,
793 rtIDs.fStencilRenderbufferID));
794 }
795 status = GR_GLEXT(fExts, CheckFramebufferStatus(GR_FRAMEBUFFER));
796
797#if GR_GL_DESKTOP
798 // On some implementations you have to be bound as DEPTH_STENCIL.
799 // (Even binding to DEPTH and STENCIL separately with the same
800 // buffer doesn't work.)
801 if (rtIDs.fStencilRenderbufferID &&
802 status != GR_FRAMEBUFFER_COMPLETE) {
803 GR_GLEXT(fExts, FramebufferRenderbuffer(GR_FRAMEBUFFER,
804 GR_STENCIL_ATTACHMENT,
805 GR_RENDERBUFFER,
806 0));
807 GR_GLEXT(fExts,
808 FramebufferRenderbuffer(GR_FRAMEBUFFER,
809 GR_DEPTH_STENCIL_ATTACHMENT,
810 GR_RENDERBUFFER,
811 rtIDs.fStencilRenderbufferID));
812 status = GR_GLEXT(fExts, CheckFramebufferStatus(GR_FRAMEBUFFER));
813 }
814#endif
815 if (status != GR_FRAMEBUFFER_COMPLETE) {
816 GrPrintf("-- glCheckFramebufferStatus %x %d %d\n",
817 status, desc.fWidth, desc.fHeight);
818#if GR_GL_DESKTOP
819 if (rtIDs.fStencilRenderbufferID) {
820 GR_GLEXT(fExts, FramebufferRenderbuffer(GR_FRAMEBUFFER,
821 GR_DEPTH_STENCIL_ATTACHMENT,
822 GR_RENDERBUFFER,
823 0));
824 }
825#endif
826 continue;
827 }
828 // we're successful!
829 failed = false;
830 break;
831 }
832 if (failed) {
833 if (rtIDs.fStencilRenderbufferID) {
834 GR_GLEXT(fExts,
835 DeleteRenderbuffers(1, &rtIDs.fStencilRenderbufferID));
836 }
837 if (rtIDs.fMSColorRenderbufferID) {
838 GR_GLEXT(fExts,
839 DeleteRenderbuffers(1, &rtIDs.fMSColorRenderbufferID));
840 }
841 if (rtIDs.fRTFBOID != rtIDs.fTexFBOID) {
842 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fRTFBOID));
843 }
844 if (rtIDs.fTexFBOID) {
845 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fTexFBOID));
846 }
847 GR_GL(DeleteTextures(1, &glDesc.fTextureID));
848 return return_null_texture();
849 }
850 }
851#ifdef TRACE_TEXTURE_CREATION
852 GrPrintf("--- new texture [%d] size=(%d %d) bpp=%d\n",
853 tex->fTextureID, width, height, tex->fUploadByteCount);
854#endif
855 GrGLTexture* tex = new GrGLTexture(glDesc, rtIDs, this);
856
857 if (0 != rtIDs.fTexFBOID) {
858 GrRenderTarget* rt = tex->asRenderTarget();
859 // We've messed with FBO state but may not have set the correct viewport
860 // so just dirty the rendertarget state to force a resend.
861 fHWDrawState.fRenderTarget = NULL;
862
863 // clear the new stencil buffer if we have one
864 if (!(desc.fFlags & kNoPathRendering_TextureFlag)) {
865 GrRenderTarget* rtSave = fCurrDrawState.fRenderTarget;
866 fCurrDrawState.fRenderTarget = rt;
867 eraseStencil(0, ~0);
868 fCurrDrawState.fRenderTarget = rtSave;
869 }
870 }
871 return tex;
872}
873
874GrRenderTarget* GrGpuGL::defaultRenderTarget() {
875 return fDefaultRenderTarget;
876}
877
878GrVertexBuffer* GrGpuGL::createVertexBuffer(uint32_t size, bool dynamic) {
879 GLuint id;
880 GR_GL(GenBuffers(1, &id));
881 if (id) {
882 GR_GL(BindBuffer(GL_ARRAY_BUFFER, id));
883 GrGLClearErr();
884 // make sure driver can allocate memory for this buffer
885 GR_GL_NO_ERR(BufferData(GL_ARRAY_BUFFER, size, NULL,
886 dynamic ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW));
887 if (glGetError() != GL_NO_ERROR) {
888 GR_GL(DeleteBuffers(1, &id));
889 // deleting bound buffer does implicit bind to 0
890 fHWGeometryState.fVertexBuffer = NULL;
891 return NULL;
892 }
893 GrGLVertexBuffer* vertexBuffer = new GrGLVertexBuffer(id, this,
894 size, dynamic);
895 fHWGeometryState.fVertexBuffer = vertexBuffer;
896 return vertexBuffer;
897 }
898 return NULL;
899}
900
901GrIndexBuffer* GrGpuGL::createIndexBuffer(uint32_t size, bool dynamic) {
902 GLuint id;
903 GR_GL(GenBuffers(1, &id));
904 if (id) {
905 GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, id));
906 GrGLClearErr();
907 // make sure driver can allocate memory for this buffer
908 GR_GL_NO_ERR(BufferData(GL_ELEMENT_ARRAY_BUFFER, size, NULL,
909 dynamic ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW));
910 if (glGetError() != GL_NO_ERROR) {
911 GR_GL(DeleteBuffers(1, &id));
912 // deleting bound buffer does implicit bind to 0
913 fHWGeometryState.fIndexBuffer = NULL;
914 return NULL;
915 }
916 GrIndexBuffer* indexBuffer = new GrGLIndexBuffer(id, this,
917 size, dynamic);
918 fHWGeometryState.fIndexBuffer = indexBuffer;
919 return indexBuffer;
920 }
921 return NULL;
922}
923
924void GrGpuGL::setDefaultRenderTargetSize(uint32_t width, uint32_t height) {
925 GrIRect viewport(0, height, width, 0);
926 if (viewport != fDefaultRenderTarget->viewport()) {
927 fDefaultRenderTarget->setViewport(viewport);
928 if (fHWDrawState.fRenderTarget == fDefaultRenderTarget) {
929 fHWDrawState.fRenderTarget = NULL;
930 }
931 }
932}
933
934void GrGpuGL::flushScissor(const GrIRect* rect) {
935 GrAssert(NULL != fCurrDrawState.fRenderTarget);
936 const GrIRect& vp =
937 ((GrGLRenderTarget*)fCurrDrawState.fRenderTarget)->viewport();
938
939 if (NULL != rect &&
940 rect->contains(vp)) {
941 rect = NULL;
942 }
943
944 if (NULL != rect) {
945 GrIRect scissor;
946 // viewport is already in GL coords
947 // create a scissor in GL coords (top > bottom)
948 scissor.setLTRB(vp.fLeft + rect->fLeft,
949 vp.fTop - rect->fTop,
950 vp.fLeft + rect->fRight,
951 vp.fTop - rect->fBottom);
952
953 if (fHWBounds.fScissorRect != scissor) {
954 GR_GL(Scissor(scissor.fLeft, scissor.fBottom,
955 scissor.width(), -scissor.height()));
956 fHWBounds.fScissorRect = scissor;
957 }
958
959 if (!fHWBounds.fScissorEnabled) {
960 GR_GL(Enable(GL_SCISSOR_TEST));
961 fHWBounds.fScissorEnabled = true;
962 }
963 } else {
964 if (fHWBounds.fScissorEnabled) {
965 GR_GL(Disable(GL_SCISSOR_TEST));
966 fHWBounds.fScissorEnabled = false;
967 }
968 }
969}
970
971void GrGpuGL::setSamplerStateImm(const GrSamplerState& state) {
972
973 GLenum filter = state.isFilter() ? GL_LINEAR : GL_NEAREST;
974 GR_GL(TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter));
975 GR_GL(TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter));
976 GR_GL(TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
977 GrGLTexture::gWrapMode2GLWrap[state.getWrapX()]));
978 GR_GL(TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
979 GrGLTexture::gWrapMode2GLWrap[state.getWrapY()]));
980
981}
982
983void GrGpuGL::eraseColor(GrColor color) {
984 flushRenderTarget();
985 if (fHWBounds.fScissorEnabled) {
986 GR_GL(Disable(GL_SCISSOR_TEST));
987 }
988 GR_GL(ColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE));
989 GR_GL(ClearColor(GrColorUnpackR(color)/255.f,
990 GrColorUnpackG(color)/255.f,
991 GrColorUnpackB(color)/255.f,
992 GrColorUnpackA(color)/255.f));
993 GR_GL(Clear(GL_COLOR_BUFFER_BIT));
994 fHWBounds.fScissorEnabled = false;
995 fWriteMaskChanged = true;
996}
997
998void GrGpuGL::eraseStencil(uint32_t value, uint32_t mask) {
999 flushRenderTarget();
1000 if (fHWBounds.fScissorEnabled) {
1001 GR_GL(Disable(GL_SCISSOR_TEST));
1002 }
1003 GR_GL(StencilMask(mask));
1004 GR_GL(ClearStencil(value));
1005 GR_GL(Clear(GL_STENCIL_BUFFER_BIT));
1006 fHWBounds.fScissorEnabled = false;
1007 fWriteMaskChanged = true;
1008}
1009
1010void GrGpuGL::eraseStencilClip() {
1011 GLint stencilBitCount;
1012 GR_GL(GetIntegerv(GL_STENCIL_BITS, &stencilBitCount));
1013 GrAssert(stencilBitCount > 0);
1014 GLint clipStencilMask = (1 << (stencilBitCount - 1));
1015 eraseStencil(0, clipStencilMask);
1016}
1017
1018void GrGpuGL::forceRenderTargetFlush() {
1019 flushRenderTarget();
1020}
1021
1022bool GrGpuGL::readPixels(int left, int top, int width, int height,
1023 GrTexture::PixelConfig config, void* buffer) {
1024 GLenum internalFormat; // we don't use this for glReadPixels
1025 GLenum format;
1026 GLenum type;
1027 if (!this->canBeTexture(config, &internalFormat, &format, &type)) {
1028 return false;
1029 }
1030
1031 GrAssert(NULL != fCurrDrawState.fRenderTarget);
1032 const GrIRect& vp = ((GrGLRenderTarget*)fCurrDrawState.fRenderTarget)->viewport();
1033
1034 // Brian says that viewport rects are already upside down (grrrrr)
1035 glReadPixels(left, -vp.height() - top - height, width, height,
1036 format, type, buffer);
1037
1038 // now reverse the order of the rows, since GL's are bottom-to-top, but our
1039 // API presents top-to-bottom
1040 {
1041 size_t stride = width * GrTexture::BytesPerPixel(config);
1042 GrAutoMalloc rowStorage(stride);
1043 void* tmp = rowStorage.get();
1044
1045 const int halfY = height >> 1;
1046 char* top = reinterpret_cast<char*>(buffer);
1047 char* bottom = top + (height - 1) * stride;
1048 for (int y = 0; y < halfY; y++) {
1049 memcpy(tmp, top, stride);
1050 memcpy(top, bottom, stride);
1051 memcpy(bottom, tmp, stride);
1052 top += stride;
1053 bottom -= stride;
1054 }
1055 }
1056 return true;
1057}
1058
1059void GrGpuGL::flushRenderTarget() {
1060 if (fHWDrawState.fRenderTarget != fCurrDrawState.fRenderTarget) {
1061 GrGLRenderTarget* rt = (GrGLRenderTarget*)fCurrDrawState.fRenderTarget;
1062 GR_GLEXT(fExts, BindFramebuffer(GR_FRAMEBUFFER, rt->renderFBOID()));
1063 #if GR_COLLECT_STATS
1064 ++fStats.fRenderTargetChngCnt;
1065 #endif
1066 rt->setDirty(true);
1067 #if GR_DEBUG
1068 GLenum status = GR_GLEXT(fExts, CheckFramebufferStatus(GR_FRAMEBUFFER));
1069 if (status != GR_FRAMEBUFFER_COMPLETE) {
1070 GrPrintf("-- glCheckFramebufferStatus %x\n", status);
1071 }
1072 #endif
1073 fHWDrawState.fRenderTarget = fCurrDrawState.fRenderTarget;
1074 const GrIRect& vp = rt->viewport();
1075 fRenderTargetChanged = true;
1076 if (fHWBounds.fViewportRect != vp) {
1077 GR_GL(Viewport(vp.fLeft,
1078 vp.fBottom,
1079 vp.width(),
1080 -vp.height()));
1081 fHWBounds.fViewportRect = vp;
1082 }
1083 }
1084}
1085
1086GLenum gPrimitiveType2GLMode[] = {
1087 GL_TRIANGLES,
1088 GL_TRIANGLE_STRIP,
1089 GL_TRIANGLE_FAN,
1090 GL_POINTS,
1091 GL_LINES,
1092 GL_LINE_STRIP
1093};
1094
1095void GrGpuGL::drawIndexedHelper(PrimitiveType type,
1096 uint32_t startVertex,
1097 uint32_t startIndex,
1098 uint32_t vertexCount,
1099 uint32_t indexCount) {
1100 GrAssert((size_t)type < GR_ARRAY_COUNT(gPrimitiveType2GLMode));
1101
1102 GLvoid* indices = (GLvoid*)(sizeof(uint16_t) * startIndex);
1103 if (kReserved_GeometrySrcType == fGeometrySrc.fIndexSrc) {
1104 indices = (GLvoid*)((intptr_t)indices + (intptr_t)fIndices.get());
1105 } else if (kArray_GeometrySrcType == fGeometrySrc.fIndexSrc) {
1106 indices = (GLvoid*)((intptr_t)indices +
1107 (intptr_t)fGeometrySrc.fIndexArray);
1108 }
1109
1110 GR_GL(DrawElements(gPrimitiveType2GLMode[type], indexCount,
1111 GL_UNSIGNED_SHORT, indices));
1112}
1113
1114void GrGpuGL::drawNonIndexedHelper(PrimitiveType type,
1115 uint32_t startVertex,
1116 uint32_t vertexCount) {
1117 GrAssert((size_t)type < GR_ARRAY_COUNT(gPrimitiveType2GLMode));
1118
1119 GR_GL(DrawArrays(gPrimitiveType2GLMode[type], 0, vertexCount));
1120}
1121
1122#if !defined(SK_GL_HAS_COLOR4UB)
1123static inline GrFixed byte2fixed(unsigned value) {
1124 return (value + (value >> 7)) << 8;
1125}
1126#endif
1127
1128void GrGpuGL::resolveTextureRenderTarget(GrGLTexture* texture) {
1129 GrGLRenderTarget* rt = (GrGLRenderTarget*) texture->asRenderTarget();
1130
1131 if (NULL != rt && rt->needsResolve()) {
1132 GrAssert(kNone_MSFBO != fMSFBOType);
1133 GrAssert(rt->textureFBOID() != rt->renderFBOID());
1134 GR_GLEXT(fExts, BindFramebuffer(GR_READ_FRAMEBUFFER,
1135 rt->renderFBOID()));
1136 GR_GLEXT(fExts, BindFramebuffer(GR_DRAW_FRAMEBUFFER,
1137 rt->textureFBOID()));
1138 #if GR_COLLECT_STATS
1139 ++fStats.fRenderTargetChngCnt;
1140 #endif
1141 // make sure we go through set render target
1142 fHWDrawState.fRenderTarget = NULL;
1143
1144 GLint left = 0;
1145 GLint right = texture->contentWidth();
1146 // we will have rendered to the top of the FBO.
1147 GLint top = texture->allocHeight();
1148 GLint bottom = texture->allocHeight() - texture->contentHeight();
1149 if (kApple_MSFBO == fMSFBOType) {
1150 GR_GL(Enable(GL_SCISSOR_TEST));
1151 GR_GL(Scissor(left, bottom, right-left, top-bottom));
1152 GR_GLEXT(fExts, ResolveMultisampleFramebuffer());
1153 fHWBounds.fScissorRect.setEmpty();
1154 fHWBounds.fScissorEnabled = true;
1155 } else {
1156 GR_GLEXT(fExts, BlitFramebuffer(left, bottom, right, top,
1157 left, bottom, right, top,
1158 GL_COLOR_BUFFER_BIT, GL_NEAREST));
1159 }
1160 rt->setDirty(false);
1161
1162 }
1163}
1164
1165void GrGpuGL::flushStencil() {
1166
1167 // use stencil for clipping if clipping is enabled and the clip
1168 // has been written into the stencil.
1169 bool stencilClip = fClipState.fClipInStencil &&
1170 (kClip_StateBit & fCurrDrawState.fFlagBits);
1171 bool stencilChange =
1172 fWriteMaskChanged ||
1173 fHWStencilClip != stencilClip ||
1174 fHWDrawState.fStencilPass != fCurrDrawState.fStencilPass ||
1175 (kNone_StencilPass != fCurrDrawState.fStencilPass &&
1176 (StencilPass)kSetClip_StencilPass != fCurrDrawState.fStencilPass &&
1177 fHWDrawState.fReverseFill != fCurrDrawState.fReverseFill);
1178
1179 if (stencilChange) {
1180 GLint stencilBitCount;
1181 GLint clipStencilMask;
1182 GLint pathStencilMask;
1183 GR_GL(GetIntegerv(GL_STENCIL_BITS, &stencilBitCount));
1184 GrAssert(stencilBitCount > 0 ||
1185 kNone_StencilPass == fCurrDrawState.fStencilPass);
1186 clipStencilMask = (1 << (stencilBitCount - 1));
1187 pathStencilMask = clipStencilMask - 1;
1188 switch (fCurrDrawState.fStencilPass) {
1189 case kNone_StencilPass:
1190 if (stencilClip) {
1191 GR_GL(Enable(GL_STENCIL_TEST));
1192 GR_GL(StencilFunc(GL_EQUAL,
1193 clipStencilMask,
1194 clipStencilMask));
1195 GR_GL(StencilOp(GL_KEEP, GL_KEEP, GL_KEEP));
1196 } else {
1197 GR_GL(Disable(GL_STENCIL_TEST));
1198 }
1199 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
1200 if (!fSingleStencilPassForWinding) {
1201 GR_GL(Disable(GL_CULL_FACE));
1202 }
1203 break;
1204 case kEvenOddStencil_StencilPass:
1205 GR_GL(Enable(GL_STENCIL_TEST));
1206 if (stencilClip) {
1207 GR_GL(StencilFunc(GL_EQUAL, clipStencilMask, clipStencilMask));
1208 } else {
1209 GR_GL(StencilFunc(GL_ALWAYS, 0x0, 0x0));
1210 }
1211 GR_GL(StencilMask(pathStencilMask));
1212 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
1213 GR_GL(StencilOp(GL_KEEP, GL_INVERT, GL_INVERT));
1214 GR_GL(ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE));
1215 if (!fSingleStencilPassForWinding) {
1216 GR_GL(Disable(GL_CULL_FACE));
1217 }
1218 break;
1219 case kEvenOddColor_StencilPass: {
1220 GR_GL(Enable(GL_STENCIL_TEST));
1221 GLint funcRef = 0;
1222 GLuint funcMask = pathStencilMask;
1223 if (stencilClip) {
1224 funcRef |= clipStencilMask;
1225 funcMask |= clipStencilMask;
1226 }
1227 if (!fCurrDrawState.fReverseFill) {
1228 funcRef |= pathStencilMask;
1229 }
1230 glStencilFunc(GL_EQUAL, funcRef, funcMask);
1231 glStencilMask(pathStencilMask);
1232 GR_GL(StencilOp(GL_ZERO, GL_ZERO, GL_ZERO));
1233 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
1234 if (!fSingleStencilPassForWinding) {
1235 GR_GL(Disable(GL_CULL_FACE));
1236 }
1237 } break;
1238 case kWindingStencil1_StencilPass:
1239 GR_GL(Enable(GL_STENCIL_TEST));
1240 if (fHasStencilWrap) {
1241 if (stencilClip) {
1242 GR_GL(StencilFunc(GL_EQUAL,
1243 clipStencilMask,
1244 clipStencilMask));
1245 } else {
1246 GR_GL(StencilFunc(GL_ALWAYS, 0x0, 0x0));
1247 }
1248 if (fSingleStencilPassForWinding) {
1249 GR_GL(StencilOpSeparate(GL_FRONT, GL_KEEP,
1250 GL_INCR_WRAP, GL_INCR_WRAP));
1251 GR_GL(StencilOpSeparate(GL_BACK, GL_KEEP,
1252 GL_DECR_WRAP, GL_DECR_WRAP));
1253 } else {
1254 GR_GL(StencilOp(GL_KEEP, GL_INCR_WRAP, GL_INCR_WRAP));
1255 GR_GL(Enable(GL_CULL_FACE));
1256 GR_GL(CullFace(GL_BACK));
1257 }
1258 } else {
1259 // If we don't have wrap then we use the Func to detect
1260 // values that would wrap (0 on decr and mask on incr). We
1261 // make the func fail on these values and use the sfail op
1262 // to effectively wrap by inverting.
1263 // This applies whether we are doing a two-pass (front faces
1264 // followed by back faces) or a single pass (separate func/op)
1265
1266 // Note that in the case where we are also using stencil to
1267 // clip this means we will write into the path bits in clipped
1268 // out pixels. We still apply the clip bit in the color pass
1269 // stencil func so we don't draw color outside the clip.
1270 // We also will clear the stencil bits in clipped pixels by
1271 // using zero in the sfail op with write mask set to the
1272 // path mask.
1273 GR_GL(Enable(GL_STENCIL_TEST));
1274 if (fSingleStencilPassForWinding) {
1275 GR_GL(StencilFuncSeparate(GL_FRONT,
1276 GL_NOTEQUAL,
1277 pathStencilMask,
1278 pathStencilMask));
1279 GR_GL(StencilFuncSeparate(GL_BACK,
1280 GL_NOTEQUAL,
1281 0x0,
1282 pathStencilMask));
1283 GR_GL(StencilOpSeparate(GL_FRONT, GL_INVERT,
1284 GL_INCR, GL_INCR));
1285 GR_GL(StencilOpSeparate(GL_BACK, GL_INVERT,
1286 GL_DECR, GL_DECR));
1287 } else {
1288 GR_GL(StencilFunc(GL_NOTEQUAL,
1289 pathStencilMask,
1290 pathStencilMask));
1291 GR_GL(StencilOp(GL_INVERT, GL_INCR, GL_INCR));
1292 GR_GL(Enable(GL_CULL_FACE));
1293 GR_GL(CullFace(GL_BACK));
1294 }
1295 }
1296 GR_GL(StencilMask(pathStencilMask));
1297 GR_GL(ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE));
1298 break;
1299 case kWindingStencil2_StencilPass:
1300 GrAssert(!fSingleStencilPassForWinding);
1301 GR_GL(Enable(GL_STENCIL_TEST));
1302 if (fHasStencilWrap) {
1303 if (stencilClip) {
1304 GR_GL(StencilFunc(GL_EQUAL,
1305 clipStencilMask,
1306 clipStencilMask));
1307 } else {
1308 GR_GL(StencilFunc(GL_ALWAYS, 0x0, 0x0));
1309 }
1310 GR_GL(StencilOp(GL_DECR_WRAP, GL_DECR_WRAP, GL_DECR_WRAP));
1311 } else {
1312 GR_GL(StencilFunc(GL_NOTEQUAL, 0x0, pathStencilMask));
1313 GR_GL(StencilOp(GL_INVERT, GL_DECR, GL_DECR));
1314 }
1315 GR_GL(StencilMask(pathStencilMask));
1316 GR_GL(Enable(GL_CULL_FACE));
1317 GR_GL(CullFace(GL_FRONT));
1318 GR_GL(ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE));
1319 break;
1320 case kWindingColor_StencilPass: {
1321 GR_GL(Enable(GL_STENCIL_TEST));
1322 GLint funcRef = 0;
1323 GLuint funcMask = pathStencilMask;
1324 GLenum funcFunc;
1325 if (stencilClip) {
1326 funcRef |= clipStencilMask;
1327 funcMask |= clipStencilMask;
1328 }
1329 if (fCurrDrawState.fReverseFill) {
1330 funcFunc = GL_EQUAL;
1331 } else {
1332 funcFunc = GL_LESS;
1333 }
1334 GR_GL(StencilFunc(funcFunc, funcRef, funcMask));
1335 GR_GL(StencilMask(pathStencilMask));
1336 // must zero in sfail because winding w/o wrap will write
1337 // path stencil bits in clipped out pixels
1338 GR_GL(StencilOp(GL_ZERO, GL_ZERO, GL_ZERO));
1339 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
1340 if (!fSingleStencilPassForWinding) {
1341 GR_GL(Disable(GL_CULL_FACE));
1342 }
1343 } break;
1344 case kSetClip_StencilPass:
1345 GR_GL(Enable(GL_STENCIL_TEST));
1346 GR_GL(StencilFunc(GL_ALWAYS, clipStencilMask, clipStencilMask));
1347 GR_GL(StencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE));
1348 GR_GL(StencilMask(clipStencilMask));
1349 GR_GL(ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE));
1350 if (!fSingleStencilPassForWinding) {
1351 GR_GL(Disable(GL_CULL_FACE));
1352 }
1353 break;
1354 default:
1355 GrAssert(!"Unexpected stencil pass.");
1356 break;
1357
1358 }
1359 fHWDrawState.fStencilPass = fCurrDrawState.fStencilPass;
1360 fHWDrawState.fReverseFill = fCurrDrawState.fReverseFill;
1361 fWriteMaskChanged = false;
1362 fHWStencilClip = stencilClip;
1363 }
1364}
1365
1366void GrGpuGL::flushGLStateCommon(PrimitiveType type) {
1367
1368 bool usingTexture = VertexHasTexCoords(fGeometrySrc.fVertexLayout);
1369
1370 // bind texture and set sampler state
1371 if (usingTexture) {
1372 GrGLTexture* nextTexture = (GrGLTexture*)fCurrDrawState.fTexture;
1373
1374 if (NULL != nextTexture) {
1375 // if we created a rt/tex and rendered to it without using a texture
1376 // and now we're texuring from the rt it will still be the last bound
1377 // texture, but it needs resolving. So keep this out of the last
1378 // != next check.
1379 resolveTextureRenderTarget(nextTexture);
1380
1381 if (fHWDrawState.fTexture != nextTexture) {
1382
1383 GR_GL(BindTexture(GL_TEXTURE_2D, nextTexture->textureID()));
1384 #if GR_COLLECT_STATS
1385 ++fStats.fTextureChngCnt;
1386 #endif
1387 //GrPrintf("---- bindtexture %d\n", nextTexture->textureID());
1388 fHWDrawState.fTexture = nextTexture;
1389 }
1390 const GrSamplerState& lastSampler = nextTexture->samplerState();
1391 if (lastSampler.isFilter() != fCurrDrawState.fSamplerState.isFilter()) {
1392 GLenum filter = fCurrDrawState.fSamplerState.isFilter() ?
1393 GL_LINEAR :
1394 GL_NEAREST;
1395 GR_GL(TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
1396 filter));
1397 GR_GL(TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
1398 filter));
1399 }
1400 if (lastSampler.getWrapX() != fCurrDrawState.fSamplerState.getWrapX()) {
1401 GR_GL(TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
1402 GrGLTexture::gWrapMode2GLWrap[
1403 fCurrDrawState.fSamplerState.getWrapX()]));
1404 }
1405 if (lastSampler.getWrapY() != fCurrDrawState.fSamplerState.getWrapY()) {
1406 GR_GL(TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
1407 GrGLTexture::gWrapMode2GLWrap[
1408 fCurrDrawState.fSamplerState.getWrapY()]));
1409 }
1410 nextTexture->setSamplerState(fCurrDrawState.fSamplerState);
1411 } else {
1412 GrAssert(!"Rendering with texture vert flag set but no texture");
1413 if (NULL != fHWDrawState.fTexture) {
1414 GR_GL(BindTexture(GL_TEXTURE_2D, 0));
1415 // GrPrintf("---- bindtexture 0\n");
1416 #if GR_COLLECT_STATS
1417 ++fStats.fTextureChngCnt;
1418 #endif
1419 fHWDrawState.fTexture = NULL;
1420 }
1421 }
1422 }
1423
1424 flushRenderTarget();
1425
1426 if ((fCurrDrawState.fFlagBits & kDither_StateBit) !=
1427 (fHWDrawState.fFlagBits & kDither_StateBit)) {
1428 if (fCurrDrawState.fFlagBits & kDither_StateBit) {
1429 GR_GL(Enable(GL_DITHER));
1430 } else {
1431 GR_GL(Disable(GL_DITHER));
1432 }
1433 }
1434
1435#if GR_GL_DESKTOP
1436 // ES doesn't support toggling GL_MULTISAMPLE and doesn't have
1437 // smooth lines.
1438 if (fRenderTargetChanged ||
1439 (fCurrDrawState.fFlagBits & kAntialias_StateBit) !=
1440 (fHWDrawState.fFlagBits & kAntialias_StateBit)) {
1441 GLint msaa = 0;
1442 // only perform query if we know MSAA is supported.
1443 // calling on non-MSAA target caused a crash in one environment,
1444 // though I don't think it should.
1445 if (!fAASamples[kHigh_AALevel]) {
1446 GR_GL(GetIntegerv(GL_SAMPLE_BUFFERS, &msaa));
1447 }
1448 if (fCurrDrawState.fFlagBits & kAntialias_StateBit) {
1449 if (msaa) {
1450 GR_GL(Enable(GL_MULTISAMPLE));
1451 } else {
1452 GR_GL(Enable(GL_LINE_SMOOTH));
1453 }
1454 } else {
1455 if (msaa) {
1456 GR_GL(Disable(GL_MULTISAMPLE));
1457 }
1458 GR_GL(Disable(GL_LINE_SMOOTH));
1459 }
1460 }
1461#endif
1462
1463 bool blendOff = canDisableBlend();
1464 if (fHWBlendDisabled != blendOff) {
1465 if (blendOff) {
1466 GR_GL(Disable(GL_BLEND));
1467 } else {
1468 GR_GL(Enable(GL_BLEND));
1469 }
1470 fHWBlendDisabled = blendOff;
1471 }
1472
1473 if (!blendOff) {
1474 if (fHWDrawState.fSrcBlend != fCurrDrawState.fSrcBlend ||
1475 fHWDrawState.fDstBlend != fCurrDrawState.fDstBlend) {
1476 GR_GL(BlendFunc(gXfermodeCoeff2Blend[fCurrDrawState.fSrcBlend],
1477 gXfermodeCoeff2Blend[fCurrDrawState.fDstBlend]));
1478 fHWDrawState.fSrcBlend = fCurrDrawState.fSrcBlend;
1479 fHWDrawState.fDstBlend = fCurrDrawState.fDstBlend;
1480 }
1481 }
1482
1483 // check for circular rendering
1484 GrAssert(!usingTexture ||
1485 NULL == fCurrDrawState.fRenderTarget ||
1486 NULL == fCurrDrawState.fTexture ||
1487 fCurrDrawState.fTexture->asRenderTarget() != fCurrDrawState.fRenderTarget);
1488
1489 flushStencil();
1490
1491 fHWDrawState.fFlagBits = fCurrDrawState.fFlagBits;
1492}
1493
1494void GrGpuGL::notifyVertexBufferBind(const GrGLVertexBuffer* buffer) {
1495 fHWGeometryState.fVertexBuffer = buffer;
1496}
1497
1498void GrGpuGL::notifyVertexBufferDelete(const GrGLVertexBuffer* buffer) {
1499 GrAssert(!(kBuffer_GeometrySrcType == fGeometrySrc.fVertexSrc &&
1500 buffer == fGeometrySrc.fVertexBuffer));
1501
1502 if (fHWGeometryState.fVertexBuffer == buffer) {
1503 // deleting bound buffer does implied bind to 0
1504 fHWGeometryState.fVertexBuffer = NULL;
1505 }
1506}
1507
1508void GrGpuGL::notifyIndexBufferBind(const GrGLIndexBuffer* buffer) {
1509 fGeometrySrc.fIndexBuffer = buffer;
1510}
1511
1512void GrGpuGL::notifyIndexBufferDelete(const GrGLIndexBuffer* buffer) {
1513 GrAssert(!(kBuffer_GeometrySrcType == fGeometrySrc.fIndexSrc &&
1514 buffer == fGeometrySrc.fIndexBuffer));
1515
1516 if (fHWGeometryState.fIndexBuffer == buffer) {
1517 // deleting bound buffer does implied bind to 0
1518 fHWGeometryState.fIndexBuffer = NULL;
1519 }
1520}
1521
1522void GrGpuGL::notifyTextureBind(GrGLTexture* texture) {
1523 fHWDrawState.fTexture = texture;
1524#if GR_COLLECT_STATS
1525 ++fStats.fTextureChngCnt;
1526#endif
1527}
1528
1529void GrGpuGL::notifyRenderTargetDelete(GrRenderTarget* renderTarget) {
1530 GrAssert(NULL != renderTarget);
1531
1532 // if the bound FBO is destroyed we can't rely on the implicit bind to 0
1533 // a) we want the default RT which may not be FBO 0
1534 // b) we set more state than just FBO based on the RT
1535 // So trash the HW state to force an RT flush next time
1536 if (fCurrDrawState.fRenderTarget == renderTarget) {
1537 fCurrDrawState.fRenderTarget = (GrRenderTarget*)&fDefaultRenderTarget;
1538 }
1539 if (fHWDrawState.fRenderTarget == renderTarget) {
1540 fHWDrawState.fRenderTarget = NULL;
1541 }
1542 if (fClipState.fStencilClipTarget == renderTarget) {
1543 fClipState.fStencilClipTarget = NULL;
1544 }
1545}
1546
1547void GrGpuGL::notifyTextureDelete(GrGLTexture* texture) {
1548 if (fCurrDrawState.fTexture == texture) {
1549 fCurrDrawState.fTexture = NULL;
1550 }
1551 if (fHWDrawState.fTexture == texture) {
1552 // deleting bound texture does implied bind to 0
1553 fHWDrawState.fTexture = NULL;
1554 }
1555}
1556
1557void GrGpuGL::notifyTextureRemoveRenderTarget(GrGLTexture* texture) {
1558 GrAssert(NULL != texture->asRenderTarget());
1559
1560 // if there is a pending resolve, perform it.
1561 resolveTextureRenderTarget(texture);
1562}
1563
1564bool GrGpuGL::canBeTexture(GrTexture::PixelConfig config,
1565 GLenum* internalFormat,
1566 GLenum* format,
1567 GLenum* type) {
1568 switch (config) {
1569 case GrTexture::kRGBA_8888_PixelConfig:
1570 case GrTexture::kRGBX_8888_PixelConfig: // todo: can we tell it our X?
1571 *format = SK_GL_32BPP_COLOR_FORMAT;
1572 *internalFormat = GL_RGBA;
1573 *type = GL_UNSIGNED_BYTE;
1574 break;
1575 case GrTexture::kRGB_565_PixelConfig:
1576 *format = GL_RGB;
1577 *internalFormat = GL_RGB;
1578 *type = GL_UNSIGNED_SHORT_5_6_5;
1579 break;
1580 case GrTexture::kRGBA_4444_PixelConfig:
1581 *format = GL_RGBA;
1582 *internalFormat = GL_RGBA;
1583 *type = GL_UNSIGNED_SHORT_4_4_4_4;
1584 break;
1585 case GrTexture::kIndex_8_PixelConfig:
1586 if (this->supports8BitPalette()) {
1587 *format = GR_PALETTE8_RGBA8;
1588 *internalFormat = GR_PALETTE8_RGBA8;
1589 *type = GL_UNSIGNED_BYTE; // unused I think
1590 } else {
1591 return false;
1592 }
1593 break;
1594 case GrTexture::kAlpha_8_PixelConfig:
1595 *format = GL_ALPHA;
1596 *internalFormat = GL_ALPHA;
1597 *type = GL_UNSIGNED_BYTE;
1598 break;
1599 default:
1600 return false;
1601 }
1602 return true;
1603}
1604
1605/* On ES the internalFormat and format must match for TexImage and we use
1606 GL_RGB, GL_RGBA for color formats. We also generally like having the driver
1607 decide the internalFormat. However, on ES internalFormat for
1608 RenderBufferStorage* has to be a specific format (not a base format like
1609 GL_RGBA).
1610 */
1611bool GrGpuGL::fboInternalFormat(GrTexture::PixelConfig config, GLenum* format) {
1612 switch (config) {
1613 case GrTexture::kRGBA_8888_PixelConfig:
1614 case GrTexture::kRGBX_8888_PixelConfig:
1615 if (fRGBA8Renderbuffer) {
1616 *format = GR_RGBA8;
1617 return true;
1618 } else {
1619 return false;
1620 }
1621#if GR_GL_ES // ES2 supports 565. ES1 supports it with FBO extension
1622 // desktop GL has no such internal format
1623 case GrTexture::kRGB_565_PixelConfig:
1624 *format = GR_RGB565;
1625 return true;
1626#endif
1627 case GrTexture::kRGBA_4444_PixelConfig:
1628 *format = GL_RGBA4;
1629 return true;
1630 default:
1631 return false;
1632 }
1633}
1634
1635///////////////////////////////////////////////////////////////////////////////
1636
1637void GrGLCheckErr(const char* location, const char* call) {
1638 uint32_t err = glGetError();
1639 if (GL_NO_ERROR != err) {
1640 GrPrintf("---- glGetError %x", err);
1641 if (NULL != location) {
1642 GrPrintf(" at\n\t%s", location);
1643 }
1644 if (NULL != call) {
1645 GrPrintf("\n\t\t%s", call);
1646 }
1647 GrPrintf("\n");
1648 }
1649}
1650
1651///////////////////////////////////////////////////////////////////////////////
1652
1653typedef void (*glProc)(void);
1654
1655void get_gl_proc(const char procName[], glProc *address) {
1656#if GR_WIN32_BUILD
1657 *address = wglGetProcAddress(procName);
1658 GrAssert(NULL != *address);
1659#elif GR_MAC_BUILD || GR_IOS_BUILD
1660 GrAssert(!"Extensions don't need to be initialized!");
1661#elif GR_ANDROID_BUILD
1662 *address = eglGetProcAddress(procName);
1663 GrAssert(NULL != *address);
1664#elif GR_LINUX_BUILD
1665 GR_STATIC_ASSERT(!"Add environment-dependent implementation here");
1666 //*address = glXGetProcAddressARB(procName);
1667 //*address = eglGetProcAddress(procName);
1668#elif GR_QNX_BUILD
1669 *address = eglGetProcAddress(procName);
1670 GrAssert(NULL != *address);
1671#else
1672 // hopefully we're on a system with EGL
1673 *address = eglGetProcAddress(procName);
1674 GrAssert(NULL != *address);
1675#endif
1676}
1677
1678#define GET_PROC(EXT_STRUCT, PROC_NAME, EXT_TAG) \
1679 get_gl_proc("gl" #PROC_NAME #EXT_TAG, (glProc*)&EXT_STRUCT-> PROC_NAME);
1680
1681extern void GrGLInitExtensions(GrGLExts* exts) {
1682 exts->GenFramebuffers = NULL;
1683 exts->BindFramebuffer = NULL;
1684 exts->FramebufferTexture2D = NULL;
1685 exts->CheckFramebufferStatus = NULL;
1686 exts->DeleteFramebuffers = NULL;
1687 exts->RenderbufferStorage = NULL;
1688 exts->GenRenderbuffers = NULL;
1689 exts->DeleteRenderbuffers = NULL;
1690 exts->FramebufferRenderbuffer = NULL;
1691 exts->BindRenderbuffer = NULL;
1692 exts->RenderbufferStorageMultisample = NULL;
1693 exts->BlitFramebuffer = NULL;
1694 exts->ResolveMultisampleFramebuffer = NULL;
1695 exts->FramebufferTexture2DMultisample = NULL;
1696 exts->MapBuffer = NULL;
1697 exts->UnmapBuffer = NULL;
1698
1699#if GR_MAC_BUILD
1700 exts->GenFramebuffers = glGenFramebuffers;
1701 exts->BindFramebuffer = glBindFramebuffer;
1702 exts->FramebufferTexture2D = glFramebufferTexture2D;
1703 exts->CheckFramebufferStatus = glCheckFramebufferStatus;
1704 exts->DeleteFramebuffers = glDeleteFramebuffers;
1705 exts->RenderbufferStorage = glRenderbufferStorage;
1706 exts->GenRenderbuffers = glGenRenderbuffers;
1707 exts->DeleteRenderbuffers = glDeleteRenderbuffers;
1708 exts->FramebufferRenderbuffer = glFramebufferRenderbuffer;
1709 exts->BindRenderbuffer = glBindRenderbuffer;
1710 exts->RenderbufferStorageMultisample = glRenderbufferStorageMultisample;
1711 exts->BlitFramebuffer = glBlitFramebuffer;
1712 exts->MapBuffer = glMapBuffer;
1713 exts->UnmapBuffer = glUnmapBuffer;
1714#elif GR_IOS_BUILD
1715 exts->GenFramebuffers = glGenFramebuffers;
1716 exts->BindFramebuffer = glBindFramebuffer;
1717 exts->FramebufferTexture2D = glFramebufferTexture2D;
1718 exts->CheckFramebufferStatus = glCheckFramebufferStatus;
1719 exts->DeleteFramebuffers = glDeleteFramebuffers;
1720 exts->RenderbufferStorage = glRenderbufferStorage;
1721 exts->GenRenderbuffers = glGenRenderbuffers;
1722 exts->DeleteRenderbuffers = glDeleteRenderbuffers;
1723 exts->FramebufferRenderbuffer = glFramebufferRenderbuffer;
1724 exts->BindRenderbuffer = glBindRenderbuffer;
1725 exts->RenderbufferStorageMultisample = glRenderbufferStorageMultisampleAPPLE;
1726 exts->ResolveMultisampleFramebuffer = glResolveMultisampleFramebufferAPPLE;
1727 exts->MapBuffer = glMapBufferOES;
1728 exts->UnmapBuffer = glUnmapBufferOES;
1729#else
1730 GLint major, minor;
1731 gl_version(&major, &minor);
1732 #if GR_GL_DESKTOP
1733 if (major >= 3) {// FBO, FBOMS, and FBOBLIT part of 3.0
1734 exts->GenFramebuffers = glGenFramebuffers;
1735 exts->BindFramebuffer = glBindFramebuffer;
1736 exts->FramebufferTexture2D = glFramebufferTexture2D;
1737 exts->CheckFramebufferStatus = glCheckFramebufferStatus;
1738 exts->DeleteFramebuffers = glDeleteFramebuffers;
1739 exts->RenderbufferStorage = glRenderbufferStorage;
1740 exts->GenRenderbuffers = glGenRenderbuffers;
1741 exts->DeleteRenderbuffers = glDeleteRenderbuffers;
1742 exts->FramebufferRenderbuffer = glFramebufferRenderbuffer;
1743 exts->BindRenderbuffer = glBindRenderbuffer;
1744 exts->RenderbufferStorageMultisample = glRenderbufferStorageMultisample;
1745 exts->BlitFramebuffer = glBlitFramebuffer;
1746 } else if (has_gl_extension("GL_ARB_framebuffer_object")) {
1747 GET_PROC(exts, GenFramebuffers, ARB);
1748 GET_PROC(exts, BindFramebuffer, ARB);
1749 GET_PROC(exts, FramebufferTexture2D, ARB);
1750 GET_PROC(exts, CheckFramebufferStatus, ARB);
1751 GET_PROC(exts, DeleteFramebuffers, ARB);
1752 GET_PROC(exts, RenderbufferStorage, ARB);
1753 GET_PROC(exts, GenRenderbuffers, ARB);
1754 GET_PROC(exts, DeleteRenderbuffers, ARB);
1755 GET_PROC(exts, FramebufferRenderbuffer, ARB);
1756 GET_PROC(exts, BindRenderbuffer, ARB);
1757 GET_PROC(exts, RenderbufferStorageMultisample, ARB);
1758 GET_PROC(exts, BlitFramebuffer, ARB);
1759 } else {
1760 // we require some form of FBO
1761 GrAssert(has_gl_extension("GL_EXT_framebuffer_object"));
1762 GET_PROC(exts, GenFramebuffers, EXT);
1763 GET_PROC(exts, BindFramebuffer, EXT);
1764 GET_PROC(exts, FramebufferTexture2D, EXT);
1765 GET_PROC(exts, CheckFramebufferStatus, EXT);
1766 GET_PROC(exts, DeleteFramebuffers, EXT);
1767 GET_PROC(exts, RenderbufferStorage, EXT);
1768 GET_PROC(exts, GenRenderbuffers, EXT);
1769 GET_PROC(exts, DeleteRenderbuffers, EXT);
1770 GET_PROC(exts, FramebufferRenderbuffer, EXT);
1771 GET_PROC(exts, BindRenderbuffer, EXT);
1772 if (has_gl_extension("GL_EXT_framebuffer_multisample")) {
1773 GET_PROC(exts, RenderbufferStorageMultisample, EXT);
1774 }
1775 if (has_gl_extension("GL_EXT_framebuffer_blit")) {
1776 GET_PROC(exts, BlitFramebuffer, EXT);
1777 }
1778 }
1779 // we assume we have at least GL 1.5 or higher (VBOs introduced in 1.5)
1780 exts->MapBuffer = glMapBuffer;
1781 exts->UnmapBuffer = glUnmapBuffer;
1782 #else // !GR_GL_DESKTOP
1783 if (major >= 2) {// ES 2.0 supports FBO
1784 exts->GenFramebuffers = glGenFramebuffers;
1785 exts->BindFramebuffer = glBindFramebuffer;
1786 exts->FramebufferTexture2D = glFramebufferTexture2D;
1787 exts->CheckFramebufferStatus = glCheckFramebufferStatus;
1788 exts->DeleteFramebuffers = glDeleteFramebuffers;
1789 exts->RenderbufferStorage = glRenderbufferStorage;
1790 exts->GenRenderbuffers = glGenRenderbuffers;
1791 exts->DeleteRenderbuffers = glDeleteRenderbuffers;
1792 exts->FramebufferRenderbuffer = glFramebufferRenderbuffer;
1793 exts->BindRenderbuffer = glBindRenderbuffer;
1794 } else {
1795 // we require some form of FBO
1796 GrAssert(has_gl_extension("GL_OES_framebuffer_object"));
1797
1798 GET_PROC(exts, GenFramebuffers, OES);
1799 GET_PROC(exts, BindFramebuffer, OES);
1800 GET_PROC(exts, FramebufferTexture2D, OES);
1801 GET_PROC(exts, CheckFramebufferStatus, OES);
1802 GET_PROC(exts, DeleteFramebuffers, OES);
1803 GET_PROC(exts, RenderbufferStorage, OES);
1804 GET_PROC(exts, GenRenderbuffers, OES);
1805 GET_PROC(exts, DeleteRenderbuffers, OES);
1806 GET_PROC(exts, FramebufferRenderbuffer, OES);
1807 GET_PROC(exts, BindRenderbuffer, OES);
1808 }
1809 if (has_gl_extension("GL_APPLE_framebuffer_multisample")) {
1810 GET_PROC(exts, ResolveMultisampleFramebuffer, APPLE);
1811 }
1812 if (has_gl_extension("GL_IMG_multisampled_render_to_texture")) {
1813 GET_PROC(exts, FramebufferTexture2DMultisample, IMG);
1814 }
1815 if (has_gl_extension("GL_OES_mapbuffer")) {
1816 GET_PROC(exts, MapBuffer, OES);
1817 GET_PROC(exts, UnmapBuffer, OES);
1818 }
1819 #endif // !GR_GL_DESKTOP
1820#endif // BUILD
1821}
1822
1823bool gPrintGL = true;
1824