blob: 2574b157a6e251607fb8f8682812fb04726c8e5d [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"
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +000019#if GR_WIN32_BUILD
20 // need to get wglGetProcAddress
21 #undef WIN32_LEAN_AND_MEAN
22 #define WIN32_LEAN_AND_MEAN 1
23 #include <windows.h>
24 #undef WIN32_LEAN_AND_MEAN
25#endif
26
reed@google.comac10a2d2010-12-22 21:39:39 +000027
28static const GLuint GR_MAX_GLUINT = ~0;
29static const GLint GR_INVAL_GLINT = ~0;
30
bsalomon@google.com316f99232011-01-13 21:28:12 +000031// we use a spare texture unit to avoid
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000032// mucking with the state of any of the stages.
bsalomon@google.com316f99232011-01-13 21:28:12 +000033static const int SPARE_TEX_UNIT = GrGpuGL::kNumStages;
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000034
reed@google.comac10a2d2010-12-22 21:39:39 +000035#define SKIP_CACHE_CHECK true
36
37static const GLenum gXfermodeCoeff2Blend[] = {
38 GL_ZERO,
39 GL_ONE,
40 GL_SRC_COLOR,
41 GL_ONE_MINUS_SRC_COLOR,
42 GL_DST_COLOR,
43 GL_ONE_MINUS_DST_COLOR,
44 GL_SRC_ALPHA,
45 GL_ONE_MINUS_SRC_ALPHA,
46 GL_DST_ALPHA,
47 GL_ONE_MINUS_DST_ALPHA,
48};
49
reed@google.comac10a2d2010-12-22 21:39:39 +000050///////////////////////////////////////////////////////////////////////////////
51
bsalomon@google.comd302f142011-03-03 13:54:13 +000052void GrGpuGL::AdjustTextureMatrix(const GrGLTexture* texture,
53 GrSamplerState::SampleMode mode,
bsalomon@google.comc6cf7232011-02-17 16:43:10 +000054 GrMatrix* matrix) {
55 GrAssert(NULL != texture);
56 GrAssert(NULL != matrix);
57 if (GR_Scalar1 != texture->contentScaleX() ||
58 GR_Scalar1 != texture->contentScaleY()) {
59 if (GrSamplerState::kRadial_SampleMode == mode) {
60 GrMatrix scale;
61 scale.setScale(texture->contentScaleX(), texture->contentScaleX());
62 matrix->postConcat(scale);
63 } else if (GrSamplerState::kNormal_SampleMode == mode) {
64 GrMatrix scale;
65 scale.setScale(texture->contentScaleX(), texture->contentScaleY());
66 matrix->postConcat(scale);
67 } else {
68 GrPrintf("We haven't handled NPOT adjustment for other sample modes!");
69 }
70 }
71 GrGLTexture::Orientation orientation = texture->orientation();
72 if (GrGLTexture::kBottomUp_Orientation == orientation) {
73 GrMatrix invY;
74 invY.setAll(GR_Scalar1, 0, 0,
75 0, -GR_Scalar1, GR_Scalar1,
76 0, 0, GrMatrix::I()[8]);
77 matrix->postConcat(invY);
78 } else {
79 GrAssert(GrGLTexture::kTopDown_Orientation == orientation);
80 }
81}
82
bsalomon@google.comd302f142011-03-03 13:54:13 +000083bool GrGpuGL::TextureMatrixIsIdentity(const GrGLTexture* texture,
bsalomon@google.comc6cf7232011-02-17 16:43:10 +000084 const GrSamplerState& sampler) {
85 GrAssert(NULL != texture);
86 if (!sampler.getMatrix().isIdentity()) {
87 return false;
88 }
89 if (GR_Scalar1 != texture->contentScaleX() ||
90 GR_Scalar1 != texture->contentScaleY()) {
91 return false;
92 }
93 GrGLTexture::Orientation orientation = texture->orientation();
94 if (GrGLTexture::kBottomUp_Orientation == orientation) {
95 return false;
96 } else {
97 GrAssert(GrGLTexture::kTopDown_Orientation == orientation);
98 }
99 return true;
100}
101
102///////////////////////////////////////////////////////////////////////////////
103
bsalomon@google.com42ab7ea2011-01-19 17:19:40 +0000104static bool gPrintStartupSpew;
105
106
bsalomon@google.comd302f142011-03-03 13:54:13 +0000107static bool fbo_test(GrGLExts exts, int w, int h) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000108
109 GLint savedFBO;
110 GLint savedTexUnit;
reed@google.com3d8de042011-01-20 02:18:00 +0000111 GR_GL_GetIntegerv(GL_ACTIVE_TEXTURE, &savedTexUnit);
112 GR_GL_GetIntegerv(GR_FRAMEBUFFER_BINDING, &savedFBO);
bsalomon@google.com316f99232011-01-13 21:28:12 +0000113
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000114 GR_GL(ActiveTexture(GL_TEXTURE0 + SPARE_TEX_UNIT));
bsalomon@google.com316f99232011-01-13 21:28:12 +0000115
reed@google.comac10a2d2010-12-22 21:39:39 +0000116 GLuint testFBO;
117 GR_GLEXT(exts, GenFramebuffers(1, &testFBO));
118 GR_GLEXT(exts, BindFramebuffer(GR_FRAMEBUFFER, testFBO));
119 GLuint testRTTex;
120 GR_GL(GenTextures(1, &testRTTex));
121 GR_GL(BindTexture(GL_TEXTURE_2D, testRTTex));
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000122 // some implementations require texture to be mip-map complete before
123 // FBO with level 0 bound as color attachment will be framebuffer complete.
124 GR_GL(TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
reed@google.comac10a2d2010-12-22 21:39:39 +0000125 GR_GL(TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h,
126 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL));
127 GR_GL(BindTexture(GL_TEXTURE_2D, 0));
128 GR_GLEXT(exts, FramebufferTexture2D(GR_FRAMEBUFFER, GR_COLOR_ATTACHMENT0,
129 GL_TEXTURE_2D, testRTTex, 0));
130 GLenum status = GR_GLEXT(exts, CheckFramebufferStatus(GR_FRAMEBUFFER));
131 GR_GLEXT(exts, DeleteFramebuffers(1, &testFBO));
132 GR_GL(DeleteTextures(1, &testRTTex));
bsalomon@google.com316f99232011-01-13 21:28:12 +0000133
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000134 GR_GL(ActiveTexture(savedTexUnit));
135 GR_GLEXT(exts, BindFramebuffer(GR_FRAMEBUFFER, savedFBO));
bsalomon@google.com316f99232011-01-13 21:28:12 +0000136
reed@google.comac10a2d2010-12-22 21:39:39 +0000137 return status == GR_FRAMEBUFFER_COMPLETE;
138}
139
reed@google.comac10a2d2010-12-22 21:39:39 +0000140GrGpuGL::GrGpuGL() {
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000141
reed@google.comeeeb5a02010-12-23 15:12:59 +0000142 if (gPrintStartupSpew) {
143 GrPrintf("------------------------- create GrGpuGL %p --------------\n",
144 this);
145 GrPrintf("------ VENDOR %s\n", glGetString(GL_VENDOR));
146 GrPrintf("------ RENDERER %s\n", glGetString(GL_RENDERER));
147 GrPrintf("------ VERSION %s\n", glGetString(GL_VERSION));
148 GrPrintf("------ EXTENSIONS\n %s \n", glGetString(GL_EXTENSIONS));
149 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000150
151 GrGLClearErr();
152
153 GrGLInitExtensions(&fExts);
154
155 resetContextHelper();
156
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000157 resetDirtyFlags();
bsalomon@google.com316f99232011-01-13 21:28:12 +0000158
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000159 GLint maxTextureUnits;
160 // check FS and fixed-function texture unit limits
161 // we only use textures in the fragment stage currently.
162 // checks are > to make sure we have a spare unit.
163#if GR_SUPPORT_GLDESKTOP || GR_SUPPORT_GLES2
reed@google.com3d8de042011-01-20 02:18:00 +0000164 GR_GL_GetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000165 GrAssert(maxTextureUnits > kNumStages);
166#endif
167#if GR_SUPPORT_GLDESKTOP || GR_SUPPORT_GLES1
reed@google.com3d8de042011-01-20 02:18:00 +0000168 GR_GL_GetIntegerv(GL_MAX_TEXTURE_UNITS, &maxTextureUnits);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000169 GrAssert(maxTextureUnits > kNumStages);
170#endif
bsalomon@google.com316f99232011-01-13 21:28:12 +0000171
reed@google.comac10a2d2010-12-22 21:39:39 +0000172 ////////////////////////////////////////////////////////////////////////////
173 // Check for supported features.
174
175 int major, minor;
176 gl_version(&major, &minor);
177
178 GLint numFormats;
reed@google.comac20fb92011-01-12 17:14:53 +0000179 GR_GL_GetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &numFormats);
reed@google.comac10a2d2010-12-22 21:39:39 +0000180 GrAutoSTMalloc<10, GLint> formats(numFormats);
reed@google.comac20fb92011-01-12 17:14:53 +0000181 GR_GL_GetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, formats);
reed@google.comac10a2d2010-12-22 21:39:39 +0000182 for (int i = 0; i < numFormats; ++i) {
183 if (formats[i] == GR_PALETTE8_RGBA8) {
184 f8bitPaletteSupport = true;
185 break;
186 }
187 }
reed@google.comeeeb5a02010-12-23 15:12:59 +0000188
189 if (gPrintStartupSpew) {
190 GrPrintf("Palette8 support: %s\n", (f8bitPaletteSupport ? "YES" : "NO"));
191 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000192
193 GR_STATIC_ASSERT(0 == kNone_AALevel);
194 GR_STATIC_ASSERT(1 == kLow_AALevel);
195 GR_STATIC_ASSERT(2 == kMed_AALevel);
196 GR_STATIC_ASSERT(3 == kHigh_AALevel);
197
198 memset(fAASamples, 0, sizeof(fAASamples));
199 fMSFBOType = kNone_MSFBO;
200 if (has_gl_extension("GL_IMG_multisampled_render_to_texture")) {
201 fMSFBOType = kIMG_MSFBO;
reed@google.comeeeb5a02010-12-23 15:12:59 +0000202 if (gPrintStartupSpew) {
203 GrPrintf("MSAA Support: IMG ES EXT.\n");
204 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000205 }
206 else if (has_gl_extension("GL_APPLE_framebuffer_multisample")) {
207 fMSFBOType = kApple_MSFBO;
reed@google.comeeeb5a02010-12-23 15:12:59 +0000208 if (gPrintStartupSpew) {
209 GrPrintf("MSAA Support: APPLE ES EXT.\n");
210 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000211 }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000212#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000213 else if ((major >= 3) ||
214 has_gl_extension("GL_ARB_framebuffer_object") ||
215 (has_gl_extension("GL_EXT_framebuffer_multisample") &&
216 has_gl_extension("GL_EXT_framebuffer_blit"))) {
217 fMSFBOType = kDesktop_MSFBO;
reed@google.comeeeb5a02010-12-23 15:12:59 +0000218 if (gPrintStartupSpew) {
219 GrPrintf("MSAA Support: DESKTOP\n");
220 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000221 }
222#endif
223 else {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000224 if (gPrintStartupSpew) {
225 GrPrintf("MSAA Support: NONE\n");
226 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000227 }
228
229 if (kNone_MSFBO != fMSFBOType) {
230 GLint maxSamples;
231 GLenum maxSampleGetter = (kIMG_MSFBO == fMSFBOType) ?
232 GR_MAX_SAMPLES_IMG :
233 GR_MAX_SAMPLES;
reed@google.comac20fb92011-01-12 17:14:53 +0000234 GR_GL_GetIntegerv(maxSampleGetter, &maxSamples);
reed@google.comac10a2d2010-12-22 21:39:39 +0000235 if (maxSamples > 1 ) {
236 fAASamples[kNone_AALevel] = 0;
237 fAASamples[kLow_AALevel] = GrMax(2,
238 GrFixedFloorToInt((GR_FixedHalf) *
239 maxSamples));
240 fAASamples[kMed_AALevel] = GrMax(2,
241 GrFixedFloorToInt(((GR_Fixed1*3)/4) *
242 maxSamples));
243 fAASamples[kHigh_AALevel] = maxSamples;
244 }
reed@google.comeeeb5a02010-12-23 15:12:59 +0000245 if (gPrintStartupSpew) {
246 GrPrintf("\tMax Samples: %d\n", maxSamples);
247 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000248 }
249
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000250#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000251 fHasStencilWrap = (major >= 2 || (major == 1 && minor >= 4)) ||
252 has_gl_extension("GL_EXT_stencil_wrap");
253#else
254 fHasStencilWrap = (major >= 2) || has_gl_extension("GL_OES_stencil_wrap");
255#endif
reed@google.comeeeb5a02010-12-23 15:12:59 +0000256 if (gPrintStartupSpew) {
257 GrPrintf("Stencil Wrap: %s\n", (fHasStencilWrap ? "YES" : "NO"));
258 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000259
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000260#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000261 // we could also look for GL_ATI_separate_stencil extension or
262 // GL_EXT_stencil_two_side but they use different function signatures
263 // than GL2.0+ (and than each other).
bsalomon@google.comd302f142011-03-03 13:54:13 +0000264 fTwoSidedStencilSupport = (major >= 2);
265 // supported on GL 1.4 and higher or by extension
266 fStencilWrapOpsSupport = (major > 1) ||
267 (1 == major) && (minor >= 4) ||
268 has_gl_extension("GL_EXT_stencil_wrap");
reed@google.comac10a2d2010-12-22 21:39:39 +0000269#else
270 // ES 2 has two sided stencil but 1.1 doesn't. There doesn't seem to be
271 // an ES1 extension.
bsalomon@google.comd302f142011-03-03 13:54:13 +0000272 fTwoSidedStencilSupport = (major >= 2);
273 // stencil wrap support is in ES2, ES1 requires extension.
274 fStencilWrapOpsSupport = (major > 1) ||
275 has_gl_extension("GL_OES_stencil_wrap");
276
reed@google.comac10a2d2010-12-22 21:39:39 +0000277#endif
reed@google.comeeeb5a02010-12-23 15:12:59 +0000278 if (gPrintStartupSpew) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000279 GrPrintf("Stencil Caps: TwoSide: %s, Wrap: %s\n",
280 (fTwoSidedStencilSupport ? "YES" : "NO"),
281 (fStencilWrapOpsSupport ? "YES" : "NO"));
reed@google.comeeeb5a02010-12-23 15:12:59 +0000282 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000283
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000284#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000285 fRGBA8Renderbuffer = true;
286#else
287 fRGBA8Renderbuffer = has_gl_extension("GL_OES_rgb8_rgba8");
288#endif
reed@google.comeeeb5a02010-12-23 15:12:59 +0000289 if (gPrintStartupSpew) {
290 GrPrintf("RGBA Renderbuffer: %s\n", (fRGBA8Renderbuffer ? "YES" : "NO"));
291 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000292
bsalomon@google.comed3a0682011-01-18 16:54:04 +0000293#if GR_SUPPORT_GLES
294 if (GR_GL_32BPP_COLOR_FORMAT == GR_BGRA) {
295 GrAssert(has_gl_extension("GL_EXT_texture_format_BGRA8888"));
296 }
297#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000298
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000299#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000300 fBufferLockSupport = true; // we require VBO support and the desktop VBO
301 // extension includes glMapBuffer.
302#else
303 fBufferLockSupport = has_gl_extension("GL_OES_mapbuffer");
304#endif
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000305
reed@google.comeeeb5a02010-12-23 15:12:59 +0000306 if (gPrintStartupSpew) {
307 GrPrintf("Map Buffer: %s\n", (fBufferLockSupport ? "YES" : "NO"));
308 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000309
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000310#if GR_SUPPORT_GLDESKTOP
bsalomon@google.com0748f212011-02-01 22:56:16 +0000311 if (major >= 2 || has_gl_extension("GL_ARB_texture_non_power_of_two")) {
312 fNPOTTextureTileSupport = true;
313 fNPOTTextureSupport = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000314 } else {
bsalomon@google.com0748f212011-02-01 22:56:16 +0000315 fNPOTTextureTileSupport = false;
316 fNPOTTextureSupport = false;
317 }
318#else
319 if (major >= 2) {
320 fNPOTTextureSupport = true;
321 fNPOTTextureTileSupport = has_gl_extension("GL_OES_texture_npot");
322 } else {
323 fNPOTTextureSupport = has_gl_extension("GL_APPLE_texture_2D_limited_npot");
324 fNPOTTextureTileSupport = false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000325 }
326#endif
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000327
reed@google.comac10a2d2010-12-22 21:39:39 +0000328 ////////////////////////////////////////////////////////////////////////////
329 // Experiments to determine limitations that can't be queried. TODO: Make
330 // these a preprocess that generate some compile time constants.
331
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000332 // sanity check to make sure we can at least create an FBO from a POT texture
bsalomon@google.com18908aa2011-02-07 14:51:55 +0000333
bsalomon@google.com0748f212011-02-01 22:56:16 +0000334 bool simpleFBOSuccess = fbo_test(fExts, 128, 128);
335 if (gPrintStartupSpew) {
336 if (!simpleFBOSuccess) {
337 GrPrintf("FBO Sanity Test: FAILED\n");
338 } else {
339 GrPrintf("FBO Sanity Test: PASSED\n");
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000340 }
341 }
bsalomon@google.com0748f212011-02-01 22:56:16 +0000342 GrAssert(simpleFBOSuccess);
reed@google.comac20fb92011-01-12 17:14:53 +0000343
reed@google.comac10a2d2010-12-22 21:39:39 +0000344 /* Experimentation has found that some GLs that support NPOT textures
345 do not support FBOs with a NPOT texture. They report "unsupported" FBO
346 status. I don't know how to explicitly query for this. Do an
347 experiment. Note they may support NPOT with a renderbuffer but not a
348 texture. Presumably, the implementation bloats the renderbuffer
349 internally to the next POT.
350 */
bsalomon@google.com0748f212011-02-01 22:56:16 +0000351 bool fNPOTRenderTargetSupport = false;
352 if (fNPOTTextureSupport) {
353 fNPOTRenderTargetSupport = fbo_test(fExts, 200, 200);
354 }
bsalomon@google.com18908aa2011-02-07 14:51:55 +0000355
bsalomon@google.com0748f212011-02-01 22:56:16 +0000356 if (gPrintStartupSpew) {
357 if (fNPOTTextureSupport) {
358 GrPrintf("NPOT textures supported\n");
359 if (fNPOTTextureTileSupport) {
360 GrPrintf("NPOT texture tiling supported\n");
361 } else {
362 GrPrintf("NPOT texture tiling NOT supported\n");
363 }
364 if (fNPOTRenderTargetSupport) {
365 GrPrintf("NPOT render targets supported\n");
366 } else {
367 GrPrintf("NPOT render targets NOT supported\n");
reed@google.comeeeb5a02010-12-23 15:12:59 +0000368 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000369 } else {
bsalomon@google.com0748f212011-02-01 22:56:16 +0000370 GrPrintf("NPOT textures NOT supported\n");
reed@google.comeeeb5a02010-12-23 15:12:59 +0000371 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000372 }
373
reed@google.comac10a2d2010-12-22 21:39:39 +0000374 /* The iPhone 4 has a restriction that for an FBO with texture color
375 attachment with height <= 8 then the width must be <= height. Here
376 we look for such a limitation.
377 */
378 fMinRenderTargetHeight = GR_INVAL_GLINT;
379 GLint maxRenderSize;
reed@google.comac20fb92011-01-12 17:14:53 +0000380 GR_GL_GetIntegerv(GR_MAX_RENDERBUFFER_SIZE, &maxRenderSize);
reed@google.comac10a2d2010-12-22 21:39:39 +0000381
reed@google.comeeeb5a02010-12-23 15:12:59 +0000382 if (gPrintStartupSpew) {
383 GrPrintf("Small height FBO texture experiments\n");
384 }
bsalomon@google.com0748f212011-02-01 22:56:16 +0000385
386 for (GLuint i = 1; i <= 256; fNPOTRenderTargetSupport ? ++i : i *= 2) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000387 GLuint w = maxRenderSize;
388 GLuint h = i;
389 if (fbo_test(fExts, w, h)) {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000390 if (gPrintStartupSpew) {
391 GrPrintf("\t[%d, %d]: PASSED\n", w, h);
392 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000393 fMinRenderTargetHeight = i;
394 break;
395 } else {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000396 if (gPrintStartupSpew) {
397 GrPrintf("\t[%d, %d]: FAILED\n", w, h);
398 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000399 }
400 }
401 GrAssert(GR_INVAL_GLINT != fMinRenderTargetHeight);
402
reed@google.comeeeb5a02010-12-23 15:12:59 +0000403 if (gPrintStartupSpew) {
404 GrPrintf("Small width FBO texture experiments\n");
405 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000406 fMinRenderTargetWidth = GR_MAX_GLUINT;
bsalomon@google.com0748f212011-02-01 22:56:16 +0000407 for (GLuint i = 1; i <= 256; fNPOTRenderTargetSupport ? i *= 2 : ++i) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000408 GLuint w = i;
409 GLuint h = maxRenderSize;
410 if (fbo_test(fExts, w, h)) {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000411 if (gPrintStartupSpew) {
412 GrPrintf("\t[%d, %d]: PASSED\n", w, h);
413 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000414 fMinRenderTargetWidth = i;
415 break;
416 } else {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000417 if (gPrintStartupSpew) {
418 GrPrintf("\t[%d, %d]: FAILED\n", w, h);
419 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000420 }
421 }
422 GrAssert(GR_INVAL_GLINT != fMinRenderTargetWidth);
423
reed@google.com02a7e6c2011-01-28 21:21:49 +0000424 GR_GL_GetIntegerv(GL_MAX_TEXTURE_SIZE, &fMaxTextureDimension);
reed@google.comac10a2d2010-12-22 21:39:39 +0000425}
426
427GrGpuGL::~GrGpuGL() {
reed@google.comac10a2d2010-12-22 21:39:39 +0000428}
429
430void GrGpuGL::resetContextHelper() {
431// We detect cases when blending is effectively off
432 fHWBlendDisabled = false;
433 GR_GL(Enable(GL_BLEND));
434
reed@google.comac10a2d2010-12-22 21:39:39 +0000435 GR_GL(Disable(GL_CULL_FACE));
bsalomon@google.comd302f142011-03-03 13:54:13 +0000436 GR_GL(FrontFace(GL_CCW));
437 fHWDrawState.fDrawFace = kBoth_DrawFace;
reed@google.comac10a2d2010-12-22 21:39:39 +0000438
439 GR_GL(Disable(GL_DITHER));
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000440#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000441 GR_GL(Disable(GL_LINE_SMOOTH));
442 GR_GL(Disable(GL_POINT_SMOOTH));
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000443 GR_GL(Disable(GL_MULTISAMPLE));
reed@google.comac10a2d2010-12-22 21:39:39 +0000444#endif
445
bsalomon@google.comd302f142011-03-03 13:54:13 +0000446 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
447 fHWDrawState.fFlagBits = 0;
448
reed@google.comac10a2d2010-12-22 21:39:39 +0000449 // we only ever use lines in hairline mode
450 GR_GL(LineWidth(1));
451
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000452 // invalid
453 fActiveTextureUnitIdx = -1;
reed@google.comac10a2d2010-12-22 21:39:39 +0000454
reed@google.comac10a2d2010-12-22 21:39:39 +0000455 // illegal values
bsalomon@google.comffca4002011-02-22 20:34:01 +0000456 fHWDrawState.fSrcBlend = (GrBlendCoeff)-1;
457 fHWDrawState.fDstBlend = (GrBlendCoeff)-1;
reed@google.comac10a2d2010-12-22 21:39:39 +0000458 fHWDrawState.fColor = GrColor_ILLEGAL;
bsalomon@google.com316f99232011-01-13 21:28:12 +0000459
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000460 fHWDrawState.fViewMatrix = GrMatrix::InvalidMatrix();
bsalomon@google.com316f99232011-01-13 21:28:12 +0000461
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000462 for (int s = 0; s < kNumStages; ++s) {
463 fHWDrawState.fTextures[s] = NULL;
464 fHWDrawState.fSamplerStates[s].setRadial2Params(-GR_ScalarMax,
465 -GR_ScalarMax,
466 true);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000467
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000468 fHWDrawState.fSamplerStates[s].setMatrix(GrMatrix::InvalidMatrix());
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000469 }
bsalomon@google.com316f99232011-01-13 21:28:12 +0000470
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000471 fHWBounds.fScissorRect.invalidate();
reed@google.comac10a2d2010-12-22 21:39:39 +0000472 fHWBounds.fScissorEnabled = false;
473 GR_GL(Disable(GL_SCISSOR_TEST));
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000474 fHWBounds.fViewportRect.invalidate();
reed@google.comac10a2d2010-12-22 21:39:39 +0000475
bsalomon@google.comd302f142011-03-03 13:54:13 +0000476 fHWDrawState.fStencilSettings.invalidate();
reed@google.comac10a2d2010-12-22 21:39:39 +0000477 fHWStencilClip = false;
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000478 fClipState.fClipIsDirty = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000479
480 fHWGeometryState.fIndexBuffer = NULL;
481 fHWGeometryState.fVertexBuffer = NULL;
482 GR_GL(BindBuffer(GL_ARRAY_BUFFER, 0));
483 GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000484 fHWGeometryState.fArrayPtrsDirty = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000485
bsalomon@google.comd302f142011-03-03 13:54:13 +0000486 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
reed@google.comac10a2d2010-12-22 21:39:39 +0000487 fHWDrawState.fRenderTarget = NULL;
488}
489
490void GrGpuGL::resetContext() {
491 INHERITED::resetContext();
492 resetContextHelper();
493}
494
reed@google.comac10a2d2010-12-22 21:39:39 +0000495GrRenderTarget* GrGpuGL::createPlatformRenderTarget(
496 intptr_t platformRenderTarget,
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000497 int stencilBits,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000498 int width,
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000499 int height) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000500 GrGLRenderTarget::GLRenderTargetIDs rtIDs;
501 rtIDs.fStencilRenderbufferID = 0;
502 rtIDs.fMSColorRenderbufferID = 0;
503 rtIDs.fTexFBOID = 0;
504 rtIDs.fOwnIDs = false;
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000505 GrGLIRect viewport;
reed@google.comac10a2d2010-12-22 21:39:39 +0000506
507 // viewport is in GL coords (top >= bottom)
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000508 viewport.fLeft = 0;
509 viewport.fBottom = 0;
510 viewport.fWidth = width;
511 viewport.fHeight = height;
reed@google.comac10a2d2010-12-22 21:39:39 +0000512
513 rtIDs.fRTFBOID = (GLuint)platformRenderTarget;
514 rtIDs.fTexFBOID = (GLuint)platformRenderTarget;
515
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000516 return new GrGLRenderTarget(rtIDs, stencilBits, viewport, NULL, this);
reed@google.comac10a2d2010-12-22 21:39:39 +0000517}
518
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000519GrRenderTarget* GrGpuGL::createRenderTargetFrom3DApiState() {
bsalomon@google.com42ab7ea2011-01-19 17:19:40 +0000520
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000521 GrGLRenderTarget::GLRenderTargetIDs rtIDs;
bsalomon@google.com42ab7ea2011-01-19 17:19:40 +0000522
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000523 GR_GL_GetIntegerv(GR_FRAMEBUFFER_BINDING, (GLint*)&rtIDs.fRTFBOID);
524 rtIDs.fTexFBOID = rtIDs.fRTFBOID;
525 rtIDs.fMSColorRenderbufferID = 0;
526 rtIDs.fStencilRenderbufferID = 0;
bsalomon@google.com42ab7ea2011-01-19 17:19:40 +0000527
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000528 GrGLIRect viewport;
529 viewport.setFromGLViewport();
530 GLuint stencilBits;
531 GR_GL_GetIntegerv(GL_STENCIL_BITS, (GLint*)&stencilBits);
532
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000533 rtIDs.fOwnIDs = false;
534
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000535 return new GrGLRenderTarget(rtIDs, stencilBits, viewport, NULL, this);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000536}
537
bsalomon@google.com5782d712011-01-21 21:03:59 +0000538///////////////////////////////////////////////////////////////////////////////
539
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000540static const GLuint UNKNOWN_BITS = ~0;
541
bsalomon@google.com3f3ffd62011-01-18 17:14:52 +0000542// defines stencil formats from more to less preferred
bsalomon@google.com5d18c382011-02-18 16:21:58 +0000543static const struct {
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000544 GLenum fEnum;
545 GLuint fBits;
546} gStencilFormats[] = {
547 {GR_STENCIL_INDEX8, 8},
reed@google.com63100f92011-01-18 21:32:14 +0000548
549#if GR_SUPPORT_GLDESKTOP
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000550 {GR_STENCIL_INDEX16, 16},
reed@google.com63100f92011-01-18 21:32:14 +0000551#endif
552
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000553 {GR_DEPTH24_STENCIL8, 8},
554 {GR_STENCIL_INDEX4, 4},
reed@google.com63100f92011-01-18 21:32:14 +0000555
556#if GR_SUPPORT_GLDESKTOP
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000557 {GL_STENCIL_INDEX, UNKNOWN_BITS},
558 {GR_DEPTH_STENCIL, UNKNOWN_BITS}
bsalomon@google.com3f3ffd62011-01-18 17:14:52 +0000559#endif
560};
561
562// good to set a break-point here to know when createTexture fails
563static GrTexture* return_null_texture() {
564// GrAssert(!"null texture");
565 return NULL;
566}
567
568#if GR_DEBUG
569static size_t as_size_t(int x) {
570 return x;
571}
572#endif
573
reed@google.comac10a2d2010-12-22 21:39:39 +0000574GrTexture* GrGpuGL::createTexture(const TextureDesc& desc,
575 const void* srcData, size_t rowBytes) {
576
577#if GR_COLLECT_STATS
578 ++fStats.fTextureCreateCnt;
579#endif
reed@google.com1fcd51e2011-01-05 15:50:27 +0000580
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000581 setSpareTextureUnit();
bsalomon@google.com316f99232011-01-13 21:28:12 +0000582
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000583 static const GrGLTexture::TexParams DEFAULT_PARAMS = {
584 GL_NEAREST,
585 GL_CLAMP_TO_EDGE,
586 GL_CLAMP_TO_EDGE
587 };
reed@google.com1fcd51e2011-01-05 15:50:27 +0000588
reed@google.comac10a2d2010-12-22 21:39:39 +0000589 GrGLTexture::GLTextureDesc glDesc;
590 GLenum internalFormat;
591
592 glDesc.fContentWidth = desc.fWidth;
593 glDesc.fContentHeight = desc.fHeight;
594 glDesc.fAllocWidth = desc.fWidth;
595 glDesc.fAllocHeight = desc.fHeight;
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000596 glDesc.fStencilBits = 0;
reed@google.comac10a2d2010-12-22 21:39:39 +0000597 glDesc.fFormat = desc.fFormat;
598
599 bool renderTarget = 0 != (desc.fFlags & kRenderTarget_TextureFlag);
600 if (!canBeTexture(desc.fFormat,
601 &internalFormat,
602 &glDesc.fUploadFormat,
603 &glDesc.fUploadType)) {
604 return return_null_texture();
605 }
606
607 GrAssert(as_size_t(desc.fAALevel) < GR_ARRAY_COUNT(fAASamples));
608 GLint samples = fAASamples[desc.fAALevel];
609 if (kNone_MSFBO == fMSFBOType && desc.fAALevel != kNone_AALevel) {
610 GrPrintf("AA RT requested but not supported on this platform.");
611 }
612
613 GR_GL(GenTextures(1, &glDesc.fTextureID));
614 if (!glDesc.fTextureID) {
615 return return_null_texture();
616 }
617
618 glDesc.fUploadByteCount = GrTexture::BytesPerPixel(desc.fFormat);
619
620 /*
621 * check if our srcData has extra bytes past each row. If so, we need
622 * to trim those off here, since GL doesn't let us pass the rowBytes as
623 * a parameter to glTexImage2D
624 */
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000625#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000626 if (srcData) {
627 GR_GL(PixelStorei(GL_UNPACK_ROW_LENGTH,
628 rowBytes / glDesc.fUploadByteCount));
629 }
630#else
631 GrAutoSMalloc<128 * 128> trimStorage;
632 size_t trimRowBytes = desc.fWidth * glDesc.fUploadByteCount;
633 if (srcData && (trimRowBytes < rowBytes)) {
634 size_t trimSize = desc.fHeight * trimRowBytes;
635 trimStorage.realloc(trimSize);
636 // now copy the data into our new storage, skipping the trailing bytes
637 const char* src = (const char*)srcData;
638 char* dst = (char*)trimStorage.get();
639 for (uint32_t y = 0; y < desc.fHeight; y++) {
640 memcpy(dst, src, trimRowBytes);
641 src += rowBytes;
642 dst += trimRowBytes;
643 }
644 // now point srcData to our trimmed version
645 srcData = trimStorage.get();
646 }
647#endif
648
reed@google.comac10a2d2010-12-22 21:39:39 +0000649 if (renderTarget) {
bsalomon@google.com0748f212011-02-01 22:56:16 +0000650 if (!this->npotRenderTargetSupport()) {
651 glDesc.fAllocWidth = GrNextPow2(desc.fWidth);
652 glDesc.fAllocHeight = GrNextPow2(desc.fHeight);
653 }
654
reed@google.comac10a2d2010-12-22 21:39:39 +0000655 glDesc.fAllocWidth = GrMax<int>(fMinRenderTargetWidth,
656 glDesc.fAllocWidth);
657 glDesc.fAllocHeight = GrMax<int>(fMinRenderTargetHeight,
658 glDesc.fAllocHeight);
bsalomon@google.com0748f212011-02-01 22:56:16 +0000659 } else if (!this->npotTextureSupport()) {
660 glDesc.fAllocWidth = GrNextPow2(desc.fWidth);
661 glDesc.fAllocHeight = GrNextPow2(desc.fHeight);
reed@google.comac10a2d2010-12-22 21:39:39 +0000662 }
663
664 GR_GL(BindTexture(GL_TEXTURE_2D, glDesc.fTextureID));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000665 GR_GL(TexParameteri(GL_TEXTURE_2D,
666 GL_TEXTURE_MAG_FILTER,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000667 DEFAULT_PARAMS.fFilter));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000668 GR_GL(TexParameteri(GL_TEXTURE_2D,
669 GL_TEXTURE_MIN_FILTER,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000670 DEFAULT_PARAMS.fFilter));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000671 GR_GL(TexParameteri(GL_TEXTURE_2D,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000672 GL_TEXTURE_WRAP_S,
673 DEFAULT_PARAMS.fWrapS));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000674 GR_GL(TexParameteri(GL_TEXTURE_2D,
675 GL_TEXTURE_WRAP_T,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000676 DEFAULT_PARAMS.fWrapT));
reed@google.comac10a2d2010-12-22 21:39:39 +0000677
678 GR_GL(PixelStorei(GL_UNPACK_ALIGNMENT, glDesc.fUploadByteCount));
679 if (GrTexture::kIndex_8_PixelConfig == desc.fFormat &&
680 supports8BitPalette()) {
681 // ES only supports CompressedTexImage2D, not CompressedTexSubimage2D
682 GrAssert(desc.fWidth == glDesc.fAllocWidth);
683 GrAssert(desc.fHeight == glDesc.fAllocHeight);
684 GLsizei imageSize = glDesc.fAllocWidth * glDesc.fAllocHeight +
685 kColorTableSize;
686 GR_GL(CompressedTexImage2D(GL_TEXTURE_2D, 0, glDesc.fUploadFormat,
687 glDesc.fAllocWidth, glDesc.fAllocHeight,
688 0, imageSize, srcData));
689 GrGL_RestoreResetRowLength();
690 } else {
691 if (NULL != srcData && (glDesc.fAllocWidth != desc.fWidth ||
692 glDesc.fAllocHeight != desc.fHeight)) {
693 GR_GL(TexImage2D(GL_TEXTURE_2D, 0, internalFormat,
694 glDesc.fAllocWidth, glDesc.fAllocHeight,
695 0, glDesc.fUploadFormat, glDesc.fUploadType, NULL));
696 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, desc.fWidth,
697 desc.fHeight, glDesc.fUploadFormat,
698 glDesc.fUploadType, srcData));
699 GrGL_RestoreResetRowLength();
700
701 uint32_t extraW = glDesc.fAllocWidth - desc.fWidth;
702 uint32_t extraH = glDesc.fAllocHeight - desc.fHeight;
703 uint32_t maxTexels = extraW * extraH;
704 maxTexels = GrMax(extraW * desc.fHeight, maxTexels);
705 maxTexels = GrMax(desc.fWidth * extraH, maxTexels);
706
707 GrAutoSMalloc<128*128> texels(glDesc.fUploadByteCount * maxTexels);
708
709 uint32_t rowSize = desc.fWidth * glDesc.fUploadByteCount;
710 if (extraH) {
711 uint8_t* lastRowStart = (uint8_t*) srcData +
712 (desc.fHeight - 1) * rowSize;
713 uint8_t* extraRowStart = (uint8_t*)texels.get();
714
715 for (uint32_t i = 0; i < extraH; ++i) {
716 memcpy(extraRowStart, lastRowStart, rowSize);
717 extraRowStart += rowSize;
718 }
719 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, 0, desc.fHeight, desc.fWidth,
720 extraH, glDesc.fUploadFormat, glDesc.fUploadType,
721 texels.get()));
722 }
723 if (extraW) {
724 uint8_t* edgeTexel = (uint8_t*)srcData + rowSize - glDesc.fUploadByteCount;
725 uint8_t* extraTexel = (uint8_t*)texels.get();
726 for (uint32_t j = 0; j < desc.fHeight; ++j) {
727 for (uint32_t i = 0; i < extraW; ++i) {
728 memcpy(extraTexel, edgeTexel, glDesc.fUploadByteCount);
729 extraTexel += glDesc.fUploadByteCount;
730 }
731 edgeTexel += rowSize;
732 }
733 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, desc.fWidth, 0, extraW,
734 desc.fHeight, glDesc.fUploadFormat,
735 glDesc.fUploadType, texels.get()));
736 }
737 if (extraW && extraH) {
738 uint8_t* cornerTexel = (uint8_t*)srcData + desc.fHeight * rowSize
739 - glDesc.fUploadByteCount;
740 uint8_t* extraTexel = (uint8_t*)texels.get();
741 for (uint32_t i = 0; i < extraW*extraH; ++i) {
742 memcpy(extraTexel, cornerTexel, glDesc.fUploadByteCount);
743 extraTexel += glDesc.fUploadByteCount;
744 }
745 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, desc.fWidth, desc.fHeight,
746 extraW, extraH, glDesc.fUploadFormat,
747 glDesc.fUploadType, texels.get()));
748 }
749
750 } else {
751 GR_GL(TexImage2D(GL_TEXTURE_2D, 0, internalFormat, glDesc.fAllocWidth,
752 glDesc.fAllocHeight, 0, glDesc.fUploadFormat,
753 glDesc.fUploadType, srcData));
754 GrGL_RestoreResetRowLength();
755 }
756 }
757
758 glDesc.fOrientation = GrGLTexture::kTopDown_Orientation;
759
760 GrGLRenderTarget::GLRenderTargetIDs rtIDs;
761 rtIDs.fStencilRenderbufferID = 0;
762 rtIDs.fMSColorRenderbufferID = 0;
763 rtIDs.fRTFBOID = 0;
764 rtIDs.fTexFBOID = 0;
765 rtIDs.fOwnIDs = true;
766 GLenum msColorRenderbufferFormat = -1;
767
768 if (renderTarget) {
769#if GR_COLLECT_STATS
770 ++fStats.fRenderTargetCreateCnt;
771#endif
772 bool failed = true;
773 GLenum status;
774 GLint err;
775
776 // If need have both RT flag and srcData we have
777 // to invert the data before uploading because FBO
778 // will be rendered bottom up
779 GrAssert(NULL == srcData);
780 glDesc.fOrientation = GrGLTexture::kBottomUp_Orientation;
781
782 GR_GLEXT(fExts, GenFramebuffers(1, &rtIDs.fTexFBOID));
783 GrAssert(rtIDs.fTexFBOID);
784
785 // If we are using multisampling and any extension other than the IMG
786 // one we will create two FBOs. We render to one and then resolve to
787 // the texture bound to the other. The IMG extension does an implicit
788 // resolve.
789 if (samples > 1 && kIMG_MSFBO != fMSFBOType && kNone_MSFBO != fMSFBOType) {
790 GR_GLEXT(fExts, GenFramebuffers(1, &rtIDs.fRTFBOID));
791 GrAssert(0 != rtIDs.fRTFBOID);
792 GR_GLEXT(fExts, GenRenderbuffers(1, &rtIDs.fMSColorRenderbufferID));
793 GrAssert(0 != rtIDs.fMSColorRenderbufferID);
794 if (!fboInternalFormat(desc.fFormat, &msColorRenderbufferFormat)) {
795 GR_GLEXT(fExts,
796 DeleteRenderbuffers(1, &rtIDs.fMSColorRenderbufferID));
797 GR_GL(DeleteTextures(1, &glDesc.fTextureID));
798 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fTexFBOID));
799 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fRTFBOID));
reed@google.comac10a2d2010-12-22 21:39:39 +0000800 return return_null_texture();
801 }
802 } else {
803 rtIDs.fRTFBOID = rtIDs.fTexFBOID;
804 }
805 int attempts = 1;
806 if (!(kNoPathRendering_TextureFlag & desc.fFlags)) {
807 GR_GLEXT(fExts, GenRenderbuffers(1, &rtIDs.fStencilRenderbufferID));
808 GrAssert(0 != rtIDs.fStencilRenderbufferID);
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000809 attempts = GR_ARRAY_COUNT(gStencilFormats);
reed@google.comac10a2d2010-12-22 21:39:39 +0000810 }
811
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000812 // someone suggested that some systems might require
bsalomon@google.com316f99232011-01-13 21:28:12 +0000813 // unbinding the texture before we call FramebufferTexture2D
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000814 // (seems unlikely)
reed@google.comac10a2d2010-12-22 21:39:39 +0000815 GR_GL(BindTexture(GL_TEXTURE_2D, 0));
reed@google.comac10a2d2010-12-22 21:39:39 +0000816
817 err = ~GL_NO_ERROR;
818 for (int i = 0; i < attempts; ++i) {
819 if (rtIDs.fStencilRenderbufferID) {
820 GR_GLEXT(fExts, BindRenderbuffer(GR_RENDERBUFFER,
821 rtIDs.fStencilRenderbufferID));
822 if (samples > 1) {
823 GR_GLEXT_NO_ERR(fExts, RenderbufferStorageMultisample(
824 GR_RENDERBUFFER,
825 samples,
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000826 gStencilFormats[i].fEnum,
reed@google.comac10a2d2010-12-22 21:39:39 +0000827 glDesc.fAllocWidth,
828 glDesc.fAllocHeight));
829 } else {
830 GR_GLEXT_NO_ERR(fExts, RenderbufferStorage(
831 GR_RENDERBUFFER,
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000832 gStencilFormats[i].fEnum,
reed@google.comac10a2d2010-12-22 21:39:39 +0000833 glDesc.fAllocWidth,
834 glDesc.fAllocHeight));
835 }
836 err = glGetError();
837 if (err != GL_NO_ERROR) {
838 continue;
839 }
840 }
841 if (rtIDs.fRTFBOID != rtIDs.fTexFBOID) {
842 GrAssert(samples > 1);
843 GR_GLEXT(fExts, BindRenderbuffer(GR_RENDERBUFFER,
844 rtIDs.fMSColorRenderbufferID));
845 GR_GLEXT_NO_ERR(fExts, RenderbufferStorageMultisample(
846 GR_RENDERBUFFER,
847 samples,
848 msColorRenderbufferFormat,
849 glDesc.fAllocWidth,
850 glDesc.fAllocHeight));
851 err = glGetError();
852 if (err != GL_NO_ERROR) {
853 continue;
854 }
855 }
856 GR_GLEXT(fExts, BindFramebuffer(GR_FRAMEBUFFER, rtIDs.fTexFBOID));
857
858#if GR_COLLECT_STATS
859 ++fStats.fRenderTargetChngCnt;
860#endif
861 if (kIMG_MSFBO == fMSFBOType && samples > 1) {
862 GR_GLEXT(fExts, FramebufferTexture2DMultisample(
863 GR_FRAMEBUFFER,
864 GR_COLOR_ATTACHMENT0,
865 GL_TEXTURE_2D,
866 glDesc.fTextureID,
867 0,
868 samples));
869
870 } else {
871 GR_GLEXT(fExts, FramebufferTexture2D(GR_FRAMEBUFFER,
872 GR_COLOR_ATTACHMENT0,
873 GL_TEXTURE_2D,
874 glDesc.fTextureID, 0));
875 }
876 if (rtIDs.fRTFBOID != rtIDs.fTexFBOID) {
877 GLenum status = GR_GLEXT(fExts,
878 CheckFramebufferStatus(GR_FRAMEBUFFER));
879 if (status != GR_FRAMEBUFFER_COMPLETE) {
880 GrPrintf("-- glCheckFramebufferStatus %x %d %d\n",
881 status, desc.fWidth, desc.fHeight);
882 continue;
883 }
884 GR_GLEXT(fExts, BindFramebuffer(GR_FRAMEBUFFER, rtIDs.fRTFBOID));
885 #if GR_COLLECT_STATS
886 ++fStats.fRenderTargetChngCnt;
887 #endif
888 GR_GLEXT(fExts, FramebufferRenderbuffer(GR_FRAMEBUFFER,
889 GR_COLOR_ATTACHMENT0,
890 GR_RENDERBUFFER,
891 rtIDs.fMSColorRenderbufferID));
892
893 }
894 if (rtIDs.fStencilRenderbufferID) {
895 // bind the stencil to rt fbo if present, othewise the tex fbo
896 GR_GLEXT(fExts, FramebufferRenderbuffer(GR_FRAMEBUFFER,
897 GR_STENCIL_ATTACHMENT,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000898 GR_RENDERBUFFER,
reed@google.comac10a2d2010-12-22 21:39:39 +0000899 rtIDs.fStencilRenderbufferID));
900 }
901 status = GR_GLEXT(fExts, CheckFramebufferStatus(GR_FRAMEBUFFER));
902
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000903#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000904 // On some implementations you have to be bound as DEPTH_STENCIL.
905 // (Even binding to DEPTH and STENCIL separately with the same
906 // buffer doesn't work.)
907 if (rtIDs.fStencilRenderbufferID &&
908 status != GR_FRAMEBUFFER_COMPLETE) {
909 GR_GLEXT(fExts, FramebufferRenderbuffer(GR_FRAMEBUFFER,
910 GR_STENCIL_ATTACHMENT,
911 GR_RENDERBUFFER,
912 0));
913 GR_GLEXT(fExts,
914 FramebufferRenderbuffer(GR_FRAMEBUFFER,
915 GR_DEPTH_STENCIL_ATTACHMENT,
916 GR_RENDERBUFFER,
917 rtIDs.fStencilRenderbufferID));
918 status = GR_GLEXT(fExts, CheckFramebufferStatus(GR_FRAMEBUFFER));
919 }
920#endif
921 if (status != GR_FRAMEBUFFER_COMPLETE) {
922 GrPrintf("-- glCheckFramebufferStatus %x %d %d\n",
923 status, desc.fWidth, desc.fHeight);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000924#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000925 if (rtIDs.fStencilRenderbufferID) {
926 GR_GLEXT(fExts, FramebufferRenderbuffer(GR_FRAMEBUFFER,
927 GR_DEPTH_STENCIL_ATTACHMENT,
928 GR_RENDERBUFFER,
929 0));
930 }
931#endif
932 continue;
933 }
934 // we're successful!
935 failed = false;
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000936 if (rtIDs.fStencilRenderbufferID) {
937 if (UNKNOWN_BITS == gStencilFormats[i].fBits) {
938 GR_GL_GetIntegerv(GL_STENCIL_BITS, (GLint*)&glDesc.fStencilBits);
939 } else {
940 glDesc.fStencilBits = gStencilFormats[i].fBits;
941 }
942 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000943 break;
944 }
945 if (failed) {
946 if (rtIDs.fStencilRenderbufferID) {
947 GR_GLEXT(fExts,
948 DeleteRenderbuffers(1, &rtIDs.fStencilRenderbufferID));
949 }
950 if (rtIDs.fMSColorRenderbufferID) {
951 GR_GLEXT(fExts,
952 DeleteRenderbuffers(1, &rtIDs.fMSColorRenderbufferID));
953 }
954 if (rtIDs.fRTFBOID != rtIDs.fTexFBOID) {
955 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fRTFBOID));
956 }
957 if (rtIDs.fTexFBOID) {
958 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fTexFBOID));
959 }
960 GR_GL(DeleteTextures(1, &glDesc.fTextureID));
961 return return_null_texture();
962 }
963 }
964#ifdef TRACE_TEXTURE_CREATION
965 GrPrintf("--- new texture [%d] size=(%d %d) bpp=%d\n",
966 tex->fTextureID, width, height, tex->fUploadByteCount);
967#endif
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000968 GrGLTexture* tex = new GrGLTexture(glDesc, rtIDs, DEFAULT_PARAMS, this);
reed@google.comac10a2d2010-12-22 21:39:39 +0000969
970 if (0 != rtIDs.fTexFBOID) {
971 GrRenderTarget* rt = tex->asRenderTarget();
972 // We've messed with FBO state but may not have set the correct viewport
973 // so just dirty the rendertarget state to force a resend.
974 fHWDrawState.fRenderTarget = NULL;
975
976 // clear the new stencil buffer if we have one
977 if (!(desc.fFlags & kNoPathRendering_TextureFlag)) {
978 GrRenderTarget* rtSave = fCurrDrawState.fRenderTarget;
979 fCurrDrawState.fRenderTarget = rt;
980 eraseStencil(0, ~0);
981 fCurrDrawState.fRenderTarget = rtSave;
982 }
983 }
984 return tex;
985}
986
reed@google.comac10a2d2010-12-22 21:39:39 +0000987GrVertexBuffer* GrGpuGL::createVertexBuffer(uint32_t size, bool dynamic) {
988 GLuint id;
989 GR_GL(GenBuffers(1, &id));
990 if (id) {
991 GR_GL(BindBuffer(GL_ARRAY_BUFFER, id));
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000992 fHWGeometryState.fArrayPtrsDirty = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000993 GrGLClearErr();
994 // make sure driver can allocate memory for this buffer
995 GR_GL_NO_ERR(BufferData(GL_ARRAY_BUFFER, size, NULL,
996 dynamic ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW));
997 if (glGetError() != GL_NO_ERROR) {
998 GR_GL(DeleteBuffers(1, &id));
999 // deleting bound buffer does implicit bind to 0
1000 fHWGeometryState.fVertexBuffer = NULL;
1001 return NULL;
1002 }
1003 GrGLVertexBuffer* vertexBuffer = new GrGLVertexBuffer(id, this,
1004 size, dynamic);
1005 fHWGeometryState.fVertexBuffer = vertexBuffer;
1006 return vertexBuffer;
1007 }
1008 return NULL;
1009}
1010
1011GrIndexBuffer* GrGpuGL::createIndexBuffer(uint32_t size, bool dynamic) {
1012 GLuint id;
1013 GR_GL(GenBuffers(1, &id));
1014 if (id) {
1015 GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, id));
1016 GrGLClearErr();
1017 // make sure driver can allocate memory for this buffer
1018 GR_GL_NO_ERR(BufferData(GL_ELEMENT_ARRAY_BUFFER, size, NULL,
1019 dynamic ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW));
1020 if (glGetError() != GL_NO_ERROR) {
1021 GR_GL(DeleteBuffers(1, &id));
1022 // deleting bound buffer does implicit bind to 0
1023 fHWGeometryState.fIndexBuffer = NULL;
1024 return NULL;
1025 }
1026 GrIndexBuffer* indexBuffer = new GrGLIndexBuffer(id, this,
1027 size, dynamic);
1028 fHWGeometryState.fIndexBuffer = indexBuffer;
1029 return indexBuffer;
1030 }
1031 return NULL;
1032}
1033
reed@google.comac10a2d2010-12-22 21:39:39 +00001034void GrGpuGL::flushScissor(const GrIRect* rect) {
1035 GrAssert(NULL != fCurrDrawState.fRenderTarget);
bsalomon@google.com8895a7a2011-02-18 16:09:55 +00001036 const GrGLIRect& vp =
bsalomon@google.comd302f142011-03-03 13:54:13 +00001037 ((GrGLRenderTarget*)fCurrDrawState.fRenderTarget)->getViewport();
reed@google.comac10a2d2010-12-22 21:39:39 +00001038
bsalomon@google.com8895a7a2011-02-18 16:09:55 +00001039 GrGLIRect scissor;
1040 if (NULL != rect) {
bsalomon@google.comd302f142011-03-03 13:54:13 +00001041 scissor.setRelativeTo(vp, rect->fLeft, rect->fTop,
bsalomon@google.com8895a7a2011-02-18 16:09:55 +00001042 rect->width(), rect->height());
1043 if (scissor.contains(vp)) {
1044 rect = NULL;
1045 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001046 }
1047
1048 if (NULL != rect) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001049 if (fHWBounds.fScissorRect != scissor) {
bsalomon@google.com8895a7a2011-02-18 16:09:55 +00001050 scissor.pushToGLScissor();
reed@google.comac10a2d2010-12-22 21:39:39 +00001051 fHWBounds.fScissorRect = scissor;
1052 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001053 if (!fHWBounds.fScissorEnabled) {
1054 GR_GL(Enable(GL_SCISSOR_TEST));
1055 fHWBounds.fScissorEnabled = true;
1056 }
1057 } else {
1058 if (fHWBounds.fScissorEnabled) {
1059 GR_GL(Disable(GL_SCISSOR_TEST));
1060 fHWBounds.fScissorEnabled = false;
1061 }
1062 }
1063}
1064
reed@google.comac10a2d2010-12-22 21:39:39 +00001065void GrGpuGL::eraseColor(GrColor color) {
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +00001066 if (NULL == fCurrDrawState.fRenderTarget) {
1067 return;
1068 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001069 flushRenderTarget();
1070 if (fHWBounds.fScissorEnabled) {
1071 GR_GL(Disable(GL_SCISSOR_TEST));
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +00001072 fHWBounds.fScissorEnabled = false;
reed@google.comac10a2d2010-12-22 21:39:39 +00001073 }
1074 GR_GL(ColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE));
bsalomon@google.comd302f142011-03-03 13:54:13 +00001075 fHWDrawState.fFlagBits &= ~kNoColorWrites_StateBit;
reed@google.comac10a2d2010-12-22 21:39:39 +00001076 GR_GL(ClearColor(GrColorUnpackR(color)/255.f,
1077 GrColorUnpackG(color)/255.f,
1078 GrColorUnpackB(color)/255.f,
1079 GrColorUnpackA(color)/255.f));
1080 GR_GL(Clear(GL_COLOR_BUFFER_BIT));
reed@google.comac10a2d2010-12-22 21:39:39 +00001081}
1082
1083void GrGpuGL::eraseStencil(uint32_t value, uint32_t mask) {
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +00001084 if (NULL == fCurrDrawState.fRenderTarget) {
1085 return;
1086 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001087 flushRenderTarget();
1088 if (fHWBounds.fScissorEnabled) {
1089 GR_GL(Disable(GL_SCISSOR_TEST));
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +00001090 fHWBounds.fScissorEnabled = false;
reed@google.comac10a2d2010-12-22 21:39:39 +00001091 }
1092 GR_GL(StencilMask(mask));
1093 GR_GL(ClearStencil(value));
1094 GR_GL(Clear(GL_STENCIL_BUFFER_BIT));
bsalomon@google.comd302f142011-03-03 13:54:13 +00001095 fHWDrawState.fStencilSettings.invalidate();
reed@google.comac10a2d2010-12-22 21:39:39 +00001096}
1097
bsalomon@google.comd302f142011-03-03 13:54:13 +00001098void GrGpuGL::eraseStencilClip(const GrIRect& rect) {
bsalomon@google.com8895a7a2011-02-18 16:09:55 +00001099 GrAssert(NULL != fCurrDrawState.fRenderTarget);
bsalomon@google.comd302f142011-03-03 13:54:13 +00001100 GLint stencilBitCount = fCurrDrawState.fRenderTarget->stencilBits();
reed@google.comac10a2d2010-12-22 21:39:39 +00001101 GrAssert(stencilBitCount > 0);
1102 GLint clipStencilMask = (1 << (stencilBitCount - 1));
bsalomon@google.comd302f142011-03-03 13:54:13 +00001103
1104 flushRenderTarget();
1105 flushScissor(&rect);
1106 GR_GL(StencilMask(clipStencilMask));
1107 GR_GL(ClearStencil(0));
1108 GR_GL(Clear(GL_STENCIL_BUFFER_BIT));
1109 fHWDrawState.fStencilSettings.invalidate();
reed@google.comac10a2d2010-12-22 21:39:39 +00001110}
1111
1112void GrGpuGL::forceRenderTargetFlush() {
1113 flushRenderTarget();
1114}
1115
1116bool GrGpuGL::readPixels(int left, int top, int width, int height,
1117 GrTexture::PixelConfig config, void* buffer) {
1118 GLenum internalFormat; // we don't use this for glReadPixels
1119 GLenum format;
1120 GLenum type;
1121 if (!this->canBeTexture(config, &internalFormat, &format, &type)) {
1122 return false;
1123 }
1124
bsalomon@google.com18908aa2011-02-07 14:51:55 +00001125 if (NULL == fCurrDrawState.fRenderTarget) {
1126 return false;
1127 }
1128 flushRenderTarget();
1129
bsalomon@google.comd302f142011-03-03 13:54:13 +00001130 const GrGLIRect& glvp = ((GrGLRenderTarget*)fCurrDrawState.fRenderTarget)->getViewport();
1131
bsalomon@google.com8895a7a2011-02-18 16:09:55 +00001132 // the read rect is viewport-relative
1133 GrGLIRect readRect;
1134 readRect.setRelativeTo(glvp, left, top, width, height);
1135 GR_GL(ReadPixels(readRect.fLeft, readRect.fBottom,
bsalomon@google.comd302f142011-03-03 13:54:13 +00001136 readRect.fWidth, readRect.fHeight,
bsalomon@google.com316f99232011-01-13 21:28:12 +00001137 format, type, buffer));
reed@google.comac10a2d2010-12-22 21:39:39 +00001138
1139 // now reverse the order of the rows, since GL's are bottom-to-top, but our
1140 // API presents top-to-bottom
1141 {
1142 size_t stride = width * GrTexture::BytesPerPixel(config);
1143 GrAutoMalloc rowStorage(stride);
1144 void* tmp = rowStorage.get();
1145
1146 const int halfY = height >> 1;
1147 char* top = reinterpret_cast<char*>(buffer);
1148 char* bottom = top + (height - 1) * stride;
1149 for (int y = 0; y < halfY; y++) {
1150 memcpy(tmp, top, stride);
1151 memcpy(top, bottom, stride);
1152 memcpy(bottom, tmp, stride);
1153 top += stride;
1154 bottom -= stride;
1155 }
1156 }
1157 return true;
1158}
1159
1160void GrGpuGL::flushRenderTarget() {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001161
1162 GrAssert(NULL != fCurrDrawState.fRenderTarget);
1163
reed@google.comac10a2d2010-12-22 21:39:39 +00001164 if (fHWDrawState.fRenderTarget != fCurrDrawState.fRenderTarget) {
1165 GrGLRenderTarget* rt = (GrGLRenderTarget*)fCurrDrawState.fRenderTarget;
1166 GR_GLEXT(fExts, BindFramebuffer(GR_FRAMEBUFFER, rt->renderFBOID()));
1167 #if GR_COLLECT_STATS
1168 ++fStats.fRenderTargetChngCnt;
1169 #endif
1170 rt->setDirty(true);
1171 #if GR_DEBUG
1172 GLenum status = GR_GLEXT(fExts, CheckFramebufferStatus(GR_FRAMEBUFFER));
1173 if (status != GR_FRAMEBUFFER_COMPLETE) {
1174 GrPrintf("-- glCheckFramebufferStatus %x\n", status);
1175 }
1176 #endif
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001177 fDirtyFlags.fRenderTargetChanged = true;
bsalomon@google.com8895a7a2011-02-18 16:09:55 +00001178 fHWDrawState.fRenderTarget = fCurrDrawState.fRenderTarget;
bsalomon@google.comd302f142011-03-03 13:54:13 +00001179 const GrGLIRect& vp = rt->getViewport();
bsalomon@google.com8895a7a2011-02-18 16:09:55 +00001180 if (true || fHWBounds.fViewportRect != vp) {
1181 vp.pushToGLViewport();
reed@google.comac10a2d2010-12-22 21:39:39 +00001182 fHWBounds.fViewportRect = vp;
1183 }
1184 }
1185}
1186
1187GLenum gPrimitiveType2GLMode[] = {
1188 GL_TRIANGLES,
1189 GL_TRIANGLE_STRIP,
1190 GL_TRIANGLE_FAN,
1191 GL_POINTS,
1192 GL_LINES,
1193 GL_LINE_STRIP
1194};
1195
bsalomon@google.comd302f142011-03-03 13:54:13 +00001196#define SWAP_PER_DRAW 0
1197
1198#if SWAP_PER_DRAW
1199 #if GR_MAC_BUILD
1200 #include <AGL/agl.h>
1201 #elif GR_WIN32_BUILD
1202 void SwapBuf() {
1203 DWORD procID = GetCurrentProcessId();
1204 HWND hwnd = GetTopWindow(GetDesktopWindow());
1205 while(hwnd) {
1206 DWORD wndProcID = 0;
1207 GetWindowThreadProcessId(hwnd, &wndProcID);
1208 if(wndProcID == procID) {
1209 SwapBuffers(GetDC(hwnd));
1210 }
1211 hwnd = GetNextWindow(hwnd, GW_HWNDNEXT);
1212 }
1213 }
1214 #endif
1215#endif
1216
bsalomon@google.comffca4002011-02-22 20:34:01 +00001217void GrGpuGL::drawIndexedHelper(GrPrimitiveType type,
reed@google.comac10a2d2010-12-22 21:39:39 +00001218 uint32_t startVertex,
1219 uint32_t startIndex,
1220 uint32_t vertexCount,
1221 uint32_t indexCount) {
1222 GrAssert((size_t)type < GR_ARRAY_COUNT(gPrimitiveType2GLMode));
1223
1224 GLvoid* indices = (GLvoid*)(sizeof(uint16_t) * startIndex);
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001225
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001226 GrAssert(NULL != fHWGeometryState.fIndexBuffer);
1227 GrAssert(NULL != fHWGeometryState.fVertexBuffer);
1228
1229 // our setupGeometry better have adjusted this to zero since
1230 // DrawElements always draws from the begining of the arrays for idx 0.
1231 GrAssert(0 == startVertex);
reed@google.comac10a2d2010-12-22 21:39:39 +00001232
1233 GR_GL(DrawElements(gPrimitiveType2GLMode[type], indexCount,
1234 GL_UNSIGNED_SHORT, indices));
bsalomon@google.comd302f142011-03-03 13:54:13 +00001235#if SWAP_PER_DRAW
1236 glFlush();
1237 #if GR_MAC_BUILD
1238 aglSwapBuffers(aglGetCurrentContext());
1239 int set_a_break_pt_here = 9;
1240 aglSwapBuffers(aglGetCurrentContext());
1241 #elif GR_WIN32_BUILD
1242 SwapBuf();
1243 int set_a_break_pt_here = 9;
1244 SwapBuf();
1245 #endif
1246#endif
reed@google.comac10a2d2010-12-22 21:39:39 +00001247}
1248
bsalomon@google.comffca4002011-02-22 20:34:01 +00001249void GrGpuGL::drawNonIndexedHelper(GrPrimitiveType type,
reed@google.comac10a2d2010-12-22 21:39:39 +00001250 uint32_t startVertex,
1251 uint32_t vertexCount) {
1252 GrAssert((size_t)type < GR_ARRAY_COUNT(gPrimitiveType2GLMode));
1253
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001254 GrAssert(NULL != fHWGeometryState.fVertexBuffer);
1255
1256 // our setupGeometry better have adjusted this to zero.
1257 // DrawElements doesn't take an offset so we always adjus the startVertex.
1258 GrAssert(0 == startVertex);
1259
1260 // pass 0 for parameter first. We have to adjust gl*Pointer() to
1261 // account for startVertex in the DrawElements case. So we always
1262 // rely on setupGeometry to have accounted for startVertex.
reed@google.comac10a2d2010-12-22 21:39:39 +00001263 GR_GL(DrawArrays(gPrimitiveType2GLMode[type], 0, vertexCount));
bsalomon@google.comd302f142011-03-03 13:54:13 +00001264#if SWAP_PER_DRAW
1265 glFlush();
1266 #if GR_MAC_BUILD
1267 aglSwapBuffers(aglGetCurrentContext());
1268 int set_a_break_pt_here = 9;
1269 aglSwapBuffers(aglGetCurrentContext());
1270 #elif GR_WIN32_BUILD
1271 SwapBuf();
1272 int set_a_break_pt_here = 9;
1273 SwapBuf();
1274 #endif
1275#endif
reed@google.comac10a2d2010-12-22 21:39:39 +00001276}
1277
reed@google.comac10a2d2010-12-22 21:39:39 +00001278void GrGpuGL::resolveTextureRenderTarget(GrGLTexture* texture) {
1279 GrGLRenderTarget* rt = (GrGLRenderTarget*) texture->asRenderTarget();
1280
1281 if (NULL != rt && rt->needsResolve()) {
1282 GrAssert(kNone_MSFBO != fMSFBOType);
1283 GrAssert(rt->textureFBOID() != rt->renderFBOID());
1284 GR_GLEXT(fExts, BindFramebuffer(GR_READ_FRAMEBUFFER,
1285 rt->renderFBOID()));
1286 GR_GLEXT(fExts, BindFramebuffer(GR_DRAW_FRAMEBUFFER,
1287 rt->textureFBOID()));
1288 #if GR_COLLECT_STATS
1289 ++fStats.fRenderTargetChngCnt;
1290 #endif
1291 // make sure we go through set render target
1292 fHWDrawState.fRenderTarget = NULL;
1293
1294 GLint left = 0;
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001295 GLint right = texture->width();
reed@google.comac10a2d2010-12-22 21:39:39 +00001296 // we will have rendered to the top of the FBO.
1297 GLint top = texture->allocHeight();
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001298 GLint bottom = texture->allocHeight() - texture->height();
reed@google.comac10a2d2010-12-22 21:39:39 +00001299 if (kApple_MSFBO == fMSFBOType) {
1300 GR_GL(Enable(GL_SCISSOR_TEST));
1301 GR_GL(Scissor(left, bottom, right-left, top-bottom));
1302 GR_GLEXT(fExts, ResolveMultisampleFramebuffer());
bsalomon@google.com8895a7a2011-02-18 16:09:55 +00001303 fHWBounds.fScissorRect.invalidate();
reed@google.comac10a2d2010-12-22 21:39:39 +00001304 fHWBounds.fScissorEnabled = true;
1305 } else {
1306 GR_GLEXT(fExts, BlitFramebuffer(left, bottom, right, top,
1307 left, bottom, right, top,
1308 GL_COLOR_BUFFER_BIT, GL_NEAREST));
1309 }
1310 rt->setDirty(false);
1311
1312 }
1313}
1314
bsalomon@google.comd302f142011-03-03 13:54:13 +00001315static const GLenum grToGLStencilFunc[] = {
1316 GL_ALWAYS, // kAlways_StencilFunc
1317 GL_NEVER, // kNever_StencilFunc
1318 GL_GREATER, // kGreater_StencilFunc
1319 GL_GEQUAL, // kGEqual_StencilFunc
1320 GL_LESS, // kLess_StencilFunc
1321 GL_LEQUAL, // kLEqual_StencilFunc,
1322 GL_EQUAL, // kEqual_StencilFunc,
1323 GL_NOTEQUAL, // kNotEqual_StencilFunc,
1324};
1325GR_STATIC_ASSERT(GR_ARRAY_COUNT(grToGLStencilFunc) == kBasicStencilFuncCount);
1326GR_STATIC_ASSERT(0 == kAlways_StencilFunc);
1327GR_STATIC_ASSERT(1 == kNever_StencilFunc);
1328GR_STATIC_ASSERT(2 == kGreater_StencilFunc);
1329GR_STATIC_ASSERT(3 == kGEqual_StencilFunc);
1330GR_STATIC_ASSERT(4 == kLess_StencilFunc);
1331GR_STATIC_ASSERT(5 == kLEqual_StencilFunc);
1332GR_STATIC_ASSERT(6 == kEqual_StencilFunc);
1333GR_STATIC_ASSERT(7 == kNotEqual_StencilFunc);
1334
1335static const GLenum grToGLStencilOp[] = {
1336 GL_KEEP, // kKeep_StencilOp
1337 GL_REPLACE, // kReplace_StencilOp
1338 GL_INCR_WRAP, // kIncWrap_StencilOp
1339 GL_INCR, // kIncClamp_StencilOp
1340 GL_DECR_WRAP, // kDecWrap_StencilOp
1341 GL_DECR, // kDecClamp_StencilOp
1342 GL_ZERO, // kZero_StencilOp
1343 GL_INVERT, // kInvert_StencilOp
1344};
1345GR_STATIC_ASSERT(GR_ARRAY_COUNT(grToGLStencilOp) == kStencilOpCount);
1346GR_STATIC_ASSERT(0 == kKeep_StencilOp);
1347GR_STATIC_ASSERT(1 == kReplace_StencilOp);
1348GR_STATIC_ASSERT(2 == kIncWrap_StencilOp);
1349GR_STATIC_ASSERT(3 == kIncClamp_StencilOp);
1350GR_STATIC_ASSERT(4 == kDecWrap_StencilOp);
1351GR_STATIC_ASSERT(5 == kDecClamp_StencilOp);
1352GR_STATIC_ASSERT(6 == kZero_StencilOp);
1353GR_STATIC_ASSERT(7 == kInvert_StencilOp);
1354
reed@google.comac10a2d2010-12-22 21:39:39 +00001355void GrGpuGL::flushStencil() {
bsalomon@google.comd302f142011-03-03 13:54:13 +00001356 const GrStencilSettings* settings = &fCurrDrawState.fStencilSettings;
reed@google.comac10a2d2010-12-22 21:39:39 +00001357
1358 // use stencil for clipping if clipping is enabled and the clip
1359 // has been written into the stencil.
1360 bool stencilClip = fClipState.fClipInStencil &&
1361 (kClip_StateBit & fCurrDrawState.fFlagBits);
bsalomon@google.comd302f142011-03-03 13:54:13 +00001362 bool stencilChange = fHWStencilClip != stencilClip ||
1363 fHWDrawState.fStencilSettings != *settings ||
1364 ((fHWDrawState.fFlagBits & kModifyStencilClip_StateBit) !=
1365 (fCurrDrawState.fFlagBits & kModifyStencilClip_StateBit));
reed@google.comac10a2d2010-12-22 21:39:39 +00001366
1367 if (stencilChange) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001368
bsalomon@google.comd302f142011-03-03 13:54:13 +00001369 // we can't simultaneously perform stencil-clipping and modify the stencil clip
1370 GrAssert(!stencilClip || !(fCurrDrawState.fFlagBits & kModifyStencilClip_StateBit));
reed@google.comac10a2d2010-12-22 21:39:39 +00001371
bsalomon@google.comd302f142011-03-03 13:54:13 +00001372 if (settings->isDisabled()) {
1373 if (stencilClip) {
1374 settings = &gClipStencilSettings;
1375 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001376 }
bsalomon@google.comd302f142011-03-03 13:54:13 +00001377
1378 if (settings->isDisabled()) {
1379 GR_GL(Disable(GL_STENCIL_TEST));
1380 } else {
1381 GR_GL(Enable(GL_STENCIL_TEST));
1382 #if GR_DEBUG
1383 if (!fStencilWrapOpsSupport) {
1384 GrAssert(settings->fFrontPassOp != kIncWrap_StencilOp);
1385 GrAssert(settings->fFrontPassOp != kDecWrap_StencilOp);
1386 GrAssert(settings->fFrontFailOp != kIncWrap_StencilOp);
1387 GrAssert(settings->fBackFailOp != kDecWrap_StencilOp);
1388 GrAssert(settings->fBackPassOp != kIncWrap_StencilOp);
1389 GrAssert(settings->fBackPassOp != kDecWrap_StencilOp);
1390 GrAssert(settings->fBackFailOp != kIncWrap_StencilOp);
1391 GrAssert(settings->fFrontFailOp != kDecWrap_StencilOp);
1392 }
1393 #endif
1394 int stencilBits = fCurrDrawState.fRenderTarget->stencilBits();
1395 GrAssert(stencilBits ||
1396 (GrStencilSettings::gDisabled ==
1397 fCurrDrawState.fStencilSettings));
1398 GLuint clipStencilMask = 1 << (stencilBits - 1);
1399 GLuint userStencilMask = clipStencilMask - 1;
1400
1401 unsigned int frontRef = settings->fFrontFuncRef;
1402 unsigned int frontMask = settings->fFrontFuncMask;
1403 unsigned int frontWriteMask = settings->fFrontWriteMask;
1404 GLenum frontFunc;
1405
1406 if (fCurrDrawState.fFlagBits & kModifyStencilClip_StateBit) {
1407
1408 GrAssert(settings->fFrontFunc < kBasicStencilFuncCount);
1409 frontFunc = grToGLStencilFunc[settings->fFrontFunc];
1410 } else {
1411 frontFunc = grToGLStencilFunc[ConvertStencilFunc(stencilClip, settings->fFrontFunc)];
1412
1413 ConvertStencilFuncAndMask(settings->fFrontFunc,
1414 stencilClip,
1415 clipStencilMask,
1416 userStencilMask,
1417 &frontRef,
1418 &frontMask);
1419 frontWriteMask &= userStencilMask;
1420 }
1421 GrAssert(settings->fFrontFailOp >= 0 &&
1422 settings->fFrontFailOp < GR_ARRAY_COUNT(grToGLStencilOp));
1423 GrAssert(settings->fFrontPassOp >= 0 &&
1424 settings->fFrontPassOp < GR_ARRAY_COUNT(grToGLStencilOp));
1425 GrAssert(settings->fBackFailOp >= 0 &&
1426 settings->fBackFailOp < GR_ARRAY_COUNT(grToGLStencilOp));
1427 GrAssert(settings->fBackPassOp >= 0 &&
1428 settings->fBackPassOp < GR_ARRAY_COUNT(grToGLStencilOp));
1429 if (fTwoSidedStencilSupport) {
1430 GLenum backFunc;
1431
1432 unsigned int backRef = settings->fBackFuncRef;
1433 unsigned int backMask = settings->fBackFuncMask;
1434 unsigned int backWriteMask = settings->fBackWriteMask;
1435
1436
1437 if (fCurrDrawState.fFlagBits & kModifyStencilClip_StateBit) {
1438 GrAssert(settings->fBackFunc < kBasicStencilFuncCount);
1439 backFunc = grToGLStencilFunc[settings->fBackFunc];
1440 } else {
1441 backFunc = grToGLStencilFunc[ConvertStencilFunc(stencilClip, settings->fBackFunc)];
1442 ConvertStencilFuncAndMask(settings->fBackFunc,
1443 stencilClip,
1444 clipStencilMask,
1445 userStencilMask,
1446 &backRef,
1447 &backMask);
1448 backWriteMask &= userStencilMask;
1449 }
1450
1451 GR_GL(StencilFuncSeparate(GL_FRONT, frontFunc, frontRef, frontMask));
1452 GR_GL(StencilMaskSeparate(GL_FRONT, frontWriteMask));
1453 GR_GL(StencilFuncSeparate(GL_BACK, backFunc, backRef, backMask));
1454 GR_GL(StencilMaskSeparate(GL_BACK, backWriteMask));
1455 GR_GL(StencilOpSeparate(GL_FRONT, grToGLStencilOp[settings->fFrontFailOp],
1456 grToGLStencilOp[settings->fFrontPassOp],
1457 grToGLStencilOp[settings->fFrontPassOp]));
1458
1459 GR_GL(StencilOpSeparate(GL_BACK, grToGLStencilOp[settings->fBackFailOp],
1460 grToGLStencilOp[settings->fBackPassOp],
1461 grToGLStencilOp[settings->fBackPassOp]));
1462 } else {
1463 GR_GL(StencilFunc(frontFunc, frontRef, frontMask));
1464 GR_GL(StencilMask(frontWriteMask));
1465 GR_GL(StencilOp(grToGLStencilOp[settings->fFrontFailOp],
1466 grToGLStencilOp[settings->fFrontPassOp],
1467 grToGLStencilOp[settings->fFrontPassOp]));
1468 }
1469 }
1470 fHWDrawState.fStencilSettings = fCurrDrawState.fStencilSettings;
reed@google.comac10a2d2010-12-22 21:39:39 +00001471 fHWStencilClip = stencilClip;
1472 }
1473}
1474
bsalomon@google.comffca4002011-02-22 20:34:01 +00001475bool GrGpuGL::flushGLStateCommon(GrPrimitiveType type) {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001476
1477 // GrGpu::setupClipAndFlushState should have already checked this
1478 // and bailed if not true.
1479 GrAssert(NULL != fCurrDrawState.fRenderTarget);
reed@google.comac10a2d2010-12-22 21:39:39 +00001480
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001481 for (int s = 0; s < kNumStages; ++s) {
1482 bool usingTexture = VertexUsesStage(s, fGeometrySrc.fVertexLayout);
reed@google.comac10a2d2010-12-22 21:39:39 +00001483
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001484 // bind texture and set sampler state
1485 if (usingTexture) {
1486 GrGLTexture* nextTexture = (GrGLTexture*)fCurrDrawState.fTextures[s];
reed@google.comac10a2d2010-12-22 21:39:39 +00001487
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001488 if (NULL != nextTexture) {
bsalomon@google.com316f99232011-01-13 21:28:12 +00001489 // if we created a rt/tex and rendered to it without using a
1490 // texture and now we're texuring from the rt it will still be
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001491 // the last bound texture, but it needs resolving. So keep this
1492 // out of the "last != next" check.
1493 resolveTextureRenderTarget(nextTexture);
reed@google.comac10a2d2010-12-22 21:39:39 +00001494
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001495 if (fHWDrawState.fTextures[s] != nextTexture) {
1496 setTextureUnit(s);
1497 GR_GL(BindTexture(GL_TEXTURE_2D, nextTexture->textureID()));
1498 #if GR_COLLECT_STATS
1499 ++fStats.fTextureChngCnt;
1500 #endif
1501 //GrPrintf("---- bindtexture %d\n", nextTexture->textureID());
1502 fHWDrawState.fTextures[s] = nextTexture;
1503 }
bsalomon@google.com316f99232011-01-13 21:28:12 +00001504
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001505 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
bsalomon@google.com316f99232011-01-13 21:28:12 +00001506 const GrGLTexture::TexParams& oldTexParams =
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001507 nextTexture->getTexParams();
1508 GrGLTexture::TexParams newTexParams;
bsalomon@google.com316f99232011-01-13 21:28:12 +00001509
1510 newTexParams.fFilter = sampler.isFilter() ? GL_LINEAR :
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001511 GL_NEAREST;
bsalomon@google.com316f99232011-01-13 21:28:12 +00001512 newTexParams.fWrapS =
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001513 GrGLTexture::gWrapMode2GLWrap[sampler.getWrapX()];
bsalomon@google.com316f99232011-01-13 21:28:12 +00001514 newTexParams.fWrapT =
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001515 GrGLTexture::gWrapMode2GLWrap[sampler.getWrapY()];
reed@google.comac10a2d2010-12-22 21:39:39 +00001516
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001517 if (newTexParams.fFilter != oldTexParams.fFilter) {
1518 setTextureUnit(s);
bsalomon@google.com316f99232011-01-13 21:28:12 +00001519 GR_GL(TexParameteri(GL_TEXTURE_2D,
1520 GL_TEXTURE_MAG_FILTER,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001521 newTexParams.fFilter));
bsalomon@google.com316f99232011-01-13 21:28:12 +00001522 GR_GL(TexParameteri(GL_TEXTURE_2D,
1523 GL_TEXTURE_MIN_FILTER,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001524 newTexParams.fFilter));
1525 }
1526 if (newTexParams.fWrapS != oldTexParams.fWrapS) {
1527 setTextureUnit(s);
bsalomon@google.com316f99232011-01-13 21:28:12 +00001528 GR_GL(TexParameteri(GL_TEXTURE_2D,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001529 GL_TEXTURE_WRAP_S,
1530 newTexParams.fWrapS));
1531 }
1532 if (newTexParams.fWrapT != oldTexParams.fWrapT) {
1533 setTextureUnit(s);
bsalomon@google.com316f99232011-01-13 21:28:12 +00001534 GR_GL(TexParameteri(GL_TEXTURE_2D,
1535 GL_TEXTURE_WRAP_T,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001536 newTexParams.fWrapT));
1537 }
1538 nextTexture->setTexParams(newTexParams);
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001539
1540 // The texture matrix has to compensate for texture width/height
1541 // and NPOT-embedded-in-POT
1542 fDirtyFlags.fTextureChangedMask |= (1 << s);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001543 } else {
1544 GrAssert(!"Rendering with texture vert flag set but no texture");
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001545 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +00001546 }
1547 }
1548 }
1549
1550 flushRenderTarget();
1551
1552 if ((fCurrDrawState.fFlagBits & kDither_StateBit) !=
1553 (fHWDrawState.fFlagBits & kDither_StateBit)) {
1554 if (fCurrDrawState.fFlagBits & kDither_StateBit) {
1555 GR_GL(Enable(GL_DITHER));
1556 } else {
1557 GR_GL(Disable(GL_DITHER));
1558 }
1559 }
1560
bsalomon@google.comd302f142011-03-03 13:54:13 +00001561 if ((fCurrDrawState.fFlagBits & kNoColorWrites_StateBit) !=
1562 (fHWDrawState.fFlagBits & kNoColorWrites_StateBit)) {
1563 GLenum mask;
1564 if (fCurrDrawState.fFlagBits & kNoColorWrites_StateBit) {
1565 mask = GL_FALSE;
1566 } else {
1567 mask = GL_TRUE;
1568 }
1569 GR_GL(ColorMask(mask, mask, mask, mask));
1570 }
1571
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001572#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +00001573 // ES doesn't support toggling GL_MULTISAMPLE and doesn't have
1574 // smooth lines.
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001575 if (fDirtyFlags.fRenderTargetChanged ||
reed@google.comac10a2d2010-12-22 21:39:39 +00001576 (fCurrDrawState.fFlagBits & kAntialias_StateBit) !=
1577 (fHWDrawState.fFlagBits & kAntialias_StateBit)) {
1578 GLint msaa = 0;
1579 // only perform query if we know MSAA is supported.
1580 // calling on non-MSAA target caused a crash in one environment,
1581 // though I don't think it should.
reed@google.coma09368c2011-02-24 21:42:29 +00001582 if (fAASamples[kHigh_AALevel]) {
reed@google.comac20fb92011-01-12 17:14:53 +00001583 GR_GL_GetIntegerv(GL_SAMPLE_BUFFERS, &msaa);
reed@google.comac10a2d2010-12-22 21:39:39 +00001584 }
1585 if (fCurrDrawState.fFlagBits & kAntialias_StateBit) {
1586 if (msaa) {
1587 GR_GL(Enable(GL_MULTISAMPLE));
1588 } else {
1589 GR_GL(Enable(GL_LINE_SMOOTH));
1590 }
1591 } else {
1592 if (msaa) {
1593 GR_GL(Disable(GL_MULTISAMPLE));
1594 }
1595 GR_GL(Disable(GL_LINE_SMOOTH));
1596 }
1597 }
1598#endif
1599
1600 bool blendOff = canDisableBlend();
1601 if (fHWBlendDisabled != blendOff) {
1602 if (blendOff) {
1603 GR_GL(Disable(GL_BLEND));
1604 } else {
1605 GR_GL(Enable(GL_BLEND));
1606 }
1607 fHWBlendDisabled = blendOff;
1608 }
1609
1610 if (!blendOff) {
1611 if (fHWDrawState.fSrcBlend != fCurrDrawState.fSrcBlend ||
1612 fHWDrawState.fDstBlend != fCurrDrawState.fDstBlend) {
1613 GR_GL(BlendFunc(gXfermodeCoeff2Blend[fCurrDrawState.fSrcBlend],
1614 gXfermodeCoeff2Blend[fCurrDrawState.fDstBlend]));
1615 fHWDrawState.fSrcBlend = fCurrDrawState.fSrcBlend;
1616 fHWDrawState.fDstBlend = fCurrDrawState.fDstBlend;
1617 }
1618 }
bsalomon@google.com316f99232011-01-13 21:28:12 +00001619
bsalomon@google.comd302f142011-03-03 13:54:13 +00001620 if (fHWDrawState.fDrawFace != fCurrDrawState.fDrawFace) {
1621 switch (fCurrDrawState.fDrawFace) {
1622 case kCCW_DrawFace:
1623 glEnable(GL_CULL_FACE);
1624 GR_GL(CullFace(GL_BACK));
1625 break;
1626 case kCW_DrawFace:
1627 GR_GL(Enable(GL_CULL_FACE));
1628 GR_GL(CullFace(GL_FRONT));
1629 break;
1630 case kBoth_DrawFace:
1631 GR_GL(Disable(GL_CULL_FACE));
1632 break;
1633 default:
1634 GrCrash("Unknown draw face.");
1635 }
1636 fHWDrawState.fDrawFace = fCurrDrawState.fDrawFace;
1637 }
1638
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001639#if GR_DEBUG
reed@google.comac10a2d2010-12-22 21:39:39 +00001640 // check for circular rendering
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001641 for (int s = 0; s < kNumStages; ++s) {
1642 GrAssert(!VertexUsesStage(s, fGeometrySrc.fVertexLayout) ||
1643 NULL == fCurrDrawState.fRenderTarget ||
1644 NULL == fCurrDrawState.fTextures[s] ||
bsalomon@google.com316f99232011-01-13 21:28:12 +00001645 fCurrDrawState.fTextures[s]->asRenderTarget() !=
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001646 fCurrDrawState.fRenderTarget);
1647 }
1648#endif
bsalomon@google.com316f99232011-01-13 21:28:12 +00001649
reed@google.comac10a2d2010-12-22 21:39:39 +00001650 flushStencil();
1651
bsalomon@google.comd302f142011-03-03 13:54:13 +00001652 // flushStencil may look at the private state bits, so keep it before this.
reed@google.comac10a2d2010-12-22 21:39:39 +00001653 fHWDrawState.fFlagBits = fCurrDrawState.fFlagBits;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001654 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +00001655}
1656
1657void GrGpuGL::notifyVertexBufferBind(const GrGLVertexBuffer* buffer) {
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001658 if (fHWGeometryState.fVertexBuffer != buffer) {
1659 fHWGeometryState.fArrayPtrsDirty = true;
1660 fHWGeometryState.fVertexBuffer = buffer;
1661 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001662}
1663
1664void GrGpuGL::notifyVertexBufferDelete(const GrGLVertexBuffer* buffer) {
1665 GrAssert(!(kBuffer_GeometrySrcType == fGeometrySrc.fVertexSrc &&
1666 buffer == fGeometrySrc.fVertexBuffer));
1667
1668 if (fHWGeometryState.fVertexBuffer == buffer) {
1669 // deleting bound buffer does implied bind to 0
1670 fHWGeometryState.fVertexBuffer = NULL;
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001671 fHWGeometryState.fArrayPtrsDirty = true;
reed@google.comac10a2d2010-12-22 21:39:39 +00001672 }
1673}
1674
1675void GrGpuGL::notifyIndexBufferBind(const GrGLIndexBuffer* buffer) {
1676 fGeometrySrc.fIndexBuffer = buffer;
1677}
1678
1679void GrGpuGL::notifyIndexBufferDelete(const GrGLIndexBuffer* buffer) {
1680 GrAssert(!(kBuffer_GeometrySrcType == fGeometrySrc.fIndexSrc &&
1681 buffer == fGeometrySrc.fIndexBuffer));
1682
1683 if (fHWGeometryState.fIndexBuffer == buffer) {
1684 // deleting bound buffer does implied bind to 0
1685 fHWGeometryState.fIndexBuffer = NULL;
1686 }
1687}
1688
reed@google.comac10a2d2010-12-22 21:39:39 +00001689void GrGpuGL::notifyRenderTargetDelete(GrRenderTarget* renderTarget) {
1690 GrAssert(NULL != renderTarget);
1691
1692 // if the bound FBO is destroyed we can't rely on the implicit bind to 0
1693 // a) we want the default RT which may not be FBO 0
1694 // b) we set more state than just FBO based on the RT
1695 // So trash the HW state to force an RT flush next time
1696 if (fCurrDrawState.fRenderTarget == renderTarget) {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001697 fCurrDrawState.fRenderTarget = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +00001698 }
1699 if (fHWDrawState.fRenderTarget == renderTarget) {
1700 fHWDrawState.fRenderTarget = NULL;
1701 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001702}
1703
1704void GrGpuGL::notifyTextureDelete(GrGLTexture* texture) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001705 for (int s = 0; s < kNumStages; ++s) {
1706 if (fCurrDrawState.fTextures[s] == texture) {
1707 fCurrDrawState.fTextures[s] = NULL;
1708 }
1709 if (fHWDrawState.fTextures[s] == texture) {
1710 // deleting bound texture does implied bind to 0
1711 fHWDrawState.fTextures[s] = NULL;
1712 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001713 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001714}
1715
1716void GrGpuGL::notifyTextureRemoveRenderTarget(GrGLTexture* texture) {
1717 GrAssert(NULL != texture->asRenderTarget());
1718
1719 // if there is a pending resolve, perform it.
1720 resolveTextureRenderTarget(texture);
1721}
1722
1723bool GrGpuGL::canBeTexture(GrTexture::PixelConfig config,
1724 GLenum* internalFormat,
1725 GLenum* format,
1726 GLenum* type) {
1727 switch (config) {
1728 case GrTexture::kRGBA_8888_PixelConfig:
1729 case GrTexture::kRGBX_8888_PixelConfig: // todo: can we tell it our X?
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +00001730 *format = GR_GL_32BPP_COLOR_FORMAT;
reed@google.com63100f92011-01-18 21:32:14 +00001731#if GR_SUPPORT_GLES
1732 // according to GL_EXT_texture_format_BGRA8888 the *internal*
1733 // format for a BGRA is BGRA not RGBA (as on desktop)
1734 *internalFormat = GR_GL_32BPP_COLOR_FORMAT;
1735#else
1736 *internalFormat = GL_RGBA;
bsalomon@google.comed3a0682011-01-18 16:54:04 +00001737#endif
reed@google.comac10a2d2010-12-22 21:39:39 +00001738 *type = GL_UNSIGNED_BYTE;
1739 break;
1740 case GrTexture::kRGB_565_PixelConfig:
1741 *format = GL_RGB;
1742 *internalFormat = GL_RGB;
1743 *type = GL_UNSIGNED_SHORT_5_6_5;
1744 break;
1745 case GrTexture::kRGBA_4444_PixelConfig:
1746 *format = GL_RGBA;
1747 *internalFormat = GL_RGBA;
1748 *type = GL_UNSIGNED_SHORT_4_4_4_4;
1749 break;
1750 case GrTexture::kIndex_8_PixelConfig:
1751 if (this->supports8BitPalette()) {
1752 *format = GR_PALETTE8_RGBA8;
1753 *internalFormat = GR_PALETTE8_RGBA8;
1754 *type = GL_UNSIGNED_BYTE; // unused I think
1755 } else {
1756 return false;
1757 }
1758 break;
1759 case GrTexture::kAlpha_8_PixelConfig:
1760 *format = GL_ALPHA;
1761 *internalFormat = GL_ALPHA;
1762 *type = GL_UNSIGNED_BYTE;
1763 break;
1764 default:
1765 return false;
1766 }
1767 return true;
1768}
1769
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001770void GrGpuGL::setTextureUnit(int unit) {
1771 GrAssert(unit >= 0 && unit < kNumStages);
1772 if (fActiveTextureUnitIdx != unit) {
1773 GR_GL(ActiveTexture(GL_TEXTURE0 + unit));
1774 fActiveTextureUnitIdx = unit;
1775 }
1776}
bsalomon@google.com316f99232011-01-13 21:28:12 +00001777
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001778void GrGpuGL::setSpareTextureUnit() {
1779 if (fActiveTextureUnitIdx != (GL_TEXTURE0 + SPARE_TEX_UNIT)) {
1780 GR_GL(ActiveTexture(GL_TEXTURE0 + SPARE_TEX_UNIT));
1781 fActiveTextureUnitIdx = SPARE_TEX_UNIT;
1782 }
1783}
1784
reed@google.comac10a2d2010-12-22 21:39:39 +00001785/* On ES the internalFormat and format must match for TexImage and we use
1786 GL_RGB, GL_RGBA for color formats. We also generally like having the driver
1787 decide the internalFormat. However, on ES internalFormat for
1788 RenderBufferStorage* has to be a specific format (not a base format like
1789 GL_RGBA).
1790 */
1791bool GrGpuGL::fboInternalFormat(GrTexture::PixelConfig config, GLenum* format) {
1792 switch (config) {
1793 case GrTexture::kRGBA_8888_PixelConfig:
1794 case GrTexture::kRGBX_8888_PixelConfig:
1795 if (fRGBA8Renderbuffer) {
1796 *format = GR_RGBA8;
1797 return true;
1798 } else {
1799 return false;
1800 }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001801#if GR_SUPPORT_GLES // ES2 supports 565. ES1 supports it with FBO extension
1802 // desktop GL has no such internal format
reed@google.comac10a2d2010-12-22 21:39:39 +00001803 case GrTexture::kRGB_565_PixelConfig:
1804 *format = GR_RGB565;
1805 return true;
1806#endif
1807 case GrTexture::kRGBA_4444_PixelConfig:
1808 *format = GL_RGBA4;
1809 return true;
1810 default:
1811 return false;
1812 }
1813}
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001814
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001815void GrGpuGL::resetDirtyFlags() {
1816 Gr_bzero(&fDirtyFlags, sizeof(fDirtyFlags));
1817}
1818
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001819void GrGpuGL::setBuffers(bool indexed,
1820 int* extraVertexOffset,
1821 int* extraIndexOffset) {
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001822
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001823 GrAssert(NULL != extraVertexOffset);
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001824
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001825 GrGLVertexBuffer* vbuf;
1826 switch (fGeometrySrc.fVertexSrc) {
1827 case kBuffer_GeometrySrcType:
1828 *extraVertexOffset = 0;
1829 vbuf = (GrGLVertexBuffer*) fGeometrySrc.fVertexBuffer;
1830 break;
1831 case kArray_GeometrySrcType:
1832 case kReserved_GeometrySrcType:
1833 finalizeReservedVertices();
1834 *extraVertexOffset = fCurrPoolStartVertex;
1835 vbuf = (GrGLVertexBuffer*) fCurrPoolVertexBuffer;
1836 break;
1837 default:
1838 vbuf = NULL; // suppress warning
1839 GrCrash("Unknown geometry src type!");
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001840 }
1841
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001842 GrAssert(NULL != vbuf);
1843 GrAssert(!vbuf->isLocked());
1844 if (fHWGeometryState.fVertexBuffer != vbuf) {
1845 GR_GL(BindBuffer(GL_ARRAY_BUFFER, vbuf->bufferID()));
1846 fHWGeometryState.fArrayPtrsDirty = true;
1847 fHWGeometryState.fVertexBuffer = vbuf;
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001848 }
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001849
1850 if (indexed) {
1851 GrAssert(NULL != extraIndexOffset);
1852
1853 GrGLIndexBuffer* ibuf;
1854 switch (fGeometrySrc.fIndexSrc) {
1855 case kBuffer_GeometrySrcType:
1856 *extraIndexOffset = 0;
1857 ibuf = (GrGLIndexBuffer*)fGeometrySrc.fIndexBuffer;
1858 break;
1859 case kArray_GeometrySrcType:
1860 case kReserved_GeometrySrcType:
1861 finalizeReservedIndices();
1862 *extraIndexOffset = fCurrPoolStartIndex;
1863 ibuf = (GrGLIndexBuffer*) fCurrPoolIndexBuffer;
1864 break;
1865 default:
1866 ibuf = NULL; // suppress warning
1867 GrCrash("Unknown geometry src type!");
1868 }
1869
1870 GrAssert(NULL != ibuf);
1871 GrAssert(!ibuf->isLocked());
1872 if (fHWGeometryState.fIndexBuffer != ibuf) {
1873 GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibuf->bufferID()));
1874 fHWGeometryState.fIndexBuffer = ibuf;
1875 }
1876 }
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001877}