blob: 1c3de1acb9aed0b967b24a73a5ddf8ce21f08417 [file] [log] [blame]
reed@google.comac10a2d2010-12-22 21:39:39 +00001/*
bsalomon@google.com1da07462011-03-10 14:51:57 +00002 Copyright 2011 Google Inc.
reed@google.comac10a2d2010-12-22 21:39:39 +00003
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
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000155 resetDirtyFlags();
bsalomon@google.com316f99232011-01-13 21:28:12 +0000156
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000157 GLint maxTextureUnits;
158 // check FS and fixed-function texture unit limits
159 // we only use textures in the fragment stage currently.
160 // checks are > to make sure we have a spare unit.
161#if GR_SUPPORT_GLDESKTOP || GR_SUPPORT_GLES2
reed@google.com3d8de042011-01-20 02:18:00 +0000162 GR_GL_GetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000163 GrAssert(maxTextureUnits > kNumStages);
164#endif
165#if GR_SUPPORT_GLDESKTOP || GR_SUPPORT_GLES1
reed@google.com3d8de042011-01-20 02:18:00 +0000166 GR_GL_GetIntegerv(GL_MAX_TEXTURE_UNITS, &maxTextureUnits);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000167 GrAssert(maxTextureUnits > kNumStages);
168#endif
bsalomon@google.com316f99232011-01-13 21:28:12 +0000169
reed@google.comac10a2d2010-12-22 21:39:39 +0000170 ////////////////////////////////////////////////////////////////////////////
171 // Check for supported features.
172
173 int major, minor;
174 gl_version(&major, &minor);
175
176 GLint numFormats;
reed@google.comac20fb92011-01-12 17:14:53 +0000177 GR_GL_GetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &numFormats);
reed@google.comac10a2d2010-12-22 21:39:39 +0000178 GrAutoSTMalloc<10, GLint> formats(numFormats);
reed@google.comac20fb92011-01-12 17:14:53 +0000179 GR_GL_GetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, formats);
reed@google.comac10a2d2010-12-22 21:39:39 +0000180 for (int i = 0; i < numFormats; ++i) {
181 if (formats[i] == GR_PALETTE8_RGBA8) {
182 f8bitPaletteSupport = true;
183 break;
184 }
185 }
reed@google.comeeeb5a02010-12-23 15:12:59 +0000186
187 if (gPrintStartupSpew) {
188 GrPrintf("Palette8 support: %s\n", (f8bitPaletteSupport ? "YES" : "NO"));
189 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000190
191 GR_STATIC_ASSERT(0 == kNone_AALevel);
192 GR_STATIC_ASSERT(1 == kLow_AALevel);
193 GR_STATIC_ASSERT(2 == kMed_AALevel);
194 GR_STATIC_ASSERT(3 == kHigh_AALevel);
195
196 memset(fAASamples, 0, sizeof(fAASamples));
197 fMSFBOType = kNone_MSFBO;
198 if (has_gl_extension("GL_IMG_multisampled_render_to_texture")) {
199 fMSFBOType = kIMG_MSFBO;
reed@google.comeeeb5a02010-12-23 15:12:59 +0000200 if (gPrintStartupSpew) {
201 GrPrintf("MSAA Support: IMG ES EXT.\n");
202 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000203 }
204 else if (has_gl_extension("GL_APPLE_framebuffer_multisample")) {
205 fMSFBOType = kApple_MSFBO;
reed@google.comeeeb5a02010-12-23 15:12:59 +0000206 if (gPrintStartupSpew) {
207 GrPrintf("MSAA Support: APPLE ES EXT.\n");
208 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000209 }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000210#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000211 else if ((major >= 3) ||
212 has_gl_extension("GL_ARB_framebuffer_object") ||
213 (has_gl_extension("GL_EXT_framebuffer_multisample") &&
214 has_gl_extension("GL_EXT_framebuffer_blit"))) {
215 fMSFBOType = kDesktop_MSFBO;
reed@google.comeeeb5a02010-12-23 15:12:59 +0000216 if (gPrintStartupSpew) {
217 GrPrintf("MSAA Support: DESKTOP\n");
218 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000219 }
220#endif
221 else {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000222 if (gPrintStartupSpew) {
223 GrPrintf("MSAA Support: NONE\n");
224 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000225 }
226
227 if (kNone_MSFBO != fMSFBOType) {
228 GLint maxSamples;
229 GLenum maxSampleGetter = (kIMG_MSFBO == fMSFBOType) ?
230 GR_MAX_SAMPLES_IMG :
231 GR_MAX_SAMPLES;
reed@google.comac20fb92011-01-12 17:14:53 +0000232 GR_GL_GetIntegerv(maxSampleGetter, &maxSamples);
reed@google.comac10a2d2010-12-22 21:39:39 +0000233 if (maxSamples > 1 ) {
234 fAASamples[kNone_AALevel] = 0;
235 fAASamples[kLow_AALevel] = GrMax(2,
236 GrFixedFloorToInt((GR_FixedHalf) *
237 maxSamples));
238 fAASamples[kMed_AALevel] = GrMax(2,
239 GrFixedFloorToInt(((GR_Fixed1*3)/4) *
240 maxSamples));
241 fAASamples[kHigh_AALevel] = maxSamples;
242 }
reed@google.comeeeb5a02010-12-23 15:12:59 +0000243 if (gPrintStartupSpew) {
244 GrPrintf("\tMax Samples: %d\n", maxSamples);
245 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000246 }
247
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000248#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000249 fHasStencilWrap = (major >= 2 || (major == 1 && minor >= 4)) ||
250 has_gl_extension("GL_EXT_stencil_wrap");
251#else
252 fHasStencilWrap = (major >= 2) || has_gl_extension("GL_OES_stencil_wrap");
253#endif
reed@google.comeeeb5a02010-12-23 15:12:59 +0000254 if (gPrintStartupSpew) {
255 GrPrintf("Stencil Wrap: %s\n", (fHasStencilWrap ? "YES" : "NO"));
256 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000257
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000258#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000259 // we could also look for GL_ATI_separate_stencil extension or
260 // GL_EXT_stencil_two_side but they use different function signatures
261 // than GL2.0+ (and than each other).
bsalomon@google.comd302f142011-03-03 13:54:13 +0000262 fTwoSidedStencilSupport = (major >= 2);
263 // supported on GL 1.4 and higher or by extension
264 fStencilWrapOpsSupport = (major > 1) ||
reed@google.comeca7d342011-03-04 19:33:13 +0000265 ((1 == major) && (minor >= 4)) ||
bsalomon@google.comd302f142011-03-03 13:54:13 +0000266 has_gl_extension("GL_EXT_stencil_wrap");
reed@google.comac10a2d2010-12-22 21:39:39 +0000267#else
268 // ES 2 has two sided stencil but 1.1 doesn't. There doesn't seem to be
269 // an ES1 extension.
bsalomon@google.comd302f142011-03-03 13:54:13 +0000270 fTwoSidedStencilSupport = (major >= 2);
271 // stencil wrap support is in ES2, ES1 requires extension.
272 fStencilWrapOpsSupport = (major > 1) ||
273 has_gl_extension("GL_OES_stencil_wrap");
274
reed@google.comac10a2d2010-12-22 21:39:39 +0000275#endif
reed@google.comeeeb5a02010-12-23 15:12:59 +0000276 if (gPrintStartupSpew) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000277 GrPrintf("Stencil Caps: TwoSide: %s, Wrap: %s\n",
278 (fTwoSidedStencilSupport ? "YES" : "NO"),
279 (fStencilWrapOpsSupport ? "YES" : "NO"));
reed@google.comeeeb5a02010-12-23 15:12:59 +0000280 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000281
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000282#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000283 fRGBA8Renderbuffer = true;
284#else
285 fRGBA8Renderbuffer = has_gl_extension("GL_OES_rgb8_rgba8");
286#endif
reed@google.comeeeb5a02010-12-23 15:12:59 +0000287 if (gPrintStartupSpew) {
288 GrPrintf("RGBA Renderbuffer: %s\n", (fRGBA8Renderbuffer ? "YES" : "NO"));
289 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000290
bsalomon@google.comed3a0682011-01-18 16:54:04 +0000291#if GR_SUPPORT_GLES
292 if (GR_GL_32BPP_COLOR_FORMAT == GR_BGRA) {
293 GrAssert(has_gl_extension("GL_EXT_texture_format_BGRA8888"));
294 }
295#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000296
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000297#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000298 fBufferLockSupport = true; // we require VBO support and the desktop VBO
299 // extension includes glMapBuffer.
300#else
301 fBufferLockSupport = has_gl_extension("GL_OES_mapbuffer");
302#endif
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000303
reed@google.comeeeb5a02010-12-23 15:12:59 +0000304 if (gPrintStartupSpew) {
305 GrPrintf("Map Buffer: %s\n", (fBufferLockSupport ? "YES" : "NO"));
306 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000307
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000308#if GR_SUPPORT_GLDESKTOP
bsalomon@google.com0748f212011-02-01 22:56:16 +0000309 if (major >= 2 || has_gl_extension("GL_ARB_texture_non_power_of_two")) {
310 fNPOTTextureTileSupport = true;
311 fNPOTTextureSupport = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000312 } else {
bsalomon@google.com0748f212011-02-01 22:56:16 +0000313 fNPOTTextureTileSupport = false;
314 fNPOTTextureSupport = false;
315 }
316#else
317 if (major >= 2) {
318 fNPOTTextureSupport = true;
319 fNPOTTextureTileSupport = has_gl_extension("GL_OES_texture_npot");
320 } else {
321 fNPOTTextureSupport = has_gl_extension("GL_APPLE_texture_2D_limited_npot");
322 fNPOTTextureTileSupport = false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000323 }
324#endif
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000325
reed@google.comac10a2d2010-12-22 21:39:39 +0000326 ////////////////////////////////////////////////////////////////////////////
327 // Experiments to determine limitations that can't be queried. TODO: Make
328 // these a preprocess that generate some compile time constants.
329
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000330 // sanity check to make sure we can at least create an FBO from a POT texture
bsalomon@google.com18908aa2011-02-07 14:51:55 +0000331
bsalomon@google.com0748f212011-02-01 22:56:16 +0000332 bool simpleFBOSuccess = fbo_test(fExts, 128, 128);
333 if (gPrintStartupSpew) {
334 if (!simpleFBOSuccess) {
335 GrPrintf("FBO Sanity Test: FAILED\n");
336 } else {
337 GrPrintf("FBO Sanity Test: PASSED\n");
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000338 }
339 }
bsalomon@google.com0748f212011-02-01 22:56:16 +0000340 GrAssert(simpleFBOSuccess);
reed@google.comac20fb92011-01-12 17:14:53 +0000341
reed@google.comac10a2d2010-12-22 21:39:39 +0000342 /* Experimentation has found that some GLs that support NPOT textures
343 do not support FBOs with a NPOT texture. They report "unsupported" FBO
344 status. I don't know how to explicitly query for this. Do an
345 experiment. Note they may support NPOT with a renderbuffer but not a
346 texture. Presumably, the implementation bloats the renderbuffer
347 internally to the next POT.
348 */
bsalomon@google.com0748f212011-02-01 22:56:16 +0000349 bool fNPOTRenderTargetSupport = false;
350 if (fNPOTTextureSupport) {
351 fNPOTRenderTargetSupport = fbo_test(fExts, 200, 200);
352 }
bsalomon@google.com18908aa2011-02-07 14:51:55 +0000353
bsalomon@google.com0748f212011-02-01 22:56:16 +0000354 if (gPrintStartupSpew) {
355 if (fNPOTTextureSupport) {
356 GrPrintf("NPOT textures supported\n");
357 if (fNPOTTextureTileSupport) {
358 GrPrintf("NPOT texture tiling supported\n");
359 } else {
360 GrPrintf("NPOT texture tiling NOT supported\n");
361 }
362 if (fNPOTRenderTargetSupport) {
363 GrPrintf("NPOT render targets supported\n");
364 } else {
365 GrPrintf("NPOT render targets NOT supported\n");
reed@google.comeeeb5a02010-12-23 15:12:59 +0000366 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000367 } else {
bsalomon@google.com0748f212011-02-01 22:56:16 +0000368 GrPrintf("NPOT textures NOT supported\n");
reed@google.comeeeb5a02010-12-23 15:12:59 +0000369 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000370 }
371
reed@google.comac10a2d2010-12-22 21:39:39 +0000372 /* The iPhone 4 has a restriction that for an FBO with texture color
373 attachment with height <= 8 then the width must be <= height. Here
374 we look for such a limitation.
375 */
376 fMinRenderTargetHeight = GR_INVAL_GLINT;
377 GLint maxRenderSize;
reed@google.comac20fb92011-01-12 17:14:53 +0000378 GR_GL_GetIntegerv(GR_MAX_RENDERBUFFER_SIZE, &maxRenderSize);
reed@google.comac10a2d2010-12-22 21:39:39 +0000379
reed@google.comeeeb5a02010-12-23 15:12:59 +0000380 if (gPrintStartupSpew) {
381 GrPrintf("Small height FBO texture experiments\n");
382 }
bsalomon@google.com0748f212011-02-01 22:56:16 +0000383
384 for (GLuint i = 1; i <= 256; fNPOTRenderTargetSupport ? ++i : i *= 2) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000385 GLuint w = maxRenderSize;
386 GLuint h = i;
387 if (fbo_test(fExts, w, h)) {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000388 if (gPrintStartupSpew) {
389 GrPrintf("\t[%d, %d]: PASSED\n", w, h);
390 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000391 fMinRenderTargetHeight = i;
392 break;
393 } else {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000394 if (gPrintStartupSpew) {
395 GrPrintf("\t[%d, %d]: FAILED\n", w, h);
396 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000397 }
398 }
399 GrAssert(GR_INVAL_GLINT != fMinRenderTargetHeight);
400
reed@google.comeeeb5a02010-12-23 15:12:59 +0000401 if (gPrintStartupSpew) {
402 GrPrintf("Small width FBO texture experiments\n");
403 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000404 fMinRenderTargetWidth = GR_MAX_GLUINT;
bsalomon@google.com0748f212011-02-01 22:56:16 +0000405 for (GLuint i = 1; i <= 256; fNPOTRenderTargetSupport ? i *= 2 : ++i) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000406 GLuint w = i;
407 GLuint h = maxRenderSize;
408 if (fbo_test(fExts, w, h)) {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000409 if (gPrintStartupSpew) {
410 GrPrintf("\t[%d, %d]: PASSED\n", w, h);
411 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000412 fMinRenderTargetWidth = i;
413 break;
414 } else {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000415 if (gPrintStartupSpew) {
416 GrPrintf("\t[%d, %d]: FAILED\n", w, h);
417 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000418 }
419 }
420 GrAssert(GR_INVAL_GLINT != fMinRenderTargetWidth);
421
reed@google.com02a7e6c2011-01-28 21:21:49 +0000422 GR_GL_GetIntegerv(GL_MAX_TEXTURE_SIZE, &fMaxTextureDimension);
reed@google.comac10a2d2010-12-22 21:39:39 +0000423}
424
425GrGpuGL::~GrGpuGL() {
reed@google.comac10a2d2010-12-22 21:39:39 +0000426}
427
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000428void GrGpuGL::resetContext() {
429 // We detect cases when blending is effectively off
reed@google.comac10a2d2010-12-22 21:39:39 +0000430 fHWBlendDisabled = false;
431 GR_GL(Enable(GL_BLEND));
432
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000433 // we don't use the zb at all
434 GR_GL(Disable(GL_DEPTH_TEST));
435 GR_GL(DepthMask(GL_FALSE));
436
reed@google.comac10a2d2010-12-22 21:39:39 +0000437 GR_GL(Disable(GL_CULL_FACE));
bsalomon@google.comd302f142011-03-03 13:54:13 +0000438 GR_GL(FrontFace(GL_CCW));
439 fHWDrawState.fDrawFace = kBoth_DrawFace;
reed@google.comac10a2d2010-12-22 21:39:39 +0000440
441 GR_GL(Disable(GL_DITHER));
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000442#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000443 GR_GL(Disable(GL_LINE_SMOOTH));
444 GR_GL(Disable(GL_POINT_SMOOTH));
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000445 GR_GL(Disable(GL_MULTISAMPLE));
reed@google.comac10a2d2010-12-22 21:39:39 +0000446#endif
447
bsalomon@google.comd302f142011-03-03 13:54:13 +0000448 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
449 fHWDrawState.fFlagBits = 0;
450
reed@google.comac10a2d2010-12-22 21:39:39 +0000451 // we only ever use lines in hairline mode
452 GR_GL(LineWidth(1));
453
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000454 // invalid
455 fActiveTextureUnitIdx = -1;
reed@google.comac10a2d2010-12-22 21:39:39 +0000456
reed@google.comac10a2d2010-12-22 21:39:39 +0000457 // illegal values
bsalomon@google.comffca4002011-02-22 20:34:01 +0000458 fHWDrawState.fSrcBlend = (GrBlendCoeff)-1;
459 fHWDrawState.fDstBlend = (GrBlendCoeff)-1;
reed@google.comac10a2d2010-12-22 21:39:39 +0000460 fHWDrawState.fColor = GrColor_ILLEGAL;
bsalomon@google.com316f99232011-01-13 21:28:12 +0000461
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000462 fHWDrawState.fViewMatrix = GrMatrix::InvalidMatrix();
bsalomon@google.com316f99232011-01-13 21:28:12 +0000463
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000464 for (int s = 0; s < kNumStages; ++s) {
465 fHWDrawState.fTextures[s] = NULL;
466 fHWDrawState.fSamplerStates[s].setRadial2Params(-GR_ScalarMax,
467 -GR_ScalarMax,
468 true);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000469
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000470 fHWDrawState.fSamplerStates[s].setMatrix(GrMatrix::InvalidMatrix());
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000471 }
bsalomon@google.com316f99232011-01-13 21:28:12 +0000472
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000473 fHWBounds.fScissorRect.invalidate();
reed@google.comac10a2d2010-12-22 21:39:39 +0000474 fHWBounds.fScissorEnabled = false;
475 GR_GL(Disable(GL_SCISSOR_TEST));
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000476 fHWBounds.fViewportRect.invalidate();
reed@google.comac10a2d2010-12-22 21:39:39 +0000477
bsalomon@google.comd302f142011-03-03 13:54:13 +0000478 fHWDrawState.fStencilSettings.invalidate();
reed@google.comac10a2d2010-12-22 21:39:39 +0000479 fHWStencilClip = false;
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000480 fClipState.fClipIsDirty = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000481
482 fHWGeometryState.fIndexBuffer = NULL;
483 fHWGeometryState.fVertexBuffer = NULL;
484 GR_GL(BindBuffer(GL_ARRAY_BUFFER, 0));
485 GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000486 fHWGeometryState.fArrayPtrsDirty = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000487
bsalomon@google.comd302f142011-03-03 13:54:13 +0000488 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
reed@google.comac10a2d2010-12-22 21:39:39 +0000489 fHWDrawState.fRenderTarget = NULL;
490}
491
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000492GrRenderTarget* GrGpuGL::createPlatformRenderTargetHelper(
reed@google.comac10a2d2010-12-22 21:39:39 +0000493 intptr_t platformRenderTarget,
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000494 int stencilBits,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000495 int width,
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000496 int height) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000497 GrGLRenderTarget::GLRenderTargetIDs rtIDs;
498 rtIDs.fStencilRenderbufferID = 0;
499 rtIDs.fMSColorRenderbufferID = 0;
500 rtIDs.fTexFBOID = 0;
501 rtIDs.fOwnIDs = false;
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000502 GrGLIRect viewport;
reed@google.comac10a2d2010-12-22 21:39:39 +0000503
504 // viewport is in GL coords (top >= bottom)
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000505 viewport.fLeft = 0;
506 viewport.fBottom = 0;
507 viewport.fWidth = width;
508 viewport.fHeight = height;
reed@google.comac10a2d2010-12-22 21:39:39 +0000509
510 rtIDs.fRTFBOID = (GLuint)platformRenderTarget;
511 rtIDs.fTexFBOID = (GLuint)platformRenderTarget;
512
bsalomon@google.com1da07462011-03-10 14:51:57 +0000513 return new GrGLRenderTarget(rtIDs, NULL, stencilBits, viewport, NULL, this);
reed@google.comac10a2d2010-12-22 21:39:39 +0000514}
515
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000516GrRenderTarget* GrGpuGL::createRenderTargetFrom3DApiStateHelper() {
bsalomon@google.com42ab7ea2011-01-19 17:19:40 +0000517
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000518 GrGLRenderTarget::GLRenderTargetIDs rtIDs;
bsalomon@google.com42ab7ea2011-01-19 17:19:40 +0000519
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000520 GR_GL_GetIntegerv(GR_FRAMEBUFFER_BINDING, (GLint*)&rtIDs.fRTFBOID);
521 rtIDs.fTexFBOID = rtIDs.fRTFBOID;
522 rtIDs.fMSColorRenderbufferID = 0;
523 rtIDs.fStencilRenderbufferID = 0;
bsalomon@google.com42ab7ea2011-01-19 17:19:40 +0000524
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000525 GrGLIRect viewport;
526 viewport.setFromGLViewport();
527 GLuint stencilBits;
528 GR_GL_GetIntegerv(GL_STENCIL_BITS, (GLint*)&stencilBits);
529
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000530 rtIDs.fOwnIDs = false;
531
bsalomon@google.com1da07462011-03-10 14:51:57 +0000532 return new GrGLRenderTarget(rtIDs, NULL, stencilBits, viewport, NULL, this);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000533}
534
bsalomon@google.com5782d712011-01-21 21:03:59 +0000535///////////////////////////////////////////////////////////////////////////////
536
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000537static const GLuint UNKNOWN_BITS = ~0;
538
bsalomon@google.com3f3ffd62011-01-18 17:14:52 +0000539// defines stencil formats from more to less preferred
bsalomon@google.com5d18c382011-02-18 16:21:58 +0000540static const struct {
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000541 GLenum fEnum;
542 GLuint fBits;
543} gStencilFormats[] = {
544 {GR_STENCIL_INDEX8, 8},
reed@google.com63100f92011-01-18 21:32:14 +0000545
546#if GR_SUPPORT_GLDESKTOP
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000547 {GR_STENCIL_INDEX16, 16},
reed@google.com63100f92011-01-18 21:32:14 +0000548#endif
549
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000550 {GR_DEPTH24_STENCIL8, 8},
551 {GR_STENCIL_INDEX4, 4},
reed@google.com63100f92011-01-18 21:32:14 +0000552
553#if GR_SUPPORT_GLDESKTOP
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000554 {GL_STENCIL_INDEX, UNKNOWN_BITS},
555 {GR_DEPTH_STENCIL, UNKNOWN_BITS}
bsalomon@google.com3f3ffd62011-01-18 17:14:52 +0000556#endif
557};
558
559// good to set a break-point here to know when createTexture fails
560static GrTexture* return_null_texture() {
561// GrAssert(!"null texture");
562 return NULL;
563}
564
565#if GR_DEBUG
566static size_t as_size_t(int x) {
567 return x;
568}
569#endif
570
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000571GrTexture* GrGpuGL::createTextureHelper(const TextureDesc& desc,
572 const void* srcData,
573 size_t rowBytes) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000574
575#if GR_COLLECT_STATS
576 ++fStats.fTextureCreateCnt;
577#endif
reed@google.com1fcd51e2011-01-05 15:50:27 +0000578
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000579 setSpareTextureUnit();
bsalomon@google.com316f99232011-01-13 21:28:12 +0000580
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000581 static const GrGLTexture::TexParams DEFAULT_PARAMS = {
582 GL_NEAREST,
583 GL_CLAMP_TO_EDGE,
584 GL_CLAMP_TO_EDGE
585 };
reed@google.com1fcd51e2011-01-05 15:50:27 +0000586
reed@google.comac10a2d2010-12-22 21:39:39 +0000587 GrGLTexture::GLTextureDesc glDesc;
588 GLenum internalFormat;
589
590 glDesc.fContentWidth = desc.fWidth;
591 glDesc.fContentHeight = desc.fHeight;
592 glDesc.fAllocWidth = desc.fWidth;
593 glDesc.fAllocHeight = desc.fHeight;
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000594 glDesc.fStencilBits = 0;
reed@google.comac10a2d2010-12-22 21:39:39 +0000595 glDesc.fFormat = desc.fFormat;
596
597 bool renderTarget = 0 != (desc.fFlags & kRenderTarget_TextureFlag);
598 if (!canBeTexture(desc.fFormat,
599 &internalFormat,
600 &glDesc.fUploadFormat,
601 &glDesc.fUploadType)) {
602 return return_null_texture();
603 }
604
605 GrAssert(as_size_t(desc.fAALevel) < GR_ARRAY_COUNT(fAASamples));
606 GLint samples = fAASamples[desc.fAALevel];
607 if (kNone_MSFBO == fMSFBOType && desc.fAALevel != kNone_AALevel) {
608 GrPrintf("AA RT requested but not supported on this platform.");
609 }
610
611 GR_GL(GenTextures(1, &glDesc.fTextureID));
612 if (!glDesc.fTextureID) {
613 return return_null_texture();
614 }
615
616 glDesc.fUploadByteCount = GrTexture::BytesPerPixel(desc.fFormat);
617
618 /*
619 * check if our srcData has extra bytes past each row. If so, we need
620 * to trim those off here, since GL doesn't let us pass the rowBytes as
621 * a parameter to glTexImage2D
622 */
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000623#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000624 if (srcData) {
625 GR_GL(PixelStorei(GL_UNPACK_ROW_LENGTH,
626 rowBytes / glDesc.fUploadByteCount));
627 }
628#else
629 GrAutoSMalloc<128 * 128> trimStorage;
630 size_t trimRowBytes = desc.fWidth * glDesc.fUploadByteCount;
631 if (srcData && (trimRowBytes < rowBytes)) {
632 size_t trimSize = desc.fHeight * trimRowBytes;
633 trimStorage.realloc(trimSize);
634 // now copy the data into our new storage, skipping the trailing bytes
635 const char* src = (const char*)srcData;
636 char* dst = (char*)trimStorage.get();
637 for (uint32_t y = 0; y < desc.fHeight; y++) {
638 memcpy(dst, src, trimRowBytes);
639 src += rowBytes;
640 dst += trimRowBytes;
641 }
642 // now point srcData to our trimmed version
643 srcData = trimStorage.get();
644 }
645#endif
646
reed@google.comac10a2d2010-12-22 21:39:39 +0000647 if (renderTarget) {
bsalomon@google.com0748f212011-02-01 22:56:16 +0000648 if (!this->npotRenderTargetSupport()) {
649 glDesc.fAllocWidth = GrNextPow2(desc.fWidth);
650 glDesc.fAllocHeight = GrNextPow2(desc.fHeight);
651 }
652
reed@google.comac10a2d2010-12-22 21:39:39 +0000653 glDesc.fAllocWidth = GrMax<int>(fMinRenderTargetWidth,
654 glDesc.fAllocWidth);
655 glDesc.fAllocHeight = GrMax<int>(fMinRenderTargetHeight,
656 glDesc.fAllocHeight);
bsalomon@google.com0748f212011-02-01 22:56:16 +0000657 } else if (!this->npotTextureSupport()) {
658 glDesc.fAllocWidth = GrNextPow2(desc.fWidth);
659 glDesc.fAllocHeight = GrNextPow2(desc.fHeight);
reed@google.comac10a2d2010-12-22 21:39:39 +0000660 }
661
662 GR_GL(BindTexture(GL_TEXTURE_2D, glDesc.fTextureID));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000663 GR_GL(TexParameteri(GL_TEXTURE_2D,
664 GL_TEXTURE_MAG_FILTER,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000665 DEFAULT_PARAMS.fFilter));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000666 GR_GL(TexParameteri(GL_TEXTURE_2D,
667 GL_TEXTURE_MIN_FILTER,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000668 DEFAULT_PARAMS.fFilter));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000669 GR_GL(TexParameteri(GL_TEXTURE_2D,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000670 GL_TEXTURE_WRAP_S,
671 DEFAULT_PARAMS.fWrapS));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000672 GR_GL(TexParameteri(GL_TEXTURE_2D,
673 GL_TEXTURE_WRAP_T,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000674 DEFAULT_PARAMS.fWrapT));
reed@google.comac10a2d2010-12-22 21:39:39 +0000675
676 GR_GL(PixelStorei(GL_UNPACK_ALIGNMENT, glDesc.fUploadByteCount));
677 if (GrTexture::kIndex_8_PixelConfig == desc.fFormat &&
678 supports8BitPalette()) {
679 // ES only supports CompressedTexImage2D, not CompressedTexSubimage2D
680 GrAssert(desc.fWidth == glDesc.fAllocWidth);
681 GrAssert(desc.fHeight == glDesc.fAllocHeight);
682 GLsizei imageSize = glDesc.fAllocWidth * glDesc.fAllocHeight +
683 kColorTableSize;
684 GR_GL(CompressedTexImage2D(GL_TEXTURE_2D, 0, glDesc.fUploadFormat,
685 glDesc.fAllocWidth, glDesc.fAllocHeight,
686 0, imageSize, srcData));
687 GrGL_RestoreResetRowLength();
688 } else {
689 if (NULL != srcData && (glDesc.fAllocWidth != desc.fWidth ||
690 glDesc.fAllocHeight != desc.fHeight)) {
691 GR_GL(TexImage2D(GL_TEXTURE_2D, 0, internalFormat,
692 glDesc.fAllocWidth, glDesc.fAllocHeight,
693 0, glDesc.fUploadFormat, glDesc.fUploadType, NULL));
694 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, desc.fWidth,
695 desc.fHeight, glDesc.fUploadFormat,
696 glDesc.fUploadType, srcData));
697 GrGL_RestoreResetRowLength();
698
699 uint32_t extraW = glDesc.fAllocWidth - desc.fWidth;
700 uint32_t extraH = glDesc.fAllocHeight - desc.fHeight;
701 uint32_t maxTexels = extraW * extraH;
702 maxTexels = GrMax(extraW * desc.fHeight, maxTexels);
703 maxTexels = GrMax(desc.fWidth * extraH, maxTexels);
704
705 GrAutoSMalloc<128*128> texels(glDesc.fUploadByteCount * maxTexels);
706
707 uint32_t rowSize = desc.fWidth * glDesc.fUploadByteCount;
708 if (extraH) {
709 uint8_t* lastRowStart = (uint8_t*) srcData +
710 (desc.fHeight - 1) * rowSize;
711 uint8_t* extraRowStart = (uint8_t*)texels.get();
712
713 for (uint32_t i = 0; i < extraH; ++i) {
714 memcpy(extraRowStart, lastRowStart, rowSize);
715 extraRowStart += rowSize;
716 }
717 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, 0, desc.fHeight, desc.fWidth,
718 extraH, glDesc.fUploadFormat, glDesc.fUploadType,
719 texels.get()));
720 }
721 if (extraW) {
722 uint8_t* edgeTexel = (uint8_t*)srcData + rowSize - glDesc.fUploadByteCount;
723 uint8_t* extraTexel = (uint8_t*)texels.get();
724 for (uint32_t j = 0; j < desc.fHeight; ++j) {
725 for (uint32_t i = 0; i < extraW; ++i) {
726 memcpy(extraTexel, edgeTexel, glDesc.fUploadByteCount);
727 extraTexel += glDesc.fUploadByteCount;
728 }
729 edgeTexel += rowSize;
730 }
731 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, desc.fWidth, 0, extraW,
732 desc.fHeight, glDesc.fUploadFormat,
733 glDesc.fUploadType, texels.get()));
734 }
735 if (extraW && extraH) {
736 uint8_t* cornerTexel = (uint8_t*)srcData + desc.fHeight * rowSize
737 - glDesc.fUploadByteCount;
738 uint8_t* extraTexel = (uint8_t*)texels.get();
739 for (uint32_t i = 0; i < extraW*extraH; ++i) {
740 memcpy(extraTexel, cornerTexel, glDesc.fUploadByteCount);
741 extraTexel += glDesc.fUploadByteCount;
742 }
743 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, desc.fWidth, desc.fHeight,
744 extraW, extraH, glDesc.fUploadFormat,
745 glDesc.fUploadType, texels.get()));
746 }
747
748 } else {
749 GR_GL(TexImage2D(GL_TEXTURE_2D, 0, internalFormat, glDesc.fAllocWidth,
750 glDesc.fAllocHeight, 0, glDesc.fUploadFormat,
751 glDesc.fUploadType, srcData));
752 GrGL_RestoreResetRowLength();
753 }
754 }
755
756 glDesc.fOrientation = GrGLTexture::kTopDown_Orientation;
757
758 GrGLRenderTarget::GLRenderTargetIDs rtIDs;
759 rtIDs.fStencilRenderbufferID = 0;
760 rtIDs.fMSColorRenderbufferID = 0;
761 rtIDs.fRTFBOID = 0;
762 rtIDs.fTexFBOID = 0;
763 rtIDs.fOwnIDs = true;
764 GLenum msColorRenderbufferFormat = -1;
765
766 if (renderTarget) {
767#if GR_COLLECT_STATS
768 ++fStats.fRenderTargetCreateCnt;
769#endif
770 bool failed = true;
771 GLenum status;
772 GLint err;
773
774 // If need have both RT flag and srcData we have
775 // to invert the data before uploading because FBO
776 // will be rendered bottom up
777 GrAssert(NULL == srcData);
778 glDesc.fOrientation = GrGLTexture::kBottomUp_Orientation;
779
780 GR_GLEXT(fExts, GenFramebuffers(1, &rtIDs.fTexFBOID));
781 GrAssert(rtIDs.fTexFBOID);
782
783 // If we are using multisampling and any extension other than the IMG
784 // one we will create two FBOs. We render to one and then resolve to
785 // the texture bound to the other. The IMG extension does an implicit
786 // resolve.
787 if (samples > 1 && kIMG_MSFBO != fMSFBOType && kNone_MSFBO != fMSFBOType) {
788 GR_GLEXT(fExts, GenFramebuffers(1, &rtIDs.fRTFBOID));
789 GrAssert(0 != rtIDs.fRTFBOID);
790 GR_GLEXT(fExts, GenRenderbuffers(1, &rtIDs.fMSColorRenderbufferID));
791 GrAssert(0 != rtIDs.fMSColorRenderbufferID);
792 if (!fboInternalFormat(desc.fFormat, &msColorRenderbufferFormat)) {
793 GR_GLEXT(fExts,
794 DeleteRenderbuffers(1, &rtIDs.fMSColorRenderbufferID));
795 GR_GL(DeleteTextures(1, &glDesc.fTextureID));
796 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fTexFBOID));
797 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fRTFBOID));
reed@google.comac10a2d2010-12-22 21:39:39 +0000798 return return_null_texture();
799 }
800 } else {
801 rtIDs.fRTFBOID = rtIDs.fTexFBOID;
802 }
803 int attempts = 1;
804 if (!(kNoPathRendering_TextureFlag & desc.fFlags)) {
805 GR_GLEXT(fExts, GenRenderbuffers(1, &rtIDs.fStencilRenderbufferID));
806 GrAssert(0 != rtIDs.fStencilRenderbufferID);
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000807 attempts = GR_ARRAY_COUNT(gStencilFormats);
reed@google.comac10a2d2010-12-22 21:39:39 +0000808 }
809
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000810 // someone suggested that some systems might require
bsalomon@google.com316f99232011-01-13 21:28:12 +0000811 // unbinding the texture before we call FramebufferTexture2D
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000812 // (seems unlikely)
reed@google.comac10a2d2010-12-22 21:39:39 +0000813 GR_GL(BindTexture(GL_TEXTURE_2D, 0));
reed@google.comac10a2d2010-12-22 21:39:39 +0000814
815 err = ~GL_NO_ERROR;
816 for (int i = 0; i < attempts; ++i) {
817 if (rtIDs.fStencilRenderbufferID) {
818 GR_GLEXT(fExts, BindRenderbuffer(GR_RENDERBUFFER,
819 rtIDs.fStencilRenderbufferID));
820 if (samples > 1) {
821 GR_GLEXT_NO_ERR(fExts, RenderbufferStorageMultisample(
822 GR_RENDERBUFFER,
823 samples,
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000824 gStencilFormats[i].fEnum,
reed@google.comac10a2d2010-12-22 21:39:39 +0000825 glDesc.fAllocWidth,
826 glDesc.fAllocHeight));
827 } else {
828 GR_GLEXT_NO_ERR(fExts, RenderbufferStorage(
829 GR_RENDERBUFFER,
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 }
834 err = glGetError();
835 if (err != GL_NO_ERROR) {
836 continue;
837 }
838 }
839 if (rtIDs.fRTFBOID != rtIDs.fTexFBOID) {
840 GrAssert(samples > 1);
841 GR_GLEXT(fExts, BindRenderbuffer(GR_RENDERBUFFER,
842 rtIDs.fMSColorRenderbufferID));
843 GR_GLEXT_NO_ERR(fExts, RenderbufferStorageMultisample(
844 GR_RENDERBUFFER,
845 samples,
846 msColorRenderbufferFormat,
847 glDesc.fAllocWidth,
848 glDesc.fAllocHeight));
849 err = glGetError();
850 if (err != GL_NO_ERROR) {
851 continue;
852 }
853 }
854 GR_GLEXT(fExts, BindFramebuffer(GR_FRAMEBUFFER, rtIDs.fTexFBOID));
855
856#if GR_COLLECT_STATS
857 ++fStats.fRenderTargetChngCnt;
858#endif
859 if (kIMG_MSFBO == fMSFBOType && samples > 1) {
860 GR_GLEXT(fExts, FramebufferTexture2DMultisample(
861 GR_FRAMEBUFFER,
862 GR_COLOR_ATTACHMENT0,
863 GL_TEXTURE_2D,
864 glDesc.fTextureID,
865 0,
866 samples));
867
868 } else {
869 GR_GLEXT(fExts, FramebufferTexture2D(GR_FRAMEBUFFER,
870 GR_COLOR_ATTACHMENT0,
871 GL_TEXTURE_2D,
872 glDesc.fTextureID, 0));
873 }
874 if (rtIDs.fRTFBOID != rtIDs.fTexFBOID) {
875 GLenum status = GR_GLEXT(fExts,
876 CheckFramebufferStatus(GR_FRAMEBUFFER));
877 if (status != GR_FRAMEBUFFER_COMPLETE) {
878 GrPrintf("-- glCheckFramebufferStatus %x %d %d\n",
879 status, desc.fWidth, desc.fHeight);
880 continue;
881 }
882 GR_GLEXT(fExts, BindFramebuffer(GR_FRAMEBUFFER, rtIDs.fRTFBOID));
883 #if GR_COLLECT_STATS
884 ++fStats.fRenderTargetChngCnt;
885 #endif
886 GR_GLEXT(fExts, FramebufferRenderbuffer(GR_FRAMEBUFFER,
887 GR_COLOR_ATTACHMENT0,
888 GR_RENDERBUFFER,
889 rtIDs.fMSColorRenderbufferID));
890
891 }
892 if (rtIDs.fStencilRenderbufferID) {
893 // bind the stencil to rt fbo if present, othewise the tex fbo
894 GR_GLEXT(fExts, FramebufferRenderbuffer(GR_FRAMEBUFFER,
895 GR_STENCIL_ATTACHMENT,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000896 GR_RENDERBUFFER,
reed@google.comac10a2d2010-12-22 21:39:39 +0000897 rtIDs.fStencilRenderbufferID));
898 }
899 status = GR_GLEXT(fExts, CheckFramebufferStatus(GR_FRAMEBUFFER));
900
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000901#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000902 // On some implementations you have to be bound as DEPTH_STENCIL.
903 // (Even binding to DEPTH and STENCIL separately with the same
904 // buffer doesn't work.)
905 if (rtIDs.fStencilRenderbufferID &&
906 status != GR_FRAMEBUFFER_COMPLETE) {
907 GR_GLEXT(fExts, FramebufferRenderbuffer(GR_FRAMEBUFFER,
908 GR_STENCIL_ATTACHMENT,
909 GR_RENDERBUFFER,
910 0));
911 GR_GLEXT(fExts,
912 FramebufferRenderbuffer(GR_FRAMEBUFFER,
913 GR_DEPTH_STENCIL_ATTACHMENT,
914 GR_RENDERBUFFER,
915 rtIDs.fStencilRenderbufferID));
916 status = GR_GLEXT(fExts, CheckFramebufferStatus(GR_FRAMEBUFFER));
917 }
918#endif
919 if (status != GR_FRAMEBUFFER_COMPLETE) {
920 GrPrintf("-- glCheckFramebufferStatus %x %d %d\n",
921 status, desc.fWidth, desc.fHeight);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000922#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000923 if (rtIDs.fStencilRenderbufferID) {
924 GR_GLEXT(fExts, FramebufferRenderbuffer(GR_FRAMEBUFFER,
925 GR_DEPTH_STENCIL_ATTACHMENT,
926 GR_RENDERBUFFER,
927 0));
928 }
929#endif
930 continue;
931 }
932 // we're successful!
933 failed = false;
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000934 if (rtIDs.fStencilRenderbufferID) {
935 if (UNKNOWN_BITS == gStencilFormats[i].fBits) {
936 GR_GL_GetIntegerv(GL_STENCIL_BITS, (GLint*)&glDesc.fStencilBits);
937 } else {
938 glDesc.fStencilBits = gStencilFormats[i].fBits;
939 }
940 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000941 break;
942 }
943 if (failed) {
944 if (rtIDs.fStencilRenderbufferID) {
945 GR_GLEXT(fExts,
946 DeleteRenderbuffers(1, &rtIDs.fStencilRenderbufferID));
947 }
948 if (rtIDs.fMSColorRenderbufferID) {
949 GR_GLEXT(fExts,
950 DeleteRenderbuffers(1, &rtIDs.fMSColorRenderbufferID));
951 }
952 if (rtIDs.fRTFBOID != rtIDs.fTexFBOID) {
953 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fRTFBOID));
954 }
955 if (rtIDs.fTexFBOID) {
956 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fTexFBOID));
957 }
958 GR_GL(DeleteTextures(1, &glDesc.fTextureID));
959 return return_null_texture();
960 }
961 }
962#ifdef TRACE_TEXTURE_CREATION
963 GrPrintf("--- new texture [%d] size=(%d %d) bpp=%d\n",
964 tex->fTextureID, width, height, tex->fUploadByteCount);
965#endif
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000966 GrGLTexture* tex = new GrGLTexture(glDesc, rtIDs, DEFAULT_PARAMS, this);
reed@google.comac10a2d2010-12-22 21:39:39 +0000967
968 if (0 != rtIDs.fTexFBOID) {
969 GrRenderTarget* rt = tex->asRenderTarget();
970 // We've messed with FBO state but may not have set the correct viewport
971 // so just dirty the rendertarget state to force a resend.
972 fHWDrawState.fRenderTarget = NULL;
973
974 // clear the new stencil buffer if we have one
975 if (!(desc.fFlags & kNoPathRendering_TextureFlag)) {
976 GrRenderTarget* rtSave = fCurrDrawState.fRenderTarget;
977 fCurrDrawState.fRenderTarget = rt;
978 eraseStencil(0, ~0);
979 fCurrDrawState.fRenderTarget = rtSave;
980 }
981 }
982 return tex;
983}
984
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000985GrVertexBuffer* GrGpuGL::createVertexBufferHelper(uint32_t size, bool dynamic) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000986 GLuint id;
987 GR_GL(GenBuffers(1, &id));
988 if (id) {
989 GR_GL(BindBuffer(GL_ARRAY_BUFFER, id));
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000990 fHWGeometryState.fArrayPtrsDirty = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000991 GrGLClearErr();
992 // make sure driver can allocate memory for this buffer
993 GR_GL_NO_ERR(BufferData(GL_ARRAY_BUFFER, size, NULL,
994 dynamic ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW));
995 if (glGetError() != GL_NO_ERROR) {
996 GR_GL(DeleteBuffers(1, &id));
997 // deleting bound buffer does implicit bind to 0
998 fHWGeometryState.fVertexBuffer = NULL;
999 return NULL;
1000 }
1001 GrGLVertexBuffer* vertexBuffer = new GrGLVertexBuffer(id, this,
1002 size, dynamic);
1003 fHWGeometryState.fVertexBuffer = vertexBuffer;
1004 return vertexBuffer;
1005 }
1006 return NULL;
1007}
1008
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001009GrIndexBuffer* GrGpuGL::createIndexBufferHelper(uint32_t size, bool dynamic) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001010 GLuint id;
1011 GR_GL(GenBuffers(1, &id));
1012 if (id) {
1013 GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, id));
1014 GrGLClearErr();
1015 // make sure driver can allocate memory for this buffer
1016 GR_GL_NO_ERR(BufferData(GL_ELEMENT_ARRAY_BUFFER, size, NULL,
1017 dynamic ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW));
1018 if (glGetError() != GL_NO_ERROR) {
1019 GR_GL(DeleteBuffers(1, &id));
1020 // deleting bound buffer does implicit bind to 0
1021 fHWGeometryState.fIndexBuffer = NULL;
1022 return NULL;
1023 }
1024 GrIndexBuffer* indexBuffer = new GrGLIndexBuffer(id, this,
1025 size, dynamic);
1026 fHWGeometryState.fIndexBuffer = indexBuffer;
1027 return indexBuffer;
1028 }
1029 return NULL;
1030}
1031
reed@google.comac10a2d2010-12-22 21:39:39 +00001032void GrGpuGL::flushScissor(const GrIRect* rect) {
1033 GrAssert(NULL != fCurrDrawState.fRenderTarget);
bsalomon@google.com8895a7a2011-02-18 16:09:55 +00001034 const GrGLIRect& vp =
bsalomon@google.comd302f142011-03-03 13:54:13 +00001035 ((GrGLRenderTarget*)fCurrDrawState.fRenderTarget)->getViewport();
reed@google.comac10a2d2010-12-22 21:39:39 +00001036
bsalomon@google.com8895a7a2011-02-18 16:09:55 +00001037 GrGLIRect scissor;
1038 if (NULL != rect) {
bsalomon@google.comd302f142011-03-03 13:54:13 +00001039 scissor.setRelativeTo(vp, rect->fLeft, rect->fTop,
bsalomon@google.com8895a7a2011-02-18 16:09:55 +00001040 rect->width(), rect->height());
1041 if (scissor.contains(vp)) {
1042 rect = NULL;
1043 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001044 }
1045
1046 if (NULL != rect) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001047 if (fHWBounds.fScissorRect != scissor) {
bsalomon@google.com8895a7a2011-02-18 16:09:55 +00001048 scissor.pushToGLScissor();
reed@google.comac10a2d2010-12-22 21:39:39 +00001049 fHWBounds.fScissorRect = scissor;
1050 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001051 if (!fHWBounds.fScissorEnabled) {
1052 GR_GL(Enable(GL_SCISSOR_TEST));
1053 fHWBounds.fScissorEnabled = true;
1054 }
1055 } else {
1056 if (fHWBounds.fScissorEnabled) {
1057 GR_GL(Disable(GL_SCISSOR_TEST));
1058 fHWBounds.fScissorEnabled = false;
1059 }
1060 }
1061}
1062
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001063void GrGpuGL::eraseColorHelper(GrColor color) {
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +00001064 if (NULL == fCurrDrawState.fRenderTarget) {
1065 return;
1066 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001067 flushRenderTarget();
1068 if (fHWBounds.fScissorEnabled) {
1069 GR_GL(Disable(GL_SCISSOR_TEST));
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +00001070 fHWBounds.fScissorEnabled = false;
reed@google.comac10a2d2010-12-22 21:39:39 +00001071 }
1072 GR_GL(ColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE));
bsalomon@google.comd302f142011-03-03 13:54:13 +00001073 fHWDrawState.fFlagBits &= ~kNoColorWrites_StateBit;
reed@google.comac10a2d2010-12-22 21:39:39 +00001074 GR_GL(ClearColor(GrColorUnpackR(color)/255.f,
1075 GrColorUnpackG(color)/255.f,
1076 GrColorUnpackB(color)/255.f,
1077 GrColorUnpackA(color)/255.f));
1078 GR_GL(Clear(GL_COLOR_BUFFER_BIT));
reed@google.comac10a2d2010-12-22 21:39:39 +00001079}
1080
1081void GrGpuGL::eraseStencil(uint32_t value, uint32_t mask) {
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +00001082 if (NULL == fCurrDrawState.fRenderTarget) {
1083 return;
1084 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001085 flushRenderTarget();
1086 if (fHWBounds.fScissorEnabled) {
1087 GR_GL(Disable(GL_SCISSOR_TEST));
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +00001088 fHWBounds.fScissorEnabled = false;
reed@google.comac10a2d2010-12-22 21:39:39 +00001089 }
1090 GR_GL(StencilMask(mask));
1091 GR_GL(ClearStencil(value));
1092 GR_GL(Clear(GL_STENCIL_BUFFER_BIT));
bsalomon@google.comd302f142011-03-03 13:54:13 +00001093 fHWDrawState.fStencilSettings.invalidate();
reed@google.comac10a2d2010-12-22 21:39:39 +00001094}
1095
bsalomon@google.comd302f142011-03-03 13:54:13 +00001096void GrGpuGL::eraseStencilClip(const GrIRect& rect) {
bsalomon@google.com8895a7a2011-02-18 16:09:55 +00001097 GrAssert(NULL != fCurrDrawState.fRenderTarget);
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +00001098#if 0
bsalomon@google.comd302f142011-03-03 13:54:13 +00001099 GLint stencilBitCount = fCurrDrawState.fRenderTarget->stencilBits();
reed@google.comac10a2d2010-12-22 21:39:39 +00001100 GrAssert(stencilBitCount > 0);
1101 GLint clipStencilMask = (1 << (stencilBitCount - 1));
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +00001102#else
1103 // we could just clear the clip bit but when we go through
1104 // angle a partial stencil mask will cause clears to be
1105 // turned into draws. Our contract on GrDrawTarget says that
1106 // changing the clip between stencil passes may or may not
1107 // zero the client's clip bits. So we just clear the whole thing.
1108 static const GLint clipStencilMask = ~0;
1109#endif
bsalomon@google.comd302f142011-03-03 13:54:13 +00001110 flushRenderTarget();
1111 flushScissor(&rect);
1112 GR_GL(StencilMask(clipStencilMask));
1113 GR_GL(ClearStencil(0));
1114 GR_GL(Clear(GL_STENCIL_BUFFER_BIT));
1115 fHWDrawState.fStencilSettings.invalidate();
reed@google.comac10a2d2010-12-22 21:39:39 +00001116}
1117
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001118void GrGpuGL::forceRenderTargetFlushHelper() {
reed@google.comac10a2d2010-12-22 21:39:39 +00001119 flushRenderTarget();
1120}
1121
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001122bool GrGpuGL::readPixelsHelper(int left, int top, int width, int height,
1123 GrTexture::PixelConfig config, void* buffer) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001124 GLenum internalFormat; // we don't use this for glReadPixels
1125 GLenum format;
1126 GLenum type;
1127 if (!this->canBeTexture(config, &internalFormat, &format, &type)) {
1128 return false;
1129 }
1130
bsalomon@google.com18908aa2011-02-07 14:51:55 +00001131 if (NULL == fCurrDrawState.fRenderTarget) {
1132 return false;
1133 }
1134 flushRenderTarget();
1135
bsalomon@google.comd302f142011-03-03 13:54:13 +00001136 const GrGLIRect& glvp = ((GrGLRenderTarget*)fCurrDrawState.fRenderTarget)->getViewport();
1137
bsalomon@google.com8895a7a2011-02-18 16:09:55 +00001138 // the read rect is viewport-relative
1139 GrGLIRect readRect;
1140 readRect.setRelativeTo(glvp, left, top, width, height);
1141 GR_GL(ReadPixels(readRect.fLeft, readRect.fBottom,
bsalomon@google.comd302f142011-03-03 13:54:13 +00001142 readRect.fWidth, readRect.fHeight,
bsalomon@google.com316f99232011-01-13 21:28:12 +00001143 format, type, buffer));
reed@google.comac10a2d2010-12-22 21:39:39 +00001144
1145 // now reverse the order of the rows, since GL's are bottom-to-top, but our
1146 // API presents top-to-bottom
1147 {
1148 size_t stride = width * GrTexture::BytesPerPixel(config);
1149 GrAutoMalloc rowStorage(stride);
1150 void* tmp = rowStorage.get();
1151
1152 const int halfY = height >> 1;
1153 char* top = reinterpret_cast<char*>(buffer);
1154 char* bottom = top + (height - 1) * stride;
1155 for (int y = 0; y < halfY; y++) {
1156 memcpy(tmp, top, stride);
1157 memcpy(top, bottom, stride);
1158 memcpy(bottom, tmp, stride);
1159 top += stride;
1160 bottom -= stride;
1161 }
1162 }
1163 return true;
1164}
1165
1166void GrGpuGL::flushRenderTarget() {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001167
1168 GrAssert(NULL != fCurrDrawState.fRenderTarget);
1169
reed@google.comac10a2d2010-12-22 21:39:39 +00001170 if (fHWDrawState.fRenderTarget != fCurrDrawState.fRenderTarget) {
1171 GrGLRenderTarget* rt = (GrGLRenderTarget*)fCurrDrawState.fRenderTarget;
1172 GR_GLEXT(fExts, BindFramebuffer(GR_FRAMEBUFFER, rt->renderFBOID()));
1173 #if GR_COLLECT_STATS
1174 ++fStats.fRenderTargetChngCnt;
1175 #endif
1176 rt->setDirty(true);
1177 #if GR_DEBUG
1178 GLenum status = GR_GLEXT(fExts, CheckFramebufferStatus(GR_FRAMEBUFFER));
1179 if (status != GR_FRAMEBUFFER_COMPLETE) {
1180 GrPrintf("-- glCheckFramebufferStatus %x\n", status);
1181 }
1182 #endif
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001183 fDirtyFlags.fRenderTargetChanged = true;
bsalomon@google.com8895a7a2011-02-18 16:09:55 +00001184 fHWDrawState.fRenderTarget = fCurrDrawState.fRenderTarget;
bsalomon@google.comd302f142011-03-03 13:54:13 +00001185 const GrGLIRect& vp = rt->getViewport();
bsalomon@google.com8895a7a2011-02-18 16:09:55 +00001186 if (true || fHWBounds.fViewportRect != vp) {
1187 vp.pushToGLViewport();
reed@google.comac10a2d2010-12-22 21:39:39 +00001188 fHWBounds.fViewportRect = vp;
1189 }
1190 }
1191}
1192
1193GLenum gPrimitiveType2GLMode[] = {
1194 GL_TRIANGLES,
1195 GL_TRIANGLE_STRIP,
1196 GL_TRIANGLE_FAN,
1197 GL_POINTS,
1198 GL_LINES,
1199 GL_LINE_STRIP
1200};
1201
bsalomon@google.comd302f142011-03-03 13:54:13 +00001202#define SWAP_PER_DRAW 0
1203
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001204#if SWAP_PER_DRAW
bsalomon@google.comd302f142011-03-03 13:54:13 +00001205 #if GR_MAC_BUILD
1206 #include <AGL/agl.h>
1207 #elif GR_WIN32_BUILD
1208 void SwapBuf() {
1209 DWORD procID = GetCurrentProcessId();
1210 HWND hwnd = GetTopWindow(GetDesktopWindow());
1211 while(hwnd) {
1212 DWORD wndProcID = 0;
1213 GetWindowThreadProcessId(hwnd, &wndProcID);
1214 if(wndProcID == procID) {
1215 SwapBuffers(GetDC(hwnd));
1216 }
1217 hwnd = GetNextWindow(hwnd, GW_HWNDNEXT);
1218 }
1219 }
1220 #endif
1221#endif
1222
bsalomon@google.comffca4002011-02-22 20:34:01 +00001223void GrGpuGL::drawIndexedHelper(GrPrimitiveType type,
reed@google.comac10a2d2010-12-22 21:39:39 +00001224 uint32_t startVertex,
1225 uint32_t startIndex,
1226 uint32_t vertexCount,
1227 uint32_t indexCount) {
1228 GrAssert((size_t)type < GR_ARRAY_COUNT(gPrimitiveType2GLMode));
1229
1230 GLvoid* indices = (GLvoid*)(sizeof(uint16_t) * startIndex);
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001231
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001232 GrAssert(NULL != fHWGeometryState.fIndexBuffer);
1233 GrAssert(NULL != fHWGeometryState.fVertexBuffer);
1234
1235 // our setupGeometry better have adjusted this to zero since
1236 // DrawElements always draws from the begining of the arrays for idx 0.
1237 GrAssert(0 == startVertex);
reed@google.comac10a2d2010-12-22 21:39:39 +00001238
1239 GR_GL(DrawElements(gPrimitiveType2GLMode[type], indexCount,
1240 GL_UNSIGNED_SHORT, indices));
bsalomon@google.comd302f142011-03-03 13:54:13 +00001241#if SWAP_PER_DRAW
1242 glFlush();
1243 #if GR_MAC_BUILD
1244 aglSwapBuffers(aglGetCurrentContext());
1245 int set_a_break_pt_here = 9;
1246 aglSwapBuffers(aglGetCurrentContext());
1247 #elif GR_WIN32_BUILD
1248 SwapBuf();
1249 int set_a_break_pt_here = 9;
1250 SwapBuf();
1251 #endif
1252#endif
reed@google.comac10a2d2010-12-22 21:39:39 +00001253}
1254
bsalomon@google.comffca4002011-02-22 20:34:01 +00001255void GrGpuGL::drawNonIndexedHelper(GrPrimitiveType type,
reed@google.comac10a2d2010-12-22 21:39:39 +00001256 uint32_t startVertex,
1257 uint32_t vertexCount) {
1258 GrAssert((size_t)type < GR_ARRAY_COUNT(gPrimitiveType2GLMode));
1259
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001260 GrAssert(NULL != fHWGeometryState.fVertexBuffer);
1261
1262 // our setupGeometry better have adjusted this to zero.
1263 // DrawElements doesn't take an offset so we always adjus the startVertex.
1264 GrAssert(0 == startVertex);
1265
1266 // pass 0 for parameter first. We have to adjust gl*Pointer() to
1267 // account for startVertex in the DrawElements case. So we always
1268 // rely on setupGeometry to have accounted for startVertex.
reed@google.comac10a2d2010-12-22 21:39:39 +00001269 GR_GL(DrawArrays(gPrimitiveType2GLMode[type], 0, vertexCount));
bsalomon@google.comd302f142011-03-03 13:54:13 +00001270#if SWAP_PER_DRAW
1271 glFlush();
1272 #if GR_MAC_BUILD
1273 aglSwapBuffers(aglGetCurrentContext());
1274 int set_a_break_pt_here = 9;
1275 aglSwapBuffers(aglGetCurrentContext());
1276 #elif GR_WIN32_BUILD
1277 SwapBuf();
1278 int set_a_break_pt_here = 9;
1279 SwapBuf();
1280 #endif
1281#endif
reed@google.comac10a2d2010-12-22 21:39:39 +00001282}
1283
reed@google.comac10a2d2010-12-22 21:39:39 +00001284void GrGpuGL::resolveTextureRenderTarget(GrGLTexture* texture) {
1285 GrGLRenderTarget* rt = (GrGLRenderTarget*) texture->asRenderTarget();
1286
1287 if (NULL != rt && rt->needsResolve()) {
1288 GrAssert(kNone_MSFBO != fMSFBOType);
1289 GrAssert(rt->textureFBOID() != rt->renderFBOID());
1290 GR_GLEXT(fExts, BindFramebuffer(GR_READ_FRAMEBUFFER,
1291 rt->renderFBOID()));
1292 GR_GLEXT(fExts, BindFramebuffer(GR_DRAW_FRAMEBUFFER,
1293 rt->textureFBOID()));
1294 #if GR_COLLECT_STATS
1295 ++fStats.fRenderTargetChngCnt;
1296 #endif
1297 // make sure we go through set render target
1298 fHWDrawState.fRenderTarget = NULL;
1299
1300 GLint left = 0;
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001301 GLint right = texture->width();
reed@google.comac10a2d2010-12-22 21:39:39 +00001302 // we will have rendered to the top of the FBO.
1303 GLint top = texture->allocHeight();
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001304 GLint bottom = texture->allocHeight() - texture->height();
reed@google.comac10a2d2010-12-22 21:39:39 +00001305 if (kApple_MSFBO == fMSFBOType) {
1306 GR_GL(Enable(GL_SCISSOR_TEST));
1307 GR_GL(Scissor(left, bottom, right-left, top-bottom));
1308 GR_GLEXT(fExts, ResolveMultisampleFramebuffer());
bsalomon@google.com8895a7a2011-02-18 16:09:55 +00001309 fHWBounds.fScissorRect.invalidate();
reed@google.comac10a2d2010-12-22 21:39:39 +00001310 fHWBounds.fScissorEnabled = true;
1311 } else {
1312 GR_GLEXT(fExts, BlitFramebuffer(left, bottom, right, top,
1313 left, bottom, right, top,
1314 GL_COLOR_BUFFER_BIT, GL_NEAREST));
1315 }
1316 rt->setDirty(false);
1317
1318 }
1319}
1320
bsalomon@google.comd302f142011-03-03 13:54:13 +00001321static const GLenum grToGLStencilFunc[] = {
1322 GL_ALWAYS, // kAlways_StencilFunc
1323 GL_NEVER, // kNever_StencilFunc
1324 GL_GREATER, // kGreater_StencilFunc
1325 GL_GEQUAL, // kGEqual_StencilFunc
1326 GL_LESS, // kLess_StencilFunc
1327 GL_LEQUAL, // kLEqual_StencilFunc,
1328 GL_EQUAL, // kEqual_StencilFunc,
1329 GL_NOTEQUAL, // kNotEqual_StencilFunc,
1330};
1331GR_STATIC_ASSERT(GR_ARRAY_COUNT(grToGLStencilFunc) == kBasicStencilFuncCount);
1332GR_STATIC_ASSERT(0 == kAlways_StencilFunc);
1333GR_STATIC_ASSERT(1 == kNever_StencilFunc);
1334GR_STATIC_ASSERT(2 == kGreater_StencilFunc);
1335GR_STATIC_ASSERT(3 == kGEqual_StencilFunc);
1336GR_STATIC_ASSERT(4 == kLess_StencilFunc);
1337GR_STATIC_ASSERT(5 == kLEqual_StencilFunc);
1338GR_STATIC_ASSERT(6 == kEqual_StencilFunc);
1339GR_STATIC_ASSERT(7 == kNotEqual_StencilFunc);
1340
1341static const GLenum grToGLStencilOp[] = {
1342 GL_KEEP, // kKeep_StencilOp
1343 GL_REPLACE, // kReplace_StencilOp
1344 GL_INCR_WRAP, // kIncWrap_StencilOp
1345 GL_INCR, // kIncClamp_StencilOp
1346 GL_DECR_WRAP, // kDecWrap_StencilOp
1347 GL_DECR, // kDecClamp_StencilOp
1348 GL_ZERO, // kZero_StencilOp
1349 GL_INVERT, // kInvert_StencilOp
1350};
1351GR_STATIC_ASSERT(GR_ARRAY_COUNT(grToGLStencilOp) == kStencilOpCount);
1352GR_STATIC_ASSERT(0 == kKeep_StencilOp);
1353GR_STATIC_ASSERT(1 == kReplace_StencilOp);
1354GR_STATIC_ASSERT(2 == kIncWrap_StencilOp);
1355GR_STATIC_ASSERT(3 == kIncClamp_StencilOp);
1356GR_STATIC_ASSERT(4 == kDecWrap_StencilOp);
1357GR_STATIC_ASSERT(5 == kDecClamp_StencilOp);
1358GR_STATIC_ASSERT(6 == kZero_StencilOp);
1359GR_STATIC_ASSERT(7 == kInvert_StencilOp);
1360
reed@google.comac10a2d2010-12-22 21:39:39 +00001361void GrGpuGL::flushStencil() {
bsalomon@google.comd302f142011-03-03 13:54:13 +00001362 const GrStencilSettings* settings = &fCurrDrawState.fStencilSettings;
reed@google.comac10a2d2010-12-22 21:39:39 +00001363
1364 // use stencil for clipping if clipping is enabled and the clip
1365 // has been written into the stencil.
1366 bool stencilClip = fClipState.fClipInStencil &&
1367 (kClip_StateBit & fCurrDrawState.fFlagBits);
bsalomon@google.comd302f142011-03-03 13:54:13 +00001368 bool stencilChange = fHWStencilClip != stencilClip ||
1369 fHWDrawState.fStencilSettings != *settings ||
1370 ((fHWDrawState.fFlagBits & kModifyStencilClip_StateBit) !=
1371 (fCurrDrawState.fFlagBits & kModifyStencilClip_StateBit));
reed@google.comac10a2d2010-12-22 21:39:39 +00001372
1373 if (stencilChange) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001374
bsalomon@google.comd302f142011-03-03 13:54:13 +00001375 // we can't simultaneously perform stencil-clipping and modify the stencil clip
1376 GrAssert(!stencilClip || !(fCurrDrawState.fFlagBits & kModifyStencilClip_StateBit));
reed@google.comac10a2d2010-12-22 21:39:39 +00001377
bsalomon@google.comd302f142011-03-03 13:54:13 +00001378 if (settings->isDisabled()) {
1379 if (stencilClip) {
1380 settings = &gClipStencilSettings;
1381 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001382 }
bsalomon@google.comd302f142011-03-03 13:54:13 +00001383
1384 if (settings->isDisabled()) {
1385 GR_GL(Disable(GL_STENCIL_TEST));
1386 } else {
1387 GR_GL(Enable(GL_STENCIL_TEST));
1388 #if GR_DEBUG
1389 if (!fStencilWrapOpsSupport) {
1390 GrAssert(settings->fFrontPassOp != kIncWrap_StencilOp);
1391 GrAssert(settings->fFrontPassOp != kDecWrap_StencilOp);
1392 GrAssert(settings->fFrontFailOp != kIncWrap_StencilOp);
1393 GrAssert(settings->fBackFailOp != kDecWrap_StencilOp);
1394 GrAssert(settings->fBackPassOp != kIncWrap_StencilOp);
1395 GrAssert(settings->fBackPassOp != kDecWrap_StencilOp);
1396 GrAssert(settings->fBackFailOp != kIncWrap_StencilOp);
1397 GrAssert(settings->fFrontFailOp != kDecWrap_StencilOp);
1398 }
1399 #endif
1400 int stencilBits = fCurrDrawState.fRenderTarget->stencilBits();
1401 GrAssert(stencilBits ||
1402 (GrStencilSettings::gDisabled ==
1403 fCurrDrawState.fStencilSettings));
1404 GLuint clipStencilMask = 1 << (stencilBits - 1);
1405 GLuint userStencilMask = clipStencilMask - 1;
1406
1407 unsigned int frontRef = settings->fFrontFuncRef;
1408 unsigned int frontMask = settings->fFrontFuncMask;
1409 unsigned int frontWriteMask = settings->fFrontWriteMask;
1410 GLenum frontFunc;
1411
1412 if (fCurrDrawState.fFlagBits & kModifyStencilClip_StateBit) {
1413
1414 GrAssert(settings->fFrontFunc < kBasicStencilFuncCount);
1415 frontFunc = grToGLStencilFunc[settings->fFrontFunc];
1416 } else {
1417 frontFunc = grToGLStencilFunc[ConvertStencilFunc(stencilClip, settings->fFrontFunc)];
1418
1419 ConvertStencilFuncAndMask(settings->fFrontFunc,
1420 stencilClip,
1421 clipStencilMask,
1422 userStencilMask,
1423 &frontRef,
1424 &frontMask);
1425 frontWriteMask &= userStencilMask;
1426 }
1427 GrAssert(settings->fFrontFailOp >= 0 &&
1428 settings->fFrontFailOp < GR_ARRAY_COUNT(grToGLStencilOp));
1429 GrAssert(settings->fFrontPassOp >= 0 &&
1430 settings->fFrontPassOp < GR_ARRAY_COUNT(grToGLStencilOp));
1431 GrAssert(settings->fBackFailOp >= 0 &&
1432 settings->fBackFailOp < GR_ARRAY_COUNT(grToGLStencilOp));
1433 GrAssert(settings->fBackPassOp >= 0 &&
1434 settings->fBackPassOp < GR_ARRAY_COUNT(grToGLStencilOp));
1435 if (fTwoSidedStencilSupport) {
1436 GLenum backFunc;
1437
1438 unsigned int backRef = settings->fBackFuncRef;
1439 unsigned int backMask = settings->fBackFuncMask;
1440 unsigned int backWriteMask = settings->fBackWriteMask;
1441
1442
1443 if (fCurrDrawState.fFlagBits & kModifyStencilClip_StateBit) {
1444 GrAssert(settings->fBackFunc < kBasicStencilFuncCount);
1445 backFunc = grToGLStencilFunc[settings->fBackFunc];
1446 } else {
1447 backFunc = grToGLStencilFunc[ConvertStencilFunc(stencilClip, settings->fBackFunc)];
1448 ConvertStencilFuncAndMask(settings->fBackFunc,
1449 stencilClip,
1450 clipStencilMask,
1451 userStencilMask,
1452 &backRef,
1453 &backMask);
1454 backWriteMask &= userStencilMask;
1455 }
1456
1457 GR_GL(StencilFuncSeparate(GL_FRONT, frontFunc, frontRef, frontMask));
1458 GR_GL(StencilMaskSeparate(GL_FRONT, frontWriteMask));
1459 GR_GL(StencilFuncSeparate(GL_BACK, backFunc, backRef, backMask));
1460 GR_GL(StencilMaskSeparate(GL_BACK, backWriteMask));
1461 GR_GL(StencilOpSeparate(GL_FRONT, grToGLStencilOp[settings->fFrontFailOp],
1462 grToGLStencilOp[settings->fFrontPassOp],
1463 grToGLStencilOp[settings->fFrontPassOp]));
1464
1465 GR_GL(StencilOpSeparate(GL_BACK, grToGLStencilOp[settings->fBackFailOp],
1466 grToGLStencilOp[settings->fBackPassOp],
1467 grToGLStencilOp[settings->fBackPassOp]));
1468 } else {
1469 GR_GL(StencilFunc(frontFunc, frontRef, frontMask));
1470 GR_GL(StencilMask(frontWriteMask));
1471 GR_GL(StencilOp(grToGLStencilOp[settings->fFrontFailOp],
1472 grToGLStencilOp[settings->fFrontPassOp],
1473 grToGLStencilOp[settings->fFrontPassOp]));
1474 }
1475 }
1476 fHWDrawState.fStencilSettings = fCurrDrawState.fStencilSettings;
reed@google.comac10a2d2010-12-22 21:39:39 +00001477 fHWStencilClip = stencilClip;
1478 }
1479}
1480
bsalomon@google.comffca4002011-02-22 20:34:01 +00001481bool GrGpuGL::flushGLStateCommon(GrPrimitiveType type) {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001482
1483 // GrGpu::setupClipAndFlushState should have already checked this
1484 // and bailed if not true.
1485 GrAssert(NULL != fCurrDrawState.fRenderTarget);
reed@google.comac10a2d2010-12-22 21:39:39 +00001486
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001487 for (int s = 0; s < kNumStages; ++s) {
1488 bool usingTexture = VertexUsesStage(s, fGeometrySrc.fVertexLayout);
reed@google.comac10a2d2010-12-22 21:39:39 +00001489
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001490 // bind texture and set sampler state
1491 if (usingTexture) {
1492 GrGLTexture* nextTexture = (GrGLTexture*)fCurrDrawState.fTextures[s];
reed@google.comac10a2d2010-12-22 21:39:39 +00001493
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001494 if (NULL != nextTexture) {
bsalomon@google.com316f99232011-01-13 21:28:12 +00001495 // if we created a rt/tex and rendered to it without using a
1496 // texture and now we're texuring from the rt it will still be
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001497 // the last bound texture, but it needs resolving. So keep this
1498 // out of the "last != next" check.
1499 resolveTextureRenderTarget(nextTexture);
reed@google.comac10a2d2010-12-22 21:39:39 +00001500
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001501 if (fHWDrawState.fTextures[s] != nextTexture) {
1502 setTextureUnit(s);
1503 GR_GL(BindTexture(GL_TEXTURE_2D, nextTexture->textureID()));
1504 #if GR_COLLECT_STATS
1505 ++fStats.fTextureChngCnt;
1506 #endif
1507 //GrPrintf("---- bindtexture %d\n", nextTexture->textureID());
1508 fHWDrawState.fTextures[s] = nextTexture;
1509 }
bsalomon@google.com316f99232011-01-13 21:28:12 +00001510
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001511 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
bsalomon@google.com316f99232011-01-13 21:28:12 +00001512 const GrGLTexture::TexParams& oldTexParams =
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001513 nextTexture->getTexParams();
1514 GrGLTexture::TexParams newTexParams;
bsalomon@google.com316f99232011-01-13 21:28:12 +00001515
1516 newTexParams.fFilter = sampler.isFilter() ? GL_LINEAR :
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001517 GL_NEAREST;
bsalomon@google.com316f99232011-01-13 21:28:12 +00001518 newTexParams.fWrapS =
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001519 GrGLTexture::gWrapMode2GLWrap[sampler.getWrapX()];
bsalomon@google.com316f99232011-01-13 21:28:12 +00001520 newTexParams.fWrapT =
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001521 GrGLTexture::gWrapMode2GLWrap[sampler.getWrapY()];
reed@google.comac10a2d2010-12-22 21:39:39 +00001522
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001523 if (newTexParams.fFilter != oldTexParams.fFilter) {
1524 setTextureUnit(s);
bsalomon@google.com316f99232011-01-13 21:28:12 +00001525 GR_GL(TexParameteri(GL_TEXTURE_2D,
1526 GL_TEXTURE_MAG_FILTER,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001527 newTexParams.fFilter));
bsalomon@google.com316f99232011-01-13 21:28:12 +00001528 GR_GL(TexParameteri(GL_TEXTURE_2D,
1529 GL_TEXTURE_MIN_FILTER,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001530 newTexParams.fFilter));
1531 }
1532 if (newTexParams.fWrapS != oldTexParams.fWrapS) {
1533 setTextureUnit(s);
bsalomon@google.com316f99232011-01-13 21:28:12 +00001534 GR_GL(TexParameteri(GL_TEXTURE_2D,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001535 GL_TEXTURE_WRAP_S,
1536 newTexParams.fWrapS));
1537 }
1538 if (newTexParams.fWrapT != oldTexParams.fWrapT) {
1539 setTextureUnit(s);
bsalomon@google.com316f99232011-01-13 21:28:12 +00001540 GR_GL(TexParameteri(GL_TEXTURE_2D,
1541 GL_TEXTURE_WRAP_T,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001542 newTexParams.fWrapT));
1543 }
1544 nextTexture->setTexParams(newTexParams);
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001545
1546 // The texture matrix has to compensate for texture width/height
1547 // and NPOT-embedded-in-POT
1548 fDirtyFlags.fTextureChangedMask |= (1 << s);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001549 } else {
1550 GrAssert(!"Rendering with texture vert flag set but no texture");
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001551 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +00001552 }
1553 }
1554 }
1555
1556 flushRenderTarget();
1557
1558 if ((fCurrDrawState.fFlagBits & kDither_StateBit) !=
1559 (fHWDrawState.fFlagBits & kDither_StateBit)) {
1560 if (fCurrDrawState.fFlagBits & kDither_StateBit) {
1561 GR_GL(Enable(GL_DITHER));
1562 } else {
1563 GR_GL(Disable(GL_DITHER));
1564 }
1565 }
1566
bsalomon@google.comd302f142011-03-03 13:54:13 +00001567 if ((fCurrDrawState.fFlagBits & kNoColorWrites_StateBit) !=
1568 (fHWDrawState.fFlagBits & kNoColorWrites_StateBit)) {
1569 GLenum mask;
1570 if (fCurrDrawState.fFlagBits & kNoColorWrites_StateBit) {
1571 mask = GL_FALSE;
1572 } else {
1573 mask = GL_TRUE;
1574 }
1575 GR_GL(ColorMask(mask, mask, mask, mask));
1576 }
1577
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001578#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +00001579 // ES doesn't support toggling GL_MULTISAMPLE and doesn't have
1580 // smooth lines.
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001581 if (fDirtyFlags.fRenderTargetChanged ||
reed@google.comac10a2d2010-12-22 21:39:39 +00001582 (fCurrDrawState.fFlagBits & kAntialias_StateBit) !=
1583 (fHWDrawState.fFlagBits & kAntialias_StateBit)) {
1584 GLint msaa = 0;
1585 // only perform query if we know MSAA is supported.
1586 // calling on non-MSAA target caused a crash in one environment,
1587 // though I don't think it should.
reed@google.coma09368c2011-02-24 21:42:29 +00001588 if (fAASamples[kHigh_AALevel]) {
reed@google.comac20fb92011-01-12 17:14:53 +00001589 GR_GL_GetIntegerv(GL_SAMPLE_BUFFERS, &msaa);
reed@google.comac10a2d2010-12-22 21:39:39 +00001590 }
1591 if (fCurrDrawState.fFlagBits & kAntialias_StateBit) {
1592 if (msaa) {
1593 GR_GL(Enable(GL_MULTISAMPLE));
1594 } else {
1595 GR_GL(Enable(GL_LINE_SMOOTH));
1596 }
1597 } else {
1598 if (msaa) {
1599 GR_GL(Disable(GL_MULTISAMPLE));
1600 }
1601 GR_GL(Disable(GL_LINE_SMOOTH));
1602 }
1603 }
1604#endif
1605
1606 bool blendOff = canDisableBlend();
1607 if (fHWBlendDisabled != blendOff) {
1608 if (blendOff) {
1609 GR_GL(Disable(GL_BLEND));
1610 } else {
1611 GR_GL(Enable(GL_BLEND));
1612 }
1613 fHWBlendDisabled = blendOff;
1614 }
1615
1616 if (!blendOff) {
1617 if (fHWDrawState.fSrcBlend != fCurrDrawState.fSrcBlend ||
1618 fHWDrawState.fDstBlend != fCurrDrawState.fDstBlend) {
1619 GR_GL(BlendFunc(gXfermodeCoeff2Blend[fCurrDrawState.fSrcBlend],
1620 gXfermodeCoeff2Blend[fCurrDrawState.fDstBlend]));
1621 fHWDrawState.fSrcBlend = fCurrDrawState.fSrcBlend;
1622 fHWDrawState.fDstBlend = fCurrDrawState.fDstBlend;
1623 }
1624 }
bsalomon@google.com316f99232011-01-13 21:28:12 +00001625
bsalomon@google.comd302f142011-03-03 13:54:13 +00001626 if (fHWDrawState.fDrawFace != fCurrDrawState.fDrawFace) {
1627 switch (fCurrDrawState.fDrawFace) {
1628 case kCCW_DrawFace:
1629 glEnable(GL_CULL_FACE);
1630 GR_GL(CullFace(GL_BACK));
1631 break;
1632 case kCW_DrawFace:
1633 GR_GL(Enable(GL_CULL_FACE));
1634 GR_GL(CullFace(GL_FRONT));
1635 break;
1636 case kBoth_DrawFace:
1637 GR_GL(Disable(GL_CULL_FACE));
1638 break;
1639 default:
1640 GrCrash("Unknown draw face.");
1641 }
1642 fHWDrawState.fDrawFace = fCurrDrawState.fDrawFace;
1643 }
1644
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001645#if GR_DEBUG
reed@google.comac10a2d2010-12-22 21:39:39 +00001646 // check for circular rendering
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001647 for (int s = 0; s < kNumStages; ++s) {
1648 GrAssert(!VertexUsesStage(s, fGeometrySrc.fVertexLayout) ||
1649 NULL == fCurrDrawState.fRenderTarget ||
1650 NULL == fCurrDrawState.fTextures[s] ||
bsalomon@google.com316f99232011-01-13 21:28:12 +00001651 fCurrDrawState.fTextures[s]->asRenderTarget() !=
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001652 fCurrDrawState.fRenderTarget);
1653 }
1654#endif
bsalomon@google.com316f99232011-01-13 21:28:12 +00001655
reed@google.comac10a2d2010-12-22 21:39:39 +00001656 flushStencil();
1657
bsalomon@google.comd302f142011-03-03 13:54:13 +00001658 // flushStencil may look at the private state bits, so keep it before this.
reed@google.comac10a2d2010-12-22 21:39:39 +00001659 fHWDrawState.fFlagBits = fCurrDrawState.fFlagBits;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001660 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +00001661}
1662
1663void GrGpuGL::notifyVertexBufferBind(const GrGLVertexBuffer* buffer) {
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001664 if (fHWGeometryState.fVertexBuffer != buffer) {
1665 fHWGeometryState.fArrayPtrsDirty = true;
1666 fHWGeometryState.fVertexBuffer = buffer;
1667 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001668}
1669
1670void GrGpuGL::notifyVertexBufferDelete(const GrGLVertexBuffer* buffer) {
1671 GrAssert(!(kBuffer_GeometrySrcType == fGeometrySrc.fVertexSrc &&
1672 buffer == fGeometrySrc.fVertexBuffer));
1673
1674 if (fHWGeometryState.fVertexBuffer == buffer) {
1675 // deleting bound buffer does implied bind to 0
1676 fHWGeometryState.fVertexBuffer = NULL;
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001677 fHWGeometryState.fArrayPtrsDirty = true;
reed@google.comac10a2d2010-12-22 21:39:39 +00001678 }
1679}
1680
1681void GrGpuGL::notifyIndexBufferBind(const GrGLIndexBuffer* buffer) {
1682 fGeometrySrc.fIndexBuffer = buffer;
1683}
1684
1685void GrGpuGL::notifyIndexBufferDelete(const GrGLIndexBuffer* buffer) {
1686 GrAssert(!(kBuffer_GeometrySrcType == fGeometrySrc.fIndexSrc &&
1687 buffer == fGeometrySrc.fIndexBuffer));
1688
1689 if (fHWGeometryState.fIndexBuffer == buffer) {
1690 // deleting bound buffer does implied bind to 0
1691 fHWGeometryState.fIndexBuffer = NULL;
1692 }
1693}
1694
reed@google.comac10a2d2010-12-22 21:39:39 +00001695void GrGpuGL::notifyRenderTargetDelete(GrRenderTarget* renderTarget) {
1696 GrAssert(NULL != renderTarget);
reed@google.comac10a2d2010-12-22 21:39:39 +00001697 if (fCurrDrawState.fRenderTarget == renderTarget) {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001698 fCurrDrawState.fRenderTarget = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +00001699 }
1700 if (fHWDrawState.fRenderTarget == renderTarget) {
1701 fHWDrawState.fRenderTarget = NULL;
1702 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001703}
1704
1705void GrGpuGL::notifyTextureDelete(GrGLTexture* texture) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001706 for (int s = 0; s < kNumStages; ++s) {
1707 if (fCurrDrawState.fTextures[s] == texture) {
1708 fCurrDrawState.fTextures[s] = NULL;
1709 }
1710 if (fHWDrawState.fTextures[s] == texture) {
1711 // deleting bound texture does implied bind to 0
1712 fHWDrawState.fTextures[s] = NULL;
1713 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001714 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001715}
1716
reed@google.comac10a2d2010-12-22 21:39:39 +00001717bool GrGpuGL::canBeTexture(GrTexture::PixelConfig config,
1718 GLenum* internalFormat,
1719 GLenum* format,
1720 GLenum* type) {
1721 switch (config) {
1722 case GrTexture::kRGBA_8888_PixelConfig:
1723 case GrTexture::kRGBX_8888_PixelConfig: // todo: can we tell it our X?
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +00001724 *format = GR_GL_32BPP_COLOR_FORMAT;
reed@google.com63100f92011-01-18 21:32:14 +00001725#if GR_SUPPORT_GLES
1726 // according to GL_EXT_texture_format_BGRA8888 the *internal*
1727 // format for a BGRA is BGRA not RGBA (as on desktop)
1728 *internalFormat = GR_GL_32BPP_COLOR_FORMAT;
1729#else
1730 *internalFormat = GL_RGBA;
bsalomon@google.comed3a0682011-01-18 16:54:04 +00001731#endif
reed@google.comac10a2d2010-12-22 21:39:39 +00001732 *type = GL_UNSIGNED_BYTE;
1733 break;
1734 case GrTexture::kRGB_565_PixelConfig:
1735 *format = GL_RGB;
1736 *internalFormat = GL_RGB;
1737 *type = GL_UNSIGNED_SHORT_5_6_5;
1738 break;
1739 case GrTexture::kRGBA_4444_PixelConfig:
1740 *format = GL_RGBA;
1741 *internalFormat = GL_RGBA;
1742 *type = GL_UNSIGNED_SHORT_4_4_4_4;
1743 break;
1744 case GrTexture::kIndex_8_PixelConfig:
1745 if (this->supports8BitPalette()) {
1746 *format = GR_PALETTE8_RGBA8;
1747 *internalFormat = GR_PALETTE8_RGBA8;
1748 *type = GL_UNSIGNED_BYTE; // unused I think
1749 } else {
1750 return false;
1751 }
1752 break;
1753 case GrTexture::kAlpha_8_PixelConfig:
1754 *format = GL_ALPHA;
1755 *internalFormat = GL_ALPHA;
1756 *type = GL_UNSIGNED_BYTE;
1757 break;
1758 default:
1759 return false;
1760 }
1761 return true;
1762}
1763
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001764void GrGpuGL::setTextureUnit(int unit) {
1765 GrAssert(unit >= 0 && unit < kNumStages);
1766 if (fActiveTextureUnitIdx != unit) {
1767 GR_GL(ActiveTexture(GL_TEXTURE0 + unit));
1768 fActiveTextureUnitIdx = unit;
1769 }
1770}
bsalomon@google.com316f99232011-01-13 21:28:12 +00001771
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001772void GrGpuGL::setSpareTextureUnit() {
1773 if (fActiveTextureUnitIdx != (GL_TEXTURE0 + SPARE_TEX_UNIT)) {
1774 GR_GL(ActiveTexture(GL_TEXTURE0 + SPARE_TEX_UNIT));
1775 fActiveTextureUnitIdx = SPARE_TEX_UNIT;
1776 }
1777}
1778
reed@google.comac10a2d2010-12-22 21:39:39 +00001779/* On ES the internalFormat and format must match for TexImage and we use
1780 GL_RGB, GL_RGBA for color formats. We also generally like having the driver
1781 decide the internalFormat. However, on ES internalFormat for
1782 RenderBufferStorage* has to be a specific format (not a base format like
1783 GL_RGBA).
1784 */
1785bool GrGpuGL::fboInternalFormat(GrTexture::PixelConfig config, GLenum* format) {
1786 switch (config) {
1787 case GrTexture::kRGBA_8888_PixelConfig:
1788 case GrTexture::kRGBX_8888_PixelConfig:
1789 if (fRGBA8Renderbuffer) {
1790 *format = GR_RGBA8;
1791 return true;
1792 } else {
1793 return false;
1794 }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001795#if GR_SUPPORT_GLES // ES2 supports 565. ES1 supports it with FBO extension
1796 // desktop GL has no such internal format
reed@google.comac10a2d2010-12-22 21:39:39 +00001797 case GrTexture::kRGB_565_PixelConfig:
1798 *format = GR_RGB565;
1799 return true;
1800#endif
1801 case GrTexture::kRGBA_4444_PixelConfig:
1802 *format = GL_RGBA4;
1803 return true;
1804 default:
1805 return false;
1806 }
1807}
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001808
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001809void GrGpuGL::resetDirtyFlags() {
1810 Gr_bzero(&fDirtyFlags, sizeof(fDirtyFlags));
1811}
1812
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001813void GrGpuGL::setBuffers(bool indexed,
1814 int* extraVertexOffset,
1815 int* extraIndexOffset) {
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001816
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001817 GrAssert(NULL != extraVertexOffset);
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001818
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001819 GrGLVertexBuffer* vbuf;
1820 switch (fGeometrySrc.fVertexSrc) {
1821 case kBuffer_GeometrySrcType:
1822 *extraVertexOffset = 0;
1823 vbuf = (GrGLVertexBuffer*) fGeometrySrc.fVertexBuffer;
1824 break;
1825 case kArray_GeometrySrcType:
1826 case kReserved_GeometrySrcType:
1827 finalizeReservedVertices();
1828 *extraVertexOffset = fCurrPoolStartVertex;
1829 vbuf = (GrGLVertexBuffer*) fCurrPoolVertexBuffer;
1830 break;
1831 default:
1832 vbuf = NULL; // suppress warning
1833 GrCrash("Unknown geometry src type!");
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001834 }
1835
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001836 GrAssert(NULL != vbuf);
1837 GrAssert(!vbuf->isLocked());
1838 if (fHWGeometryState.fVertexBuffer != vbuf) {
1839 GR_GL(BindBuffer(GL_ARRAY_BUFFER, vbuf->bufferID()));
1840 fHWGeometryState.fArrayPtrsDirty = true;
1841 fHWGeometryState.fVertexBuffer = vbuf;
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001842 }
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001843
1844 if (indexed) {
1845 GrAssert(NULL != extraIndexOffset);
1846
1847 GrGLIndexBuffer* ibuf;
1848 switch (fGeometrySrc.fIndexSrc) {
1849 case kBuffer_GeometrySrcType:
1850 *extraIndexOffset = 0;
1851 ibuf = (GrGLIndexBuffer*)fGeometrySrc.fIndexBuffer;
1852 break;
1853 case kArray_GeometrySrcType:
1854 case kReserved_GeometrySrcType:
1855 finalizeReservedIndices();
1856 *extraIndexOffset = fCurrPoolStartIndex;
1857 ibuf = (GrGLIndexBuffer*) fCurrPoolIndexBuffer;
1858 break;
1859 default:
1860 ibuf = NULL; // suppress warning
1861 GrCrash("Unknown geometry src type!");
1862 }
1863
1864 GrAssert(NULL != ibuf);
1865 GrAssert(!ibuf->isLocked());
1866 if (fHWGeometryState.fIndexBuffer != ibuf) {
1867 GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibuf->bufferID()));
1868 fHWGeometryState.fIndexBuffer = ibuf;
1869 }
1870 }
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001871}