blob: 3ee524b74bc9c8e9630d5441d3bda24aa9fc8e78 [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) ||
reed@google.comeca7d342011-03-04 19:33:13 +0000267 ((1 == major) && (minor >= 4)) ||
bsalomon@google.comd302f142011-03-03 13:54:13 +0000268 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
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000435 // we don't use the zb at all
436 GR_GL(Disable(GL_DEPTH_TEST));
437 GR_GL(DepthMask(GL_FALSE));
438
reed@google.comac10a2d2010-12-22 21:39:39 +0000439 GR_GL(Disable(GL_CULL_FACE));
bsalomon@google.comd302f142011-03-03 13:54:13 +0000440 GR_GL(FrontFace(GL_CCW));
441 fHWDrawState.fDrawFace = kBoth_DrawFace;
reed@google.comac10a2d2010-12-22 21:39:39 +0000442
443 GR_GL(Disable(GL_DITHER));
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000444#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000445 GR_GL(Disable(GL_LINE_SMOOTH));
446 GR_GL(Disable(GL_POINT_SMOOTH));
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000447 GR_GL(Disable(GL_MULTISAMPLE));
reed@google.comac10a2d2010-12-22 21:39:39 +0000448#endif
449
bsalomon@google.comd302f142011-03-03 13:54:13 +0000450 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
451 fHWDrawState.fFlagBits = 0;
452
reed@google.comac10a2d2010-12-22 21:39:39 +0000453 // we only ever use lines in hairline mode
454 GR_GL(LineWidth(1));
455
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000456 // invalid
457 fActiveTextureUnitIdx = -1;
reed@google.comac10a2d2010-12-22 21:39:39 +0000458
reed@google.comac10a2d2010-12-22 21:39:39 +0000459 // illegal values
bsalomon@google.comffca4002011-02-22 20:34:01 +0000460 fHWDrawState.fSrcBlend = (GrBlendCoeff)-1;
461 fHWDrawState.fDstBlend = (GrBlendCoeff)-1;
reed@google.comac10a2d2010-12-22 21:39:39 +0000462 fHWDrawState.fColor = GrColor_ILLEGAL;
bsalomon@google.com316f99232011-01-13 21:28:12 +0000463
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000464 fHWDrawState.fViewMatrix = GrMatrix::InvalidMatrix();
bsalomon@google.com316f99232011-01-13 21:28:12 +0000465
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000466 for (int s = 0; s < kNumStages; ++s) {
467 fHWDrawState.fTextures[s] = NULL;
468 fHWDrawState.fSamplerStates[s].setRadial2Params(-GR_ScalarMax,
469 -GR_ScalarMax,
470 true);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000471
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000472 fHWDrawState.fSamplerStates[s].setMatrix(GrMatrix::InvalidMatrix());
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000473 }
bsalomon@google.com316f99232011-01-13 21:28:12 +0000474
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000475 fHWBounds.fScissorRect.invalidate();
reed@google.comac10a2d2010-12-22 21:39:39 +0000476 fHWBounds.fScissorEnabled = false;
477 GR_GL(Disable(GL_SCISSOR_TEST));
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000478 fHWBounds.fViewportRect.invalidate();
reed@google.comac10a2d2010-12-22 21:39:39 +0000479
bsalomon@google.comd302f142011-03-03 13:54:13 +0000480 fHWDrawState.fStencilSettings.invalidate();
reed@google.comac10a2d2010-12-22 21:39:39 +0000481 fHWStencilClip = false;
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000482 fClipState.fClipIsDirty = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000483
484 fHWGeometryState.fIndexBuffer = NULL;
485 fHWGeometryState.fVertexBuffer = NULL;
486 GR_GL(BindBuffer(GL_ARRAY_BUFFER, 0));
487 GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000488 fHWGeometryState.fArrayPtrsDirty = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000489
bsalomon@google.comd302f142011-03-03 13:54:13 +0000490 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
reed@google.comac10a2d2010-12-22 21:39:39 +0000491 fHWDrawState.fRenderTarget = NULL;
492}
493
494void GrGpuGL::resetContext() {
495 INHERITED::resetContext();
496 resetContextHelper();
497}
498
reed@google.comac10a2d2010-12-22 21:39:39 +0000499GrRenderTarget* GrGpuGL::createPlatformRenderTarget(
500 intptr_t platformRenderTarget,
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000501 int stencilBits,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000502 int width,
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000503 int height) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000504 GrGLRenderTarget::GLRenderTargetIDs rtIDs;
505 rtIDs.fStencilRenderbufferID = 0;
506 rtIDs.fMSColorRenderbufferID = 0;
507 rtIDs.fTexFBOID = 0;
508 rtIDs.fOwnIDs = false;
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000509 GrGLIRect viewport;
reed@google.comac10a2d2010-12-22 21:39:39 +0000510
511 // viewport is in GL coords (top >= bottom)
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000512 viewport.fLeft = 0;
513 viewport.fBottom = 0;
514 viewport.fWidth = width;
515 viewport.fHeight = height;
reed@google.comac10a2d2010-12-22 21:39:39 +0000516
517 rtIDs.fRTFBOID = (GLuint)platformRenderTarget;
518 rtIDs.fTexFBOID = (GLuint)platformRenderTarget;
519
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000520 return new GrGLRenderTarget(rtIDs, stencilBits, viewport, NULL, this);
reed@google.comac10a2d2010-12-22 21:39:39 +0000521}
522
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000523GrRenderTarget* GrGpuGL::createRenderTargetFrom3DApiState() {
bsalomon@google.com42ab7ea2011-01-19 17:19:40 +0000524
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000525 GrGLRenderTarget::GLRenderTargetIDs rtIDs;
bsalomon@google.com42ab7ea2011-01-19 17:19:40 +0000526
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000527 GR_GL_GetIntegerv(GR_FRAMEBUFFER_BINDING, (GLint*)&rtIDs.fRTFBOID);
528 rtIDs.fTexFBOID = rtIDs.fRTFBOID;
529 rtIDs.fMSColorRenderbufferID = 0;
530 rtIDs.fStencilRenderbufferID = 0;
bsalomon@google.com42ab7ea2011-01-19 17:19:40 +0000531
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000532 GrGLIRect viewport;
533 viewport.setFromGLViewport();
534 GLuint stencilBits;
535 GR_GL_GetIntegerv(GL_STENCIL_BITS, (GLint*)&stencilBits);
536
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000537 rtIDs.fOwnIDs = false;
538
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000539 return new GrGLRenderTarget(rtIDs, stencilBits, viewport, NULL, this);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000540}
541
bsalomon@google.com5782d712011-01-21 21:03:59 +0000542///////////////////////////////////////////////////////////////////////////////
543
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000544static const GLuint UNKNOWN_BITS = ~0;
545
bsalomon@google.com3f3ffd62011-01-18 17:14:52 +0000546// defines stencil formats from more to less preferred
bsalomon@google.com5d18c382011-02-18 16:21:58 +0000547static const struct {
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000548 GLenum fEnum;
549 GLuint fBits;
550} gStencilFormats[] = {
551 {GR_STENCIL_INDEX8, 8},
reed@google.com63100f92011-01-18 21:32:14 +0000552
553#if GR_SUPPORT_GLDESKTOP
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000554 {GR_STENCIL_INDEX16, 16},
reed@google.com63100f92011-01-18 21:32:14 +0000555#endif
556
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000557 {GR_DEPTH24_STENCIL8, 8},
558 {GR_STENCIL_INDEX4, 4},
reed@google.com63100f92011-01-18 21:32:14 +0000559
560#if GR_SUPPORT_GLDESKTOP
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000561 {GL_STENCIL_INDEX, UNKNOWN_BITS},
562 {GR_DEPTH_STENCIL, UNKNOWN_BITS}
bsalomon@google.com3f3ffd62011-01-18 17:14:52 +0000563#endif
564};
565
566// good to set a break-point here to know when createTexture fails
567static GrTexture* return_null_texture() {
568// GrAssert(!"null texture");
569 return NULL;
570}
571
572#if GR_DEBUG
573static size_t as_size_t(int x) {
574 return x;
575}
576#endif
577
reed@google.comac10a2d2010-12-22 21:39:39 +0000578GrTexture* GrGpuGL::createTexture(const TextureDesc& desc,
579 const void* srcData, size_t rowBytes) {
580
581#if GR_COLLECT_STATS
582 ++fStats.fTextureCreateCnt;
583#endif
reed@google.com1fcd51e2011-01-05 15:50:27 +0000584
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000585 setSpareTextureUnit();
bsalomon@google.com316f99232011-01-13 21:28:12 +0000586
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000587 static const GrGLTexture::TexParams DEFAULT_PARAMS = {
588 GL_NEAREST,
589 GL_CLAMP_TO_EDGE,
590 GL_CLAMP_TO_EDGE
591 };
reed@google.com1fcd51e2011-01-05 15:50:27 +0000592
reed@google.comac10a2d2010-12-22 21:39:39 +0000593 GrGLTexture::GLTextureDesc glDesc;
594 GLenum internalFormat;
595
596 glDesc.fContentWidth = desc.fWidth;
597 glDesc.fContentHeight = desc.fHeight;
598 glDesc.fAllocWidth = desc.fWidth;
599 glDesc.fAllocHeight = desc.fHeight;
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000600 glDesc.fStencilBits = 0;
reed@google.comac10a2d2010-12-22 21:39:39 +0000601 glDesc.fFormat = desc.fFormat;
602
603 bool renderTarget = 0 != (desc.fFlags & kRenderTarget_TextureFlag);
604 if (!canBeTexture(desc.fFormat,
605 &internalFormat,
606 &glDesc.fUploadFormat,
607 &glDesc.fUploadType)) {
608 return return_null_texture();
609 }
610
611 GrAssert(as_size_t(desc.fAALevel) < GR_ARRAY_COUNT(fAASamples));
612 GLint samples = fAASamples[desc.fAALevel];
613 if (kNone_MSFBO == fMSFBOType && desc.fAALevel != kNone_AALevel) {
614 GrPrintf("AA RT requested but not supported on this platform.");
615 }
616
617 GR_GL(GenTextures(1, &glDesc.fTextureID));
618 if (!glDesc.fTextureID) {
619 return return_null_texture();
620 }
621
622 glDesc.fUploadByteCount = GrTexture::BytesPerPixel(desc.fFormat);
623
624 /*
625 * check if our srcData has extra bytes past each row. If so, we need
626 * to trim those off here, since GL doesn't let us pass the rowBytes as
627 * a parameter to glTexImage2D
628 */
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000629#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000630 if (srcData) {
631 GR_GL(PixelStorei(GL_UNPACK_ROW_LENGTH,
632 rowBytes / glDesc.fUploadByteCount));
633 }
634#else
635 GrAutoSMalloc<128 * 128> trimStorage;
636 size_t trimRowBytes = desc.fWidth * glDesc.fUploadByteCount;
637 if (srcData && (trimRowBytes < rowBytes)) {
638 size_t trimSize = desc.fHeight * trimRowBytes;
639 trimStorage.realloc(trimSize);
640 // now copy the data into our new storage, skipping the trailing bytes
641 const char* src = (const char*)srcData;
642 char* dst = (char*)trimStorage.get();
643 for (uint32_t y = 0; y < desc.fHeight; y++) {
644 memcpy(dst, src, trimRowBytes);
645 src += rowBytes;
646 dst += trimRowBytes;
647 }
648 // now point srcData to our trimmed version
649 srcData = trimStorage.get();
650 }
651#endif
652
reed@google.comac10a2d2010-12-22 21:39:39 +0000653 if (renderTarget) {
bsalomon@google.com0748f212011-02-01 22:56:16 +0000654 if (!this->npotRenderTargetSupport()) {
655 glDesc.fAllocWidth = GrNextPow2(desc.fWidth);
656 glDesc.fAllocHeight = GrNextPow2(desc.fHeight);
657 }
658
reed@google.comac10a2d2010-12-22 21:39:39 +0000659 glDesc.fAllocWidth = GrMax<int>(fMinRenderTargetWidth,
660 glDesc.fAllocWidth);
661 glDesc.fAllocHeight = GrMax<int>(fMinRenderTargetHeight,
662 glDesc.fAllocHeight);
bsalomon@google.com0748f212011-02-01 22:56:16 +0000663 } else if (!this->npotTextureSupport()) {
664 glDesc.fAllocWidth = GrNextPow2(desc.fWidth);
665 glDesc.fAllocHeight = GrNextPow2(desc.fHeight);
reed@google.comac10a2d2010-12-22 21:39:39 +0000666 }
667
668 GR_GL(BindTexture(GL_TEXTURE_2D, glDesc.fTextureID));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000669 GR_GL(TexParameteri(GL_TEXTURE_2D,
670 GL_TEXTURE_MAG_FILTER,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000671 DEFAULT_PARAMS.fFilter));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000672 GR_GL(TexParameteri(GL_TEXTURE_2D,
673 GL_TEXTURE_MIN_FILTER,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000674 DEFAULT_PARAMS.fFilter));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000675 GR_GL(TexParameteri(GL_TEXTURE_2D,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000676 GL_TEXTURE_WRAP_S,
677 DEFAULT_PARAMS.fWrapS));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000678 GR_GL(TexParameteri(GL_TEXTURE_2D,
679 GL_TEXTURE_WRAP_T,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000680 DEFAULT_PARAMS.fWrapT));
reed@google.comac10a2d2010-12-22 21:39:39 +0000681
682 GR_GL(PixelStorei(GL_UNPACK_ALIGNMENT, glDesc.fUploadByteCount));
683 if (GrTexture::kIndex_8_PixelConfig == desc.fFormat &&
684 supports8BitPalette()) {
685 // ES only supports CompressedTexImage2D, not CompressedTexSubimage2D
686 GrAssert(desc.fWidth == glDesc.fAllocWidth);
687 GrAssert(desc.fHeight == glDesc.fAllocHeight);
688 GLsizei imageSize = glDesc.fAllocWidth * glDesc.fAllocHeight +
689 kColorTableSize;
690 GR_GL(CompressedTexImage2D(GL_TEXTURE_2D, 0, glDesc.fUploadFormat,
691 glDesc.fAllocWidth, glDesc.fAllocHeight,
692 0, imageSize, srcData));
693 GrGL_RestoreResetRowLength();
694 } else {
695 if (NULL != srcData && (glDesc.fAllocWidth != desc.fWidth ||
696 glDesc.fAllocHeight != desc.fHeight)) {
697 GR_GL(TexImage2D(GL_TEXTURE_2D, 0, internalFormat,
698 glDesc.fAllocWidth, glDesc.fAllocHeight,
699 0, glDesc.fUploadFormat, glDesc.fUploadType, NULL));
700 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, desc.fWidth,
701 desc.fHeight, glDesc.fUploadFormat,
702 glDesc.fUploadType, srcData));
703 GrGL_RestoreResetRowLength();
704
705 uint32_t extraW = glDesc.fAllocWidth - desc.fWidth;
706 uint32_t extraH = glDesc.fAllocHeight - desc.fHeight;
707 uint32_t maxTexels = extraW * extraH;
708 maxTexels = GrMax(extraW * desc.fHeight, maxTexels);
709 maxTexels = GrMax(desc.fWidth * extraH, maxTexels);
710
711 GrAutoSMalloc<128*128> texels(glDesc.fUploadByteCount * maxTexels);
712
713 uint32_t rowSize = desc.fWidth * glDesc.fUploadByteCount;
714 if (extraH) {
715 uint8_t* lastRowStart = (uint8_t*) srcData +
716 (desc.fHeight - 1) * rowSize;
717 uint8_t* extraRowStart = (uint8_t*)texels.get();
718
719 for (uint32_t i = 0; i < extraH; ++i) {
720 memcpy(extraRowStart, lastRowStart, rowSize);
721 extraRowStart += rowSize;
722 }
723 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, 0, desc.fHeight, desc.fWidth,
724 extraH, glDesc.fUploadFormat, glDesc.fUploadType,
725 texels.get()));
726 }
727 if (extraW) {
728 uint8_t* edgeTexel = (uint8_t*)srcData + rowSize - glDesc.fUploadByteCount;
729 uint8_t* extraTexel = (uint8_t*)texels.get();
730 for (uint32_t j = 0; j < desc.fHeight; ++j) {
731 for (uint32_t i = 0; i < extraW; ++i) {
732 memcpy(extraTexel, edgeTexel, glDesc.fUploadByteCount);
733 extraTexel += glDesc.fUploadByteCount;
734 }
735 edgeTexel += rowSize;
736 }
737 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, desc.fWidth, 0, extraW,
738 desc.fHeight, glDesc.fUploadFormat,
739 glDesc.fUploadType, texels.get()));
740 }
741 if (extraW && extraH) {
742 uint8_t* cornerTexel = (uint8_t*)srcData + desc.fHeight * rowSize
743 - glDesc.fUploadByteCount;
744 uint8_t* extraTexel = (uint8_t*)texels.get();
745 for (uint32_t i = 0; i < extraW*extraH; ++i) {
746 memcpy(extraTexel, cornerTexel, glDesc.fUploadByteCount);
747 extraTexel += glDesc.fUploadByteCount;
748 }
749 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, desc.fWidth, desc.fHeight,
750 extraW, extraH, glDesc.fUploadFormat,
751 glDesc.fUploadType, texels.get()));
752 }
753
754 } else {
755 GR_GL(TexImage2D(GL_TEXTURE_2D, 0, internalFormat, glDesc.fAllocWidth,
756 glDesc.fAllocHeight, 0, glDesc.fUploadFormat,
757 glDesc.fUploadType, srcData));
758 GrGL_RestoreResetRowLength();
759 }
760 }
761
762 glDesc.fOrientation = GrGLTexture::kTopDown_Orientation;
763
764 GrGLRenderTarget::GLRenderTargetIDs rtIDs;
765 rtIDs.fStencilRenderbufferID = 0;
766 rtIDs.fMSColorRenderbufferID = 0;
767 rtIDs.fRTFBOID = 0;
768 rtIDs.fTexFBOID = 0;
769 rtIDs.fOwnIDs = true;
770 GLenum msColorRenderbufferFormat = -1;
771
772 if (renderTarget) {
773#if GR_COLLECT_STATS
774 ++fStats.fRenderTargetCreateCnt;
775#endif
776 bool failed = true;
777 GLenum status;
778 GLint err;
779
780 // If need have both RT flag and srcData we have
781 // to invert the data before uploading because FBO
782 // will be rendered bottom up
783 GrAssert(NULL == srcData);
784 glDesc.fOrientation = GrGLTexture::kBottomUp_Orientation;
785
786 GR_GLEXT(fExts, GenFramebuffers(1, &rtIDs.fTexFBOID));
787 GrAssert(rtIDs.fTexFBOID);
788
789 // If we are using multisampling and any extension other than the IMG
790 // one we will create two FBOs. We render to one and then resolve to
791 // the texture bound to the other. The IMG extension does an implicit
792 // resolve.
793 if (samples > 1 && kIMG_MSFBO != fMSFBOType && kNone_MSFBO != fMSFBOType) {
794 GR_GLEXT(fExts, GenFramebuffers(1, &rtIDs.fRTFBOID));
795 GrAssert(0 != rtIDs.fRTFBOID);
796 GR_GLEXT(fExts, GenRenderbuffers(1, &rtIDs.fMSColorRenderbufferID));
797 GrAssert(0 != rtIDs.fMSColorRenderbufferID);
798 if (!fboInternalFormat(desc.fFormat, &msColorRenderbufferFormat)) {
799 GR_GLEXT(fExts,
800 DeleteRenderbuffers(1, &rtIDs.fMSColorRenderbufferID));
801 GR_GL(DeleteTextures(1, &glDesc.fTextureID));
802 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fTexFBOID));
803 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fRTFBOID));
reed@google.comac10a2d2010-12-22 21:39:39 +0000804 return return_null_texture();
805 }
806 } else {
807 rtIDs.fRTFBOID = rtIDs.fTexFBOID;
808 }
809 int attempts = 1;
810 if (!(kNoPathRendering_TextureFlag & desc.fFlags)) {
811 GR_GLEXT(fExts, GenRenderbuffers(1, &rtIDs.fStencilRenderbufferID));
812 GrAssert(0 != rtIDs.fStencilRenderbufferID);
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000813 attempts = GR_ARRAY_COUNT(gStencilFormats);
reed@google.comac10a2d2010-12-22 21:39:39 +0000814 }
815
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000816 // someone suggested that some systems might require
bsalomon@google.com316f99232011-01-13 21:28:12 +0000817 // unbinding the texture before we call FramebufferTexture2D
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000818 // (seems unlikely)
reed@google.comac10a2d2010-12-22 21:39:39 +0000819 GR_GL(BindTexture(GL_TEXTURE_2D, 0));
reed@google.comac10a2d2010-12-22 21:39:39 +0000820
821 err = ~GL_NO_ERROR;
822 for (int i = 0; i < attempts; ++i) {
823 if (rtIDs.fStencilRenderbufferID) {
824 GR_GLEXT(fExts, BindRenderbuffer(GR_RENDERBUFFER,
825 rtIDs.fStencilRenderbufferID));
826 if (samples > 1) {
827 GR_GLEXT_NO_ERR(fExts, RenderbufferStorageMultisample(
828 GR_RENDERBUFFER,
829 samples,
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000830 gStencilFormats[i].fEnum,
reed@google.comac10a2d2010-12-22 21:39:39 +0000831 glDesc.fAllocWidth,
832 glDesc.fAllocHeight));
833 } else {
834 GR_GLEXT_NO_ERR(fExts, RenderbufferStorage(
835 GR_RENDERBUFFER,
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000836 gStencilFormats[i].fEnum,
reed@google.comac10a2d2010-12-22 21:39:39 +0000837 glDesc.fAllocWidth,
838 glDesc.fAllocHeight));
839 }
840 err = glGetError();
841 if (err != GL_NO_ERROR) {
842 continue;
843 }
844 }
845 if (rtIDs.fRTFBOID != rtIDs.fTexFBOID) {
846 GrAssert(samples > 1);
847 GR_GLEXT(fExts, BindRenderbuffer(GR_RENDERBUFFER,
848 rtIDs.fMSColorRenderbufferID));
849 GR_GLEXT_NO_ERR(fExts, RenderbufferStorageMultisample(
850 GR_RENDERBUFFER,
851 samples,
852 msColorRenderbufferFormat,
853 glDesc.fAllocWidth,
854 glDesc.fAllocHeight));
855 err = glGetError();
856 if (err != GL_NO_ERROR) {
857 continue;
858 }
859 }
860 GR_GLEXT(fExts, BindFramebuffer(GR_FRAMEBUFFER, rtIDs.fTexFBOID));
861
862#if GR_COLLECT_STATS
863 ++fStats.fRenderTargetChngCnt;
864#endif
865 if (kIMG_MSFBO == fMSFBOType && samples > 1) {
866 GR_GLEXT(fExts, FramebufferTexture2DMultisample(
867 GR_FRAMEBUFFER,
868 GR_COLOR_ATTACHMENT0,
869 GL_TEXTURE_2D,
870 glDesc.fTextureID,
871 0,
872 samples));
873
874 } else {
875 GR_GLEXT(fExts, FramebufferTexture2D(GR_FRAMEBUFFER,
876 GR_COLOR_ATTACHMENT0,
877 GL_TEXTURE_2D,
878 glDesc.fTextureID, 0));
879 }
880 if (rtIDs.fRTFBOID != rtIDs.fTexFBOID) {
881 GLenum status = GR_GLEXT(fExts,
882 CheckFramebufferStatus(GR_FRAMEBUFFER));
883 if (status != GR_FRAMEBUFFER_COMPLETE) {
884 GrPrintf("-- glCheckFramebufferStatus %x %d %d\n",
885 status, desc.fWidth, desc.fHeight);
886 continue;
887 }
888 GR_GLEXT(fExts, BindFramebuffer(GR_FRAMEBUFFER, rtIDs.fRTFBOID));
889 #if GR_COLLECT_STATS
890 ++fStats.fRenderTargetChngCnt;
891 #endif
892 GR_GLEXT(fExts, FramebufferRenderbuffer(GR_FRAMEBUFFER,
893 GR_COLOR_ATTACHMENT0,
894 GR_RENDERBUFFER,
895 rtIDs.fMSColorRenderbufferID));
896
897 }
898 if (rtIDs.fStencilRenderbufferID) {
899 // bind the stencil to rt fbo if present, othewise the tex fbo
900 GR_GLEXT(fExts, FramebufferRenderbuffer(GR_FRAMEBUFFER,
901 GR_STENCIL_ATTACHMENT,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000902 GR_RENDERBUFFER,
reed@google.comac10a2d2010-12-22 21:39:39 +0000903 rtIDs.fStencilRenderbufferID));
904 }
905 status = GR_GLEXT(fExts, CheckFramebufferStatus(GR_FRAMEBUFFER));
906
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000907#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000908 // On some implementations you have to be bound as DEPTH_STENCIL.
909 // (Even binding to DEPTH and STENCIL separately with the same
910 // buffer doesn't work.)
911 if (rtIDs.fStencilRenderbufferID &&
912 status != GR_FRAMEBUFFER_COMPLETE) {
913 GR_GLEXT(fExts, FramebufferRenderbuffer(GR_FRAMEBUFFER,
914 GR_STENCIL_ATTACHMENT,
915 GR_RENDERBUFFER,
916 0));
917 GR_GLEXT(fExts,
918 FramebufferRenderbuffer(GR_FRAMEBUFFER,
919 GR_DEPTH_STENCIL_ATTACHMENT,
920 GR_RENDERBUFFER,
921 rtIDs.fStencilRenderbufferID));
922 status = GR_GLEXT(fExts, CheckFramebufferStatus(GR_FRAMEBUFFER));
923 }
924#endif
925 if (status != GR_FRAMEBUFFER_COMPLETE) {
926 GrPrintf("-- glCheckFramebufferStatus %x %d %d\n",
927 status, desc.fWidth, desc.fHeight);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000928#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000929 if (rtIDs.fStencilRenderbufferID) {
930 GR_GLEXT(fExts, FramebufferRenderbuffer(GR_FRAMEBUFFER,
931 GR_DEPTH_STENCIL_ATTACHMENT,
932 GR_RENDERBUFFER,
933 0));
934 }
935#endif
936 continue;
937 }
938 // we're successful!
939 failed = false;
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000940 if (rtIDs.fStencilRenderbufferID) {
941 if (UNKNOWN_BITS == gStencilFormats[i].fBits) {
942 GR_GL_GetIntegerv(GL_STENCIL_BITS, (GLint*)&glDesc.fStencilBits);
943 } else {
944 glDesc.fStencilBits = gStencilFormats[i].fBits;
945 }
946 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000947 break;
948 }
949 if (failed) {
950 if (rtIDs.fStencilRenderbufferID) {
951 GR_GLEXT(fExts,
952 DeleteRenderbuffers(1, &rtIDs.fStencilRenderbufferID));
953 }
954 if (rtIDs.fMSColorRenderbufferID) {
955 GR_GLEXT(fExts,
956 DeleteRenderbuffers(1, &rtIDs.fMSColorRenderbufferID));
957 }
958 if (rtIDs.fRTFBOID != rtIDs.fTexFBOID) {
959 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fRTFBOID));
960 }
961 if (rtIDs.fTexFBOID) {
962 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fTexFBOID));
963 }
964 GR_GL(DeleteTextures(1, &glDesc.fTextureID));
965 return return_null_texture();
966 }
967 }
968#ifdef TRACE_TEXTURE_CREATION
969 GrPrintf("--- new texture [%d] size=(%d %d) bpp=%d\n",
970 tex->fTextureID, width, height, tex->fUploadByteCount);
971#endif
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000972 GrGLTexture* tex = new GrGLTexture(glDesc, rtIDs, DEFAULT_PARAMS, this);
reed@google.comac10a2d2010-12-22 21:39:39 +0000973
974 if (0 != rtIDs.fTexFBOID) {
975 GrRenderTarget* rt = tex->asRenderTarget();
976 // We've messed with FBO state but may not have set the correct viewport
977 // so just dirty the rendertarget state to force a resend.
978 fHWDrawState.fRenderTarget = NULL;
979
980 // clear the new stencil buffer if we have one
981 if (!(desc.fFlags & kNoPathRendering_TextureFlag)) {
982 GrRenderTarget* rtSave = fCurrDrawState.fRenderTarget;
983 fCurrDrawState.fRenderTarget = rt;
984 eraseStencil(0, ~0);
985 fCurrDrawState.fRenderTarget = rtSave;
986 }
987 }
988 return tex;
989}
990
reed@google.comac10a2d2010-12-22 21:39:39 +0000991GrVertexBuffer* GrGpuGL::createVertexBuffer(uint32_t size, bool dynamic) {
992 GLuint id;
993 GR_GL(GenBuffers(1, &id));
994 if (id) {
995 GR_GL(BindBuffer(GL_ARRAY_BUFFER, id));
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000996 fHWGeometryState.fArrayPtrsDirty = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000997 GrGLClearErr();
998 // make sure driver can allocate memory for this buffer
999 GR_GL_NO_ERR(BufferData(GL_ARRAY_BUFFER, size, NULL,
1000 dynamic ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW));
1001 if (glGetError() != GL_NO_ERROR) {
1002 GR_GL(DeleteBuffers(1, &id));
1003 // deleting bound buffer does implicit bind to 0
1004 fHWGeometryState.fVertexBuffer = NULL;
1005 return NULL;
1006 }
1007 GrGLVertexBuffer* vertexBuffer = new GrGLVertexBuffer(id, this,
1008 size, dynamic);
1009 fHWGeometryState.fVertexBuffer = vertexBuffer;
1010 return vertexBuffer;
1011 }
1012 return NULL;
1013}
1014
1015GrIndexBuffer* GrGpuGL::createIndexBuffer(uint32_t size, bool dynamic) {
1016 GLuint id;
1017 GR_GL(GenBuffers(1, &id));
1018 if (id) {
1019 GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, id));
1020 GrGLClearErr();
1021 // make sure driver can allocate memory for this buffer
1022 GR_GL_NO_ERR(BufferData(GL_ELEMENT_ARRAY_BUFFER, size, NULL,
1023 dynamic ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW));
1024 if (glGetError() != GL_NO_ERROR) {
1025 GR_GL(DeleteBuffers(1, &id));
1026 // deleting bound buffer does implicit bind to 0
1027 fHWGeometryState.fIndexBuffer = NULL;
1028 return NULL;
1029 }
1030 GrIndexBuffer* indexBuffer = new GrGLIndexBuffer(id, this,
1031 size, dynamic);
1032 fHWGeometryState.fIndexBuffer = indexBuffer;
1033 return indexBuffer;
1034 }
1035 return NULL;
1036}
1037
reed@google.comac10a2d2010-12-22 21:39:39 +00001038void GrGpuGL::flushScissor(const GrIRect* rect) {
1039 GrAssert(NULL != fCurrDrawState.fRenderTarget);
bsalomon@google.com8895a7a2011-02-18 16:09:55 +00001040 const GrGLIRect& vp =
bsalomon@google.comd302f142011-03-03 13:54:13 +00001041 ((GrGLRenderTarget*)fCurrDrawState.fRenderTarget)->getViewport();
reed@google.comac10a2d2010-12-22 21:39:39 +00001042
bsalomon@google.com8895a7a2011-02-18 16:09:55 +00001043 GrGLIRect scissor;
1044 if (NULL != rect) {
bsalomon@google.comd302f142011-03-03 13:54:13 +00001045 scissor.setRelativeTo(vp, rect->fLeft, rect->fTop,
bsalomon@google.com8895a7a2011-02-18 16:09:55 +00001046 rect->width(), rect->height());
1047 if (scissor.contains(vp)) {
1048 rect = NULL;
1049 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001050 }
1051
1052 if (NULL != rect) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001053 if (fHWBounds.fScissorRect != scissor) {
bsalomon@google.com8895a7a2011-02-18 16:09:55 +00001054 scissor.pushToGLScissor();
reed@google.comac10a2d2010-12-22 21:39:39 +00001055 fHWBounds.fScissorRect = scissor;
1056 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001057 if (!fHWBounds.fScissorEnabled) {
1058 GR_GL(Enable(GL_SCISSOR_TEST));
1059 fHWBounds.fScissorEnabled = true;
1060 }
1061 } else {
1062 if (fHWBounds.fScissorEnabled) {
1063 GR_GL(Disable(GL_SCISSOR_TEST));
1064 fHWBounds.fScissorEnabled = false;
1065 }
1066 }
1067}
1068
reed@google.comac10a2d2010-12-22 21:39:39 +00001069void GrGpuGL::eraseColor(GrColor color) {
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +00001070 if (NULL == fCurrDrawState.fRenderTarget) {
1071 return;
1072 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001073 flushRenderTarget();
1074 if (fHWBounds.fScissorEnabled) {
1075 GR_GL(Disable(GL_SCISSOR_TEST));
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +00001076 fHWBounds.fScissorEnabled = false;
reed@google.comac10a2d2010-12-22 21:39:39 +00001077 }
1078 GR_GL(ColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE));
bsalomon@google.comd302f142011-03-03 13:54:13 +00001079 fHWDrawState.fFlagBits &= ~kNoColorWrites_StateBit;
reed@google.comac10a2d2010-12-22 21:39:39 +00001080 GR_GL(ClearColor(GrColorUnpackR(color)/255.f,
1081 GrColorUnpackG(color)/255.f,
1082 GrColorUnpackB(color)/255.f,
1083 GrColorUnpackA(color)/255.f));
1084 GR_GL(Clear(GL_COLOR_BUFFER_BIT));
reed@google.comac10a2d2010-12-22 21:39:39 +00001085}
1086
1087void GrGpuGL::eraseStencil(uint32_t value, uint32_t mask) {
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +00001088 if (NULL == fCurrDrawState.fRenderTarget) {
1089 return;
1090 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001091 flushRenderTarget();
1092 if (fHWBounds.fScissorEnabled) {
1093 GR_GL(Disable(GL_SCISSOR_TEST));
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +00001094 fHWBounds.fScissorEnabled = false;
reed@google.comac10a2d2010-12-22 21:39:39 +00001095 }
1096 GR_GL(StencilMask(mask));
1097 GR_GL(ClearStencil(value));
1098 GR_GL(Clear(GL_STENCIL_BUFFER_BIT));
bsalomon@google.comd302f142011-03-03 13:54:13 +00001099 fHWDrawState.fStencilSettings.invalidate();
reed@google.comac10a2d2010-12-22 21:39:39 +00001100}
1101
bsalomon@google.comd302f142011-03-03 13:54:13 +00001102void GrGpuGL::eraseStencilClip(const GrIRect& rect) {
bsalomon@google.com8895a7a2011-02-18 16:09:55 +00001103 GrAssert(NULL != fCurrDrawState.fRenderTarget);
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +00001104#if 0
bsalomon@google.comd302f142011-03-03 13:54:13 +00001105 GLint stencilBitCount = fCurrDrawState.fRenderTarget->stencilBits();
reed@google.comac10a2d2010-12-22 21:39:39 +00001106 GrAssert(stencilBitCount > 0);
1107 GLint clipStencilMask = (1 << (stencilBitCount - 1));
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +00001108#else
1109 // we could just clear the clip bit but when we go through
1110 // angle a partial stencil mask will cause clears to be
1111 // turned into draws. Our contract on GrDrawTarget says that
1112 // changing the clip between stencil passes may or may not
1113 // zero the client's clip bits. So we just clear the whole thing.
1114 static const GLint clipStencilMask = ~0;
1115#endif
bsalomon@google.comd302f142011-03-03 13:54:13 +00001116 flushRenderTarget();
1117 flushScissor(&rect);
1118 GR_GL(StencilMask(clipStencilMask));
1119 GR_GL(ClearStencil(0));
1120 GR_GL(Clear(GL_STENCIL_BUFFER_BIT));
1121 fHWDrawState.fStencilSettings.invalidate();
reed@google.comac10a2d2010-12-22 21:39:39 +00001122}
1123
1124void GrGpuGL::forceRenderTargetFlush() {
1125 flushRenderTarget();
1126}
1127
1128bool GrGpuGL::readPixels(int left, int top, int width, int height,
1129 GrTexture::PixelConfig config, void* buffer) {
1130 GLenum internalFormat; // we don't use this for glReadPixels
1131 GLenum format;
1132 GLenum type;
1133 if (!this->canBeTexture(config, &internalFormat, &format, &type)) {
1134 return false;
1135 }
1136
bsalomon@google.com18908aa2011-02-07 14:51:55 +00001137 if (NULL == fCurrDrawState.fRenderTarget) {
1138 return false;
1139 }
1140 flushRenderTarget();
1141
bsalomon@google.comd302f142011-03-03 13:54:13 +00001142 const GrGLIRect& glvp = ((GrGLRenderTarget*)fCurrDrawState.fRenderTarget)->getViewport();
1143
bsalomon@google.com8895a7a2011-02-18 16:09:55 +00001144 // the read rect is viewport-relative
1145 GrGLIRect readRect;
1146 readRect.setRelativeTo(glvp, left, top, width, height);
1147 GR_GL(ReadPixels(readRect.fLeft, readRect.fBottom,
bsalomon@google.comd302f142011-03-03 13:54:13 +00001148 readRect.fWidth, readRect.fHeight,
bsalomon@google.com316f99232011-01-13 21:28:12 +00001149 format, type, buffer));
reed@google.comac10a2d2010-12-22 21:39:39 +00001150
1151 // now reverse the order of the rows, since GL's are bottom-to-top, but our
1152 // API presents top-to-bottom
1153 {
1154 size_t stride = width * GrTexture::BytesPerPixel(config);
1155 GrAutoMalloc rowStorage(stride);
1156 void* tmp = rowStorage.get();
1157
1158 const int halfY = height >> 1;
1159 char* top = reinterpret_cast<char*>(buffer);
1160 char* bottom = top + (height - 1) * stride;
1161 for (int y = 0; y < halfY; y++) {
1162 memcpy(tmp, top, stride);
1163 memcpy(top, bottom, stride);
1164 memcpy(bottom, tmp, stride);
1165 top += stride;
1166 bottom -= stride;
1167 }
1168 }
1169 return true;
1170}
1171
1172void GrGpuGL::flushRenderTarget() {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001173
1174 GrAssert(NULL != fCurrDrawState.fRenderTarget);
1175
reed@google.comac10a2d2010-12-22 21:39:39 +00001176 if (fHWDrawState.fRenderTarget != fCurrDrawState.fRenderTarget) {
1177 GrGLRenderTarget* rt = (GrGLRenderTarget*)fCurrDrawState.fRenderTarget;
1178 GR_GLEXT(fExts, BindFramebuffer(GR_FRAMEBUFFER, rt->renderFBOID()));
1179 #if GR_COLLECT_STATS
1180 ++fStats.fRenderTargetChngCnt;
1181 #endif
1182 rt->setDirty(true);
1183 #if GR_DEBUG
1184 GLenum status = GR_GLEXT(fExts, CheckFramebufferStatus(GR_FRAMEBUFFER));
1185 if (status != GR_FRAMEBUFFER_COMPLETE) {
1186 GrPrintf("-- glCheckFramebufferStatus %x\n", status);
1187 }
1188 #endif
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001189 fDirtyFlags.fRenderTargetChanged = true;
bsalomon@google.com8895a7a2011-02-18 16:09:55 +00001190 fHWDrawState.fRenderTarget = fCurrDrawState.fRenderTarget;
bsalomon@google.comd302f142011-03-03 13:54:13 +00001191 const GrGLIRect& vp = rt->getViewport();
bsalomon@google.com8895a7a2011-02-18 16:09:55 +00001192 if (true || fHWBounds.fViewportRect != vp) {
1193 vp.pushToGLViewport();
reed@google.comac10a2d2010-12-22 21:39:39 +00001194 fHWBounds.fViewportRect = vp;
1195 }
1196 }
1197}
1198
1199GLenum gPrimitiveType2GLMode[] = {
1200 GL_TRIANGLES,
1201 GL_TRIANGLE_STRIP,
1202 GL_TRIANGLE_FAN,
1203 GL_POINTS,
1204 GL_LINES,
1205 GL_LINE_STRIP
1206};
1207
bsalomon@google.comd302f142011-03-03 13:54:13 +00001208#define SWAP_PER_DRAW 0
1209
1210#if SWAP_PER_DRAW
1211 #if GR_MAC_BUILD
1212 #include <AGL/agl.h>
1213 #elif GR_WIN32_BUILD
1214 void SwapBuf() {
1215 DWORD procID = GetCurrentProcessId();
1216 HWND hwnd = GetTopWindow(GetDesktopWindow());
1217 while(hwnd) {
1218 DWORD wndProcID = 0;
1219 GetWindowThreadProcessId(hwnd, &wndProcID);
1220 if(wndProcID == procID) {
1221 SwapBuffers(GetDC(hwnd));
1222 }
1223 hwnd = GetNextWindow(hwnd, GW_HWNDNEXT);
1224 }
1225 }
1226 #endif
1227#endif
1228
bsalomon@google.comffca4002011-02-22 20:34:01 +00001229void GrGpuGL::drawIndexedHelper(GrPrimitiveType type,
reed@google.comac10a2d2010-12-22 21:39:39 +00001230 uint32_t startVertex,
1231 uint32_t startIndex,
1232 uint32_t vertexCount,
1233 uint32_t indexCount) {
1234 GrAssert((size_t)type < GR_ARRAY_COUNT(gPrimitiveType2GLMode));
1235
1236 GLvoid* indices = (GLvoid*)(sizeof(uint16_t) * startIndex);
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001237
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001238 GrAssert(NULL != fHWGeometryState.fIndexBuffer);
1239 GrAssert(NULL != fHWGeometryState.fVertexBuffer);
1240
1241 // our setupGeometry better have adjusted this to zero since
1242 // DrawElements always draws from the begining of the arrays for idx 0.
1243 GrAssert(0 == startVertex);
reed@google.comac10a2d2010-12-22 21:39:39 +00001244
1245 GR_GL(DrawElements(gPrimitiveType2GLMode[type], indexCount,
1246 GL_UNSIGNED_SHORT, indices));
bsalomon@google.comd302f142011-03-03 13:54:13 +00001247#if SWAP_PER_DRAW
1248 glFlush();
1249 #if GR_MAC_BUILD
1250 aglSwapBuffers(aglGetCurrentContext());
1251 int set_a_break_pt_here = 9;
1252 aglSwapBuffers(aglGetCurrentContext());
1253 #elif GR_WIN32_BUILD
1254 SwapBuf();
1255 int set_a_break_pt_here = 9;
1256 SwapBuf();
1257 #endif
1258#endif
reed@google.comac10a2d2010-12-22 21:39:39 +00001259}
1260
bsalomon@google.comffca4002011-02-22 20:34:01 +00001261void GrGpuGL::drawNonIndexedHelper(GrPrimitiveType type,
reed@google.comac10a2d2010-12-22 21:39:39 +00001262 uint32_t startVertex,
1263 uint32_t vertexCount) {
1264 GrAssert((size_t)type < GR_ARRAY_COUNT(gPrimitiveType2GLMode));
1265
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001266 GrAssert(NULL != fHWGeometryState.fVertexBuffer);
1267
1268 // our setupGeometry better have adjusted this to zero.
1269 // DrawElements doesn't take an offset so we always adjus the startVertex.
1270 GrAssert(0 == startVertex);
1271
1272 // pass 0 for parameter first. We have to adjust gl*Pointer() to
1273 // account for startVertex in the DrawElements case. So we always
1274 // rely on setupGeometry to have accounted for startVertex.
reed@google.comac10a2d2010-12-22 21:39:39 +00001275 GR_GL(DrawArrays(gPrimitiveType2GLMode[type], 0, vertexCount));
bsalomon@google.comd302f142011-03-03 13:54:13 +00001276#if SWAP_PER_DRAW
1277 glFlush();
1278 #if GR_MAC_BUILD
1279 aglSwapBuffers(aglGetCurrentContext());
1280 int set_a_break_pt_here = 9;
1281 aglSwapBuffers(aglGetCurrentContext());
1282 #elif GR_WIN32_BUILD
1283 SwapBuf();
1284 int set_a_break_pt_here = 9;
1285 SwapBuf();
1286 #endif
1287#endif
reed@google.comac10a2d2010-12-22 21:39:39 +00001288}
1289
reed@google.comac10a2d2010-12-22 21:39:39 +00001290void GrGpuGL::resolveTextureRenderTarget(GrGLTexture* texture) {
1291 GrGLRenderTarget* rt = (GrGLRenderTarget*) texture->asRenderTarget();
1292
1293 if (NULL != rt && rt->needsResolve()) {
1294 GrAssert(kNone_MSFBO != fMSFBOType);
1295 GrAssert(rt->textureFBOID() != rt->renderFBOID());
1296 GR_GLEXT(fExts, BindFramebuffer(GR_READ_FRAMEBUFFER,
1297 rt->renderFBOID()));
1298 GR_GLEXT(fExts, BindFramebuffer(GR_DRAW_FRAMEBUFFER,
1299 rt->textureFBOID()));
1300 #if GR_COLLECT_STATS
1301 ++fStats.fRenderTargetChngCnt;
1302 #endif
1303 // make sure we go through set render target
1304 fHWDrawState.fRenderTarget = NULL;
1305
1306 GLint left = 0;
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001307 GLint right = texture->width();
reed@google.comac10a2d2010-12-22 21:39:39 +00001308 // we will have rendered to the top of the FBO.
1309 GLint top = texture->allocHeight();
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001310 GLint bottom = texture->allocHeight() - texture->height();
reed@google.comac10a2d2010-12-22 21:39:39 +00001311 if (kApple_MSFBO == fMSFBOType) {
1312 GR_GL(Enable(GL_SCISSOR_TEST));
1313 GR_GL(Scissor(left, bottom, right-left, top-bottom));
1314 GR_GLEXT(fExts, ResolveMultisampleFramebuffer());
bsalomon@google.com8895a7a2011-02-18 16:09:55 +00001315 fHWBounds.fScissorRect.invalidate();
reed@google.comac10a2d2010-12-22 21:39:39 +00001316 fHWBounds.fScissorEnabled = true;
1317 } else {
1318 GR_GLEXT(fExts, BlitFramebuffer(left, bottom, right, top,
1319 left, bottom, right, top,
1320 GL_COLOR_BUFFER_BIT, GL_NEAREST));
1321 }
1322 rt->setDirty(false);
1323
1324 }
1325}
1326
bsalomon@google.comd302f142011-03-03 13:54:13 +00001327static const GLenum grToGLStencilFunc[] = {
1328 GL_ALWAYS, // kAlways_StencilFunc
1329 GL_NEVER, // kNever_StencilFunc
1330 GL_GREATER, // kGreater_StencilFunc
1331 GL_GEQUAL, // kGEqual_StencilFunc
1332 GL_LESS, // kLess_StencilFunc
1333 GL_LEQUAL, // kLEqual_StencilFunc,
1334 GL_EQUAL, // kEqual_StencilFunc,
1335 GL_NOTEQUAL, // kNotEqual_StencilFunc,
1336};
1337GR_STATIC_ASSERT(GR_ARRAY_COUNT(grToGLStencilFunc) == kBasicStencilFuncCount);
1338GR_STATIC_ASSERT(0 == kAlways_StencilFunc);
1339GR_STATIC_ASSERT(1 == kNever_StencilFunc);
1340GR_STATIC_ASSERT(2 == kGreater_StencilFunc);
1341GR_STATIC_ASSERT(3 == kGEqual_StencilFunc);
1342GR_STATIC_ASSERT(4 == kLess_StencilFunc);
1343GR_STATIC_ASSERT(5 == kLEqual_StencilFunc);
1344GR_STATIC_ASSERT(6 == kEqual_StencilFunc);
1345GR_STATIC_ASSERT(7 == kNotEqual_StencilFunc);
1346
1347static const GLenum grToGLStencilOp[] = {
1348 GL_KEEP, // kKeep_StencilOp
1349 GL_REPLACE, // kReplace_StencilOp
1350 GL_INCR_WRAP, // kIncWrap_StencilOp
1351 GL_INCR, // kIncClamp_StencilOp
1352 GL_DECR_WRAP, // kDecWrap_StencilOp
1353 GL_DECR, // kDecClamp_StencilOp
1354 GL_ZERO, // kZero_StencilOp
1355 GL_INVERT, // kInvert_StencilOp
1356};
1357GR_STATIC_ASSERT(GR_ARRAY_COUNT(grToGLStencilOp) == kStencilOpCount);
1358GR_STATIC_ASSERT(0 == kKeep_StencilOp);
1359GR_STATIC_ASSERT(1 == kReplace_StencilOp);
1360GR_STATIC_ASSERT(2 == kIncWrap_StencilOp);
1361GR_STATIC_ASSERT(3 == kIncClamp_StencilOp);
1362GR_STATIC_ASSERT(4 == kDecWrap_StencilOp);
1363GR_STATIC_ASSERT(5 == kDecClamp_StencilOp);
1364GR_STATIC_ASSERT(6 == kZero_StencilOp);
1365GR_STATIC_ASSERT(7 == kInvert_StencilOp);
1366
reed@google.comac10a2d2010-12-22 21:39:39 +00001367void GrGpuGL::flushStencil() {
bsalomon@google.comd302f142011-03-03 13:54:13 +00001368 const GrStencilSettings* settings = &fCurrDrawState.fStencilSettings;
reed@google.comac10a2d2010-12-22 21:39:39 +00001369
1370 // use stencil for clipping if clipping is enabled and the clip
1371 // has been written into the stencil.
1372 bool stencilClip = fClipState.fClipInStencil &&
1373 (kClip_StateBit & fCurrDrawState.fFlagBits);
bsalomon@google.comd302f142011-03-03 13:54:13 +00001374 bool stencilChange = fHWStencilClip != stencilClip ||
1375 fHWDrawState.fStencilSettings != *settings ||
1376 ((fHWDrawState.fFlagBits & kModifyStencilClip_StateBit) !=
1377 (fCurrDrawState.fFlagBits & kModifyStencilClip_StateBit));
reed@google.comac10a2d2010-12-22 21:39:39 +00001378
1379 if (stencilChange) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001380
bsalomon@google.comd302f142011-03-03 13:54:13 +00001381 // we can't simultaneously perform stencil-clipping and modify the stencil clip
1382 GrAssert(!stencilClip || !(fCurrDrawState.fFlagBits & kModifyStencilClip_StateBit));
reed@google.comac10a2d2010-12-22 21:39:39 +00001383
bsalomon@google.comd302f142011-03-03 13:54:13 +00001384 if (settings->isDisabled()) {
1385 if (stencilClip) {
1386 settings = &gClipStencilSettings;
1387 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001388 }
bsalomon@google.comd302f142011-03-03 13:54:13 +00001389
1390 if (settings->isDisabled()) {
1391 GR_GL(Disable(GL_STENCIL_TEST));
1392 } else {
1393 GR_GL(Enable(GL_STENCIL_TEST));
1394 #if GR_DEBUG
1395 if (!fStencilWrapOpsSupport) {
1396 GrAssert(settings->fFrontPassOp != kIncWrap_StencilOp);
1397 GrAssert(settings->fFrontPassOp != kDecWrap_StencilOp);
1398 GrAssert(settings->fFrontFailOp != kIncWrap_StencilOp);
1399 GrAssert(settings->fBackFailOp != kDecWrap_StencilOp);
1400 GrAssert(settings->fBackPassOp != kIncWrap_StencilOp);
1401 GrAssert(settings->fBackPassOp != kDecWrap_StencilOp);
1402 GrAssert(settings->fBackFailOp != kIncWrap_StencilOp);
1403 GrAssert(settings->fFrontFailOp != kDecWrap_StencilOp);
1404 }
1405 #endif
1406 int stencilBits = fCurrDrawState.fRenderTarget->stencilBits();
1407 GrAssert(stencilBits ||
1408 (GrStencilSettings::gDisabled ==
1409 fCurrDrawState.fStencilSettings));
1410 GLuint clipStencilMask = 1 << (stencilBits - 1);
1411 GLuint userStencilMask = clipStencilMask - 1;
1412
1413 unsigned int frontRef = settings->fFrontFuncRef;
1414 unsigned int frontMask = settings->fFrontFuncMask;
1415 unsigned int frontWriteMask = settings->fFrontWriteMask;
1416 GLenum frontFunc;
1417
1418 if (fCurrDrawState.fFlagBits & kModifyStencilClip_StateBit) {
1419
1420 GrAssert(settings->fFrontFunc < kBasicStencilFuncCount);
1421 frontFunc = grToGLStencilFunc[settings->fFrontFunc];
1422 } else {
1423 frontFunc = grToGLStencilFunc[ConvertStencilFunc(stencilClip, settings->fFrontFunc)];
1424
1425 ConvertStencilFuncAndMask(settings->fFrontFunc,
1426 stencilClip,
1427 clipStencilMask,
1428 userStencilMask,
1429 &frontRef,
1430 &frontMask);
1431 frontWriteMask &= userStencilMask;
1432 }
1433 GrAssert(settings->fFrontFailOp >= 0 &&
1434 settings->fFrontFailOp < GR_ARRAY_COUNT(grToGLStencilOp));
1435 GrAssert(settings->fFrontPassOp >= 0 &&
1436 settings->fFrontPassOp < GR_ARRAY_COUNT(grToGLStencilOp));
1437 GrAssert(settings->fBackFailOp >= 0 &&
1438 settings->fBackFailOp < GR_ARRAY_COUNT(grToGLStencilOp));
1439 GrAssert(settings->fBackPassOp >= 0 &&
1440 settings->fBackPassOp < GR_ARRAY_COUNT(grToGLStencilOp));
1441 if (fTwoSidedStencilSupport) {
1442 GLenum backFunc;
1443
1444 unsigned int backRef = settings->fBackFuncRef;
1445 unsigned int backMask = settings->fBackFuncMask;
1446 unsigned int backWriteMask = settings->fBackWriteMask;
1447
1448
1449 if (fCurrDrawState.fFlagBits & kModifyStencilClip_StateBit) {
1450 GrAssert(settings->fBackFunc < kBasicStencilFuncCount);
1451 backFunc = grToGLStencilFunc[settings->fBackFunc];
1452 } else {
1453 backFunc = grToGLStencilFunc[ConvertStencilFunc(stencilClip, settings->fBackFunc)];
1454 ConvertStencilFuncAndMask(settings->fBackFunc,
1455 stencilClip,
1456 clipStencilMask,
1457 userStencilMask,
1458 &backRef,
1459 &backMask);
1460 backWriteMask &= userStencilMask;
1461 }
1462
1463 GR_GL(StencilFuncSeparate(GL_FRONT, frontFunc, frontRef, frontMask));
1464 GR_GL(StencilMaskSeparate(GL_FRONT, frontWriteMask));
1465 GR_GL(StencilFuncSeparate(GL_BACK, backFunc, backRef, backMask));
1466 GR_GL(StencilMaskSeparate(GL_BACK, backWriteMask));
1467 GR_GL(StencilOpSeparate(GL_FRONT, grToGLStencilOp[settings->fFrontFailOp],
1468 grToGLStencilOp[settings->fFrontPassOp],
1469 grToGLStencilOp[settings->fFrontPassOp]));
1470
1471 GR_GL(StencilOpSeparate(GL_BACK, grToGLStencilOp[settings->fBackFailOp],
1472 grToGLStencilOp[settings->fBackPassOp],
1473 grToGLStencilOp[settings->fBackPassOp]));
1474 } else {
1475 GR_GL(StencilFunc(frontFunc, frontRef, frontMask));
1476 GR_GL(StencilMask(frontWriteMask));
1477 GR_GL(StencilOp(grToGLStencilOp[settings->fFrontFailOp],
1478 grToGLStencilOp[settings->fFrontPassOp],
1479 grToGLStencilOp[settings->fFrontPassOp]));
1480 }
1481 }
1482 fHWDrawState.fStencilSettings = fCurrDrawState.fStencilSettings;
reed@google.comac10a2d2010-12-22 21:39:39 +00001483 fHWStencilClip = stencilClip;
1484 }
1485}
1486
bsalomon@google.comffca4002011-02-22 20:34:01 +00001487bool GrGpuGL::flushGLStateCommon(GrPrimitiveType type) {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001488
1489 // GrGpu::setupClipAndFlushState should have already checked this
1490 // and bailed if not true.
1491 GrAssert(NULL != fCurrDrawState.fRenderTarget);
reed@google.comac10a2d2010-12-22 21:39:39 +00001492
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001493 for (int s = 0; s < kNumStages; ++s) {
1494 bool usingTexture = VertexUsesStage(s, fGeometrySrc.fVertexLayout);
reed@google.comac10a2d2010-12-22 21:39:39 +00001495
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001496 // bind texture and set sampler state
1497 if (usingTexture) {
1498 GrGLTexture* nextTexture = (GrGLTexture*)fCurrDrawState.fTextures[s];
reed@google.comac10a2d2010-12-22 21:39:39 +00001499
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001500 if (NULL != nextTexture) {
bsalomon@google.com316f99232011-01-13 21:28:12 +00001501 // if we created a rt/tex and rendered to it without using a
1502 // texture and now we're texuring from the rt it will still be
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001503 // the last bound texture, but it needs resolving. So keep this
1504 // out of the "last != next" check.
1505 resolveTextureRenderTarget(nextTexture);
reed@google.comac10a2d2010-12-22 21:39:39 +00001506
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001507 if (fHWDrawState.fTextures[s] != nextTexture) {
1508 setTextureUnit(s);
1509 GR_GL(BindTexture(GL_TEXTURE_2D, nextTexture->textureID()));
1510 #if GR_COLLECT_STATS
1511 ++fStats.fTextureChngCnt;
1512 #endif
1513 //GrPrintf("---- bindtexture %d\n", nextTexture->textureID());
1514 fHWDrawState.fTextures[s] = nextTexture;
1515 }
bsalomon@google.com316f99232011-01-13 21:28:12 +00001516
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001517 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
bsalomon@google.com316f99232011-01-13 21:28:12 +00001518 const GrGLTexture::TexParams& oldTexParams =
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001519 nextTexture->getTexParams();
1520 GrGLTexture::TexParams newTexParams;
bsalomon@google.com316f99232011-01-13 21:28:12 +00001521
1522 newTexParams.fFilter = sampler.isFilter() ? GL_LINEAR :
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001523 GL_NEAREST;
bsalomon@google.com316f99232011-01-13 21:28:12 +00001524 newTexParams.fWrapS =
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001525 GrGLTexture::gWrapMode2GLWrap[sampler.getWrapX()];
bsalomon@google.com316f99232011-01-13 21:28:12 +00001526 newTexParams.fWrapT =
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001527 GrGLTexture::gWrapMode2GLWrap[sampler.getWrapY()];
reed@google.comac10a2d2010-12-22 21:39:39 +00001528
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001529 if (newTexParams.fFilter != oldTexParams.fFilter) {
1530 setTextureUnit(s);
bsalomon@google.com316f99232011-01-13 21:28:12 +00001531 GR_GL(TexParameteri(GL_TEXTURE_2D,
1532 GL_TEXTURE_MAG_FILTER,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001533 newTexParams.fFilter));
bsalomon@google.com316f99232011-01-13 21:28:12 +00001534 GR_GL(TexParameteri(GL_TEXTURE_2D,
1535 GL_TEXTURE_MIN_FILTER,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001536 newTexParams.fFilter));
1537 }
1538 if (newTexParams.fWrapS != oldTexParams.fWrapS) {
1539 setTextureUnit(s);
bsalomon@google.com316f99232011-01-13 21:28:12 +00001540 GR_GL(TexParameteri(GL_TEXTURE_2D,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001541 GL_TEXTURE_WRAP_S,
1542 newTexParams.fWrapS));
1543 }
1544 if (newTexParams.fWrapT != oldTexParams.fWrapT) {
1545 setTextureUnit(s);
bsalomon@google.com316f99232011-01-13 21:28:12 +00001546 GR_GL(TexParameteri(GL_TEXTURE_2D,
1547 GL_TEXTURE_WRAP_T,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001548 newTexParams.fWrapT));
1549 }
1550 nextTexture->setTexParams(newTexParams);
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001551
1552 // The texture matrix has to compensate for texture width/height
1553 // and NPOT-embedded-in-POT
1554 fDirtyFlags.fTextureChangedMask |= (1 << s);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001555 } else {
1556 GrAssert(!"Rendering with texture vert flag set but no texture");
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001557 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +00001558 }
1559 }
1560 }
1561
1562 flushRenderTarget();
1563
1564 if ((fCurrDrawState.fFlagBits & kDither_StateBit) !=
1565 (fHWDrawState.fFlagBits & kDither_StateBit)) {
1566 if (fCurrDrawState.fFlagBits & kDither_StateBit) {
1567 GR_GL(Enable(GL_DITHER));
1568 } else {
1569 GR_GL(Disable(GL_DITHER));
1570 }
1571 }
1572
bsalomon@google.comd302f142011-03-03 13:54:13 +00001573 if ((fCurrDrawState.fFlagBits & kNoColorWrites_StateBit) !=
1574 (fHWDrawState.fFlagBits & kNoColorWrites_StateBit)) {
1575 GLenum mask;
1576 if (fCurrDrawState.fFlagBits & kNoColorWrites_StateBit) {
1577 mask = GL_FALSE;
1578 } else {
1579 mask = GL_TRUE;
1580 }
1581 GR_GL(ColorMask(mask, mask, mask, mask));
1582 }
1583
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001584#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +00001585 // ES doesn't support toggling GL_MULTISAMPLE and doesn't have
1586 // smooth lines.
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001587 if (fDirtyFlags.fRenderTargetChanged ||
reed@google.comac10a2d2010-12-22 21:39:39 +00001588 (fCurrDrawState.fFlagBits & kAntialias_StateBit) !=
1589 (fHWDrawState.fFlagBits & kAntialias_StateBit)) {
1590 GLint msaa = 0;
1591 // only perform query if we know MSAA is supported.
1592 // calling on non-MSAA target caused a crash in one environment,
1593 // though I don't think it should.
reed@google.coma09368c2011-02-24 21:42:29 +00001594 if (fAASamples[kHigh_AALevel]) {
reed@google.comac20fb92011-01-12 17:14:53 +00001595 GR_GL_GetIntegerv(GL_SAMPLE_BUFFERS, &msaa);
reed@google.comac10a2d2010-12-22 21:39:39 +00001596 }
1597 if (fCurrDrawState.fFlagBits & kAntialias_StateBit) {
1598 if (msaa) {
1599 GR_GL(Enable(GL_MULTISAMPLE));
1600 } else {
1601 GR_GL(Enable(GL_LINE_SMOOTH));
1602 }
1603 } else {
1604 if (msaa) {
1605 GR_GL(Disable(GL_MULTISAMPLE));
1606 }
1607 GR_GL(Disable(GL_LINE_SMOOTH));
1608 }
1609 }
1610#endif
1611
1612 bool blendOff = canDisableBlend();
1613 if (fHWBlendDisabled != blendOff) {
1614 if (blendOff) {
1615 GR_GL(Disable(GL_BLEND));
1616 } else {
1617 GR_GL(Enable(GL_BLEND));
1618 }
1619 fHWBlendDisabled = blendOff;
1620 }
1621
1622 if (!blendOff) {
1623 if (fHWDrawState.fSrcBlend != fCurrDrawState.fSrcBlend ||
1624 fHWDrawState.fDstBlend != fCurrDrawState.fDstBlend) {
1625 GR_GL(BlendFunc(gXfermodeCoeff2Blend[fCurrDrawState.fSrcBlend],
1626 gXfermodeCoeff2Blend[fCurrDrawState.fDstBlend]));
1627 fHWDrawState.fSrcBlend = fCurrDrawState.fSrcBlend;
1628 fHWDrawState.fDstBlend = fCurrDrawState.fDstBlend;
1629 }
1630 }
bsalomon@google.com316f99232011-01-13 21:28:12 +00001631
bsalomon@google.comd302f142011-03-03 13:54:13 +00001632 if (fHWDrawState.fDrawFace != fCurrDrawState.fDrawFace) {
1633 switch (fCurrDrawState.fDrawFace) {
1634 case kCCW_DrawFace:
1635 glEnable(GL_CULL_FACE);
1636 GR_GL(CullFace(GL_BACK));
1637 break;
1638 case kCW_DrawFace:
1639 GR_GL(Enable(GL_CULL_FACE));
1640 GR_GL(CullFace(GL_FRONT));
1641 break;
1642 case kBoth_DrawFace:
1643 GR_GL(Disable(GL_CULL_FACE));
1644 break;
1645 default:
1646 GrCrash("Unknown draw face.");
1647 }
1648 fHWDrawState.fDrawFace = fCurrDrawState.fDrawFace;
1649 }
1650
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001651#if GR_DEBUG
reed@google.comac10a2d2010-12-22 21:39:39 +00001652 // check for circular rendering
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001653 for (int s = 0; s < kNumStages; ++s) {
1654 GrAssert(!VertexUsesStage(s, fGeometrySrc.fVertexLayout) ||
1655 NULL == fCurrDrawState.fRenderTarget ||
1656 NULL == fCurrDrawState.fTextures[s] ||
bsalomon@google.com316f99232011-01-13 21:28:12 +00001657 fCurrDrawState.fTextures[s]->asRenderTarget() !=
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001658 fCurrDrawState.fRenderTarget);
1659 }
1660#endif
bsalomon@google.com316f99232011-01-13 21:28:12 +00001661
reed@google.comac10a2d2010-12-22 21:39:39 +00001662 flushStencil();
1663
bsalomon@google.comd302f142011-03-03 13:54:13 +00001664 // flushStencil may look at the private state bits, so keep it before this.
reed@google.comac10a2d2010-12-22 21:39:39 +00001665 fHWDrawState.fFlagBits = fCurrDrawState.fFlagBits;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001666 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +00001667}
1668
1669void GrGpuGL::notifyVertexBufferBind(const GrGLVertexBuffer* buffer) {
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001670 if (fHWGeometryState.fVertexBuffer != buffer) {
1671 fHWGeometryState.fArrayPtrsDirty = true;
1672 fHWGeometryState.fVertexBuffer = buffer;
1673 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001674}
1675
1676void GrGpuGL::notifyVertexBufferDelete(const GrGLVertexBuffer* buffer) {
1677 GrAssert(!(kBuffer_GeometrySrcType == fGeometrySrc.fVertexSrc &&
1678 buffer == fGeometrySrc.fVertexBuffer));
1679
1680 if (fHWGeometryState.fVertexBuffer == buffer) {
1681 // deleting bound buffer does implied bind to 0
1682 fHWGeometryState.fVertexBuffer = NULL;
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001683 fHWGeometryState.fArrayPtrsDirty = true;
reed@google.comac10a2d2010-12-22 21:39:39 +00001684 }
1685}
1686
1687void GrGpuGL::notifyIndexBufferBind(const GrGLIndexBuffer* buffer) {
1688 fGeometrySrc.fIndexBuffer = buffer;
1689}
1690
1691void GrGpuGL::notifyIndexBufferDelete(const GrGLIndexBuffer* buffer) {
1692 GrAssert(!(kBuffer_GeometrySrcType == fGeometrySrc.fIndexSrc &&
1693 buffer == fGeometrySrc.fIndexBuffer));
1694
1695 if (fHWGeometryState.fIndexBuffer == buffer) {
1696 // deleting bound buffer does implied bind to 0
1697 fHWGeometryState.fIndexBuffer = NULL;
1698 }
1699}
1700
reed@google.comac10a2d2010-12-22 21:39:39 +00001701void GrGpuGL::notifyRenderTargetDelete(GrRenderTarget* renderTarget) {
1702 GrAssert(NULL != renderTarget);
1703
1704 // if the bound FBO is destroyed we can't rely on the implicit bind to 0
1705 // a) we want the default RT which may not be FBO 0
1706 // b) we set more state than just FBO based on the RT
1707 // So trash the HW state to force an RT flush next time
1708 if (fCurrDrawState.fRenderTarget == renderTarget) {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001709 fCurrDrawState.fRenderTarget = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +00001710 }
1711 if (fHWDrawState.fRenderTarget == renderTarget) {
1712 fHWDrawState.fRenderTarget = NULL;
1713 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001714}
1715
1716void GrGpuGL::notifyTextureDelete(GrGLTexture* texture) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001717 for (int s = 0; s < kNumStages; ++s) {
1718 if (fCurrDrawState.fTextures[s] == texture) {
1719 fCurrDrawState.fTextures[s] = NULL;
1720 }
1721 if (fHWDrawState.fTextures[s] == texture) {
1722 // deleting bound texture does implied bind to 0
1723 fHWDrawState.fTextures[s] = NULL;
1724 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001725 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001726}
1727
1728void GrGpuGL::notifyTextureRemoveRenderTarget(GrGLTexture* texture) {
1729 GrAssert(NULL != texture->asRenderTarget());
1730
1731 // if there is a pending resolve, perform it.
1732 resolveTextureRenderTarget(texture);
1733}
1734
1735bool GrGpuGL::canBeTexture(GrTexture::PixelConfig config,
1736 GLenum* internalFormat,
1737 GLenum* format,
1738 GLenum* type) {
1739 switch (config) {
1740 case GrTexture::kRGBA_8888_PixelConfig:
1741 case GrTexture::kRGBX_8888_PixelConfig: // todo: can we tell it our X?
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +00001742 *format = GR_GL_32BPP_COLOR_FORMAT;
reed@google.com63100f92011-01-18 21:32:14 +00001743#if GR_SUPPORT_GLES
1744 // according to GL_EXT_texture_format_BGRA8888 the *internal*
1745 // format for a BGRA is BGRA not RGBA (as on desktop)
1746 *internalFormat = GR_GL_32BPP_COLOR_FORMAT;
1747#else
1748 *internalFormat = GL_RGBA;
bsalomon@google.comed3a0682011-01-18 16:54:04 +00001749#endif
reed@google.comac10a2d2010-12-22 21:39:39 +00001750 *type = GL_UNSIGNED_BYTE;
1751 break;
1752 case GrTexture::kRGB_565_PixelConfig:
1753 *format = GL_RGB;
1754 *internalFormat = GL_RGB;
1755 *type = GL_UNSIGNED_SHORT_5_6_5;
1756 break;
1757 case GrTexture::kRGBA_4444_PixelConfig:
1758 *format = GL_RGBA;
1759 *internalFormat = GL_RGBA;
1760 *type = GL_UNSIGNED_SHORT_4_4_4_4;
1761 break;
1762 case GrTexture::kIndex_8_PixelConfig:
1763 if (this->supports8BitPalette()) {
1764 *format = GR_PALETTE8_RGBA8;
1765 *internalFormat = GR_PALETTE8_RGBA8;
1766 *type = GL_UNSIGNED_BYTE; // unused I think
1767 } else {
1768 return false;
1769 }
1770 break;
1771 case GrTexture::kAlpha_8_PixelConfig:
1772 *format = GL_ALPHA;
1773 *internalFormat = GL_ALPHA;
1774 *type = GL_UNSIGNED_BYTE;
1775 break;
1776 default:
1777 return false;
1778 }
1779 return true;
1780}
1781
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001782void GrGpuGL::setTextureUnit(int unit) {
1783 GrAssert(unit >= 0 && unit < kNumStages);
1784 if (fActiveTextureUnitIdx != unit) {
1785 GR_GL(ActiveTexture(GL_TEXTURE0 + unit));
1786 fActiveTextureUnitIdx = unit;
1787 }
1788}
bsalomon@google.com316f99232011-01-13 21:28:12 +00001789
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001790void GrGpuGL::setSpareTextureUnit() {
1791 if (fActiveTextureUnitIdx != (GL_TEXTURE0 + SPARE_TEX_UNIT)) {
1792 GR_GL(ActiveTexture(GL_TEXTURE0 + SPARE_TEX_UNIT));
1793 fActiveTextureUnitIdx = SPARE_TEX_UNIT;
1794 }
1795}
1796
reed@google.comac10a2d2010-12-22 21:39:39 +00001797/* On ES the internalFormat and format must match for TexImage and we use
1798 GL_RGB, GL_RGBA for color formats. We also generally like having the driver
1799 decide the internalFormat. However, on ES internalFormat for
1800 RenderBufferStorage* has to be a specific format (not a base format like
1801 GL_RGBA).
1802 */
1803bool GrGpuGL::fboInternalFormat(GrTexture::PixelConfig config, GLenum* format) {
1804 switch (config) {
1805 case GrTexture::kRGBA_8888_PixelConfig:
1806 case GrTexture::kRGBX_8888_PixelConfig:
1807 if (fRGBA8Renderbuffer) {
1808 *format = GR_RGBA8;
1809 return true;
1810 } else {
1811 return false;
1812 }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001813#if GR_SUPPORT_GLES // ES2 supports 565. ES1 supports it with FBO extension
1814 // desktop GL has no such internal format
reed@google.comac10a2d2010-12-22 21:39:39 +00001815 case GrTexture::kRGB_565_PixelConfig:
1816 *format = GR_RGB565;
1817 return true;
1818#endif
1819 case GrTexture::kRGBA_4444_PixelConfig:
1820 *format = GL_RGBA4;
1821 return true;
1822 default:
1823 return false;
1824 }
1825}
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001826
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001827void GrGpuGL::resetDirtyFlags() {
1828 Gr_bzero(&fDirtyFlags, sizeof(fDirtyFlags));
1829}
1830
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001831void GrGpuGL::setBuffers(bool indexed,
1832 int* extraVertexOffset,
1833 int* extraIndexOffset) {
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001834
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001835 GrAssert(NULL != extraVertexOffset);
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001836
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001837 GrGLVertexBuffer* vbuf;
1838 switch (fGeometrySrc.fVertexSrc) {
1839 case kBuffer_GeometrySrcType:
1840 *extraVertexOffset = 0;
1841 vbuf = (GrGLVertexBuffer*) fGeometrySrc.fVertexBuffer;
1842 break;
1843 case kArray_GeometrySrcType:
1844 case kReserved_GeometrySrcType:
1845 finalizeReservedVertices();
1846 *extraVertexOffset = fCurrPoolStartVertex;
1847 vbuf = (GrGLVertexBuffer*) fCurrPoolVertexBuffer;
1848 break;
1849 default:
1850 vbuf = NULL; // suppress warning
1851 GrCrash("Unknown geometry src type!");
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001852 }
1853
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001854 GrAssert(NULL != vbuf);
1855 GrAssert(!vbuf->isLocked());
1856 if (fHWGeometryState.fVertexBuffer != vbuf) {
1857 GR_GL(BindBuffer(GL_ARRAY_BUFFER, vbuf->bufferID()));
1858 fHWGeometryState.fArrayPtrsDirty = true;
1859 fHWGeometryState.fVertexBuffer = vbuf;
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001860 }
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001861
1862 if (indexed) {
1863 GrAssert(NULL != extraIndexOffset);
1864
1865 GrGLIndexBuffer* ibuf;
1866 switch (fGeometrySrc.fIndexSrc) {
1867 case kBuffer_GeometrySrcType:
1868 *extraIndexOffset = 0;
1869 ibuf = (GrGLIndexBuffer*)fGeometrySrc.fIndexBuffer;
1870 break;
1871 case kArray_GeometrySrcType:
1872 case kReserved_GeometrySrcType:
1873 finalizeReservedIndices();
1874 *extraIndexOffset = fCurrPoolStartIndex;
1875 ibuf = (GrGLIndexBuffer*) fCurrPoolIndexBuffer;
1876 break;
1877 default:
1878 ibuf = NULL; // suppress warning
1879 GrCrash("Unknown geometry src type!");
1880 }
1881
1882 GrAssert(NULL != ibuf);
1883 GrAssert(!ibuf->isLocked());
1884 if (fHWGeometryState.fIndexBuffer != ibuf) {
1885 GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibuf->bufferID()));
1886 fHWGeometryState.fIndexBuffer = ibuf;
1887 }
1888 }
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001889}