blob: 94e9bfd591c342745767106a0bd31a5fd7ba9ead [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
twiz@google.com59a190b2011-03-14 21:23:01 +0000106static bool fbo_test(int w, int h) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000107
108 GLint savedFBO;
109 GLint savedTexUnit;
reed@google.com3d8de042011-01-20 02:18:00 +0000110 GR_GL_GetIntegerv(GL_ACTIVE_TEXTURE, &savedTexUnit);
111 GR_GL_GetIntegerv(GR_FRAMEBUFFER_BINDING, &savedFBO);
bsalomon@google.com316f99232011-01-13 21:28:12 +0000112
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000113 GR_GL(ActiveTexture(GL_TEXTURE0 + SPARE_TEX_UNIT));
bsalomon@google.com316f99232011-01-13 21:28:12 +0000114
reed@google.comac10a2d2010-12-22 21:39:39 +0000115 GLuint testFBO;
twiz@google.com59a190b2011-03-14 21:23:01 +0000116 GR_GL(GenFramebuffers(1, &testFBO));
117 GR_GL(BindFramebuffer(GR_FRAMEBUFFER, testFBO));
reed@google.comac10a2d2010-12-22 21:39:39 +0000118 GLuint testRTTex;
119 GR_GL(GenTextures(1, &testRTTex));
120 GR_GL(BindTexture(GL_TEXTURE_2D, testRTTex));
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000121 // some implementations require texture to be mip-map complete before
122 // FBO with level 0 bound as color attachment will be framebuffer complete.
123 GR_GL(TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
reed@google.comac10a2d2010-12-22 21:39:39 +0000124 GR_GL(TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h,
125 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL));
126 GR_GL(BindTexture(GL_TEXTURE_2D, 0));
twiz@google.com59a190b2011-03-14 21:23:01 +0000127 GR_GL(FramebufferTexture2D(GR_FRAMEBUFFER, GR_COLOR_ATTACHMENT0,
128 GL_TEXTURE_2D, testRTTex, 0));
129 GLenum status = GR_GL(CheckFramebufferStatus(GR_FRAMEBUFFER));
130 GR_GL(DeleteFramebuffers(1, &testFBO));
reed@google.comac10a2d2010-12-22 21:39:39 +0000131 GR_GL(DeleteTextures(1, &testRTTex));
bsalomon@google.com316f99232011-01-13 21:28:12 +0000132
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000133 GR_GL(ActiveTexture(savedTexUnit));
twiz@google.com59a190b2011-03-14 21:23:01 +0000134 GR_GL(BindFramebuffer(GR_FRAMEBUFFER, savedFBO));
bsalomon@google.com316f99232011-01-13 21:28:12 +0000135
reed@google.comac10a2d2010-12-22 21:39:39 +0000136 return status == GR_FRAMEBUFFER_COMPLETE;
137}
138
reed@google.comac10a2d2010-12-22 21:39:39 +0000139GrGpuGL::GrGpuGL() {
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000140
reed@google.comeeeb5a02010-12-23 15:12:59 +0000141 if (gPrintStartupSpew) {
142 GrPrintf("------------------------- create GrGpuGL %p --------------\n",
143 this);
twiz@google.com59a190b2011-03-14 21:23:01 +0000144 GrPrintf("------ VENDOR %s\n",
145 GrGLGetGLInterface()->fGetString(GL_VENDOR));
146 GrPrintf("------ RENDERER %s\n",
147 GrGLGetGLInterface()->fGetString(GL_RENDERER));
148 GrPrintf("------ VERSION %s\n",
149 GrGLGetGLInterface()->fGetString(GL_VERSION));
150 GrPrintf("------ EXTENSIONS\n %s \n",
151 GrGLGetGLInterface()->fGetString(GL_EXTENSIONS));
reed@google.comeeeb5a02010-12-23 15:12:59 +0000152 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000153
154 GrGLClearErr();
155
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000156 resetDirtyFlags();
bsalomon@google.com316f99232011-01-13 21:28:12 +0000157
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000158 GLint maxTextureUnits;
159 // check FS and fixed-function texture unit limits
160 // we only use textures in the fragment stage currently.
161 // checks are > to make sure we have a spare unit.
162#if GR_SUPPORT_GLDESKTOP || GR_SUPPORT_GLES2
reed@google.com3d8de042011-01-20 02:18:00 +0000163 GR_GL_GetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000164 GrAssert(maxTextureUnits > kNumStages);
165#endif
166#if GR_SUPPORT_GLDESKTOP || GR_SUPPORT_GLES1
reed@google.com3d8de042011-01-20 02:18:00 +0000167 GR_GL_GetIntegerv(GL_MAX_TEXTURE_UNITS, &maxTextureUnits);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000168 GrAssert(maxTextureUnits > kNumStages);
169#endif
bsalomon@google.com316f99232011-01-13 21:28:12 +0000170
reed@google.comac10a2d2010-12-22 21:39:39 +0000171 ////////////////////////////////////////////////////////////////////////////
172 // Check for supported features.
173
174 int major, minor;
175 gl_version(&major, &minor);
176
177 GLint numFormats;
reed@google.comac20fb92011-01-12 17:14:53 +0000178 GR_GL_GetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &numFormats);
reed@google.comac10a2d2010-12-22 21:39:39 +0000179 GrAutoSTMalloc<10, GLint> formats(numFormats);
reed@google.comac20fb92011-01-12 17:14:53 +0000180 GR_GL_GetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, formats);
reed@google.comac10a2d2010-12-22 21:39:39 +0000181 for (int i = 0; i < numFormats; ++i) {
182 if (formats[i] == GR_PALETTE8_RGBA8) {
183 f8bitPaletteSupport = true;
184 break;
185 }
186 }
reed@google.comeeeb5a02010-12-23 15:12:59 +0000187
188 if (gPrintStartupSpew) {
189 GrPrintf("Palette8 support: %s\n", (f8bitPaletteSupport ? "YES" : "NO"));
190 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000191
192 GR_STATIC_ASSERT(0 == kNone_AALevel);
193 GR_STATIC_ASSERT(1 == kLow_AALevel);
194 GR_STATIC_ASSERT(2 == kMed_AALevel);
195 GR_STATIC_ASSERT(3 == kHigh_AALevel);
196
197 memset(fAASamples, 0, sizeof(fAASamples));
198 fMSFBOType = kNone_MSFBO;
199 if (has_gl_extension("GL_IMG_multisampled_render_to_texture")) {
200 fMSFBOType = kIMG_MSFBO;
reed@google.comeeeb5a02010-12-23 15:12:59 +0000201 if (gPrintStartupSpew) {
202 GrPrintf("MSAA Support: IMG ES EXT.\n");
203 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000204 }
205 else if (has_gl_extension("GL_APPLE_framebuffer_multisample")) {
206 fMSFBOType = kApple_MSFBO;
reed@google.comeeeb5a02010-12-23 15:12:59 +0000207 if (gPrintStartupSpew) {
208 GrPrintf("MSAA Support: APPLE ES EXT.\n");
209 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000210 }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000211#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000212 else if ((major >= 3) ||
213 has_gl_extension("GL_ARB_framebuffer_object") ||
214 (has_gl_extension("GL_EXT_framebuffer_multisample") &&
215 has_gl_extension("GL_EXT_framebuffer_blit"))) {
216 fMSFBOType = kDesktop_MSFBO;
reed@google.comeeeb5a02010-12-23 15:12:59 +0000217 if (gPrintStartupSpew) {
218 GrPrintf("MSAA Support: DESKTOP\n");
219 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000220 }
221#endif
222 else {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000223 if (gPrintStartupSpew) {
224 GrPrintf("MSAA Support: NONE\n");
225 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000226 }
227
228 if (kNone_MSFBO != fMSFBOType) {
229 GLint maxSamples;
230 GLenum maxSampleGetter = (kIMG_MSFBO == fMSFBOType) ?
231 GR_MAX_SAMPLES_IMG :
232 GR_MAX_SAMPLES;
reed@google.comac20fb92011-01-12 17:14:53 +0000233 GR_GL_GetIntegerv(maxSampleGetter, &maxSamples);
reed@google.comac10a2d2010-12-22 21:39:39 +0000234 if (maxSamples > 1 ) {
235 fAASamples[kNone_AALevel] = 0;
236 fAASamples[kLow_AALevel] = GrMax(2,
237 GrFixedFloorToInt((GR_FixedHalf) *
238 maxSamples));
239 fAASamples[kMed_AALevel] = GrMax(2,
240 GrFixedFloorToInt(((GR_Fixed1*3)/4) *
241 maxSamples));
242 fAASamples[kHigh_AALevel] = maxSamples;
243 }
reed@google.comeeeb5a02010-12-23 15:12:59 +0000244 if (gPrintStartupSpew) {
245 GrPrintf("\tMax Samples: %d\n", maxSamples);
246 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000247 }
248
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000249#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000250 fHasStencilWrap = (major >= 2 || (major == 1 && minor >= 4)) ||
251 has_gl_extension("GL_EXT_stencil_wrap");
252#else
253 fHasStencilWrap = (major >= 2) || has_gl_extension("GL_OES_stencil_wrap");
254#endif
reed@google.comeeeb5a02010-12-23 15:12:59 +0000255 if (gPrintStartupSpew) {
256 GrPrintf("Stencil Wrap: %s\n", (fHasStencilWrap ? "YES" : "NO"));
257 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000258
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000259#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000260 // we could also look for GL_ATI_separate_stencil extension or
261 // GL_EXT_stencil_two_side but they use different function signatures
262 // than GL2.0+ (and than each other).
bsalomon@google.comd302f142011-03-03 13:54:13 +0000263 fTwoSidedStencilSupport = (major >= 2);
264 // supported on GL 1.4 and higher or by extension
265 fStencilWrapOpsSupport = (major > 1) ||
reed@google.comeca7d342011-03-04 19:33:13 +0000266 ((1 == major) && (minor >= 4)) ||
bsalomon@google.comd302f142011-03-03 13:54:13 +0000267 has_gl_extension("GL_EXT_stencil_wrap");
reed@google.comac10a2d2010-12-22 21:39:39 +0000268#else
269 // ES 2 has two sided stencil but 1.1 doesn't. There doesn't seem to be
270 // an ES1 extension.
bsalomon@google.comd302f142011-03-03 13:54:13 +0000271 fTwoSidedStencilSupport = (major >= 2);
272 // stencil wrap support is in ES2, ES1 requires extension.
273 fStencilWrapOpsSupport = (major > 1) ||
274 has_gl_extension("GL_OES_stencil_wrap");
275
reed@google.comac10a2d2010-12-22 21:39:39 +0000276#endif
reed@google.comeeeb5a02010-12-23 15:12:59 +0000277 if (gPrintStartupSpew) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000278 GrPrintf("Stencil Caps: TwoSide: %s, Wrap: %s\n",
279 (fTwoSidedStencilSupport ? "YES" : "NO"),
280 (fStencilWrapOpsSupport ? "YES" : "NO"));
reed@google.comeeeb5a02010-12-23 15:12:59 +0000281 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000282
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000283#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000284 fRGBA8Renderbuffer = true;
285#else
286 fRGBA8Renderbuffer = has_gl_extension("GL_OES_rgb8_rgba8");
287#endif
reed@google.comeeeb5a02010-12-23 15:12:59 +0000288 if (gPrintStartupSpew) {
289 GrPrintf("RGBA Renderbuffer: %s\n", (fRGBA8Renderbuffer ? "YES" : "NO"));
290 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000291
bsalomon@google.comed3a0682011-01-18 16:54:04 +0000292#if GR_SUPPORT_GLES
293 if (GR_GL_32BPP_COLOR_FORMAT == GR_BGRA) {
294 GrAssert(has_gl_extension("GL_EXT_texture_format_BGRA8888"));
295 }
296#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000297
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000298#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000299 fBufferLockSupport = true; // we require VBO support and the desktop VBO
300 // extension includes glMapBuffer.
301#else
302 fBufferLockSupport = has_gl_extension("GL_OES_mapbuffer");
303#endif
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000304
reed@google.comeeeb5a02010-12-23 15:12:59 +0000305 if (gPrintStartupSpew) {
306 GrPrintf("Map Buffer: %s\n", (fBufferLockSupport ? "YES" : "NO"));
307 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000308
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000309#if GR_SUPPORT_GLDESKTOP
bsalomon@google.com0748f212011-02-01 22:56:16 +0000310 if (major >= 2 || has_gl_extension("GL_ARB_texture_non_power_of_two")) {
311 fNPOTTextureTileSupport = true;
312 fNPOTTextureSupport = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000313 } else {
bsalomon@google.com0748f212011-02-01 22:56:16 +0000314 fNPOTTextureTileSupport = false;
315 fNPOTTextureSupport = false;
316 }
317#else
318 if (major >= 2) {
319 fNPOTTextureSupport = true;
320 fNPOTTextureTileSupport = has_gl_extension("GL_OES_texture_npot");
321 } else {
322 fNPOTTextureSupport = has_gl_extension("GL_APPLE_texture_2D_limited_npot");
323 fNPOTTextureTileSupport = false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000324 }
325#endif
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000326
reed@google.comac10a2d2010-12-22 21:39:39 +0000327 ////////////////////////////////////////////////////////////////////////////
328 // Experiments to determine limitations that can't be queried. TODO: Make
329 // these a preprocess that generate some compile time constants.
330
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000331 // sanity check to make sure we can at least create an FBO from a POT texture
bsalomon@google.com18908aa2011-02-07 14:51:55 +0000332
twiz@google.com59a190b2011-03-14 21:23:01 +0000333 bool simpleFBOSuccess = fbo_test(128, 128);
bsalomon@google.com0748f212011-02-01 22:56:16 +0000334 if (gPrintStartupSpew) {
335 if (!simpleFBOSuccess) {
336 GrPrintf("FBO Sanity Test: FAILED\n");
337 } else {
338 GrPrintf("FBO Sanity Test: PASSED\n");
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000339 }
340 }
bsalomon@google.com0748f212011-02-01 22:56:16 +0000341 GrAssert(simpleFBOSuccess);
reed@google.comac20fb92011-01-12 17:14:53 +0000342
reed@google.comac10a2d2010-12-22 21:39:39 +0000343 /* Experimentation has found that some GLs that support NPOT textures
344 do not support FBOs with a NPOT texture. They report "unsupported" FBO
345 status. I don't know how to explicitly query for this. Do an
346 experiment. Note they may support NPOT with a renderbuffer but not a
347 texture. Presumably, the implementation bloats the renderbuffer
348 internally to the next POT.
349 */
bsalomon@google.com0748f212011-02-01 22:56:16 +0000350 bool fNPOTRenderTargetSupport = false;
351 if (fNPOTTextureSupport) {
twiz@google.com59a190b2011-03-14 21:23:01 +0000352 fNPOTRenderTargetSupport = fbo_test(200, 200);
bsalomon@google.com0748f212011-02-01 22:56:16 +0000353 }
bsalomon@google.com18908aa2011-02-07 14:51:55 +0000354
bsalomon@google.com0748f212011-02-01 22:56:16 +0000355 if (gPrintStartupSpew) {
356 if (fNPOTTextureSupport) {
357 GrPrintf("NPOT textures supported\n");
358 if (fNPOTTextureTileSupport) {
359 GrPrintf("NPOT texture tiling supported\n");
360 } else {
361 GrPrintf("NPOT texture tiling NOT supported\n");
362 }
363 if (fNPOTRenderTargetSupport) {
364 GrPrintf("NPOT render targets supported\n");
365 } else {
366 GrPrintf("NPOT render targets NOT supported\n");
reed@google.comeeeb5a02010-12-23 15:12:59 +0000367 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000368 } else {
bsalomon@google.com0748f212011-02-01 22:56:16 +0000369 GrPrintf("NPOT textures NOT supported\n");
reed@google.comeeeb5a02010-12-23 15:12:59 +0000370 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000371 }
372
reed@google.comac10a2d2010-12-22 21:39:39 +0000373 /* The iPhone 4 has a restriction that for an FBO with texture color
374 attachment with height <= 8 then the width must be <= height. Here
375 we look for such a limitation.
376 */
377 fMinRenderTargetHeight = GR_INVAL_GLINT;
378 GLint maxRenderSize;
reed@google.comac20fb92011-01-12 17:14:53 +0000379 GR_GL_GetIntegerv(GR_MAX_RENDERBUFFER_SIZE, &maxRenderSize);
reed@google.comac10a2d2010-12-22 21:39:39 +0000380
reed@google.comeeeb5a02010-12-23 15:12:59 +0000381 if (gPrintStartupSpew) {
382 GrPrintf("Small height FBO texture experiments\n");
383 }
bsalomon@google.com0748f212011-02-01 22:56:16 +0000384
385 for (GLuint i = 1; i <= 256; fNPOTRenderTargetSupport ? ++i : i *= 2) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000386 GLuint w = maxRenderSize;
387 GLuint h = i;
twiz@google.com59a190b2011-03-14 21:23:01 +0000388 if (fbo_test(w, h)) {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000389 if (gPrintStartupSpew) {
390 GrPrintf("\t[%d, %d]: PASSED\n", w, h);
391 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000392 fMinRenderTargetHeight = i;
393 break;
394 } else {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000395 if (gPrintStartupSpew) {
396 GrPrintf("\t[%d, %d]: FAILED\n", w, h);
397 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000398 }
399 }
400 GrAssert(GR_INVAL_GLINT != fMinRenderTargetHeight);
401
reed@google.comeeeb5a02010-12-23 15:12:59 +0000402 if (gPrintStartupSpew) {
403 GrPrintf("Small width FBO texture experiments\n");
404 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000405 fMinRenderTargetWidth = GR_MAX_GLUINT;
bsalomon@google.com0748f212011-02-01 22:56:16 +0000406 for (GLuint i = 1; i <= 256; fNPOTRenderTargetSupport ? i *= 2 : ++i) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000407 GLuint w = i;
408 GLuint h = maxRenderSize;
twiz@google.com59a190b2011-03-14 21:23:01 +0000409 if (fbo_test(w, h)) {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000410 if (gPrintStartupSpew) {
411 GrPrintf("\t[%d, %d]: PASSED\n", w, h);
412 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000413 fMinRenderTargetWidth = i;
414 break;
415 } else {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000416 if (gPrintStartupSpew) {
417 GrPrintf("\t[%d, %d]: FAILED\n", w, h);
418 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000419 }
420 }
421 GrAssert(GR_INVAL_GLINT != fMinRenderTargetWidth);
422
reed@google.com02a7e6c2011-01-28 21:21:49 +0000423 GR_GL_GetIntegerv(GL_MAX_TEXTURE_SIZE, &fMaxTextureDimension);
reed@google.comac10a2d2010-12-22 21:39:39 +0000424}
425
426GrGpuGL::~GrGpuGL() {
reed@google.comac10a2d2010-12-22 21:39:39 +0000427}
428
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000429void GrGpuGL::resetContext() {
430 // We detect cases when blending is effectively off
reed@google.comac10a2d2010-12-22 21:39:39 +0000431 fHWBlendDisabled = false;
432 GR_GL(Enable(GL_BLEND));
433
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000434 // we don't use the zb at all
435 GR_GL(Disable(GL_DEPTH_TEST));
436 GR_GL(DepthMask(GL_FALSE));
437
reed@google.comac10a2d2010-12-22 21:39:39 +0000438 GR_GL(Disable(GL_CULL_FACE));
bsalomon@google.comd302f142011-03-03 13:54:13 +0000439 GR_GL(FrontFace(GL_CCW));
440 fHWDrawState.fDrawFace = kBoth_DrawFace;
reed@google.comac10a2d2010-12-22 21:39:39 +0000441
442 GR_GL(Disable(GL_DITHER));
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000443#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000444 GR_GL(Disable(GL_LINE_SMOOTH));
445 GR_GL(Disable(GL_POINT_SMOOTH));
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000446 GR_GL(Disable(GL_MULTISAMPLE));
reed@google.comac10a2d2010-12-22 21:39:39 +0000447#endif
448
bsalomon@google.comd302f142011-03-03 13:54:13 +0000449 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
450 fHWDrawState.fFlagBits = 0;
451
reed@google.comac10a2d2010-12-22 21:39:39 +0000452 // we only ever use lines in hairline mode
453 GR_GL(LineWidth(1));
454
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000455 // invalid
456 fActiveTextureUnitIdx = -1;
reed@google.comac10a2d2010-12-22 21:39:39 +0000457
reed@google.comac10a2d2010-12-22 21:39:39 +0000458 // illegal values
bsalomon@google.comffca4002011-02-22 20:34:01 +0000459 fHWDrawState.fSrcBlend = (GrBlendCoeff)-1;
460 fHWDrawState.fDstBlend = (GrBlendCoeff)-1;
reed@google.comac10a2d2010-12-22 21:39:39 +0000461 fHWDrawState.fColor = GrColor_ILLEGAL;
bsalomon@google.com316f99232011-01-13 21:28:12 +0000462
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000463 fHWDrawState.fViewMatrix = GrMatrix::InvalidMatrix();
bsalomon@google.com316f99232011-01-13 21:28:12 +0000464
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000465 for (int s = 0; s < kNumStages; ++s) {
466 fHWDrawState.fTextures[s] = NULL;
467 fHWDrawState.fSamplerStates[s].setRadial2Params(-GR_ScalarMax,
468 -GR_ScalarMax,
469 true);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000470
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000471 fHWDrawState.fSamplerStates[s].setMatrix(GrMatrix::InvalidMatrix());
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000472 }
bsalomon@google.com316f99232011-01-13 21:28:12 +0000473
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000474 fHWBounds.fScissorRect.invalidate();
reed@google.comac10a2d2010-12-22 21:39:39 +0000475 fHWBounds.fScissorEnabled = false;
476 GR_GL(Disable(GL_SCISSOR_TEST));
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000477 fHWBounds.fViewportRect.invalidate();
reed@google.comac10a2d2010-12-22 21:39:39 +0000478
bsalomon@google.comd302f142011-03-03 13:54:13 +0000479 fHWDrawState.fStencilSettings.invalidate();
reed@google.comac10a2d2010-12-22 21:39:39 +0000480 fHWStencilClip = false;
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000481 fClipState.fClipIsDirty = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000482
483 fHWGeometryState.fIndexBuffer = NULL;
484 fHWGeometryState.fVertexBuffer = NULL;
485 GR_GL(BindBuffer(GL_ARRAY_BUFFER, 0));
486 GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000487 fHWGeometryState.fArrayPtrsDirty = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000488
bsalomon@google.comd302f142011-03-03 13:54:13 +0000489 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
reed@google.comac10a2d2010-12-22 21:39:39 +0000490 fHWDrawState.fRenderTarget = NULL;
491}
492
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000493GrRenderTarget* GrGpuGL::createPlatformRenderTargetHelper(
reed@google.comac10a2d2010-12-22 21:39:39 +0000494 intptr_t platformRenderTarget,
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000495 int stencilBits,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000496 int width,
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000497 int height) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000498 GrGLRenderTarget::GLRenderTargetIDs rtIDs;
499 rtIDs.fStencilRenderbufferID = 0;
500 rtIDs.fMSColorRenderbufferID = 0;
501 rtIDs.fTexFBOID = 0;
502 rtIDs.fOwnIDs = false;
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000503 GrGLIRect viewport;
reed@google.comac10a2d2010-12-22 21:39:39 +0000504
505 // viewport is in GL coords (top >= bottom)
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000506 viewport.fLeft = 0;
507 viewport.fBottom = 0;
508 viewport.fWidth = width;
509 viewport.fHeight = height;
reed@google.comac10a2d2010-12-22 21:39:39 +0000510
511 rtIDs.fRTFBOID = (GLuint)platformRenderTarget;
512 rtIDs.fTexFBOID = (GLuint)platformRenderTarget;
513
bsalomon@google.com1da07462011-03-10 14:51:57 +0000514 return new GrGLRenderTarget(rtIDs, NULL, stencilBits, viewport, NULL, this);
reed@google.comac10a2d2010-12-22 21:39:39 +0000515}
516
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000517GrRenderTarget* GrGpuGL::createRenderTargetFrom3DApiStateHelper() {
bsalomon@google.com42ab7ea2011-01-19 17:19:40 +0000518
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000519 GrGLRenderTarget::GLRenderTargetIDs rtIDs;
bsalomon@google.com42ab7ea2011-01-19 17:19:40 +0000520
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000521 GR_GL_GetIntegerv(GR_FRAMEBUFFER_BINDING, (GLint*)&rtIDs.fRTFBOID);
522 rtIDs.fTexFBOID = rtIDs.fRTFBOID;
523 rtIDs.fMSColorRenderbufferID = 0;
524 rtIDs.fStencilRenderbufferID = 0;
bsalomon@google.com42ab7ea2011-01-19 17:19:40 +0000525
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000526 GrGLIRect viewport;
527 viewport.setFromGLViewport();
528 GLuint stencilBits;
529 GR_GL_GetIntegerv(GL_STENCIL_BITS, (GLint*)&stencilBits);
530
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000531 rtIDs.fOwnIDs = false;
532
bsalomon@google.com1da07462011-03-10 14:51:57 +0000533 return new GrGLRenderTarget(rtIDs, NULL, stencilBits, viewport, NULL, this);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000534}
535
bsalomon@google.com5782d712011-01-21 21:03:59 +0000536///////////////////////////////////////////////////////////////////////////////
537
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000538static const GLuint UNKNOWN_BITS = ~0;
539
bsalomon@google.com3f3ffd62011-01-18 17:14:52 +0000540// defines stencil formats from more to less preferred
bsalomon@google.com5d18c382011-02-18 16:21:58 +0000541static const struct {
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000542 GLenum fEnum;
543 GLuint fBits;
544} gStencilFormats[] = {
545 {GR_STENCIL_INDEX8, 8},
reed@google.com63100f92011-01-18 21:32:14 +0000546
547#if GR_SUPPORT_GLDESKTOP
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000548 {GR_STENCIL_INDEX16, 16},
reed@google.com63100f92011-01-18 21:32:14 +0000549#endif
550
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000551 {GR_DEPTH24_STENCIL8, 8},
552 {GR_STENCIL_INDEX4, 4},
reed@google.com63100f92011-01-18 21:32:14 +0000553
554#if GR_SUPPORT_GLDESKTOP
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000555 {GL_STENCIL_INDEX, UNKNOWN_BITS},
556 {GR_DEPTH_STENCIL, UNKNOWN_BITS}
bsalomon@google.com3f3ffd62011-01-18 17:14:52 +0000557#endif
558};
559
560// good to set a break-point here to know when createTexture fails
561static GrTexture* return_null_texture() {
562// GrAssert(!"null texture");
563 return NULL;
564}
565
566#if GR_DEBUG
567static size_t as_size_t(int x) {
568 return x;
569}
570#endif
571
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000572GrTexture* GrGpuGL::createTextureHelper(const TextureDesc& desc,
573 const void* srcData,
574 size_t rowBytes) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000575
576#if GR_COLLECT_STATS
577 ++fStats.fTextureCreateCnt;
578#endif
reed@google.com1fcd51e2011-01-05 15:50:27 +0000579
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000580 setSpareTextureUnit();
bsalomon@google.com316f99232011-01-13 21:28:12 +0000581
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000582 static const GrGLTexture::TexParams DEFAULT_PARAMS = {
583 GL_NEAREST,
584 GL_CLAMP_TO_EDGE,
585 GL_CLAMP_TO_EDGE
586 };
reed@google.com1fcd51e2011-01-05 15:50:27 +0000587
reed@google.comac10a2d2010-12-22 21:39:39 +0000588 GrGLTexture::GLTextureDesc glDesc;
589 GLenum internalFormat;
590
591 glDesc.fContentWidth = desc.fWidth;
592 glDesc.fContentHeight = desc.fHeight;
593 glDesc.fAllocWidth = desc.fWidth;
594 glDesc.fAllocHeight = desc.fHeight;
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000595 glDesc.fStencilBits = 0;
reed@google.comac10a2d2010-12-22 21:39:39 +0000596 glDesc.fFormat = desc.fFormat;
597
598 bool renderTarget = 0 != (desc.fFlags & kRenderTarget_TextureFlag);
599 if (!canBeTexture(desc.fFormat,
600 &internalFormat,
601 &glDesc.fUploadFormat,
602 &glDesc.fUploadType)) {
603 return return_null_texture();
604 }
605
606 GrAssert(as_size_t(desc.fAALevel) < GR_ARRAY_COUNT(fAASamples));
607 GLint samples = fAASamples[desc.fAALevel];
608 if (kNone_MSFBO == fMSFBOType && desc.fAALevel != kNone_AALevel) {
609 GrPrintf("AA RT requested but not supported on this platform.");
610 }
611
612 GR_GL(GenTextures(1, &glDesc.fTextureID));
613 if (!glDesc.fTextureID) {
614 return return_null_texture();
615 }
616
617 glDesc.fUploadByteCount = GrTexture::BytesPerPixel(desc.fFormat);
618
619 /*
620 * check if our srcData has extra bytes past each row. If so, we need
621 * to trim those off here, since GL doesn't let us pass the rowBytes as
622 * a parameter to glTexImage2D
623 */
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000624#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000625 if (srcData) {
626 GR_GL(PixelStorei(GL_UNPACK_ROW_LENGTH,
627 rowBytes / glDesc.fUploadByteCount));
628 }
629#else
630 GrAutoSMalloc<128 * 128> trimStorage;
631 size_t trimRowBytes = desc.fWidth * glDesc.fUploadByteCount;
632 if (srcData && (trimRowBytes < rowBytes)) {
633 size_t trimSize = desc.fHeight * trimRowBytes;
634 trimStorage.realloc(trimSize);
635 // now copy the data into our new storage, skipping the trailing bytes
636 const char* src = (const char*)srcData;
637 char* dst = (char*)trimStorage.get();
638 for (uint32_t y = 0; y < desc.fHeight; y++) {
639 memcpy(dst, src, trimRowBytes);
640 src += rowBytes;
641 dst += trimRowBytes;
642 }
643 // now point srcData to our trimmed version
644 srcData = trimStorage.get();
645 }
646#endif
647
reed@google.comac10a2d2010-12-22 21:39:39 +0000648 if (renderTarget) {
bsalomon@google.com0748f212011-02-01 22:56:16 +0000649 if (!this->npotRenderTargetSupport()) {
650 glDesc.fAllocWidth = GrNextPow2(desc.fWidth);
651 glDesc.fAllocHeight = GrNextPow2(desc.fHeight);
652 }
653
reed@google.comac10a2d2010-12-22 21:39:39 +0000654 glDesc.fAllocWidth = GrMax<int>(fMinRenderTargetWidth,
655 glDesc.fAllocWidth);
656 glDesc.fAllocHeight = GrMax<int>(fMinRenderTargetHeight,
657 glDesc.fAllocHeight);
bsalomon@google.com0748f212011-02-01 22:56:16 +0000658 } else if (!this->npotTextureSupport()) {
659 glDesc.fAllocWidth = GrNextPow2(desc.fWidth);
660 glDesc.fAllocHeight = GrNextPow2(desc.fHeight);
reed@google.comac10a2d2010-12-22 21:39:39 +0000661 }
662
663 GR_GL(BindTexture(GL_TEXTURE_2D, glDesc.fTextureID));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000664 GR_GL(TexParameteri(GL_TEXTURE_2D,
665 GL_TEXTURE_MAG_FILTER,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000666 DEFAULT_PARAMS.fFilter));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000667 GR_GL(TexParameteri(GL_TEXTURE_2D,
668 GL_TEXTURE_MIN_FILTER,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000669 DEFAULT_PARAMS.fFilter));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000670 GR_GL(TexParameteri(GL_TEXTURE_2D,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000671 GL_TEXTURE_WRAP_S,
672 DEFAULT_PARAMS.fWrapS));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000673 GR_GL(TexParameteri(GL_TEXTURE_2D,
674 GL_TEXTURE_WRAP_T,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000675 DEFAULT_PARAMS.fWrapT));
reed@google.comac10a2d2010-12-22 21:39:39 +0000676
677 GR_GL(PixelStorei(GL_UNPACK_ALIGNMENT, glDesc.fUploadByteCount));
678 if (GrTexture::kIndex_8_PixelConfig == desc.fFormat &&
679 supports8BitPalette()) {
680 // ES only supports CompressedTexImage2D, not CompressedTexSubimage2D
681 GrAssert(desc.fWidth == glDesc.fAllocWidth);
682 GrAssert(desc.fHeight == glDesc.fAllocHeight);
683 GLsizei imageSize = glDesc.fAllocWidth * glDesc.fAllocHeight +
684 kColorTableSize;
685 GR_GL(CompressedTexImage2D(GL_TEXTURE_2D, 0, glDesc.fUploadFormat,
686 glDesc.fAllocWidth, glDesc.fAllocHeight,
687 0, imageSize, srcData));
688 GrGL_RestoreResetRowLength();
689 } else {
690 if (NULL != srcData && (glDesc.fAllocWidth != desc.fWidth ||
691 glDesc.fAllocHeight != desc.fHeight)) {
692 GR_GL(TexImage2D(GL_TEXTURE_2D, 0, internalFormat,
693 glDesc.fAllocWidth, glDesc.fAllocHeight,
694 0, glDesc.fUploadFormat, glDesc.fUploadType, NULL));
695 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, desc.fWidth,
696 desc.fHeight, glDesc.fUploadFormat,
697 glDesc.fUploadType, srcData));
698 GrGL_RestoreResetRowLength();
699
700 uint32_t extraW = glDesc.fAllocWidth - desc.fWidth;
701 uint32_t extraH = glDesc.fAllocHeight - desc.fHeight;
702 uint32_t maxTexels = extraW * extraH;
703 maxTexels = GrMax(extraW * desc.fHeight, maxTexels);
704 maxTexels = GrMax(desc.fWidth * extraH, maxTexels);
705
706 GrAutoSMalloc<128*128> texels(glDesc.fUploadByteCount * maxTexels);
707
708 uint32_t rowSize = desc.fWidth * glDesc.fUploadByteCount;
709 if (extraH) {
710 uint8_t* lastRowStart = (uint8_t*) srcData +
711 (desc.fHeight - 1) * rowSize;
712 uint8_t* extraRowStart = (uint8_t*)texels.get();
713
714 for (uint32_t i = 0; i < extraH; ++i) {
715 memcpy(extraRowStart, lastRowStart, rowSize);
716 extraRowStart += rowSize;
717 }
718 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, 0, desc.fHeight, desc.fWidth,
719 extraH, glDesc.fUploadFormat, glDesc.fUploadType,
720 texels.get()));
721 }
722 if (extraW) {
723 uint8_t* edgeTexel = (uint8_t*)srcData + rowSize - glDesc.fUploadByteCount;
724 uint8_t* extraTexel = (uint8_t*)texels.get();
725 for (uint32_t j = 0; j < desc.fHeight; ++j) {
726 for (uint32_t i = 0; i < extraW; ++i) {
727 memcpy(extraTexel, edgeTexel, glDesc.fUploadByteCount);
728 extraTexel += glDesc.fUploadByteCount;
729 }
730 edgeTexel += rowSize;
731 }
732 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, desc.fWidth, 0, extraW,
733 desc.fHeight, glDesc.fUploadFormat,
734 glDesc.fUploadType, texels.get()));
735 }
736 if (extraW && extraH) {
737 uint8_t* cornerTexel = (uint8_t*)srcData + desc.fHeight * rowSize
738 - glDesc.fUploadByteCount;
739 uint8_t* extraTexel = (uint8_t*)texels.get();
740 for (uint32_t i = 0; i < extraW*extraH; ++i) {
741 memcpy(extraTexel, cornerTexel, glDesc.fUploadByteCount);
742 extraTexel += glDesc.fUploadByteCount;
743 }
744 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, desc.fWidth, desc.fHeight,
745 extraW, extraH, glDesc.fUploadFormat,
746 glDesc.fUploadType, texels.get()));
747 }
748
749 } else {
750 GR_GL(TexImage2D(GL_TEXTURE_2D, 0, internalFormat, glDesc.fAllocWidth,
751 glDesc.fAllocHeight, 0, glDesc.fUploadFormat,
752 glDesc.fUploadType, srcData));
753 GrGL_RestoreResetRowLength();
754 }
755 }
756
757 glDesc.fOrientation = GrGLTexture::kTopDown_Orientation;
758
759 GrGLRenderTarget::GLRenderTargetIDs rtIDs;
760 rtIDs.fStencilRenderbufferID = 0;
761 rtIDs.fMSColorRenderbufferID = 0;
762 rtIDs.fRTFBOID = 0;
763 rtIDs.fTexFBOID = 0;
764 rtIDs.fOwnIDs = true;
765 GLenum msColorRenderbufferFormat = -1;
766
767 if (renderTarget) {
768#if GR_COLLECT_STATS
769 ++fStats.fRenderTargetCreateCnt;
770#endif
771 bool failed = true;
772 GLenum status;
773 GLint err;
774
775 // If need have both RT flag and srcData we have
776 // to invert the data before uploading because FBO
777 // will be rendered bottom up
778 GrAssert(NULL == srcData);
779 glDesc.fOrientation = GrGLTexture::kBottomUp_Orientation;
780
twiz@google.com59a190b2011-03-14 21:23:01 +0000781 GR_GL(GenFramebuffers(1, &rtIDs.fTexFBOID));
reed@google.comac10a2d2010-12-22 21:39:39 +0000782 GrAssert(rtIDs.fTexFBOID);
783
784 // If we are using multisampling and any extension other than the IMG
785 // one we will create two FBOs. We render to one and then resolve to
786 // the texture bound to the other. The IMG extension does an implicit
787 // resolve.
788 if (samples > 1 && kIMG_MSFBO != fMSFBOType && kNone_MSFBO != fMSFBOType) {
twiz@google.com59a190b2011-03-14 21:23:01 +0000789 GR_GL(GenFramebuffers(1, &rtIDs.fRTFBOID));
reed@google.comac10a2d2010-12-22 21:39:39 +0000790 GrAssert(0 != rtIDs.fRTFBOID);
twiz@google.com59a190b2011-03-14 21:23:01 +0000791 GR_GL(GenRenderbuffers(1, &rtIDs.fMSColorRenderbufferID));
reed@google.comac10a2d2010-12-22 21:39:39 +0000792 GrAssert(0 != rtIDs.fMSColorRenderbufferID);
793 if (!fboInternalFormat(desc.fFormat, &msColorRenderbufferFormat)) {
twiz@google.com59a190b2011-03-14 21:23:01 +0000794 GR_GL(DeleteRenderbuffers(1, &rtIDs.fMSColorRenderbufferID));
reed@google.comac10a2d2010-12-22 21:39:39 +0000795 GR_GL(DeleteTextures(1, &glDesc.fTextureID));
twiz@google.com59a190b2011-03-14 21:23:01 +0000796 GR_GL(DeleteFramebuffers(1, &rtIDs.fTexFBOID));
797 GR_GL(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)) {
twiz@google.com59a190b2011-03-14 21:23:01 +0000805 GR_GL(GenRenderbuffers(1, &rtIDs.fStencilRenderbufferID));
reed@google.comac10a2d2010-12-22 21:39:39 +0000806 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) {
twiz@google.com59a190b2011-03-14 21:23:01 +0000818 GR_GL(BindRenderbuffer(GR_RENDERBUFFER,
819 rtIDs.fStencilRenderbufferID));
reed@google.comac10a2d2010-12-22 21:39:39 +0000820 if (samples > 1) {
twiz@google.com59a190b2011-03-14 21:23:01 +0000821 GR_GL_NO_ERR(RenderbufferStorageMultisample(
reed@google.comac10a2d2010-12-22 21:39:39 +0000822 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 {
twiz@google.com59a190b2011-03-14 21:23:01 +0000828 GR_GL_NO_ERR(RenderbufferStorage(GR_RENDERBUFFER,
829 gStencilFormats[i].fEnum,
830 glDesc.fAllocWidth,
831 glDesc.fAllocHeight));
reed@google.comac10a2d2010-12-22 21:39:39 +0000832 }
833 err = glGetError();
834 if (err != GL_NO_ERROR) {
835 continue;
836 }
837 }
838 if (rtIDs.fRTFBOID != rtIDs.fTexFBOID) {
839 GrAssert(samples > 1);
twiz@google.com59a190b2011-03-14 21:23:01 +0000840 GR_GL(BindRenderbuffer(GR_RENDERBUFFER,
841 rtIDs.fMSColorRenderbufferID));
842 GR_GL_NO_ERR(RenderbufferStorageMultisample(
reed@google.comac10a2d2010-12-22 21:39:39 +0000843 GR_RENDERBUFFER,
844 samples,
845 msColorRenderbufferFormat,
846 glDesc.fAllocWidth,
847 glDesc.fAllocHeight));
848 err = glGetError();
849 if (err != GL_NO_ERROR) {
850 continue;
851 }
852 }
twiz@google.com59a190b2011-03-14 21:23:01 +0000853 GR_GL(BindFramebuffer(GR_FRAMEBUFFER, rtIDs.fTexFBOID));
reed@google.comac10a2d2010-12-22 21:39:39 +0000854
855#if GR_COLLECT_STATS
856 ++fStats.fRenderTargetChngCnt;
857#endif
858 if (kIMG_MSFBO == fMSFBOType && samples > 1) {
twiz@google.com59a190b2011-03-14 21:23:01 +0000859 GR_GL(FramebufferTexture2DMultisample(GR_FRAMEBUFFER,
860 GR_COLOR_ATTACHMENT0,
861 GL_TEXTURE_2D,
862 glDesc.fTextureID,
863 0,
864 samples));
reed@google.comac10a2d2010-12-22 21:39:39 +0000865
866 } else {
twiz@google.com59a190b2011-03-14 21:23:01 +0000867 GR_GL(FramebufferTexture2D(GR_FRAMEBUFFER,
868 GR_COLOR_ATTACHMENT0,
869 GL_TEXTURE_2D,
870 glDesc.fTextureID, 0));
reed@google.comac10a2d2010-12-22 21:39:39 +0000871 }
872 if (rtIDs.fRTFBOID != rtIDs.fTexFBOID) {
twiz@google.com59a190b2011-03-14 21:23:01 +0000873 GLenum status = GR_GL(CheckFramebufferStatus(GR_FRAMEBUFFER));
reed@google.comac10a2d2010-12-22 21:39:39 +0000874 if (status != GR_FRAMEBUFFER_COMPLETE) {
875 GrPrintf("-- glCheckFramebufferStatus %x %d %d\n",
876 status, desc.fWidth, desc.fHeight);
877 continue;
878 }
twiz@google.com59a190b2011-03-14 21:23:01 +0000879 GR_GL(BindFramebuffer(GR_FRAMEBUFFER, rtIDs.fRTFBOID));
reed@google.comac10a2d2010-12-22 21:39:39 +0000880 #if GR_COLLECT_STATS
881 ++fStats.fRenderTargetChngCnt;
882 #endif
twiz@google.com59a190b2011-03-14 21:23:01 +0000883 GR_GL(FramebufferRenderbuffer(GR_FRAMEBUFFER,
884 GR_COLOR_ATTACHMENT0,
885 GR_RENDERBUFFER,
886 rtIDs.fMSColorRenderbufferID));
reed@google.comac10a2d2010-12-22 21:39:39 +0000887
888 }
889 if (rtIDs.fStencilRenderbufferID) {
890 // bind the stencil to rt fbo if present, othewise the tex fbo
twiz@google.com59a190b2011-03-14 21:23:01 +0000891 GR_GL(FramebufferRenderbuffer(GR_FRAMEBUFFER,
892 GR_STENCIL_ATTACHMENT,
893 GR_RENDERBUFFER,
894 rtIDs.fStencilRenderbufferID));
reed@google.comac10a2d2010-12-22 21:39:39 +0000895 }
twiz@google.com59a190b2011-03-14 21:23:01 +0000896 status = GR_GL(CheckFramebufferStatus(GR_FRAMEBUFFER));
reed@google.comac10a2d2010-12-22 21:39:39 +0000897
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000898#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000899 // On some implementations you have to be bound as DEPTH_STENCIL.
900 // (Even binding to DEPTH and STENCIL separately with the same
901 // buffer doesn't work.)
902 if (rtIDs.fStencilRenderbufferID &&
903 status != GR_FRAMEBUFFER_COMPLETE) {
twiz@google.com59a190b2011-03-14 21:23:01 +0000904 GR_GL(FramebufferRenderbuffer(GR_FRAMEBUFFER,
905 GR_STENCIL_ATTACHMENT,
906 GR_RENDERBUFFER,
907 0));
908 GR_GL(FramebufferRenderbuffer(GR_FRAMEBUFFER,
909 GR_DEPTH_STENCIL_ATTACHMENT,
910 GR_RENDERBUFFER,
911 rtIDs.fStencilRenderbufferID));
912 status = GR_GL(CheckFramebufferStatus(GR_FRAMEBUFFER));
reed@google.comac10a2d2010-12-22 21:39:39 +0000913 }
914#endif
915 if (status != GR_FRAMEBUFFER_COMPLETE) {
916 GrPrintf("-- glCheckFramebufferStatus %x %d %d\n",
917 status, desc.fWidth, desc.fHeight);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000918#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000919 if (rtIDs.fStencilRenderbufferID) {
twiz@google.com59a190b2011-03-14 21:23:01 +0000920 GR_GL(FramebufferRenderbuffer(GR_FRAMEBUFFER,
921 GR_DEPTH_STENCIL_ATTACHMENT,
922 GR_RENDERBUFFER,
923 0));
reed@google.comac10a2d2010-12-22 21:39:39 +0000924 }
925#endif
926 continue;
927 }
928 // we're successful!
929 failed = false;
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000930 if (rtIDs.fStencilRenderbufferID) {
931 if (UNKNOWN_BITS == gStencilFormats[i].fBits) {
932 GR_GL_GetIntegerv(GL_STENCIL_BITS, (GLint*)&glDesc.fStencilBits);
933 } else {
934 glDesc.fStencilBits = gStencilFormats[i].fBits;
935 }
936 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000937 break;
938 }
939 if (failed) {
940 if (rtIDs.fStencilRenderbufferID) {
twiz@google.com59a190b2011-03-14 21:23:01 +0000941 GR_GL(DeleteRenderbuffers(1, &rtIDs.fStencilRenderbufferID));
reed@google.comac10a2d2010-12-22 21:39:39 +0000942 }
943 if (rtIDs.fMSColorRenderbufferID) {
twiz@google.com59a190b2011-03-14 21:23:01 +0000944 GR_GL(DeleteRenderbuffers(1, &rtIDs.fMSColorRenderbufferID));
reed@google.comac10a2d2010-12-22 21:39:39 +0000945 }
946 if (rtIDs.fRTFBOID != rtIDs.fTexFBOID) {
twiz@google.com59a190b2011-03-14 21:23:01 +0000947 GR_GL(DeleteFramebuffers(1, &rtIDs.fRTFBOID));
reed@google.comac10a2d2010-12-22 21:39:39 +0000948 }
949 if (rtIDs.fTexFBOID) {
twiz@google.com59a190b2011-03-14 21:23:01 +0000950 GR_GL(DeleteFramebuffers(1, &rtIDs.fTexFBOID));
reed@google.comac10a2d2010-12-22 21:39:39 +0000951 }
952 GR_GL(DeleteTextures(1, &glDesc.fTextureID));
953 return return_null_texture();
954 }
955 }
956#ifdef TRACE_TEXTURE_CREATION
957 GrPrintf("--- new texture [%d] size=(%d %d) bpp=%d\n",
958 tex->fTextureID, width, height, tex->fUploadByteCount);
959#endif
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000960 GrGLTexture* tex = new GrGLTexture(glDesc, rtIDs, DEFAULT_PARAMS, this);
reed@google.comac10a2d2010-12-22 21:39:39 +0000961
962 if (0 != rtIDs.fTexFBOID) {
963 GrRenderTarget* rt = tex->asRenderTarget();
964 // We've messed with FBO state but may not have set the correct viewport
965 // so just dirty the rendertarget state to force a resend.
966 fHWDrawState.fRenderTarget = NULL;
967
968 // clear the new stencil buffer if we have one
969 if (!(desc.fFlags & kNoPathRendering_TextureFlag)) {
970 GrRenderTarget* rtSave = fCurrDrawState.fRenderTarget;
971 fCurrDrawState.fRenderTarget = rt;
972 eraseStencil(0, ~0);
973 fCurrDrawState.fRenderTarget = rtSave;
974 }
975 }
976 return tex;
977}
978
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000979GrVertexBuffer* GrGpuGL::createVertexBufferHelper(uint32_t size, bool dynamic) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000980 GLuint id;
981 GR_GL(GenBuffers(1, &id));
982 if (id) {
983 GR_GL(BindBuffer(GL_ARRAY_BUFFER, id));
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000984 fHWGeometryState.fArrayPtrsDirty = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000985 GrGLClearErr();
986 // make sure driver can allocate memory for this buffer
987 GR_GL_NO_ERR(BufferData(GL_ARRAY_BUFFER, size, NULL,
988 dynamic ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW));
989 if (glGetError() != GL_NO_ERROR) {
990 GR_GL(DeleteBuffers(1, &id));
991 // deleting bound buffer does implicit bind to 0
992 fHWGeometryState.fVertexBuffer = NULL;
993 return NULL;
994 }
995 GrGLVertexBuffer* vertexBuffer = new GrGLVertexBuffer(id, this,
996 size, dynamic);
997 fHWGeometryState.fVertexBuffer = vertexBuffer;
998 return vertexBuffer;
999 }
1000 return NULL;
1001}
1002
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001003GrIndexBuffer* GrGpuGL::createIndexBufferHelper(uint32_t size, bool dynamic) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001004 GLuint id;
1005 GR_GL(GenBuffers(1, &id));
1006 if (id) {
1007 GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, id));
1008 GrGLClearErr();
1009 // make sure driver can allocate memory for this buffer
1010 GR_GL_NO_ERR(BufferData(GL_ELEMENT_ARRAY_BUFFER, size, NULL,
1011 dynamic ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW));
1012 if (glGetError() != GL_NO_ERROR) {
1013 GR_GL(DeleteBuffers(1, &id));
1014 // deleting bound buffer does implicit bind to 0
1015 fHWGeometryState.fIndexBuffer = NULL;
1016 return NULL;
1017 }
1018 GrIndexBuffer* indexBuffer = new GrGLIndexBuffer(id, this,
1019 size, dynamic);
1020 fHWGeometryState.fIndexBuffer = indexBuffer;
1021 return indexBuffer;
1022 }
1023 return NULL;
1024}
1025
reed@google.comac10a2d2010-12-22 21:39:39 +00001026void GrGpuGL::flushScissor(const GrIRect* rect) {
1027 GrAssert(NULL != fCurrDrawState.fRenderTarget);
bsalomon@google.com8895a7a2011-02-18 16:09:55 +00001028 const GrGLIRect& vp =
bsalomon@google.comd302f142011-03-03 13:54:13 +00001029 ((GrGLRenderTarget*)fCurrDrawState.fRenderTarget)->getViewport();
reed@google.comac10a2d2010-12-22 21:39:39 +00001030
bsalomon@google.com8895a7a2011-02-18 16:09:55 +00001031 GrGLIRect scissor;
1032 if (NULL != rect) {
bsalomon@google.comd302f142011-03-03 13:54:13 +00001033 scissor.setRelativeTo(vp, rect->fLeft, rect->fTop,
bsalomon@google.com8895a7a2011-02-18 16:09:55 +00001034 rect->width(), rect->height());
1035 if (scissor.contains(vp)) {
1036 rect = NULL;
1037 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001038 }
1039
1040 if (NULL != rect) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001041 if (fHWBounds.fScissorRect != scissor) {
bsalomon@google.com8895a7a2011-02-18 16:09:55 +00001042 scissor.pushToGLScissor();
reed@google.comac10a2d2010-12-22 21:39:39 +00001043 fHWBounds.fScissorRect = scissor;
1044 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001045 if (!fHWBounds.fScissorEnabled) {
1046 GR_GL(Enable(GL_SCISSOR_TEST));
1047 fHWBounds.fScissorEnabled = true;
1048 }
1049 } else {
1050 if (fHWBounds.fScissorEnabled) {
1051 GR_GL(Disable(GL_SCISSOR_TEST));
1052 fHWBounds.fScissorEnabled = false;
1053 }
1054 }
1055}
1056
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001057void GrGpuGL::eraseColorHelper(GrColor color) {
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +00001058 if (NULL == fCurrDrawState.fRenderTarget) {
1059 return;
1060 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001061 flushRenderTarget();
1062 if (fHWBounds.fScissorEnabled) {
1063 GR_GL(Disable(GL_SCISSOR_TEST));
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +00001064 fHWBounds.fScissorEnabled = false;
reed@google.comac10a2d2010-12-22 21:39:39 +00001065 }
1066 GR_GL(ColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE));
bsalomon@google.comd302f142011-03-03 13:54:13 +00001067 fHWDrawState.fFlagBits &= ~kNoColorWrites_StateBit;
reed@google.comac10a2d2010-12-22 21:39:39 +00001068 GR_GL(ClearColor(GrColorUnpackR(color)/255.f,
1069 GrColorUnpackG(color)/255.f,
1070 GrColorUnpackB(color)/255.f,
1071 GrColorUnpackA(color)/255.f));
1072 GR_GL(Clear(GL_COLOR_BUFFER_BIT));
reed@google.comac10a2d2010-12-22 21:39:39 +00001073}
1074
1075void GrGpuGL::eraseStencil(uint32_t value, uint32_t mask) {
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +00001076 if (NULL == fCurrDrawState.fRenderTarget) {
1077 return;
1078 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001079 flushRenderTarget();
1080 if (fHWBounds.fScissorEnabled) {
1081 GR_GL(Disable(GL_SCISSOR_TEST));
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +00001082 fHWBounds.fScissorEnabled = false;
reed@google.comac10a2d2010-12-22 21:39:39 +00001083 }
1084 GR_GL(StencilMask(mask));
1085 GR_GL(ClearStencil(value));
1086 GR_GL(Clear(GL_STENCIL_BUFFER_BIT));
bsalomon@google.comd302f142011-03-03 13:54:13 +00001087 fHWDrawState.fStencilSettings.invalidate();
reed@google.comac10a2d2010-12-22 21:39:39 +00001088}
1089
bsalomon@google.comd302f142011-03-03 13:54:13 +00001090void GrGpuGL::eraseStencilClip(const GrIRect& rect) {
bsalomon@google.com8895a7a2011-02-18 16:09:55 +00001091 GrAssert(NULL != fCurrDrawState.fRenderTarget);
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +00001092#if 0
bsalomon@google.comd302f142011-03-03 13:54:13 +00001093 GLint stencilBitCount = fCurrDrawState.fRenderTarget->stencilBits();
reed@google.comac10a2d2010-12-22 21:39:39 +00001094 GrAssert(stencilBitCount > 0);
1095 GLint clipStencilMask = (1 << (stencilBitCount - 1));
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +00001096#else
1097 // we could just clear the clip bit but when we go through
1098 // angle a partial stencil mask will cause clears to be
1099 // turned into draws. Our contract on GrDrawTarget says that
1100 // changing the clip between stencil passes may or may not
1101 // zero the client's clip bits. So we just clear the whole thing.
1102 static const GLint clipStencilMask = ~0;
1103#endif
bsalomon@google.comd302f142011-03-03 13:54:13 +00001104 flushRenderTarget();
1105 flushScissor(&rect);
1106 GR_GL(StencilMask(clipStencilMask));
1107 GR_GL(ClearStencil(0));
1108 GR_GL(Clear(GL_STENCIL_BUFFER_BIT));
1109 fHWDrawState.fStencilSettings.invalidate();
reed@google.comac10a2d2010-12-22 21:39:39 +00001110}
1111
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001112void GrGpuGL::forceRenderTargetFlushHelper() {
reed@google.comac10a2d2010-12-22 21:39:39 +00001113 flushRenderTarget();
1114}
1115
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001116bool GrGpuGL::readPixelsHelper(int left, int top, int width, int height,
1117 GrTexture::PixelConfig config, void* buffer) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001118 GLenum internalFormat; // we don't use this for glReadPixels
1119 GLenum format;
1120 GLenum type;
1121 if (!this->canBeTexture(config, &internalFormat, &format, &type)) {
1122 return false;
1123 }
1124
bsalomon@google.com18908aa2011-02-07 14:51:55 +00001125 if (NULL == fCurrDrawState.fRenderTarget) {
1126 return false;
1127 }
1128 flushRenderTarget();
1129
bsalomon@google.comd302f142011-03-03 13:54:13 +00001130 const GrGLIRect& glvp = ((GrGLRenderTarget*)fCurrDrawState.fRenderTarget)->getViewport();
1131
bsalomon@google.com8895a7a2011-02-18 16:09:55 +00001132 // the read rect is viewport-relative
1133 GrGLIRect readRect;
1134 readRect.setRelativeTo(glvp, left, top, width, height);
1135 GR_GL(ReadPixels(readRect.fLeft, readRect.fBottom,
bsalomon@google.comd302f142011-03-03 13:54:13 +00001136 readRect.fWidth, readRect.fHeight,
bsalomon@google.com316f99232011-01-13 21:28:12 +00001137 format, type, buffer));
reed@google.comac10a2d2010-12-22 21:39:39 +00001138
1139 // now reverse the order of the rows, since GL's are bottom-to-top, but our
1140 // API presents top-to-bottom
1141 {
1142 size_t stride = width * GrTexture::BytesPerPixel(config);
1143 GrAutoMalloc rowStorage(stride);
1144 void* tmp = rowStorage.get();
1145
1146 const int halfY = height >> 1;
1147 char* top = reinterpret_cast<char*>(buffer);
1148 char* bottom = top + (height - 1) * stride;
1149 for (int y = 0; y < halfY; y++) {
1150 memcpy(tmp, top, stride);
1151 memcpy(top, bottom, stride);
1152 memcpy(bottom, tmp, stride);
1153 top += stride;
1154 bottom -= stride;
1155 }
1156 }
1157 return true;
1158}
1159
1160void GrGpuGL::flushRenderTarget() {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001161
1162 GrAssert(NULL != fCurrDrawState.fRenderTarget);
1163
reed@google.comac10a2d2010-12-22 21:39:39 +00001164 if (fHWDrawState.fRenderTarget != fCurrDrawState.fRenderTarget) {
1165 GrGLRenderTarget* rt = (GrGLRenderTarget*)fCurrDrawState.fRenderTarget;
twiz@google.com59a190b2011-03-14 21:23:01 +00001166 GR_GL(BindFramebuffer(GR_FRAMEBUFFER, rt->renderFBOID()));
reed@google.comac10a2d2010-12-22 21:39:39 +00001167 #if GR_COLLECT_STATS
1168 ++fStats.fRenderTargetChngCnt;
1169 #endif
1170 rt->setDirty(true);
1171 #if GR_DEBUG
twiz@google.com59a190b2011-03-14 21:23:01 +00001172 GLenum status = GR_GL(CheckFramebufferStatus(GR_FRAMEBUFFER));
reed@google.comac10a2d2010-12-22 21:39:39 +00001173 if (status != GR_FRAMEBUFFER_COMPLETE) {
1174 GrPrintf("-- glCheckFramebufferStatus %x\n", status);
1175 }
1176 #endif
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001177 fDirtyFlags.fRenderTargetChanged = true;
bsalomon@google.com8895a7a2011-02-18 16:09:55 +00001178 fHWDrawState.fRenderTarget = fCurrDrawState.fRenderTarget;
bsalomon@google.comd302f142011-03-03 13:54:13 +00001179 const GrGLIRect& vp = rt->getViewport();
bsalomon@google.com649a8622011-03-10 14:53:38 +00001180 if (fHWBounds.fViewportRect != vp) {
bsalomon@google.com8895a7a2011-02-18 16:09:55 +00001181 vp.pushToGLViewport();
reed@google.comac10a2d2010-12-22 21:39:39 +00001182 fHWBounds.fViewportRect = vp;
1183 }
1184 }
1185}
1186
1187GLenum gPrimitiveType2GLMode[] = {
1188 GL_TRIANGLES,
1189 GL_TRIANGLE_STRIP,
1190 GL_TRIANGLE_FAN,
1191 GL_POINTS,
1192 GL_LINES,
1193 GL_LINE_STRIP
1194};
1195
bsalomon@google.comd302f142011-03-03 13:54:13 +00001196#define SWAP_PER_DRAW 0
1197
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001198#if SWAP_PER_DRAW
bsalomon@google.comd302f142011-03-03 13:54:13 +00001199 #if GR_MAC_BUILD
1200 #include <AGL/agl.h>
1201 #elif GR_WIN32_BUILD
1202 void SwapBuf() {
1203 DWORD procID = GetCurrentProcessId();
1204 HWND hwnd = GetTopWindow(GetDesktopWindow());
1205 while(hwnd) {
1206 DWORD wndProcID = 0;
1207 GetWindowThreadProcessId(hwnd, &wndProcID);
1208 if(wndProcID == procID) {
1209 SwapBuffers(GetDC(hwnd));
1210 }
1211 hwnd = GetNextWindow(hwnd, GW_HWNDNEXT);
1212 }
1213 }
1214 #endif
1215#endif
1216
bsalomon@google.comffca4002011-02-22 20:34:01 +00001217void GrGpuGL::drawIndexedHelper(GrPrimitiveType type,
reed@google.comac10a2d2010-12-22 21:39:39 +00001218 uint32_t startVertex,
1219 uint32_t startIndex,
1220 uint32_t vertexCount,
1221 uint32_t indexCount) {
1222 GrAssert((size_t)type < GR_ARRAY_COUNT(gPrimitiveType2GLMode));
1223
1224 GLvoid* indices = (GLvoid*)(sizeof(uint16_t) * startIndex);
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001225
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001226 GrAssert(NULL != fHWGeometryState.fIndexBuffer);
1227 GrAssert(NULL != fHWGeometryState.fVertexBuffer);
1228
1229 // our setupGeometry better have adjusted this to zero since
1230 // DrawElements always draws from the begining of the arrays for idx 0.
1231 GrAssert(0 == startVertex);
reed@google.comac10a2d2010-12-22 21:39:39 +00001232
1233 GR_GL(DrawElements(gPrimitiveType2GLMode[type], indexCount,
1234 GL_UNSIGNED_SHORT, indices));
bsalomon@google.comd302f142011-03-03 13:54:13 +00001235#if SWAP_PER_DRAW
1236 glFlush();
1237 #if GR_MAC_BUILD
1238 aglSwapBuffers(aglGetCurrentContext());
1239 int set_a_break_pt_here = 9;
1240 aglSwapBuffers(aglGetCurrentContext());
1241 #elif GR_WIN32_BUILD
1242 SwapBuf();
1243 int set_a_break_pt_here = 9;
1244 SwapBuf();
1245 #endif
1246#endif
reed@google.comac10a2d2010-12-22 21:39:39 +00001247}
1248
bsalomon@google.comffca4002011-02-22 20:34:01 +00001249void GrGpuGL::drawNonIndexedHelper(GrPrimitiveType type,
reed@google.comac10a2d2010-12-22 21:39:39 +00001250 uint32_t startVertex,
1251 uint32_t vertexCount) {
1252 GrAssert((size_t)type < GR_ARRAY_COUNT(gPrimitiveType2GLMode));
1253
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001254 GrAssert(NULL != fHWGeometryState.fVertexBuffer);
1255
1256 // our setupGeometry better have adjusted this to zero.
1257 // DrawElements doesn't take an offset so we always adjus the startVertex.
1258 GrAssert(0 == startVertex);
1259
1260 // pass 0 for parameter first. We have to adjust gl*Pointer() to
1261 // account for startVertex in the DrawElements case. So we always
1262 // rely on setupGeometry to have accounted for startVertex.
reed@google.comac10a2d2010-12-22 21:39:39 +00001263 GR_GL(DrawArrays(gPrimitiveType2GLMode[type], 0, vertexCount));
bsalomon@google.comd302f142011-03-03 13:54:13 +00001264#if SWAP_PER_DRAW
1265 glFlush();
1266 #if GR_MAC_BUILD
1267 aglSwapBuffers(aglGetCurrentContext());
1268 int set_a_break_pt_here = 9;
1269 aglSwapBuffers(aglGetCurrentContext());
1270 #elif GR_WIN32_BUILD
1271 SwapBuf();
1272 int set_a_break_pt_here = 9;
1273 SwapBuf();
1274 #endif
1275#endif
reed@google.comac10a2d2010-12-22 21:39:39 +00001276}
1277
reed@google.comac10a2d2010-12-22 21:39:39 +00001278void GrGpuGL::resolveTextureRenderTarget(GrGLTexture* texture) {
1279 GrGLRenderTarget* rt = (GrGLRenderTarget*) texture->asRenderTarget();
1280
1281 if (NULL != rt && rt->needsResolve()) {
1282 GrAssert(kNone_MSFBO != fMSFBOType);
1283 GrAssert(rt->textureFBOID() != rt->renderFBOID());
twiz@google.com59a190b2011-03-14 21:23:01 +00001284 GR_GL(BindFramebuffer(GR_READ_FRAMEBUFFER,
reed@google.comac10a2d2010-12-22 21:39:39 +00001285 rt->renderFBOID()));
twiz@google.com59a190b2011-03-14 21:23:01 +00001286 GR_GL(BindFramebuffer(GR_DRAW_FRAMEBUFFER,
reed@google.comac10a2d2010-12-22 21:39:39 +00001287 rt->textureFBOID()));
1288 #if GR_COLLECT_STATS
1289 ++fStats.fRenderTargetChngCnt;
1290 #endif
1291 // make sure we go through set render target
1292 fHWDrawState.fRenderTarget = NULL;
1293
1294 GLint left = 0;
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001295 GLint right = texture->width();
reed@google.comac10a2d2010-12-22 21:39:39 +00001296 // we will have rendered to the top of the FBO.
1297 GLint top = texture->allocHeight();
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001298 GLint bottom = texture->allocHeight() - texture->height();
reed@google.comac10a2d2010-12-22 21:39:39 +00001299 if (kApple_MSFBO == fMSFBOType) {
1300 GR_GL(Enable(GL_SCISSOR_TEST));
1301 GR_GL(Scissor(left, bottom, right-left, top-bottom));
twiz@google.com59a190b2011-03-14 21:23:01 +00001302 GR_GL(ResolveMultisampleFramebuffer());
bsalomon@google.com8895a7a2011-02-18 16:09:55 +00001303 fHWBounds.fScissorRect.invalidate();
reed@google.comac10a2d2010-12-22 21:39:39 +00001304 fHWBounds.fScissorEnabled = true;
1305 } else {
twiz@google.com59a190b2011-03-14 21:23:01 +00001306 GR_GL(BlitFramebuffer(left, bottom, right, top,
reed@google.comac10a2d2010-12-22 21:39:39 +00001307 left, bottom, right, top,
1308 GL_COLOR_BUFFER_BIT, GL_NEAREST));
1309 }
1310 rt->setDirty(false);
1311
1312 }
1313}
1314
bsalomon@google.comd302f142011-03-03 13:54:13 +00001315static const GLenum grToGLStencilFunc[] = {
1316 GL_ALWAYS, // kAlways_StencilFunc
1317 GL_NEVER, // kNever_StencilFunc
1318 GL_GREATER, // kGreater_StencilFunc
1319 GL_GEQUAL, // kGEqual_StencilFunc
1320 GL_LESS, // kLess_StencilFunc
1321 GL_LEQUAL, // kLEqual_StencilFunc,
1322 GL_EQUAL, // kEqual_StencilFunc,
1323 GL_NOTEQUAL, // kNotEqual_StencilFunc,
1324};
1325GR_STATIC_ASSERT(GR_ARRAY_COUNT(grToGLStencilFunc) == kBasicStencilFuncCount);
1326GR_STATIC_ASSERT(0 == kAlways_StencilFunc);
1327GR_STATIC_ASSERT(1 == kNever_StencilFunc);
1328GR_STATIC_ASSERT(2 == kGreater_StencilFunc);
1329GR_STATIC_ASSERT(3 == kGEqual_StencilFunc);
1330GR_STATIC_ASSERT(4 == kLess_StencilFunc);
1331GR_STATIC_ASSERT(5 == kLEqual_StencilFunc);
1332GR_STATIC_ASSERT(6 == kEqual_StencilFunc);
1333GR_STATIC_ASSERT(7 == kNotEqual_StencilFunc);
1334
1335static const GLenum grToGLStencilOp[] = {
1336 GL_KEEP, // kKeep_StencilOp
1337 GL_REPLACE, // kReplace_StencilOp
1338 GL_INCR_WRAP, // kIncWrap_StencilOp
1339 GL_INCR, // kIncClamp_StencilOp
1340 GL_DECR_WRAP, // kDecWrap_StencilOp
1341 GL_DECR, // kDecClamp_StencilOp
1342 GL_ZERO, // kZero_StencilOp
1343 GL_INVERT, // kInvert_StencilOp
1344};
1345GR_STATIC_ASSERT(GR_ARRAY_COUNT(grToGLStencilOp) == kStencilOpCount);
1346GR_STATIC_ASSERT(0 == kKeep_StencilOp);
1347GR_STATIC_ASSERT(1 == kReplace_StencilOp);
1348GR_STATIC_ASSERT(2 == kIncWrap_StencilOp);
1349GR_STATIC_ASSERT(3 == kIncClamp_StencilOp);
1350GR_STATIC_ASSERT(4 == kDecWrap_StencilOp);
1351GR_STATIC_ASSERT(5 == kDecClamp_StencilOp);
1352GR_STATIC_ASSERT(6 == kZero_StencilOp);
1353GR_STATIC_ASSERT(7 == kInvert_StencilOp);
1354
reed@google.comac10a2d2010-12-22 21:39:39 +00001355void GrGpuGL::flushStencil() {
bsalomon@google.comd302f142011-03-03 13:54:13 +00001356 const GrStencilSettings* settings = &fCurrDrawState.fStencilSettings;
reed@google.comac10a2d2010-12-22 21:39:39 +00001357
1358 // use stencil for clipping if clipping is enabled and the clip
1359 // has been written into the stencil.
1360 bool stencilClip = fClipState.fClipInStencil &&
1361 (kClip_StateBit & fCurrDrawState.fFlagBits);
bsalomon@google.comd302f142011-03-03 13:54:13 +00001362 bool stencilChange = fHWStencilClip != stencilClip ||
1363 fHWDrawState.fStencilSettings != *settings ||
1364 ((fHWDrawState.fFlagBits & kModifyStencilClip_StateBit) !=
1365 (fCurrDrawState.fFlagBits & kModifyStencilClip_StateBit));
reed@google.comac10a2d2010-12-22 21:39:39 +00001366
1367 if (stencilChange) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001368
bsalomon@google.comd302f142011-03-03 13:54:13 +00001369 // we can't simultaneously perform stencil-clipping and modify the stencil clip
1370 GrAssert(!stencilClip || !(fCurrDrawState.fFlagBits & kModifyStencilClip_StateBit));
reed@google.comac10a2d2010-12-22 21:39:39 +00001371
bsalomon@google.comd302f142011-03-03 13:54:13 +00001372 if (settings->isDisabled()) {
1373 if (stencilClip) {
1374 settings = &gClipStencilSettings;
1375 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001376 }
bsalomon@google.comd302f142011-03-03 13:54:13 +00001377
1378 if (settings->isDisabled()) {
1379 GR_GL(Disable(GL_STENCIL_TEST));
1380 } else {
1381 GR_GL(Enable(GL_STENCIL_TEST));
1382 #if GR_DEBUG
1383 if (!fStencilWrapOpsSupport) {
1384 GrAssert(settings->fFrontPassOp != kIncWrap_StencilOp);
1385 GrAssert(settings->fFrontPassOp != kDecWrap_StencilOp);
1386 GrAssert(settings->fFrontFailOp != kIncWrap_StencilOp);
1387 GrAssert(settings->fBackFailOp != kDecWrap_StencilOp);
1388 GrAssert(settings->fBackPassOp != kIncWrap_StencilOp);
1389 GrAssert(settings->fBackPassOp != kDecWrap_StencilOp);
1390 GrAssert(settings->fBackFailOp != kIncWrap_StencilOp);
1391 GrAssert(settings->fFrontFailOp != kDecWrap_StencilOp);
1392 }
1393 #endif
1394 int stencilBits = fCurrDrawState.fRenderTarget->stencilBits();
1395 GrAssert(stencilBits ||
1396 (GrStencilSettings::gDisabled ==
1397 fCurrDrawState.fStencilSettings));
1398 GLuint clipStencilMask = 1 << (stencilBits - 1);
1399 GLuint userStencilMask = clipStencilMask - 1;
1400
1401 unsigned int frontRef = settings->fFrontFuncRef;
1402 unsigned int frontMask = settings->fFrontFuncMask;
1403 unsigned int frontWriteMask = settings->fFrontWriteMask;
1404 GLenum frontFunc;
1405
1406 if (fCurrDrawState.fFlagBits & kModifyStencilClip_StateBit) {
1407
1408 GrAssert(settings->fFrontFunc < kBasicStencilFuncCount);
1409 frontFunc = grToGLStencilFunc[settings->fFrontFunc];
1410 } else {
1411 frontFunc = grToGLStencilFunc[ConvertStencilFunc(stencilClip, settings->fFrontFunc)];
1412
1413 ConvertStencilFuncAndMask(settings->fFrontFunc,
1414 stencilClip,
1415 clipStencilMask,
1416 userStencilMask,
1417 &frontRef,
1418 &frontMask);
1419 frontWriteMask &= userStencilMask;
1420 }
1421 GrAssert(settings->fFrontFailOp >= 0 &&
1422 settings->fFrontFailOp < GR_ARRAY_COUNT(grToGLStencilOp));
1423 GrAssert(settings->fFrontPassOp >= 0 &&
1424 settings->fFrontPassOp < GR_ARRAY_COUNT(grToGLStencilOp));
1425 GrAssert(settings->fBackFailOp >= 0 &&
1426 settings->fBackFailOp < GR_ARRAY_COUNT(grToGLStencilOp));
1427 GrAssert(settings->fBackPassOp >= 0 &&
1428 settings->fBackPassOp < GR_ARRAY_COUNT(grToGLStencilOp));
1429 if (fTwoSidedStencilSupport) {
1430 GLenum backFunc;
1431
1432 unsigned int backRef = settings->fBackFuncRef;
1433 unsigned int backMask = settings->fBackFuncMask;
1434 unsigned int backWriteMask = settings->fBackWriteMask;
1435
1436
1437 if (fCurrDrawState.fFlagBits & kModifyStencilClip_StateBit) {
1438 GrAssert(settings->fBackFunc < kBasicStencilFuncCount);
1439 backFunc = grToGLStencilFunc[settings->fBackFunc];
1440 } else {
1441 backFunc = grToGLStencilFunc[ConvertStencilFunc(stencilClip, settings->fBackFunc)];
1442 ConvertStencilFuncAndMask(settings->fBackFunc,
1443 stencilClip,
1444 clipStencilMask,
1445 userStencilMask,
1446 &backRef,
1447 &backMask);
1448 backWriteMask &= userStencilMask;
1449 }
1450
1451 GR_GL(StencilFuncSeparate(GL_FRONT, frontFunc, frontRef, frontMask));
1452 GR_GL(StencilMaskSeparate(GL_FRONT, frontWriteMask));
1453 GR_GL(StencilFuncSeparate(GL_BACK, backFunc, backRef, backMask));
1454 GR_GL(StencilMaskSeparate(GL_BACK, backWriteMask));
1455 GR_GL(StencilOpSeparate(GL_FRONT, grToGLStencilOp[settings->fFrontFailOp],
1456 grToGLStencilOp[settings->fFrontPassOp],
1457 grToGLStencilOp[settings->fFrontPassOp]));
1458
1459 GR_GL(StencilOpSeparate(GL_BACK, grToGLStencilOp[settings->fBackFailOp],
1460 grToGLStencilOp[settings->fBackPassOp],
1461 grToGLStencilOp[settings->fBackPassOp]));
1462 } else {
1463 GR_GL(StencilFunc(frontFunc, frontRef, frontMask));
1464 GR_GL(StencilMask(frontWriteMask));
1465 GR_GL(StencilOp(grToGLStencilOp[settings->fFrontFailOp],
1466 grToGLStencilOp[settings->fFrontPassOp],
1467 grToGLStencilOp[settings->fFrontPassOp]));
1468 }
1469 }
1470 fHWDrawState.fStencilSettings = fCurrDrawState.fStencilSettings;
reed@google.comac10a2d2010-12-22 21:39:39 +00001471 fHWStencilClip = stencilClip;
1472 }
1473}
1474
bsalomon@google.comffca4002011-02-22 20:34:01 +00001475bool GrGpuGL::flushGLStateCommon(GrPrimitiveType type) {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001476
1477 // GrGpu::setupClipAndFlushState should have already checked this
1478 // and bailed if not true.
1479 GrAssert(NULL != fCurrDrawState.fRenderTarget);
reed@google.comac10a2d2010-12-22 21:39:39 +00001480
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001481 for (int s = 0; s < kNumStages; ++s) {
1482 bool usingTexture = VertexUsesStage(s, fGeometrySrc.fVertexLayout);
reed@google.comac10a2d2010-12-22 21:39:39 +00001483
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001484 // bind texture and set sampler state
1485 if (usingTexture) {
1486 GrGLTexture* nextTexture = (GrGLTexture*)fCurrDrawState.fTextures[s];
reed@google.comac10a2d2010-12-22 21:39:39 +00001487
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001488 if (NULL != nextTexture) {
bsalomon@google.com316f99232011-01-13 21:28:12 +00001489 // if we created a rt/tex and rendered to it without using a
1490 // texture and now we're texuring from the rt it will still be
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001491 // the last bound texture, but it needs resolving. So keep this
1492 // out of the "last != next" check.
1493 resolveTextureRenderTarget(nextTexture);
reed@google.comac10a2d2010-12-22 21:39:39 +00001494
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001495 if (fHWDrawState.fTextures[s] != nextTexture) {
1496 setTextureUnit(s);
1497 GR_GL(BindTexture(GL_TEXTURE_2D, nextTexture->textureID()));
1498 #if GR_COLLECT_STATS
1499 ++fStats.fTextureChngCnt;
1500 #endif
1501 //GrPrintf("---- bindtexture %d\n", nextTexture->textureID());
1502 fHWDrawState.fTextures[s] = nextTexture;
1503 }
bsalomon@google.com316f99232011-01-13 21:28:12 +00001504
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001505 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
bsalomon@google.com316f99232011-01-13 21:28:12 +00001506 const GrGLTexture::TexParams& oldTexParams =
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001507 nextTexture->getTexParams();
1508 GrGLTexture::TexParams newTexParams;
bsalomon@google.com316f99232011-01-13 21:28:12 +00001509
1510 newTexParams.fFilter = sampler.isFilter() ? GL_LINEAR :
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001511 GL_NEAREST;
bsalomon@google.com316f99232011-01-13 21:28:12 +00001512 newTexParams.fWrapS =
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001513 GrGLTexture::gWrapMode2GLWrap[sampler.getWrapX()];
bsalomon@google.com316f99232011-01-13 21:28:12 +00001514 newTexParams.fWrapT =
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001515 GrGLTexture::gWrapMode2GLWrap[sampler.getWrapY()];
reed@google.comac10a2d2010-12-22 21:39:39 +00001516
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001517 if (newTexParams.fFilter != oldTexParams.fFilter) {
1518 setTextureUnit(s);
bsalomon@google.com316f99232011-01-13 21:28:12 +00001519 GR_GL(TexParameteri(GL_TEXTURE_2D,
1520 GL_TEXTURE_MAG_FILTER,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001521 newTexParams.fFilter));
bsalomon@google.com316f99232011-01-13 21:28:12 +00001522 GR_GL(TexParameteri(GL_TEXTURE_2D,
1523 GL_TEXTURE_MIN_FILTER,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001524 newTexParams.fFilter));
1525 }
1526 if (newTexParams.fWrapS != oldTexParams.fWrapS) {
1527 setTextureUnit(s);
bsalomon@google.com316f99232011-01-13 21:28:12 +00001528 GR_GL(TexParameteri(GL_TEXTURE_2D,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001529 GL_TEXTURE_WRAP_S,
1530 newTexParams.fWrapS));
1531 }
1532 if (newTexParams.fWrapT != oldTexParams.fWrapT) {
1533 setTextureUnit(s);
bsalomon@google.com316f99232011-01-13 21:28:12 +00001534 GR_GL(TexParameteri(GL_TEXTURE_2D,
1535 GL_TEXTURE_WRAP_T,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001536 newTexParams.fWrapT));
1537 }
1538 nextTexture->setTexParams(newTexParams);
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001539
1540 // The texture matrix has to compensate for texture width/height
1541 // and NPOT-embedded-in-POT
1542 fDirtyFlags.fTextureChangedMask |= (1 << s);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001543 } else {
1544 GrAssert(!"Rendering with texture vert flag set but no texture");
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001545 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +00001546 }
1547 }
1548 }
1549
1550 flushRenderTarget();
1551
1552 if ((fCurrDrawState.fFlagBits & kDither_StateBit) !=
1553 (fHWDrawState.fFlagBits & kDither_StateBit)) {
1554 if (fCurrDrawState.fFlagBits & kDither_StateBit) {
1555 GR_GL(Enable(GL_DITHER));
1556 } else {
1557 GR_GL(Disable(GL_DITHER));
1558 }
1559 }
1560
bsalomon@google.comd302f142011-03-03 13:54:13 +00001561 if ((fCurrDrawState.fFlagBits & kNoColorWrites_StateBit) !=
1562 (fHWDrawState.fFlagBits & kNoColorWrites_StateBit)) {
1563 GLenum mask;
1564 if (fCurrDrawState.fFlagBits & kNoColorWrites_StateBit) {
1565 mask = GL_FALSE;
1566 } else {
1567 mask = GL_TRUE;
1568 }
1569 GR_GL(ColorMask(mask, mask, mask, mask));
1570 }
1571
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001572#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +00001573 // ES doesn't support toggling GL_MULTISAMPLE and doesn't have
1574 // smooth lines.
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001575 if (fDirtyFlags.fRenderTargetChanged ||
reed@google.comac10a2d2010-12-22 21:39:39 +00001576 (fCurrDrawState.fFlagBits & kAntialias_StateBit) !=
1577 (fHWDrawState.fFlagBits & kAntialias_StateBit)) {
1578 GLint msaa = 0;
1579 // only perform query if we know MSAA is supported.
1580 // calling on non-MSAA target caused a crash in one environment,
1581 // though I don't think it should.
reed@google.coma09368c2011-02-24 21:42:29 +00001582 if (fAASamples[kHigh_AALevel]) {
reed@google.comac20fb92011-01-12 17:14:53 +00001583 GR_GL_GetIntegerv(GL_SAMPLE_BUFFERS, &msaa);
reed@google.comac10a2d2010-12-22 21:39:39 +00001584 }
1585 if (fCurrDrawState.fFlagBits & kAntialias_StateBit) {
1586 if (msaa) {
1587 GR_GL(Enable(GL_MULTISAMPLE));
1588 } else {
1589 GR_GL(Enable(GL_LINE_SMOOTH));
1590 }
1591 } else {
1592 if (msaa) {
1593 GR_GL(Disable(GL_MULTISAMPLE));
1594 }
1595 GR_GL(Disable(GL_LINE_SMOOTH));
1596 }
1597 }
1598#endif
1599
1600 bool blendOff = canDisableBlend();
1601 if (fHWBlendDisabled != blendOff) {
1602 if (blendOff) {
1603 GR_GL(Disable(GL_BLEND));
1604 } else {
1605 GR_GL(Enable(GL_BLEND));
1606 }
1607 fHWBlendDisabled = blendOff;
1608 }
1609
1610 if (!blendOff) {
1611 if (fHWDrawState.fSrcBlend != fCurrDrawState.fSrcBlend ||
1612 fHWDrawState.fDstBlend != fCurrDrawState.fDstBlend) {
1613 GR_GL(BlendFunc(gXfermodeCoeff2Blend[fCurrDrawState.fSrcBlend],
1614 gXfermodeCoeff2Blend[fCurrDrawState.fDstBlend]));
1615 fHWDrawState.fSrcBlend = fCurrDrawState.fSrcBlend;
1616 fHWDrawState.fDstBlend = fCurrDrawState.fDstBlend;
1617 }
1618 }
bsalomon@google.com316f99232011-01-13 21:28:12 +00001619
bsalomon@google.comd302f142011-03-03 13:54:13 +00001620 if (fHWDrawState.fDrawFace != fCurrDrawState.fDrawFace) {
1621 switch (fCurrDrawState.fDrawFace) {
1622 case kCCW_DrawFace:
1623 glEnable(GL_CULL_FACE);
1624 GR_GL(CullFace(GL_BACK));
1625 break;
1626 case kCW_DrawFace:
1627 GR_GL(Enable(GL_CULL_FACE));
1628 GR_GL(CullFace(GL_FRONT));
1629 break;
1630 case kBoth_DrawFace:
1631 GR_GL(Disable(GL_CULL_FACE));
1632 break;
1633 default:
1634 GrCrash("Unknown draw face.");
1635 }
1636 fHWDrawState.fDrawFace = fCurrDrawState.fDrawFace;
1637 }
1638
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001639#if GR_DEBUG
reed@google.comac10a2d2010-12-22 21:39:39 +00001640 // check for circular rendering
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001641 for (int s = 0; s < kNumStages; ++s) {
1642 GrAssert(!VertexUsesStage(s, fGeometrySrc.fVertexLayout) ||
1643 NULL == fCurrDrawState.fRenderTarget ||
1644 NULL == fCurrDrawState.fTextures[s] ||
bsalomon@google.com316f99232011-01-13 21:28:12 +00001645 fCurrDrawState.fTextures[s]->asRenderTarget() !=
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001646 fCurrDrawState.fRenderTarget);
1647 }
1648#endif
bsalomon@google.com316f99232011-01-13 21:28:12 +00001649
reed@google.comac10a2d2010-12-22 21:39:39 +00001650 flushStencil();
1651
bsalomon@google.comd302f142011-03-03 13:54:13 +00001652 // flushStencil may look at the private state bits, so keep it before this.
reed@google.comac10a2d2010-12-22 21:39:39 +00001653 fHWDrawState.fFlagBits = fCurrDrawState.fFlagBits;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001654 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +00001655}
1656
1657void GrGpuGL::notifyVertexBufferBind(const GrGLVertexBuffer* buffer) {
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001658 if (fHWGeometryState.fVertexBuffer != buffer) {
1659 fHWGeometryState.fArrayPtrsDirty = true;
1660 fHWGeometryState.fVertexBuffer = buffer;
1661 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001662}
1663
1664void GrGpuGL::notifyVertexBufferDelete(const GrGLVertexBuffer* buffer) {
1665 GrAssert(!(kBuffer_GeometrySrcType == fGeometrySrc.fVertexSrc &&
1666 buffer == fGeometrySrc.fVertexBuffer));
1667
1668 if (fHWGeometryState.fVertexBuffer == buffer) {
1669 // deleting bound buffer does implied bind to 0
1670 fHWGeometryState.fVertexBuffer = NULL;
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001671 fHWGeometryState.fArrayPtrsDirty = true;
reed@google.comac10a2d2010-12-22 21:39:39 +00001672 }
1673}
1674
1675void GrGpuGL::notifyIndexBufferBind(const GrGLIndexBuffer* buffer) {
1676 fGeometrySrc.fIndexBuffer = buffer;
1677}
1678
1679void GrGpuGL::notifyIndexBufferDelete(const GrGLIndexBuffer* buffer) {
1680 GrAssert(!(kBuffer_GeometrySrcType == fGeometrySrc.fIndexSrc &&
1681 buffer == fGeometrySrc.fIndexBuffer));
1682
1683 if (fHWGeometryState.fIndexBuffer == buffer) {
1684 // deleting bound buffer does implied bind to 0
1685 fHWGeometryState.fIndexBuffer = NULL;
1686 }
1687}
1688
reed@google.comac10a2d2010-12-22 21:39:39 +00001689void GrGpuGL::notifyRenderTargetDelete(GrRenderTarget* renderTarget) {
1690 GrAssert(NULL != renderTarget);
reed@google.comac10a2d2010-12-22 21:39:39 +00001691 if (fCurrDrawState.fRenderTarget == renderTarget) {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001692 fCurrDrawState.fRenderTarget = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +00001693 }
1694 if (fHWDrawState.fRenderTarget == renderTarget) {
1695 fHWDrawState.fRenderTarget = NULL;
1696 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001697}
1698
1699void GrGpuGL::notifyTextureDelete(GrGLTexture* texture) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001700 for (int s = 0; s < kNumStages; ++s) {
1701 if (fCurrDrawState.fTextures[s] == texture) {
1702 fCurrDrawState.fTextures[s] = NULL;
1703 }
1704 if (fHWDrawState.fTextures[s] == texture) {
1705 // deleting bound texture does implied bind to 0
1706 fHWDrawState.fTextures[s] = NULL;
1707 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001708 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001709}
1710
reed@google.comac10a2d2010-12-22 21:39:39 +00001711bool GrGpuGL::canBeTexture(GrTexture::PixelConfig config,
1712 GLenum* internalFormat,
1713 GLenum* format,
1714 GLenum* type) {
1715 switch (config) {
1716 case GrTexture::kRGBA_8888_PixelConfig:
1717 case GrTexture::kRGBX_8888_PixelConfig: // todo: can we tell it our X?
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +00001718 *format = GR_GL_32BPP_COLOR_FORMAT;
reed@google.com63100f92011-01-18 21:32:14 +00001719#if GR_SUPPORT_GLES
1720 // according to GL_EXT_texture_format_BGRA8888 the *internal*
1721 // format for a BGRA is BGRA not RGBA (as on desktop)
1722 *internalFormat = GR_GL_32BPP_COLOR_FORMAT;
1723#else
1724 *internalFormat = GL_RGBA;
bsalomon@google.comed3a0682011-01-18 16:54:04 +00001725#endif
reed@google.comac10a2d2010-12-22 21:39:39 +00001726 *type = GL_UNSIGNED_BYTE;
1727 break;
1728 case GrTexture::kRGB_565_PixelConfig:
1729 *format = GL_RGB;
1730 *internalFormat = GL_RGB;
1731 *type = GL_UNSIGNED_SHORT_5_6_5;
1732 break;
1733 case GrTexture::kRGBA_4444_PixelConfig:
1734 *format = GL_RGBA;
1735 *internalFormat = GL_RGBA;
1736 *type = GL_UNSIGNED_SHORT_4_4_4_4;
1737 break;
1738 case GrTexture::kIndex_8_PixelConfig:
1739 if (this->supports8BitPalette()) {
1740 *format = GR_PALETTE8_RGBA8;
1741 *internalFormat = GR_PALETTE8_RGBA8;
1742 *type = GL_UNSIGNED_BYTE; // unused I think
1743 } else {
1744 return false;
1745 }
1746 break;
1747 case GrTexture::kAlpha_8_PixelConfig:
1748 *format = GL_ALPHA;
1749 *internalFormat = GL_ALPHA;
1750 *type = GL_UNSIGNED_BYTE;
1751 break;
1752 default:
1753 return false;
1754 }
1755 return true;
1756}
1757
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001758void GrGpuGL::setTextureUnit(int unit) {
1759 GrAssert(unit >= 0 && unit < kNumStages);
1760 if (fActiveTextureUnitIdx != unit) {
1761 GR_GL(ActiveTexture(GL_TEXTURE0 + unit));
1762 fActiveTextureUnitIdx = unit;
1763 }
1764}
bsalomon@google.com316f99232011-01-13 21:28:12 +00001765
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001766void GrGpuGL::setSpareTextureUnit() {
1767 if (fActiveTextureUnitIdx != (GL_TEXTURE0 + SPARE_TEX_UNIT)) {
1768 GR_GL(ActiveTexture(GL_TEXTURE0 + SPARE_TEX_UNIT));
1769 fActiveTextureUnitIdx = SPARE_TEX_UNIT;
1770 }
1771}
1772
reed@google.comac10a2d2010-12-22 21:39:39 +00001773/* On ES the internalFormat and format must match for TexImage and we use
1774 GL_RGB, GL_RGBA for color formats. We also generally like having the driver
1775 decide the internalFormat. However, on ES internalFormat for
1776 RenderBufferStorage* has to be a specific format (not a base format like
1777 GL_RGBA).
1778 */
1779bool GrGpuGL::fboInternalFormat(GrTexture::PixelConfig config, GLenum* format) {
1780 switch (config) {
1781 case GrTexture::kRGBA_8888_PixelConfig:
1782 case GrTexture::kRGBX_8888_PixelConfig:
1783 if (fRGBA8Renderbuffer) {
1784 *format = GR_RGBA8;
1785 return true;
1786 } else {
1787 return false;
1788 }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001789#if GR_SUPPORT_GLES // ES2 supports 565. ES1 supports it with FBO extension
1790 // desktop GL has no such internal format
reed@google.comac10a2d2010-12-22 21:39:39 +00001791 case GrTexture::kRGB_565_PixelConfig:
1792 *format = GR_RGB565;
1793 return true;
1794#endif
1795 case GrTexture::kRGBA_4444_PixelConfig:
1796 *format = GL_RGBA4;
1797 return true;
1798 default:
1799 return false;
1800 }
1801}
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001802
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001803void GrGpuGL::resetDirtyFlags() {
1804 Gr_bzero(&fDirtyFlags, sizeof(fDirtyFlags));
1805}
1806
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001807void GrGpuGL::setBuffers(bool indexed,
1808 int* extraVertexOffset,
1809 int* extraIndexOffset) {
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001810
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001811 GrAssert(NULL != extraVertexOffset);
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001812
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001813 GrGLVertexBuffer* vbuf;
1814 switch (fGeometrySrc.fVertexSrc) {
1815 case kBuffer_GeometrySrcType:
1816 *extraVertexOffset = 0;
1817 vbuf = (GrGLVertexBuffer*) fGeometrySrc.fVertexBuffer;
1818 break;
1819 case kArray_GeometrySrcType:
1820 case kReserved_GeometrySrcType:
1821 finalizeReservedVertices();
1822 *extraVertexOffset = fCurrPoolStartVertex;
1823 vbuf = (GrGLVertexBuffer*) fCurrPoolVertexBuffer;
1824 break;
1825 default:
1826 vbuf = NULL; // suppress warning
1827 GrCrash("Unknown geometry src type!");
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001828 }
1829
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001830 GrAssert(NULL != vbuf);
1831 GrAssert(!vbuf->isLocked());
1832 if (fHWGeometryState.fVertexBuffer != vbuf) {
1833 GR_GL(BindBuffer(GL_ARRAY_BUFFER, vbuf->bufferID()));
1834 fHWGeometryState.fArrayPtrsDirty = true;
1835 fHWGeometryState.fVertexBuffer = vbuf;
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001836 }
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001837
1838 if (indexed) {
1839 GrAssert(NULL != extraIndexOffset);
1840
1841 GrGLIndexBuffer* ibuf;
1842 switch (fGeometrySrc.fIndexSrc) {
1843 case kBuffer_GeometrySrcType:
1844 *extraIndexOffset = 0;
1845 ibuf = (GrGLIndexBuffer*)fGeometrySrc.fIndexBuffer;
1846 break;
1847 case kArray_GeometrySrcType:
1848 case kReserved_GeometrySrcType:
1849 finalizeReservedIndices();
1850 *extraIndexOffset = fCurrPoolStartIndex;
1851 ibuf = (GrGLIndexBuffer*) fCurrPoolIndexBuffer;
1852 break;
1853 default:
1854 ibuf = NULL; // suppress warning
1855 GrCrash("Unknown geometry src type!");
1856 }
1857
1858 GrAssert(NULL != ibuf);
1859 GrAssert(!ibuf->isLocked());
1860 if (fHWGeometryState.fIndexBuffer != ibuf) {
1861 GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibuf->bufferID()));
1862 fHWGeometryState.fIndexBuffer = ibuf;
1863 }
1864 }
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001865}