blob: 87d69bc39c406078c508695e6fa43c388dc110c3 [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
reed@google.com1fcd51e2011-01-05 15:50:27 +0000536
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000537 static const GrGLTexture::TexParams DEFAULT_PARAMS = {
538 GL_NEAREST,
539 GL_CLAMP_TO_EDGE,
540 GL_CLAMP_TO_EDGE
541 };
reed@google.com1fcd51e2011-01-05 15:50:27 +0000542
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));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000617 GR_GL(TexParameteri(GL_TEXTURE_2D,
618 GL_TEXTURE_MAG_FILTER,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000619 DEFAULT_PARAMS.fFilter));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000620 GR_GL(TexParameteri(GL_TEXTURE_2D,
621 GL_TEXTURE_MIN_FILTER,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000622 DEFAULT_PARAMS.fFilter));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000623 GR_GL(TexParameteri(GL_TEXTURE_2D,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000624 GL_TEXTURE_WRAP_S,
625 DEFAULT_PARAMS.fWrapS));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000626 GR_GL(TexParameteri(GL_TEXTURE_2D,
627 GL_TEXTURE_WRAP_T,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000628 DEFAULT_PARAMS.fWrapT));
reed@google.comac10a2d2010-12-22 21:39:39 +0000629#if GR_COLLECT_STATS
630 ++fStats.fTextureChngCnt;
631#endif
bsalomon@google.come9557f92010-12-23 20:59:40 +0000632 fHWDrawState.fTexture = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +0000633
634 GR_GL(PixelStorei(GL_UNPACK_ALIGNMENT, glDesc.fUploadByteCount));
635 if (GrTexture::kIndex_8_PixelConfig == desc.fFormat &&
636 supports8BitPalette()) {
637 // ES only supports CompressedTexImage2D, not CompressedTexSubimage2D
638 GrAssert(desc.fWidth == glDesc.fAllocWidth);
639 GrAssert(desc.fHeight == glDesc.fAllocHeight);
640 GLsizei imageSize = glDesc.fAllocWidth * glDesc.fAllocHeight +
641 kColorTableSize;
642 GR_GL(CompressedTexImage2D(GL_TEXTURE_2D, 0, glDesc.fUploadFormat,
643 glDesc.fAllocWidth, glDesc.fAllocHeight,
644 0, imageSize, srcData));
645 GrGL_RestoreResetRowLength();
646 } else {
647 if (NULL != srcData && (glDesc.fAllocWidth != desc.fWidth ||
648 glDesc.fAllocHeight != desc.fHeight)) {
649 GR_GL(TexImage2D(GL_TEXTURE_2D, 0, internalFormat,
650 glDesc.fAllocWidth, glDesc.fAllocHeight,
651 0, glDesc.fUploadFormat, glDesc.fUploadType, NULL));
652 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, desc.fWidth,
653 desc.fHeight, glDesc.fUploadFormat,
654 glDesc.fUploadType, srcData));
655 GrGL_RestoreResetRowLength();
656
657 uint32_t extraW = glDesc.fAllocWidth - desc.fWidth;
658 uint32_t extraH = glDesc.fAllocHeight - desc.fHeight;
659 uint32_t maxTexels = extraW * extraH;
660 maxTexels = GrMax(extraW * desc.fHeight, maxTexels);
661 maxTexels = GrMax(desc.fWidth * extraH, maxTexels);
662
663 GrAutoSMalloc<128*128> texels(glDesc.fUploadByteCount * maxTexels);
664
665 uint32_t rowSize = desc.fWidth * glDesc.fUploadByteCount;
666 if (extraH) {
667 uint8_t* lastRowStart = (uint8_t*) srcData +
668 (desc.fHeight - 1) * rowSize;
669 uint8_t* extraRowStart = (uint8_t*)texels.get();
670
671 for (uint32_t i = 0; i < extraH; ++i) {
672 memcpy(extraRowStart, lastRowStart, rowSize);
673 extraRowStart += rowSize;
674 }
675 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, 0, desc.fHeight, desc.fWidth,
676 extraH, glDesc.fUploadFormat, glDesc.fUploadType,
677 texels.get()));
678 }
679 if (extraW) {
680 uint8_t* edgeTexel = (uint8_t*)srcData + rowSize - glDesc.fUploadByteCount;
681 uint8_t* extraTexel = (uint8_t*)texels.get();
682 for (uint32_t j = 0; j < desc.fHeight; ++j) {
683 for (uint32_t i = 0; i < extraW; ++i) {
684 memcpy(extraTexel, edgeTexel, glDesc.fUploadByteCount);
685 extraTexel += glDesc.fUploadByteCount;
686 }
687 edgeTexel += rowSize;
688 }
689 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, desc.fWidth, 0, extraW,
690 desc.fHeight, glDesc.fUploadFormat,
691 glDesc.fUploadType, texels.get()));
692 }
693 if (extraW && extraH) {
694 uint8_t* cornerTexel = (uint8_t*)srcData + desc.fHeight * rowSize
695 - glDesc.fUploadByteCount;
696 uint8_t* extraTexel = (uint8_t*)texels.get();
697 for (uint32_t i = 0; i < extraW*extraH; ++i) {
698 memcpy(extraTexel, cornerTexel, glDesc.fUploadByteCount);
699 extraTexel += glDesc.fUploadByteCount;
700 }
701 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, desc.fWidth, desc.fHeight,
702 extraW, extraH, glDesc.fUploadFormat,
703 glDesc.fUploadType, texels.get()));
704 }
705
706 } else {
707 GR_GL(TexImage2D(GL_TEXTURE_2D, 0, internalFormat, glDesc.fAllocWidth,
708 glDesc.fAllocHeight, 0, glDesc.fUploadFormat,
709 glDesc.fUploadType, srcData));
710 GrGL_RestoreResetRowLength();
711 }
712 }
713
714 glDesc.fOrientation = GrGLTexture::kTopDown_Orientation;
715
716 GrGLRenderTarget::GLRenderTargetIDs rtIDs;
717 rtIDs.fStencilRenderbufferID = 0;
718 rtIDs.fMSColorRenderbufferID = 0;
719 rtIDs.fRTFBOID = 0;
720 rtIDs.fTexFBOID = 0;
721 rtIDs.fOwnIDs = true;
722 GLenum msColorRenderbufferFormat = -1;
723
724 if (renderTarget) {
725#if GR_COLLECT_STATS
726 ++fStats.fRenderTargetCreateCnt;
727#endif
728 bool failed = true;
729 GLenum status;
730 GLint err;
731
732 // If need have both RT flag and srcData we have
733 // to invert the data before uploading because FBO
734 // will be rendered bottom up
735 GrAssert(NULL == srcData);
736 glDesc.fOrientation = GrGLTexture::kBottomUp_Orientation;
737
738 GR_GLEXT(fExts, GenFramebuffers(1, &rtIDs.fTexFBOID));
739 GrAssert(rtIDs.fTexFBOID);
740
741 // If we are using multisampling and any extension other than the IMG
742 // one we will create two FBOs. We render to one and then resolve to
743 // the texture bound to the other. The IMG extension does an implicit
744 // resolve.
745 if (samples > 1 && kIMG_MSFBO != fMSFBOType && kNone_MSFBO != fMSFBOType) {
746 GR_GLEXT(fExts, GenFramebuffers(1, &rtIDs.fRTFBOID));
747 GrAssert(0 != rtIDs.fRTFBOID);
748 GR_GLEXT(fExts, GenRenderbuffers(1, &rtIDs.fMSColorRenderbufferID));
749 GrAssert(0 != rtIDs.fMSColorRenderbufferID);
750 if (!fboInternalFormat(desc.fFormat, &msColorRenderbufferFormat)) {
751 GR_GLEXT(fExts,
752 DeleteRenderbuffers(1, &rtIDs.fMSColorRenderbufferID));
753 GR_GL(DeleteTextures(1, &glDesc.fTextureID));
754 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fTexFBOID));
755 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fRTFBOID));
756 fHWDrawState.fTexture = NULL;
757 return return_null_texture();
758 }
759 } else {
760 rtIDs.fRTFBOID = rtIDs.fTexFBOID;
761 }
762 int attempts = 1;
763 if (!(kNoPathRendering_TextureFlag & desc.fFlags)) {
764 GR_GLEXT(fExts, GenRenderbuffers(1, &rtIDs.fStencilRenderbufferID));
765 GrAssert(0 != rtIDs.fStencilRenderbufferID);
766 attempts = GR_ARRAY_COUNT(GR_GL_STENCIL_FORMAT_ARRAY);
767 }
768
769 // need to unbind the texture before we call FramebufferTexture2D
770 GR_GL(BindTexture(GL_TEXTURE_2D, 0));
771#if GR_COLLECT_STATS
772 ++fStats.fTextureChngCnt;
773#endif
bsalomon@google.come9557f92010-12-23 20:59:40 +0000774 GrAssert(NULL == fHWDrawState.fTexture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000775
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.come9557f92010-12-23 20:59:40 +00001443
bsalomon@google.comda96ea02010-12-23 16:53:57 +00001444 const GrGLTexture::TexParams& oldTexParams = nextTexture->getTexParams();
1445 GrGLTexture::TexParams newTexParams;
reed@google.com1fcd51e2011-01-05 15:50:27 +00001446 newTexParams.fFilter = fCurrDrawState.fSamplerState.isFilter() ?
bsalomon@google.comda96ea02010-12-23 16:53:57 +00001447 GL_LINEAR :
1448 GL_NEAREST;
1449 newTexParams.fWrapS = GrGLTexture::gWrapMode2GLWrap[fCurrDrawState.fSamplerState.getWrapX()];
1450 newTexParams.fWrapT = GrGLTexture::gWrapMode2GLWrap[fCurrDrawState.fSamplerState.getWrapY()];
1451
1452 if (newTexParams.fFilter != oldTexParams.fFilter) {
reed@google.com1fcd51e2011-01-05 15:50:27 +00001453 GR_GL(TexParameteri(GL_TEXTURE_2D,
1454 GL_TEXTURE_MAG_FILTER,
bsalomon@google.comda96ea02010-12-23 16:53:57 +00001455 newTexParams.fFilter));
reed@google.com1fcd51e2011-01-05 15:50:27 +00001456 GR_GL(TexParameteri(GL_TEXTURE_2D,
1457 GL_TEXTURE_MIN_FILTER,
bsalomon@google.comda96ea02010-12-23 16:53:57 +00001458 newTexParams.fFilter));
reed@google.comac10a2d2010-12-22 21:39:39 +00001459 }
bsalomon@google.comda96ea02010-12-23 16:53:57 +00001460 if (newTexParams.fWrapS != oldTexParams.fWrapS) {
reed@google.com1fcd51e2011-01-05 15:50:27 +00001461 GR_GL(TexParameteri(GL_TEXTURE_2D,
bsalomon@google.comda96ea02010-12-23 16:53:57 +00001462 GL_TEXTURE_WRAP_S,
1463 newTexParams.fWrapS));
reed@google.comac10a2d2010-12-22 21:39:39 +00001464 }
bsalomon@google.comda96ea02010-12-23 16:53:57 +00001465 if (newTexParams.fWrapT != oldTexParams.fWrapT) {
reed@google.com1fcd51e2011-01-05 15:50:27 +00001466 GR_GL(TexParameteri(GL_TEXTURE_2D,
1467 GL_TEXTURE_WRAP_T,
bsalomon@google.comda96ea02010-12-23 16:53:57 +00001468 newTexParams.fWrapT));
reed@google.comac10a2d2010-12-22 21:39:39 +00001469 }
bsalomon@google.comda96ea02010-12-23 16:53:57 +00001470 nextTexture->setTexParams(newTexParams);
reed@google.comac10a2d2010-12-22 21:39:39 +00001471 } else {
1472 GrAssert(!"Rendering with texture vert flag set but no texture");
1473 if (NULL != fHWDrawState.fTexture) {
1474 GR_GL(BindTexture(GL_TEXTURE_2D, 0));
1475 // GrPrintf("---- bindtexture 0\n");
1476 #if GR_COLLECT_STATS
1477 ++fStats.fTextureChngCnt;
1478 #endif
1479 fHWDrawState.fTexture = NULL;
1480 }
1481 }
1482 }
1483
1484 flushRenderTarget();
1485
1486 if ((fCurrDrawState.fFlagBits & kDither_StateBit) !=
1487 (fHWDrawState.fFlagBits & kDither_StateBit)) {
1488 if (fCurrDrawState.fFlagBits & kDither_StateBit) {
1489 GR_GL(Enable(GL_DITHER));
1490 } else {
1491 GR_GL(Disable(GL_DITHER));
1492 }
1493 }
1494
1495#if GR_GL_DESKTOP
1496 // ES doesn't support toggling GL_MULTISAMPLE and doesn't have
1497 // smooth lines.
1498 if (fRenderTargetChanged ||
1499 (fCurrDrawState.fFlagBits & kAntialias_StateBit) !=
1500 (fHWDrawState.fFlagBits & kAntialias_StateBit)) {
1501 GLint msaa = 0;
1502 // only perform query if we know MSAA is supported.
1503 // calling on non-MSAA target caused a crash in one environment,
1504 // though I don't think it should.
1505 if (!fAASamples[kHigh_AALevel]) {
1506 GR_GL(GetIntegerv(GL_SAMPLE_BUFFERS, &msaa));
1507 }
1508 if (fCurrDrawState.fFlagBits & kAntialias_StateBit) {
1509 if (msaa) {
1510 GR_GL(Enable(GL_MULTISAMPLE));
1511 } else {
1512 GR_GL(Enable(GL_LINE_SMOOTH));
1513 }
1514 } else {
1515 if (msaa) {
1516 GR_GL(Disable(GL_MULTISAMPLE));
1517 }
1518 GR_GL(Disable(GL_LINE_SMOOTH));
1519 }
1520 }
1521#endif
1522
1523 bool blendOff = canDisableBlend();
1524 if (fHWBlendDisabled != blendOff) {
1525 if (blendOff) {
1526 GR_GL(Disable(GL_BLEND));
1527 } else {
1528 GR_GL(Enable(GL_BLEND));
1529 }
1530 fHWBlendDisabled = blendOff;
1531 }
1532
1533 if (!blendOff) {
1534 if (fHWDrawState.fSrcBlend != fCurrDrawState.fSrcBlend ||
1535 fHWDrawState.fDstBlend != fCurrDrawState.fDstBlend) {
1536 GR_GL(BlendFunc(gXfermodeCoeff2Blend[fCurrDrawState.fSrcBlend],
1537 gXfermodeCoeff2Blend[fCurrDrawState.fDstBlend]));
1538 fHWDrawState.fSrcBlend = fCurrDrawState.fSrcBlend;
1539 fHWDrawState.fDstBlend = fCurrDrawState.fDstBlend;
1540 }
1541 }
1542
1543 // check for circular rendering
1544 GrAssert(!usingTexture ||
1545 NULL == fCurrDrawState.fRenderTarget ||
1546 NULL == fCurrDrawState.fTexture ||
1547 fCurrDrawState.fTexture->asRenderTarget() != fCurrDrawState.fRenderTarget);
1548
1549 flushStencil();
1550
1551 fHWDrawState.fFlagBits = fCurrDrawState.fFlagBits;
1552}
1553
1554void GrGpuGL::notifyVertexBufferBind(const GrGLVertexBuffer* buffer) {
1555 fHWGeometryState.fVertexBuffer = buffer;
1556}
1557
1558void GrGpuGL::notifyVertexBufferDelete(const GrGLVertexBuffer* buffer) {
1559 GrAssert(!(kBuffer_GeometrySrcType == fGeometrySrc.fVertexSrc &&
1560 buffer == fGeometrySrc.fVertexBuffer));
1561
1562 if (fHWGeometryState.fVertexBuffer == buffer) {
1563 // deleting bound buffer does implied bind to 0
1564 fHWGeometryState.fVertexBuffer = NULL;
1565 }
1566}
1567
1568void GrGpuGL::notifyIndexBufferBind(const GrGLIndexBuffer* buffer) {
1569 fGeometrySrc.fIndexBuffer = buffer;
1570}
1571
1572void GrGpuGL::notifyIndexBufferDelete(const GrGLIndexBuffer* buffer) {
1573 GrAssert(!(kBuffer_GeometrySrcType == fGeometrySrc.fIndexSrc &&
1574 buffer == fGeometrySrc.fIndexBuffer));
1575
1576 if (fHWGeometryState.fIndexBuffer == buffer) {
1577 // deleting bound buffer does implied bind to 0
1578 fHWGeometryState.fIndexBuffer = NULL;
1579 }
1580}
1581
1582void GrGpuGL::notifyTextureBind(GrGLTexture* texture) {
1583 fHWDrawState.fTexture = texture;
1584#if GR_COLLECT_STATS
1585 ++fStats.fTextureChngCnt;
1586#endif
1587}
1588
1589void GrGpuGL::notifyRenderTargetDelete(GrRenderTarget* renderTarget) {
1590 GrAssert(NULL != renderTarget);
1591
1592 // if the bound FBO is destroyed we can't rely on the implicit bind to 0
1593 // a) we want the default RT which may not be FBO 0
1594 // b) we set more state than just FBO based on the RT
1595 // So trash the HW state to force an RT flush next time
1596 if (fCurrDrawState.fRenderTarget == renderTarget) {
reed@google.com1fcd51e2011-01-05 15:50:27 +00001597 fCurrDrawState.fRenderTarget = fDefaultRenderTarget;
reed@google.comac10a2d2010-12-22 21:39:39 +00001598 }
1599 if (fHWDrawState.fRenderTarget == renderTarget) {
1600 fHWDrawState.fRenderTarget = NULL;
1601 }
1602 if (fClipState.fStencilClipTarget == renderTarget) {
1603 fClipState.fStencilClipTarget = NULL;
1604 }
1605}
1606
1607void GrGpuGL::notifyTextureDelete(GrGLTexture* texture) {
1608 if (fCurrDrawState.fTexture == texture) {
1609 fCurrDrawState.fTexture = NULL;
1610 }
1611 if (fHWDrawState.fTexture == texture) {
1612 // deleting bound texture does implied bind to 0
1613 fHWDrawState.fTexture = NULL;
1614 }
1615}
1616
1617void GrGpuGL::notifyTextureRemoveRenderTarget(GrGLTexture* texture) {
1618 GrAssert(NULL != texture->asRenderTarget());
1619
1620 // if there is a pending resolve, perform it.
1621 resolveTextureRenderTarget(texture);
1622}
1623
1624bool GrGpuGL::canBeTexture(GrTexture::PixelConfig config,
1625 GLenum* internalFormat,
1626 GLenum* format,
1627 GLenum* type) {
1628 switch (config) {
1629 case GrTexture::kRGBA_8888_PixelConfig:
1630 case GrTexture::kRGBX_8888_PixelConfig: // todo: can we tell it our X?
1631 *format = SK_GL_32BPP_COLOR_FORMAT;
1632 *internalFormat = GL_RGBA;
1633 *type = GL_UNSIGNED_BYTE;
1634 break;
1635 case GrTexture::kRGB_565_PixelConfig:
1636 *format = GL_RGB;
1637 *internalFormat = GL_RGB;
1638 *type = GL_UNSIGNED_SHORT_5_6_5;
1639 break;
1640 case GrTexture::kRGBA_4444_PixelConfig:
1641 *format = GL_RGBA;
1642 *internalFormat = GL_RGBA;
1643 *type = GL_UNSIGNED_SHORT_4_4_4_4;
1644 break;
1645 case GrTexture::kIndex_8_PixelConfig:
1646 if (this->supports8BitPalette()) {
1647 *format = GR_PALETTE8_RGBA8;
1648 *internalFormat = GR_PALETTE8_RGBA8;
1649 *type = GL_UNSIGNED_BYTE; // unused I think
1650 } else {
1651 return false;
1652 }
1653 break;
1654 case GrTexture::kAlpha_8_PixelConfig:
1655 *format = GL_ALPHA;
1656 *internalFormat = GL_ALPHA;
1657 *type = GL_UNSIGNED_BYTE;
1658 break;
1659 default:
1660 return false;
1661 }
1662 return true;
1663}
1664
1665/* On ES the internalFormat and format must match for TexImage and we use
1666 GL_RGB, GL_RGBA for color formats. We also generally like having the driver
1667 decide the internalFormat. However, on ES internalFormat for
1668 RenderBufferStorage* has to be a specific format (not a base format like
1669 GL_RGBA).
1670 */
1671bool GrGpuGL::fboInternalFormat(GrTexture::PixelConfig config, GLenum* format) {
1672 switch (config) {
1673 case GrTexture::kRGBA_8888_PixelConfig:
1674 case GrTexture::kRGBX_8888_PixelConfig:
1675 if (fRGBA8Renderbuffer) {
1676 *format = GR_RGBA8;
1677 return true;
1678 } else {
1679 return false;
1680 }
1681#if GR_GL_ES // ES2 supports 565. ES1 supports it with FBO extension
1682 // desktop GL has no such internal format
1683 case GrTexture::kRGB_565_PixelConfig:
1684 *format = GR_RGB565;
1685 return true;
1686#endif
1687 case GrTexture::kRGBA_4444_PixelConfig:
1688 *format = GL_RGBA4;
1689 return true;
1690 default:
1691 return false;
1692 }
1693}
1694
1695///////////////////////////////////////////////////////////////////////////////
1696
1697void GrGLCheckErr(const char* location, const char* call) {
1698 uint32_t err = glGetError();
1699 if (GL_NO_ERROR != err) {
1700 GrPrintf("---- glGetError %x", err);
1701 if (NULL != location) {
1702 GrPrintf(" at\n\t%s", location);
1703 }
1704 if (NULL != call) {
1705 GrPrintf("\n\t\t%s", call);
1706 }
1707 GrPrintf("\n");
1708 }
1709}
1710
1711///////////////////////////////////////////////////////////////////////////////
1712
1713typedef void (*glProc)(void);
1714
1715void get_gl_proc(const char procName[], glProc *address) {
1716#if GR_WIN32_BUILD
1717 *address = wglGetProcAddress(procName);
1718 GrAssert(NULL != *address);
1719#elif GR_MAC_BUILD || GR_IOS_BUILD
1720 GrAssert(!"Extensions don't need to be initialized!");
1721#elif GR_ANDROID_BUILD
1722 *address = eglGetProcAddress(procName);
1723 GrAssert(NULL != *address);
1724#elif GR_LINUX_BUILD
reed@google.com37df17d2010-12-23 20:20:51 +00001725// GR_STATIC_ASSERT(!"Add environment-dependent implementation here");
reed@google.comac10a2d2010-12-22 21:39:39 +00001726 //*address = glXGetProcAddressARB(procName);
reed@google.com37df17d2010-12-23 20:20:51 +00001727 *address = NULL;//eglGetProcAddress(procName);
reed@google.comac10a2d2010-12-22 21:39:39 +00001728#elif GR_QNX_BUILD
1729 *address = eglGetProcAddress(procName);
1730 GrAssert(NULL != *address);
1731#else
1732 // hopefully we're on a system with EGL
1733 *address = eglGetProcAddress(procName);
1734 GrAssert(NULL != *address);
1735#endif
1736}
1737
1738#define GET_PROC(EXT_STRUCT, PROC_NAME, EXT_TAG) \
1739 get_gl_proc("gl" #PROC_NAME #EXT_TAG, (glProc*)&EXT_STRUCT-> PROC_NAME);
1740
1741extern void GrGLInitExtensions(GrGLExts* exts) {
1742 exts->GenFramebuffers = NULL;
1743 exts->BindFramebuffer = NULL;
1744 exts->FramebufferTexture2D = NULL;
1745 exts->CheckFramebufferStatus = NULL;
1746 exts->DeleteFramebuffers = NULL;
1747 exts->RenderbufferStorage = NULL;
1748 exts->GenRenderbuffers = NULL;
1749 exts->DeleteRenderbuffers = NULL;
1750 exts->FramebufferRenderbuffer = NULL;
1751 exts->BindRenderbuffer = NULL;
1752 exts->RenderbufferStorageMultisample = NULL;
1753 exts->BlitFramebuffer = NULL;
1754 exts->ResolveMultisampleFramebuffer = NULL;
1755 exts->FramebufferTexture2DMultisample = NULL;
1756 exts->MapBuffer = NULL;
1757 exts->UnmapBuffer = NULL;
1758
1759#if GR_MAC_BUILD
1760 exts->GenFramebuffers = glGenFramebuffers;
1761 exts->BindFramebuffer = glBindFramebuffer;
1762 exts->FramebufferTexture2D = glFramebufferTexture2D;
1763 exts->CheckFramebufferStatus = glCheckFramebufferStatus;
1764 exts->DeleteFramebuffers = glDeleteFramebuffers;
1765 exts->RenderbufferStorage = glRenderbufferStorage;
1766 exts->GenRenderbuffers = glGenRenderbuffers;
1767 exts->DeleteRenderbuffers = glDeleteRenderbuffers;
1768 exts->FramebufferRenderbuffer = glFramebufferRenderbuffer;
1769 exts->BindRenderbuffer = glBindRenderbuffer;
1770 exts->RenderbufferStorageMultisample = glRenderbufferStorageMultisample;
1771 exts->BlitFramebuffer = glBlitFramebuffer;
1772 exts->MapBuffer = glMapBuffer;
1773 exts->UnmapBuffer = glUnmapBuffer;
1774#elif GR_IOS_BUILD
1775 exts->GenFramebuffers = glGenFramebuffers;
1776 exts->BindFramebuffer = glBindFramebuffer;
1777 exts->FramebufferTexture2D = glFramebufferTexture2D;
1778 exts->CheckFramebufferStatus = glCheckFramebufferStatus;
1779 exts->DeleteFramebuffers = glDeleteFramebuffers;
1780 exts->RenderbufferStorage = glRenderbufferStorage;
1781 exts->GenRenderbuffers = glGenRenderbuffers;
1782 exts->DeleteRenderbuffers = glDeleteRenderbuffers;
1783 exts->FramebufferRenderbuffer = glFramebufferRenderbuffer;
1784 exts->BindRenderbuffer = glBindRenderbuffer;
1785 exts->RenderbufferStorageMultisample = glRenderbufferStorageMultisampleAPPLE;
1786 exts->ResolveMultisampleFramebuffer = glResolveMultisampleFramebufferAPPLE;
1787 exts->MapBuffer = glMapBufferOES;
1788 exts->UnmapBuffer = glUnmapBufferOES;
1789#else
1790 GLint major, minor;
1791 gl_version(&major, &minor);
1792 #if GR_GL_DESKTOP
1793 if (major >= 3) {// FBO, FBOMS, and FBOBLIT part of 3.0
1794 exts->GenFramebuffers = glGenFramebuffers;
1795 exts->BindFramebuffer = glBindFramebuffer;
1796 exts->FramebufferTexture2D = glFramebufferTexture2D;
1797 exts->CheckFramebufferStatus = glCheckFramebufferStatus;
1798 exts->DeleteFramebuffers = glDeleteFramebuffers;
1799 exts->RenderbufferStorage = glRenderbufferStorage;
1800 exts->GenRenderbuffers = glGenRenderbuffers;
1801 exts->DeleteRenderbuffers = glDeleteRenderbuffers;
1802 exts->FramebufferRenderbuffer = glFramebufferRenderbuffer;
1803 exts->BindRenderbuffer = glBindRenderbuffer;
1804 exts->RenderbufferStorageMultisample = glRenderbufferStorageMultisample;
1805 exts->BlitFramebuffer = glBlitFramebuffer;
1806 } else if (has_gl_extension("GL_ARB_framebuffer_object")) {
1807 GET_PROC(exts, GenFramebuffers, ARB);
1808 GET_PROC(exts, BindFramebuffer, ARB);
1809 GET_PROC(exts, FramebufferTexture2D, ARB);
1810 GET_PROC(exts, CheckFramebufferStatus, ARB);
1811 GET_PROC(exts, DeleteFramebuffers, ARB);
1812 GET_PROC(exts, RenderbufferStorage, ARB);
1813 GET_PROC(exts, GenRenderbuffers, ARB);
1814 GET_PROC(exts, DeleteRenderbuffers, ARB);
1815 GET_PROC(exts, FramebufferRenderbuffer, ARB);
1816 GET_PROC(exts, BindRenderbuffer, ARB);
1817 GET_PROC(exts, RenderbufferStorageMultisample, ARB);
1818 GET_PROC(exts, BlitFramebuffer, ARB);
1819 } else {
1820 // we require some form of FBO
1821 GrAssert(has_gl_extension("GL_EXT_framebuffer_object"));
1822 GET_PROC(exts, GenFramebuffers, EXT);
1823 GET_PROC(exts, BindFramebuffer, EXT);
1824 GET_PROC(exts, FramebufferTexture2D, EXT);
1825 GET_PROC(exts, CheckFramebufferStatus, EXT);
1826 GET_PROC(exts, DeleteFramebuffers, EXT);
1827 GET_PROC(exts, RenderbufferStorage, EXT);
1828 GET_PROC(exts, GenRenderbuffers, EXT);
1829 GET_PROC(exts, DeleteRenderbuffers, EXT);
1830 GET_PROC(exts, FramebufferRenderbuffer, EXT);
1831 GET_PROC(exts, BindRenderbuffer, EXT);
1832 if (has_gl_extension("GL_EXT_framebuffer_multisample")) {
1833 GET_PROC(exts, RenderbufferStorageMultisample, EXT);
1834 }
1835 if (has_gl_extension("GL_EXT_framebuffer_blit")) {
1836 GET_PROC(exts, BlitFramebuffer, EXT);
1837 }
1838 }
1839 // we assume we have at least GL 1.5 or higher (VBOs introduced in 1.5)
1840 exts->MapBuffer = glMapBuffer;
1841 exts->UnmapBuffer = glUnmapBuffer;
1842 #else // !GR_GL_DESKTOP
1843 if (major >= 2) {// ES 2.0 supports FBO
1844 exts->GenFramebuffers = glGenFramebuffers;
1845 exts->BindFramebuffer = glBindFramebuffer;
1846 exts->FramebufferTexture2D = glFramebufferTexture2D;
1847 exts->CheckFramebufferStatus = glCheckFramebufferStatus;
1848 exts->DeleteFramebuffers = glDeleteFramebuffers;
1849 exts->RenderbufferStorage = glRenderbufferStorage;
1850 exts->GenRenderbuffers = glGenRenderbuffers;
1851 exts->DeleteRenderbuffers = glDeleteRenderbuffers;
1852 exts->FramebufferRenderbuffer = glFramebufferRenderbuffer;
1853 exts->BindRenderbuffer = glBindRenderbuffer;
1854 } else {
1855 // we require some form of FBO
1856 GrAssert(has_gl_extension("GL_OES_framebuffer_object"));
1857
1858 GET_PROC(exts, GenFramebuffers, OES);
1859 GET_PROC(exts, BindFramebuffer, OES);
1860 GET_PROC(exts, FramebufferTexture2D, OES);
1861 GET_PROC(exts, CheckFramebufferStatus, OES);
1862 GET_PROC(exts, DeleteFramebuffers, OES);
1863 GET_PROC(exts, RenderbufferStorage, OES);
1864 GET_PROC(exts, GenRenderbuffers, OES);
1865 GET_PROC(exts, DeleteRenderbuffers, OES);
1866 GET_PROC(exts, FramebufferRenderbuffer, OES);
1867 GET_PROC(exts, BindRenderbuffer, OES);
1868 }
1869 if (has_gl_extension("GL_APPLE_framebuffer_multisample")) {
1870 GET_PROC(exts, ResolveMultisampleFramebuffer, APPLE);
1871 }
1872 if (has_gl_extension("GL_IMG_multisampled_render_to_texture")) {
1873 GET_PROC(exts, FramebufferTexture2DMultisample, IMG);
1874 }
1875 if (has_gl_extension("GL_OES_mapbuffer")) {
1876 GET_PROC(exts, MapBuffer, OES);
1877 GET_PROC(exts, UnmapBuffer, OES);
1878 }
1879 #endif // !GR_GL_DESKTOP
1880#endif // BUILD
1881}
1882
1883bool gPrintGL = true;
1884