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