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