blob: f0c7cff8810e4073a529797fc56cb702f7e364b2 [file] [log] [blame]
reed@google.comac10a2d2010-12-22 21:39:39 +00001/*
2 Copyright 2010 Google Inc.
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17#include "GrGpuGL.h"
18#include "GrMemory.h"
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +000019#if GR_WIN32_BUILD
20 // need to get wglGetProcAddress
21 #undef WIN32_LEAN_AND_MEAN
22 #define WIN32_LEAN_AND_MEAN 1
23 #include <windows.h>
24 #undef WIN32_LEAN_AND_MEAN
25#endif
26
reed@google.comac10a2d2010-12-22 21:39:39 +000027
28static const GLuint GR_MAX_GLUINT = ~0;
29static const GLint GR_INVAL_GLINT = ~0;
30
bsalomon@google.com316f99232011-01-13 21:28:12 +000031// we use a spare texture unit to avoid
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000032// mucking with the state of any of the stages.
bsalomon@google.com316f99232011-01-13 21:28:12 +000033static const int SPARE_TEX_UNIT = GrGpuGL::kNumStages;
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000034
reed@google.comac10a2d2010-12-22 21:39:39 +000035#define SKIP_CACHE_CHECK true
36
37static const GLenum gXfermodeCoeff2Blend[] = {
38 GL_ZERO,
39 GL_ONE,
40 GL_SRC_COLOR,
41 GL_ONE_MINUS_SRC_COLOR,
42 GL_DST_COLOR,
43 GL_ONE_MINUS_DST_COLOR,
44 GL_SRC_ALPHA,
45 GL_ONE_MINUS_SRC_ALPHA,
46 GL_DST_ALPHA,
47 GL_ONE_MINUS_DST_ALPHA,
48};
49
reed@google.comac10a2d2010-12-22 21:39:39 +000050
reed@google.comac10a2d2010-12-22 21:39:39 +000051
reed@google.comac10a2d2010-12-22 21:39:39 +000052///////////////////////////////////////////////////////////////////////////////
53
bsalomon@google.com42ab7ea2011-01-19 17:19:40 +000054static bool gPrintStartupSpew;
55
56
reed@google.comac10a2d2010-12-22 21:39:39 +000057bool fbo_test(GrGLExts exts, int w, int h) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000058
59 GLint savedFBO;
60 GLint savedTexUnit;
reed@google.com3d8de042011-01-20 02:18:00 +000061 GR_GL_GetIntegerv(GL_ACTIVE_TEXTURE, &savedTexUnit);
62 GR_GL_GetIntegerv(GR_FRAMEBUFFER_BINDING, &savedFBO);
bsalomon@google.com316f99232011-01-13 21:28:12 +000063
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000064 GR_GL(ActiveTexture(GL_TEXTURE0 + SPARE_TEX_UNIT));
bsalomon@google.com316f99232011-01-13 21:28:12 +000065
reed@google.comac10a2d2010-12-22 21:39:39 +000066 GLuint testFBO;
67 GR_GLEXT(exts, GenFramebuffers(1, &testFBO));
68 GR_GLEXT(exts, BindFramebuffer(GR_FRAMEBUFFER, testFBO));
69 GLuint testRTTex;
70 GR_GL(GenTextures(1, &testRTTex));
71 GR_GL(BindTexture(GL_TEXTURE_2D, testRTTex));
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +000072 // some implementations require texture to be mip-map complete before
73 // FBO with level 0 bound as color attachment will be framebuffer complete.
74 GR_GL(TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
reed@google.comac10a2d2010-12-22 21:39:39 +000075 GR_GL(TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h,
76 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL));
77 GR_GL(BindTexture(GL_TEXTURE_2D, 0));
78 GR_GLEXT(exts, FramebufferTexture2D(GR_FRAMEBUFFER, GR_COLOR_ATTACHMENT0,
79 GL_TEXTURE_2D, testRTTex, 0));
80 GLenum status = GR_GLEXT(exts, CheckFramebufferStatus(GR_FRAMEBUFFER));
81 GR_GLEXT(exts, DeleteFramebuffers(1, &testFBO));
82 GR_GL(DeleteTextures(1, &testRTTex));
bsalomon@google.com316f99232011-01-13 21:28:12 +000083
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000084 GR_GL(ActiveTexture(savedTexUnit));
85 GR_GLEXT(exts, BindFramebuffer(GR_FRAMEBUFFER, savedFBO));
bsalomon@google.com316f99232011-01-13 21:28:12 +000086
reed@google.comac10a2d2010-12-22 21:39:39 +000087 return status == GR_FRAMEBUFFER_COMPLETE;
88}
89
reed@google.comac10a2d2010-12-22 21:39:39 +000090GrGpuGL::GrGpuGL() {
reed@google.comeeeb5a02010-12-23 15:12:59 +000091 if (gPrintStartupSpew) {
92 GrPrintf("------------------------- create GrGpuGL %p --------------\n",
93 this);
94 GrPrintf("------ VENDOR %s\n", glGetString(GL_VENDOR));
95 GrPrintf("------ RENDERER %s\n", glGetString(GL_RENDERER));
96 GrPrintf("------ VERSION %s\n", glGetString(GL_VERSION));
97 GrPrintf("------ EXTENSIONS\n %s \n", glGetString(GL_EXTENSIONS));
98 }
reed@google.comac10a2d2010-12-22 21:39:39 +000099
100 GrGLClearErr();
101
102 GrGLInitExtensions(&fExts);
103
104 resetContextHelper();
105
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000106 fHWDrawState.fRenderTarget = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +0000107 fRenderTargetChanged = true;
bsalomon@google.com316f99232011-01-13 21:28:12 +0000108
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000109 GLint maxTextureUnits;
110 // check FS and fixed-function texture unit limits
111 // we only use textures in the fragment stage currently.
112 // checks are > to make sure we have a spare unit.
113#if GR_SUPPORT_GLDESKTOP || GR_SUPPORT_GLES2
reed@google.com3d8de042011-01-20 02:18:00 +0000114 GR_GL_GetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000115 GrAssert(maxTextureUnits > kNumStages);
116#endif
117#if GR_SUPPORT_GLDESKTOP || GR_SUPPORT_GLES1
reed@google.com3d8de042011-01-20 02:18:00 +0000118 GR_GL_GetIntegerv(GL_MAX_TEXTURE_UNITS, &maxTextureUnits);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000119 GrAssert(maxTextureUnits > kNumStages);
120#endif
bsalomon@google.com316f99232011-01-13 21:28:12 +0000121
reed@google.comac10a2d2010-12-22 21:39:39 +0000122 fCurrDrawState = fHWDrawState;
123
124 ////////////////////////////////////////////////////////////////////////////
125 // Check for supported features.
126
127 int major, minor;
128 gl_version(&major, &minor);
129
130 GLint numFormats;
reed@google.comac20fb92011-01-12 17:14:53 +0000131 GR_GL_GetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &numFormats);
reed@google.comac10a2d2010-12-22 21:39:39 +0000132 GrAutoSTMalloc<10, GLint> formats(numFormats);
reed@google.comac20fb92011-01-12 17:14:53 +0000133 GR_GL_GetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, formats);
reed@google.comac10a2d2010-12-22 21:39:39 +0000134 for (int i = 0; i < numFormats; ++i) {
135 if (formats[i] == GR_PALETTE8_RGBA8) {
136 f8bitPaletteSupport = true;
137 break;
138 }
139 }
reed@google.comeeeb5a02010-12-23 15:12:59 +0000140
141 if (gPrintStartupSpew) {
142 GrPrintf("Palette8 support: %s\n", (f8bitPaletteSupport ? "YES" : "NO"));
143 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000144
145 GR_STATIC_ASSERT(0 == kNone_AALevel);
146 GR_STATIC_ASSERT(1 == kLow_AALevel);
147 GR_STATIC_ASSERT(2 == kMed_AALevel);
148 GR_STATIC_ASSERT(3 == kHigh_AALevel);
149
150 memset(fAASamples, 0, sizeof(fAASamples));
151 fMSFBOType = kNone_MSFBO;
152 if (has_gl_extension("GL_IMG_multisampled_render_to_texture")) {
153 fMSFBOType = kIMG_MSFBO;
reed@google.comeeeb5a02010-12-23 15:12:59 +0000154 if (gPrintStartupSpew) {
155 GrPrintf("MSAA Support: IMG ES EXT.\n");
156 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000157 }
158 else if (has_gl_extension("GL_APPLE_framebuffer_multisample")) {
159 fMSFBOType = kApple_MSFBO;
reed@google.comeeeb5a02010-12-23 15:12:59 +0000160 if (gPrintStartupSpew) {
161 GrPrintf("MSAA Support: APPLE ES EXT.\n");
162 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000163 }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000164#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000165 else if ((major >= 3) ||
166 has_gl_extension("GL_ARB_framebuffer_object") ||
167 (has_gl_extension("GL_EXT_framebuffer_multisample") &&
168 has_gl_extension("GL_EXT_framebuffer_blit"))) {
169 fMSFBOType = kDesktop_MSFBO;
reed@google.comeeeb5a02010-12-23 15:12:59 +0000170 if (gPrintStartupSpew) {
171 GrPrintf("MSAA Support: DESKTOP\n");
172 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000173 }
174#endif
175 else {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000176 if (gPrintStartupSpew) {
177 GrPrintf("MSAA Support: NONE\n");
178 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000179 }
180
181 if (kNone_MSFBO != fMSFBOType) {
182 GLint maxSamples;
183 GLenum maxSampleGetter = (kIMG_MSFBO == fMSFBOType) ?
184 GR_MAX_SAMPLES_IMG :
185 GR_MAX_SAMPLES;
reed@google.comac20fb92011-01-12 17:14:53 +0000186 GR_GL_GetIntegerv(maxSampleGetter, &maxSamples);
reed@google.comac10a2d2010-12-22 21:39:39 +0000187 if (maxSamples > 1 ) {
188 fAASamples[kNone_AALevel] = 0;
189 fAASamples[kLow_AALevel] = GrMax(2,
190 GrFixedFloorToInt((GR_FixedHalf) *
191 maxSamples));
192 fAASamples[kMed_AALevel] = GrMax(2,
193 GrFixedFloorToInt(((GR_Fixed1*3)/4) *
194 maxSamples));
195 fAASamples[kHigh_AALevel] = maxSamples;
196 }
reed@google.comeeeb5a02010-12-23 15:12:59 +0000197 if (gPrintStartupSpew) {
198 GrPrintf("\tMax Samples: %d\n", maxSamples);
199 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000200 }
201
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000202#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000203 fHasStencilWrap = (major >= 2 || (major == 1 && minor >= 4)) ||
204 has_gl_extension("GL_EXT_stencil_wrap");
205#else
206 fHasStencilWrap = (major >= 2) || has_gl_extension("GL_OES_stencil_wrap");
207#endif
reed@google.comeeeb5a02010-12-23 15:12:59 +0000208 if (gPrintStartupSpew) {
209 GrPrintf("Stencil Wrap: %s\n", (fHasStencilWrap ? "YES" : "NO"));
210 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000211
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000212#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000213 // we could also look for GL_ATI_separate_stencil extension or
214 // GL_EXT_stencil_two_side but they use different function signatures
215 // than GL2.0+ (and than each other).
216 fSingleStencilPassForWinding = (major >= 2);
217#else
218 // ES 2 has two sided stencil but 1.1 doesn't. There doesn't seem to be
219 // an ES1 extension.
220 fSingleStencilPassForWinding = (major >= 2);
221#endif
reed@google.comeeeb5a02010-12-23 15:12:59 +0000222 if (gPrintStartupSpew) {
223 GrPrintf("Single Stencil Pass For Winding: %s\n", (fSingleStencilPassForWinding ? "YES" : "NO"));
224 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000225
226
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000227#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000228 fRGBA8Renderbuffer = true;
229#else
230 fRGBA8Renderbuffer = has_gl_extension("GL_OES_rgb8_rgba8");
231#endif
reed@google.comeeeb5a02010-12-23 15:12:59 +0000232 if (gPrintStartupSpew) {
233 GrPrintf("RGBA Renderbuffer: %s\n", (fRGBA8Renderbuffer ? "YES" : "NO"));
234 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000235
bsalomon@google.comed3a0682011-01-18 16:54:04 +0000236#if GR_SUPPORT_GLES
237 if (GR_GL_32BPP_COLOR_FORMAT == GR_BGRA) {
238 GrAssert(has_gl_extension("GL_EXT_texture_format_BGRA8888"));
239 }
240#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000241
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000242#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000243 fBufferLockSupport = true; // we require VBO support and the desktop VBO
244 // extension includes glMapBuffer.
245#else
246 fBufferLockSupport = has_gl_extension("GL_OES_mapbuffer");
247#endif
reed@google.comeeeb5a02010-12-23 15:12:59 +0000248 if (gPrintStartupSpew) {
249 GrPrintf("Map Buffer: %s\n", (fBufferLockSupport ? "YES" : "NO"));
250 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000251
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000252#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000253 fNPOTTextureSupport =
254 (major >= 2 || has_gl_extension("GL_ARB_texture_non_power_of_two")) ?
255 kFull_NPOTTextureType :
256 kNone_NPOTTextureType;
257#else
258 if (has_gl_extension("GL_OES_texture_npot")) {
259 fNPOTTextureSupport = kFull_NPOTTextureType;
260 } else if (major >= 2 ||
261 has_gl_extension("GL_APPLE_texture_2D_limited_npot")) {
262 fNPOTTextureSupport = kNoRepeat_NPOTTextureType;
263 } else {
264 fNPOTTextureSupport = kNone_NPOTTextureType;
265 }
266#endif
267 ////////////////////////////////////////////////////////////////////////////
268 // Experiments to determine limitations that can't be queried. TODO: Make
269 // these a preprocess that generate some compile time constants.
270
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000271 // sanity check to make sure we can at least create an FBO from a POT texture
272 if (fNPOTTextureSupport < kFull_NPOTTextureType) {
273 bool npotFBOSuccess = fbo_test(fExts, 128, 128);
274 if (gPrintStartupSpew) {
275 if (!npotFBOSuccess) {
276 GrPrintf("FBO Sanity Test: FAILED\n");
277 } else {
278 GrPrintf("FBO Sanity Test: PASSED\n");
279 }
280 }
281 }
reed@google.comac20fb92011-01-12 17:14:53 +0000282
reed@google.comac10a2d2010-12-22 21:39:39 +0000283 /* Experimentation has found that some GLs that support NPOT textures
284 do not support FBOs with a NPOT texture. They report "unsupported" FBO
285 status. I don't know how to explicitly query for this. Do an
286 experiment. Note they may support NPOT with a renderbuffer but not a
287 texture. Presumably, the implementation bloats the renderbuffer
288 internally to the next POT.
289 */
290 if (fNPOTTextureSupport == kFull_NPOTTextureType) {
291 bool npotFBOSuccess = fbo_test(fExts, 200, 200);
292 if (!npotFBOSuccess) {
293 fNPOTTextureSupport = kNonRendertarget_NPOTTextureType;
reed@google.comeeeb5a02010-12-23 15:12:59 +0000294 if (gPrintStartupSpew) {
295 GrPrintf("NPOT Renderbuffer Test: FAILED\n");
296 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000297 } else {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000298 if (gPrintStartupSpew) {
299 GrPrintf("NPOT Renderbuffer Test: PASSED\n");
300 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000301 }
302 }
reed@google.comeeeb5a02010-12-23 15:12:59 +0000303
304 if (gPrintStartupSpew) {
305 switch (fNPOTTextureSupport) {
306 case kNone_NPOTTextureType:
307 GrPrintf("NPOT Support: NONE\n");
308 break;
309 case kNoRepeat_NPOTTextureType:
310 GrPrintf("NPOT Support: NO REPEAT\n");
311 break;
312 case kNonRendertarget_NPOTTextureType:
313 GrPrintf("NPOT Support: NO FBOTEX\n");
314 break;
315 case kFull_NPOTTextureType:
316 GrPrintf("NPOT Support: FULL\n");
317 break;
318 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000319 }
320
reed@google.comac10a2d2010-12-22 21:39:39 +0000321 /* The iPhone 4 has a restriction that for an FBO with texture color
322 attachment with height <= 8 then the width must be <= height. Here
323 we look for such a limitation.
324 */
325 fMinRenderTargetHeight = GR_INVAL_GLINT;
326 GLint maxRenderSize;
reed@google.comac20fb92011-01-12 17:14:53 +0000327 GR_GL_GetIntegerv(GR_MAX_RENDERBUFFER_SIZE, &maxRenderSize);
reed@google.comac10a2d2010-12-22 21:39:39 +0000328
reed@google.comeeeb5a02010-12-23 15:12:59 +0000329 if (gPrintStartupSpew) {
330 GrPrintf("Small height FBO texture experiments\n");
331 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000332 for (GLuint i = 1; i <= 256;
333 (kFull_NPOTTextureType != fNPOTTextureSupport) ? i *= 2 : ++i) {
334 GLuint w = maxRenderSize;
335 GLuint h = i;
336 if (fbo_test(fExts, w, h)) {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000337 if (gPrintStartupSpew) {
338 GrPrintf("\t[%d, %d]: PASSED\n", w, h);
339 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000340 fMinRenderTargetHeight = i;
341 break;
342 } else {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000343 if (gPrintStartupSpew) {
344 GrPrintf("\t[%d, %d]: FAILED\n", w, h);
345 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000346 }
347 }
348 GrAssert(GR_INVAL_GLINT != fMinRenderTargetHeight);
349
reed@google.comeeeb5a02010-12-23 15:12:59 +0000350 if (gPrintStartupSpew) {
351 GrPrintf("Small width FBO texture experiments\n");
352 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000353 fMinRenderTargetWidth = GR_MAX_GLUINT;
354 for (GLuint i = 1; i <= 256;
355 (kFull_NPOTTextureType != fNPOTTextureSupport) ? i *= 2 : ++i) {
356 GLuint w = i;
357 GLuint h = maxRenderSize;
358 if (fbo_test(fExts, w, h)) {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000359 if (gPrintStartupSpew) {
360 GrPrintf("\t[%d, %d]: PASSED\n", w, h);
361 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000362 fMinRenderTargetWidth = i;
363 break;
364 } else {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000365 if (gPrintStartupSpew) {
366 GrPrintf("\t[%d, %d]: FAILED\n", w, h);
367 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000368 }
369 }
370 GrAssert(GR_INVAL_GLINT != fMinRenderTargetWidth);
371
372#if GR_IOS_BUILD
373 /*
374 The iPad seems to fail, at least sometimes, if the height is < 16,
375 so we pin the values here for now. A better fix might be to
376 conditionalize this based on known that its an iPad (or some other
377 check).
378 */
379 fMinRenderTargetWidth = GrMax<GLuint>(fMinRenderTargetWidth, 16);
380 fMinRenderTargetHeight = GrMax<GLuint>(fMinRenderTargetHeight, 16);
381#endif
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000382
reed@google.comac10a2d2010-12-22 21:39:39 +0000383#if GR_COLLECT_STATS
384 ++fStats.fRenderTargetChngCnt;
385#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000386}
387
388GrGpuGL::~GrGpuGL() {
reed@google.comac10a2d2010-12-22 21:39:39 +0000389}
390
391void GrGpuGL::resetContextHelper() {
392// We detect cases when blending is effectively off
393 fHWBlendDisabled = false;
394 GR_GL(Enable(GL_BLEND));
395
396 // this is always disabled
397 GR_GL(Disable(GL_CULL_FACE));
398
399 GR_GL(Disable(GL_DITHER));
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000400#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000401 GR_GL(Disable(GL_LINE_SMOOTH));
402 GR_GL(Disable(GL_POINT_SMOOTH));
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000403 GR_GL(Disable(GL_MULTISAMPLE));
reed@google.comac10a2d2010-12-22 21:39:39 +0000404#endif
405
406 // we only ever use lines in hairline mode
407 GR_GL(LineWidth(1));
408
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000409 // invalid
410 fActiveTextureUnitIdx = -1;
reed@google.comac10a2d2010-12-22 21:39:39 +0000411
412 fHWDrawState.fFlagBits = 0;
413
414 // illegal values
415 fHWDrawState.fSrcBlend = (BlendCoeff)-1;
416 fHWDrawState.fDstBlend = (BlendCoeff)-1;
417 fHWDrawState.fColor = GrColor_ILLEGAL;
bsalomon@google.com316f99232011-01-13 21:28:12 +0000418
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000419 fHWDrawState.fViewMatrix.setScale(GR_ScalarMax, GR_ScalarMax); // illegal
bsalomon@google.com316f99232011-01-13 21:28:12 +0000420
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000421 for (int s = 0; s < kNumStages; ++s) {
422 fHWDrawState.fTextures[s] = NULL;
423 fHWDrawState.fSamplerStates[s].setRadial2Params(-GR_ScalarMax,
424 -GR_ScalarMax,
425 true);
bsalomon@google.com316f99232011-01-13 21:28:12 +0000426 fHWDrawState.fTextureMatrices[s].setScale(GR_ScalarMax, GR_ScalarMax);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000427 }
bsalomon@google.com316f99232011-01-13 21:28:12 +0000428
reed@google.comac10a2d2010-12-22 21:39:39 +0000429 GR_GL(Scissor(0,0,0,0));
430 fHWBounds.fScissorRect.setLTRB(0,0,0,0);
431 fHWBounds.fScissorEnabled = false;
432 GR_GL(Disable(GL_SCISSOR_TEST));
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000433 fHWBounds.fViewportRect.setLTRB(-1,-1,-1,-1);
reed@google.comac10a2d2010-12-22 21:39:39 +0000434
reed@google.comac10a2d2010-12-22 21:39:39 +0000435 // disabling the stencil test also disables
436 // stencil buffer writes
437 GR_GL(Disable(GL_STENCIL_TEST));
438 GR_GL(StencilMask(0xffffffff));
439 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
440 fHWDrawState.fReverseFill = false;
441 fHWDrawState.fStencilPass = kNone_StencilPass;
442 fHWStencilClip = false;
443
444 fHWGeometryState.fIndexBuffer = NULL;
445 fHWGeometryState.fVertexBuffer = NULL;
446 GR_GL(BindBuffer(GL_ARRAY_BUFFER, 0));
447 GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
448
449 fHWDrawState.fRenderTarget = NULL;
450}
451
452void GrGpuGL::resetContext() {
453 INHERITED::resetContext();
454 resetContextHelper();
455}
456
reed@google.comac10a2d2010-12-22 21:39:39 +0000457GrRenderTarget* GrGpuGL::createPlatformRenderTarget(
458 intptr_t platformRenderTarget,
459 int width, int height) {
460 GrGLRenderTarget::GLRenderTargetIDs rtIDs;
461 rtIDs.fStencilRenderbufferID = 0;
462 rtIDs.fMSColorRenderbufferID = 0;
463 rtIDs.fTexFBOID = 0;
464 rtIDs.fOwnIDs = false;
465
466 GrIRect viewport;
467
468 // viewport is in GL coords (top >= bottom)
469 viewport.setLTRB(0, height, width, 0);
470
471 rtIDs.fRTFBOID = (GLuint)platformRenderTarget;
472 rtIDs.fTexFBOID = (GLuint)platformRenderTarget;
473
474 GrGLRenderTarget* rt = new GrGLRenderTarget(rtIDs, viewport, NULL, this);
475
476 return rt;
477}
478
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000479GrRenderTarget* GrGpuGL::createRenderTargetFrom3DApiState() {
bsalomon@google.com42ab7ea2011-01-19 17:19:40 +0000480
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000481 GrGLRenderTarget::GLRenderTargetIDs rtIDs;
bsalomon@google.com42ab7ea2011-01-19 17:19:40 +0000482
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000483 GR_GL_GetIntegerv(GR_FRAMEBUFFER_BINDING, (GLint*)&rtIDs.fRTFBOID);
484 rtIDs.fTexFBOID = rtIDs.fRTFBOID;
485 rtIDs.fMSColorRenderbufferID = 0;
486 rtIDs.fStencilRenderbufferID = 0;
bsalomon@google.com42ab7ea2011-01-19 17:19:40 +0000487
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000488 GLint vp[4];
489 GR_GL_GetIntegerv(GL_VIEWPORT, vp);
490 GrIRect viewportRect;
491 viewportRect.setLTRB(vp[0],
492 vp[1] + vp[3],
493 vp[0] + vp[2],
494 vp[1]);
495 rtIDs.fOwnIDs = false;
496
497 return new GrGLRenderTarget(rtIDs,
498 viewportRect,
499 NULL,
500 this);
501}
502
bsalomon@google.com5782d712011-01-21 21:03:59 +0000503///////////////////////////////////////////////////////////////////////////////
504
bsalomon@google.com3f3ffd62011-01-18 17:14:52 +0000505// defines stencil formats from more to less preferred
reed@google.com63100f92011-01-18 21:32:14 +0000506GLenum GR_GL_STENCIL_FORMAT_ARRAY[] = {
507 GR_STENCIL_INDEX8,
508
509#if GR_SUPPORT_GLDESKTOP
510 GR_STENCIL_INDEX16,
511#endif
512
513 GR_DEPTH24_STENCIL8,
514 GR_STENCIL_INDEX4,
515
516#if GR_SUPPORT_GLDESKTOP
bsalomon@google.com3f3ffd62011-01-18 17:14:52 +0000517 GL_STENCIL_INDEX,
518 GR_DEPTH_STENCIL,
519#endif
520};
521
522// good to set a break-point here to know when createTexture fails
523static GrTexture* return_null_texture() {
524// GrAssert(!"null texture");
525 return NULL;
526}
527
528#if GR_DEBUG
529static size_t as_size_t(int x) {
530 return x;
531}
532#endif
533
reed@google.comac10a2d2010-12-22 21:39:39 +0000534GrTexture* GrGpuGL::createTexture(const TextureDesc& desc,
535 const void* srcData, size_t rowBytes) {
536
537#if GR_COLLECT_STATS
538 ++fStats.fTextureCreateCnt;
539#endif
reed@google.com1fcd51e2011-01-05 15:50:27 +0000540
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000541 setSpareTextureUnit();
bsalomon@google.com316f99232011-01-13 21:28:12 +0000542
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000543 static const GrGLTexture::TexParams DEFAULT_PARAMS = {
544 GL_NEAREST,
545 GL_CLAMP_TO_EDGE,
546 GL_CLAMP_TO_EDGE
547 };
reed@google.com1fcd51e2011-01-05 15:50:27 +0000548
reed@google.comac10a2d2010-12-22 21:39:39 +0000549 GrGLTexture::GLTextureDesc glDesc;
550 GLenum internalFormat;
551
552 glDesc.fContentWidth = desc.fWidth;
553 glDesc.fContentHeight = desc.fHeight;
554 glDesc.fAllocWidth = desc.fWidth;
555 glDesc.fAllocHeight = desc.fHeight;
556 glDesc.fFormat = desc.fFormat;
557
558 bool renderTarget = 0 != (desc.fFlags & kRenderTarget_TextureFlag);
559 if (!canBeTexture(desc.fFormat,
560 &internalFormat,
561 &glDesc.fUploadFormat,
562 &glDesc.fUploadType)) {
563 return return_null_texture();
564 }
565
566 GrAssert(as_size_t(desc.fAALevel) < GR_ARRAY_COUNT(fAASamples));
567 GLint samples = fAASamples[desc.fAALevel];
568 if (kNone_MSFBO == fMSFBOType && desc.fAALevel != kNone_AALevel) {
569 GrPrintf("AA RT requested but not supported on this platform.");
570 }
571
572 GR_GL(GenTextures(1, &glDesc.fTextureID));
573 if (!glDesc.fTextureID) {
574 return return_null_texture();
575 }
576
577 glDesc.fUploadByteCount = GrTexture::BytesPerPixel(desc.fFormat);
578
579 /*
580 * check if our srcData has extra bytes past each row. If so, we need
581 * to trim those off here, since GL doesn't let us pass the rowBytes as
582 * a parameter to glTexImage2D
583 */
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000584#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000585 if (srcData) {
586 GR_GL(PixelStorei(GL_UNPACK_ROW_LENGTH,
587 rowBytes / glDesc.fUploadByteCount));
588 }
589#else
590 GrAutoSMalloc<128 * 128> trimStorage;
591 size_t trimRowBytes = desc.fWidth * glDesc.fUploadByteCount;
592 if (srcData && (trimRowBytes < rowBytes)) {
593 size_t trimSize = desc.fHeight * trimRowBytes;
594 trimStorage.realloc(trimSize);
595 // now copy the data into our new storage, skipping the trailing bytes
596 const char* src = (const char*)srcData;
597 char* dst = (char*)trimStorage.get();
598 for (uint32_t y = 0; y < desc.fHeight; y++) {
599 memcpy(dst, src, trimRowBytes);
600 src += rowBytes;
601 dst += trimRowBytes;
602 }
603 // now point srcData to our trimmed version
604 srcData = trimStorage.get();
605 }
606#endif
607
608 if (fNPOTTextureSupport < kNonRendertarget_NPOTTextureType ||
609 (fNPOTTextureSupport == kNonRendertarget_NPOTTextureType &&
610 renderTarget)) {
611 glDesc.fAllocWidth = GrNextPow2(desc.fWidth);
612 glDesc.fAllocHeight = GrNextPow2(desc.fHeight);
613 }
614
615 if (renderTarget) {
616 glDesc.fAllocWidth = GrMax<int>(fMinRenderTargetWidth,
617 glDesc.fAllocWidth);
618 glDesc.fAllocHeight = GrMax<int>(fMinRenderTargetHeight,
619 glDesc.fAllocHeight);
620 }
621
622 GR_GL(BindTexture(GL_TEXTURE_2D, glDesc.fTextureID));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000623 GR_GL(TexParameteri(GL_TEXTURE_2D,
624 GL_TEXTURE_MAG_FILTER,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000625 DEFAULT_PARAMS.fFilter));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000626 GR_GL(TexParameteri(GL_TEXTURE_2D,
627 GL_TEXTURE_MIN_FILTER,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000628 DEFAULT_PARAMS.fFilter));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000629 GR_GL(TexParameteri(GL_TEXTURE_2D,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000630 GL_TEXTURE_WRAP_S,
631 DEFAULT_PARAMS.fWrapS));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000632 GR_GL(TexParameteri(GL_TEXTURE_2D,
633 GL_TEXTURE_WRAP_T,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000634 DEFAULT_PARAMS.fWrapT));
reed@google.comac10a2d2010-12-22 21:39:39 +0000635
636 GR_GL(PixelStorei(GL_UNPACK_ALIGNMENT, glDesc.fUploadByteCount));
637 if (GrTexture::kIndex_8_PixelConfig == desc.fFormat &&
638 supports8BitPalette()) {
639 // ES only supports CompressedTexImage2D, not CompressedTexSubimage2D
640 GrAssert(desc.fWidth == glDesc.fAllocWidth);
641 GrAssert(desc.fHeight == glDesc.fAllocHeight);
642 GLsizei imageSize = glDesc.fAllocWidth * glDesc.fAllocHeight +
643 kColorTableSize;
644 GR_GL(CompressedTexImage2D(GL_TEXTURE_2D, 0, glDesc.fUploadFormat,
645 glDesc.fAllocWidth, glDesc.fAllocHeight,
646 0, imageSize, srcData));
647 GrGL_RestoreResetRowLength();
648 } else {
649 if (NULL != srcData && (glDesc.fAllocWidth != desc.fWidth ||
650 glDesc.fAllocHeight != desc.fHeight)) {
651 GR_GL(TexImage2D(GL_TEXTURE_2D, 0, internalFormat,
652 glDesc.fAllocWidth, glDesc.fAllocHeight,
653 0, glDesc.fUploadFormat, glDesc.fUploadType, NULL));
654 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, desc.fWidth,
655 desc.fHeight, glDesc.fUploadFormat,
656 glDesc.fUploadType, srcData));
657 GrGL_RestoreResetRowLength();
658
659 uint32_t extraW = glDesc.fAllocWidth - desc.fWidth;
660 uint32_t extraH = glDesc.fAllocHeight - desc.fHeight;
661 uint32_t maxTexels = extraW * extraH;
662 maxTexels = GrMax(extraW * desc.fHeight, maxTexels);
663 maxTexels = GrMax(desc.fWidth * extraH, maxTexels);
664
665 GrAutoSMalloc<128*128> texels(glDesc.fUploadByteCount * maxTexels);
666
667 uint32_t rowSize = desc.fWidth * glDesc.fUploadByteCount;
668 if (extraH) {
669 uint8_t* lastRowStart = (uint8_t*) srcData +
670 (desc.fHeight - 1) * rowSize;
671 uint8_t* extraRowStart = (uint8_t*)texels.get();
672
673 for (uint32_t i = 0; i < extraH; ++i) {
674 memcpy(extraRowStart, lastRowStart, rowSize);
675 extraRowStart += rowSize;
676 }
677 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, 0, desc.fHeight, desc.fWidth,
678 extraH, glDesc.fUploadFormat, glDesc.fUploadType,
679 texels.get()));
680 }
681 if (extraW) {
682 uint8_t* edgeTexel = (uint8_t*)srcData + rowSize - glDesc.fUploadByteCount;
683 uint8_t* extraTexel = (uint8_t*)texels.get();
684 for (uint32_t j = 0; j < desc.fHeight; ++j) {
685 for (uint32_t i = 0; i < extraW; ++i) {
686 memcpy(extraTexel, edgeTexel, glDesc.fUploadByteCount);
687 extraTexel += glDesc.fUploadByteCount;
688 }
689 edgeTexel += rowSize;
690 }
691 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, desc.fWidth, 0, extraW,
692 desc.fHeight, glDesc.fUploadFormat,
693 glDesc.fUploadType, texels.get()));
694 }
695 if (extraW && extraH) {
696 uint8_t* cornerTexel = (uint8_t*)srcData + desc.fHeight * rowSize
697 - glDesc.fUploadByteCount;
698 uint8_t* extraTexel = (uint8_t*)texels.get();
699 for (uint32_t i = 0; i < extraW*extraH; ++i) {
700 memcpy(extraTexel, cornerTexel, glDesc.fUploadByteCount);
701 extraTexel += glDesc.fUploadByteCount;
702 }
703 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, desc.fWidth, desc.fHeight,
704 extraW, extraH, glDesc.fUploadFormat,
705 glDesc.fUploadType, texels.get()));
706 }
707
708 } else {
709 GR_GL(TexImage2D(GL_TEXTURE_2D, 0, internalFormat, glDesc.fAllocWidth,
710 glDesc.fAllocHeight, 0, glDesc.fUploadFormat,
711 glDesc.fUploadType, srcData));
712 GrGL_RestoreResetRowLength();
713 }
714 }
715
716 glDesc.fOrientation = GrGLTexture::kTopDown_Orientation;
717
718 GrGLRenderTarget::GLRenderTargetIDs rtIDs;
719 rtIDs.fStencilRenderbufferID = 0;
720 rtIDs.fMSColorRenderbufferID = 0;
721 rtIDs.fRTFBOID = 0;
722 rtIDs.fTexFBOID = 0;
723 rtIDs.fOwnIDs = true;
724 GLenum msColorRenderbufferFormat = -1;
725
726 if (renderTarget) {
727#if GR_COLLECT_STATS
728 ++fStats.fRenderTargetCreateCnt;
729#endif
730 bool failed = true;
731 GLenum status;
732 GLint err;
733
734 // If need have both RT flag and srcData we have
735 // to invert the data before uploading because FBO
736 // will be rendered bottom up
737 GrAssert(NULL == srcData);
738 glDesc.fOrientation = GrGLTexture::kBottomUp_Orientation;
739
740 GR_GLEXT(fExts, GenFramebuffers(1, &rtIDs.fTexFBOID));
741 GrAssert(rtIDs.fTexFBOID);
742
743 // If we are using multisampling and any extension other than the IMG
744 // one we will create two FBOs. We render to one and then resolve to
745 // the texture bound to the other. The IMG extension does an implicit
746 // resolve.
747 if (samples > 1 && kIMG_MSFBO != fMSFBOType && kNone_MSFBO != fMSFBOType) {
748 GR_GLEXT(fExts, GenFramebuffers(1, &rtIDs.fRTFBOID));
749 GrAssert(0 != rtIDs.fRTFBOID);
750 GR_GLEXT(fExts, GenRenderbuffers(1, &rtIDs.fMSColorRenderbufferID));
751 GrAssert(0 != rtIDs.fMSColorRenderbufferID);
752 if (!fboInternalFormat(desc.fFormat, &msColorRenderbufferFormat)) {
753 GR_GLEXT(fExts,
754 DeleteRenderbuffers(1, &rtIDs.fMSColorRenderbufferID));
755 GR_GL(DeleteTextures(1, &glDesc.fTextureID));
756 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fTexFBOID));
757 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fRTFBOID));
reed@google.comac10a2d2010-12-22 21:39:39 +0000758 return return_null_texture();
759 }
760 } else {
761 rtIDs.fRTFBOID = rtIDs.fTexFBOID;
762 }
763 int attempts = 1;
764 if (!(kNoPathRendering_TextureFlag & desc.fFlags)) {
765 GR_GLEXT(fExts, GenRenderbuffers(1, &rtIDs.fStencilRenderbufferID));
766 GrAssert(0 != rtIDs.fStencilRenderbufferID);
767 attempts = GR_ARRAY_COUNT(GR_GL_STENCIL_FORMAT_ARRAY);
768 }
769
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000770 // someone suggested that some systems might require
bsalomon@google.com316f99232011-01-13 21:28:12 +0000771 // unbinding the texture before we call FramebufferTexture2D
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000772 // (seems unlikely)
reed@google.comac10a2d2010-12-22 21:39:39 +0000773 GR_GL(BindTexture(GL_TEXTURE_2D, 0));
reed@google.comac10a2d2010-12-22 21:39:39 +0000774
775 err = ~GL_NO_ERROR;
776 for (int i = 0; i < attempts; ++i) {
777 if (rtIDs.fStencilRenderbufferID) {
778 GR_GLEXT(fExts, BindRenderbuffer(GR_RENDERBUFFER,
779 rtIDs.fStencilRenderbufferID));
780 if (samples > 1) {
781 GR_GLEXT_NO_ERR(fExts, RenderbufferStorageMultisample(
782 GR_RENDERBUFFER,
783 samples,
784 GR_GL_STENCIL_FORMAT_ARRAY[i],
785 glDesc.fAllocWidth,
786 glDesc.fAllocHeight));
787 } else {
788 GR_GLEXT_NO_ERR(fExts, RenderbufferStorage(
789 GR_RENDERBUFFER,
790 GR_GL_STENCIL_FORMAT_ARRAY[i],
791 glDesc.fAllocWidth,
792 glDesc.fAllocHeight));
793 }
794 err = glGetError();
795 if (err != GL_NO_ERROR) {
796 continue;
797 }
798 }
799 if (rtIDs.fRTFBOID != rtIDs.fTexFBOID) {
800 GrAssert(samples > 1);
801 GR_GLEXT(fExts, BindRenderbuffer(GR_RENDERBUFFER,
802 rtIDs.fMSColorRenderbufferID));
803 GR_GLEXT_NO_ERR(fExts, RenderbufferStorageMultisample(
804 GR_RENDERBUFFER,
805 samples,
806 msColorRenderbufferFormat,
807 glDesc.fAllocWidth,
808 glDesc.fAllocHeight));
809 err = glGetError();
810 if (err != GL_NO_ERROR) {
811 continue;
812 }
813 }
814 GR_GLEXT(fExts, BindFramebuffer(GR_FRAMEBUFFER, rtIDs.fTexFBOID));
815
816#if GR_COLLECT_STATS
817 ++fStats.fRenderTargetChngCnt;
818#endif
819 if (kIMG_MSFBO == fMSFBOType && samples > 1) {
820 GR_GLEXT(fExts, FramebufferTexture2DMultisample(
821 GR_FRAMEBUFFER,
822 GR_COLOR_ATTACHMENT0,
823 GL_TEXTURE_2D,
824 glDesc.fTextureID,
825 0,
826 samples));
827
828 } else {
829 GR_GLEXT(fExts, FramebufferTexture2D(GR_FRAMEBUFFER,
830 GR_COLOR_ATTACHMENT0,
831 GL_TEXTURE_2D,
832 glDesc.fTextureID, 0));
833 }
834 if (rtIDs.fRTFBOID != rtIDs.fTexFBOID) {
835 GLenum status = GR_GLEXT(fExts,
836 CheckFramebufferStatus(GR_FRAMEBUFFER));
837 if (status != GR_FRAMEBUFFER_COMPLETE) {
838 GrPrintf("-- glCheckFramebufferStatus %x %d %d\n",
839 status, desc.fWidth, desc.fHeight);
840 continue;
841 }
842 GR_GLEXT(fExts, BindFramebuffer(GR_FRAMEBUFFER, rtIDs.fRTFBOID));
843 #if GR_COLLECT_STATS
844 ++fStats.fRenderTargetChngCnt;
845 #endif
846 GR_GLEXT(fExts, FramebufferRenderbuffer(GR_FRAMEBUFFER,
847 GR_COLOR_ATTACHMENT0,
848 GR_RENDERBUFFER,
849 rtIDs.fMSColorRenderbufferID));
850
851 }
852 if (rtIDs.fStencilRenderbufferID) {
853 // bind the stencil to rt fbo if present, othewise the tex fbo
854 GR_GLEXT(fExts, FramebufferRenderbuffer(GR_FRAMEBUFFER,
855 GR_STENCIL_ATTACHMENT,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000856 GR_RENDERBUFFER,
reed@google.comac10a2d2010-12-22 21:39:39 +0000857 rtIDs.fStencilRenderbufferID));
858 }
859 status = GR_GLEXT(fExts, CheckFramebufferStatus(GR_FRAMEBUFFER));
860
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000861#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000862 // On some implementations you have to be bound as DEPTH_STENCIL.
863 // (Even binding to DEPTH and STENCIL separately with the same
864 // buffer doesn't work.)
865 if (rtIDs.fStencilRenderbufferID &&
866 status != GR_FRAMEBUFFER_COMPLETE) {
867 GR_GLEXT(fExts, FramebufferRenderbuffer(GR_FRAMEBUFFER,
868 GR_STENCIL_ATTACHMENT,
869 GR_RENDERBUFFER,
870 0));
871 GR_GLEXT(fExts,
872 FramebufferRenderbuffer(GR_FRAMEBUFFER,
873 GR_DEPTH_STENCIL_ATTACHMENT,
874 GR_RENDERBUFFER,
875 rtIDs.fStencilRenderbufferID));
876 status = GR_GLEXT(fExts, CheckFramebufferStatus(GR_FRAMEBUFFER));
877 }
878#endif
879 if (status != GR_FRAMEBUFFER_COMPLETE) {
880 GrPrintf("-- glCheckFramebufferStatus %x %d %d\n",
881 status, desc.fWidth, desc.fHeight);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000882#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000883 if (rtIDs.fStencilRenderbufferID) {
884 GR_GLEXT(fExts, FramebufferRenderbuffer(GR_FRAMEBUFFER,
885 GR_DEPTH_STENCIL_ATTACHMENT,
886 GR_RENDERBUFFER,
887 0));
888 }
889#endif
890 continue;
891 }
892 // we're successful!
893 failed = false;
894 break;
895 }
896 if (failed) {
897 if (rtIDs.fStencilRenderbufferID) {
898 GR_GLEXT(fExts,
899 DeleteRenderbuffers(1, &rtIDs.fStencilRenderbufferID));
900 }
901 if (rtIDs.fMSColorRenderbufferID) {
902 GR_GLEXT(fExts,
903 DeleteRenderbuffers(1, &rtIDs.fMSColorRenderbufferID));
904 }
905 if (rtIDs.fRTFBOID != rtIDs.fTexFBOID) {
906 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fRTFBOID));
907 }
908 if (rtIDs.fTexFBOID) {
909 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fTexFBOID));
910 }
911 GR_GL(DeleteTextures(1, &glDesc.fTextureID));
912 return return_null_texture();
913 }
914 }
915#ifdef TRACE_TEXTURE_CREATION
916 GrPrintf("--- new texture [%d] size=(%d %d) bpp=%d\n",
917 tex->fTextureID, width, height, tex->fUploadByteCount);
918#endif
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000919 GrGLTexture* tex = new GrGLTexture(glDesc, rtIDs, DEFAULT_PARAMS, this);
reed@google.comac10a2d2010-12-22 21:39:39 +0000920
921 if (0 != rtIDs.fTexFBOID) {
922 GrRenderTarget* rt = tex->asRenderTarget();
923 // We've messed with FBO state but may not have set the correct viewport
924 // so just dirty the rendertarget state to force a resend.
925 fHWDrawState.fRenderTarget = NULL;
926
927 // clear the new stencil buffer if we have one
928 if (!(desc.fFlags & kNoPathRendering_TextureFlag)) {
929 GrRenderTarget* rtSave = fCurrDrawState.fRenderTarget;
930 fCurrDrawState.fRenderTarget = rt;
931 eraseStencil(0, ~0);
932 fCurrDrawState.fRenderTarget = rtSave;
933 }
934 }
935 return tex;
936}
937
reed@google.comac10a2d2010-12-22 21:39:39 +0000938GrVertexBuffer* GrGpuGL::createVertexBuffer(uint32_t size, bool dynamic) {
939 GLuint id;
940 GR_GL(GenBuffers(1, &id));
941 if (id) {
942 GR_GL(BindBuffer(GL_ARRAY_BUFFER, id));
943 GrGLClearErr();
944 // make sure driver can allocate memory for this buffer
945 GR_GL_NO_ERR(BufferData(GL_ARRAY_BUFFER, size, NULL,
946 dynamic ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW));
947 if (glGetError() != GL_NO_ERROR) {
948 GR_GL(DeleteBuffers(1, &id));
949 // deleting bound buffer does implicit bind to 0
950 fHWGeometryState.fVertexBuffer = NULL;
951 return NULL;
952 }
953 GrGLVertexBuffer* vertexBuffer = new GrGLVertexBuffer(id, this,
954 size, dynamic);
955 fHWGeometryState.fVertexBuffer = vertexBuffer;
956 return vertexBuffer;
957 }
958 return NULL;
959}
960
961GrIndexBuffer* GrGpuGL::createIndexBuffer(uint32_t size, bool dynamic) {
962 GLuint id;
963 GR_GL(GenBuffers(1, &id));
964 if (id) {
965 GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, id));
966 GrGLClearErr();
967 // make sure driver can allocate memory for this buffer
968 GR_GL_NO_ERR(BufferData(GL_ELEMENT_ARRAY_BUFFER, size, NULL,
969 dynamic ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW));
970 if (glGetError() != GL_NO_ERROR) {
971 GR_GL(DeleteBuffers(1, &id));
972 // deleting bound buffer does implicit bind to 0
973 fHWGeometryState.fIndexBuffer = NULL;
974 return NULL;
975 }
976 GrIndexBuffer* indexBuffer = new GrGLIndexBuffer(id, this,
977 size, dynamic);
978 fHWGeometryState.fIndexBuffer = indexBuffer;
979 return indexBuffer;
980 }
981 return NULL;
982}
983
reed@google.comac10a2d2010-12-22 21:39:39 +0000984void GrGpuGL::flushScissor(const GrIRect* rect) {
985 GrAssert(NULL != fCurrDrawState.fRenderTarget);
986 const GrIRect& vp =
987 ((GrGLRenderTarget*)fCurrDrawState.fRenderTarget)->viewport();
988
989 if (NULL != rect &&
990 rect->contains(vp)) {
991 rect = NULL;
992 }
993
994 if (NULL != rect) {
995 GrIRect scissor;
996 // viewport is already in GL coords
997 // create a scissor in GL coords (top > bottom)
998 scissor.setLTRB(vp.fLeft + rect->fLeft,
999 vp.fTop - rect->fTop,
1000 vp.fLeft + rect->fRight,
1001 vp.fTop - rect->fBottom);
1002
1003 if (fHWBounds.fScissorRect != scissor) {
1004 GR_GL(Scissor(scissor.fLeft, scissor.fBottom,
1005 scissor.width(), -scissor.height()));
1006 fHWBounds.fScissorRect = scissor;
1007 }
1008
1009 if (!fHWBounds.fScissorEnabled) {
1010 GR_GL(Enable(GL_SCISSOR_TEST));
1011 fHWBounds.fScissorEnabled = true;
1012 }
1013 } else {
1014 if (fHWBounds.fScissorEnabled) {
1015 GR_GL(Disable(GL_SCISSOR_TEST));
1016 fHWBounds.fScissorEnabled = false;
1017 }
1018 }
1019}
1020
reed@google.comac10a2d2010-12-22 21:39:39 +00001021void GrGpuGL::eraseColor(GrColor color) {
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +00001022 if (NULL == fCurrDrawState.fRenderTarget) {
1023 return;
1024 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001025 flushRenderTarget();
1026 if (fHWBounds.fScissorEnabled) {
1027 GR_GL(Disable(GL_SCISSOR_TEST));
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +00001028 fHWBounds.fScissorEnabled = false;
reed@google.comac10a2d2010-12-22 21:39:39 +00001029 }
1030 GR_GL(ColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE));
1031 GR_GL(ClearColor(GrColorUnpackR(color)/255.f,
1032 GrColorUnpackG(color)/255.f,
1033 GrColorUnpackB(color)/255.f,
1034 GrColorUnpackA(color)/255.f));
1035 GR_GL(Clear(GL_COLOR_BUFFER_BIT));
reed@google.comac10a2d2010-12-22 21:39:39 +00001036 fWriteMaskChanged = true;
1037}
1038
1039void GrGpuGL::eraseStencil(uint32_t value, uint32_t mask) {
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +00001040 if (NULL == fCurrDrawState.fRenderTarget) {
1041 return;
1042 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001043 flushRenderTarget();
1044 if (fHWBounds.fScissorEnabled) {
1045 GR_GL(Disable(GL_SCISSOR_TEST));
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +00001046 fHWBounds.fScissorEnabled = false;
reed@google.comac10a2d2010-12-22 21:39:39 +00001047 }
1048 GR_GL(StencilMask(mask));
1049 GR_GL(ClearStencil(value));
1050 GR_GL(Clear(GL_STENCIL_BUFFER_BIT));
reed@google.comac10a2d2010-12-22 21:39:39 +00001051 fWriteMaskChanged = true;
1052}
1053
1054void GrGpuGL::eraseStencilClip() {
1055 GLint stencilBitCount;
reed@google.comac20fb92011-01-12 17:14:53 +00001056 GR_GL_GetIntegerv(GL_STENCIL_BITS, &stencilBitCount);
reed@google.comac10a2d2010-12-22 21:39:39 +00001057 GrAssert(stencilBitCount > 0);
1058 GLint clipStencilMask = (1 << (stencilBitCount - 1));
1059 eraseStencil(0, clipStencilMask);
1060}
1061
1062void GrGpuGL::forceRenderTargetFlush() {
1063 flushRenderTarget();
1064}
1065
1066bool GrGpuGL::readPixels(int left, int top, int width, int height,
1067 GrTexture::PixelConfig config, void* buffer) {
1068 GLenum internalFormat; // we don't use this for glReadPixels
1069 GLenum format;
1070 GLenum type;
1071 if (!this->canBeTexture(config, &internalFormat, &format, &type)) {
1072 return false;
1073 }
1074
1075 GrAssert(NULL != fCurrDrawState.fRenderTarget);
1076 const GrIRect& vp = ((GrGLRenderTarget*)fCurrDrawState.fRenderTarget)->viewport();
1077
1078 // Brian says that viewport rects are already upside down (grrrrr)
bsalomon@google.com316f99232011-01-13 21:28:12 +00001079 GR_GL(ReadPixels(left, -vp.height() - top - height, width, height,
1080 format, type, buffer));
reed@google.comac10a2d2010-12-22 21:39:39 +00001081
1082 // now reverse the order of the rows, since GL's are bottom-to-top, but our
1083 // API presents top-to-bottom
1084 {
1085 size_t stride = width * GrTexture::BytesPerPixel(config);
1086 GrAutoMalloc rowStorage(stride);
1087 void* tmp = rowStorage.get();
1088
1089 const int halfY = height >> 1;
1090 char* top = reinterpret_cast<char*>(buffer);
1091 char* bottom = top + (height - 1) * stride;
1092 for (int y = 0; y < halfY; y++) {
1093 memcpy(tmp, top, stride);
1094 memcpy(top, bottom, stride);
1095 memcpy(bottom, tmp, stride);
1096 top += stride;
1097 bottom -= stride;
1098 }
1099 }
1100 return true;
1101}
1102
1103void GrGpuGL::flushRenderTarget() {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001104
1105 GrAssert(NULL != fCurrDrawState.fRenderTarget);
1106
reed@google.comac10a2d2010-12-22 21:39:39 +00001107 if (fHWDrawState.fRenderTarget != fCurrDrawState.fRenderTarget) {
1108 GrGLRenderTarget* rt = (GrGLRenderTarget*)fCurrDrawState.fRenderTarget;
1109 GR_GLEXT(fExts, BindFramebuffer(GR_FRAMEBUFFER, rt->renderFBOID()));
1110 #if GR_COLLECT_STATS
1111 ++fStats.fRenderTargetChngCnt;
1112 #endif
1113 rt->setDirty(true);
1114 #if GR_DEBUG
1115 GLenum status = GR_GLEXT(fExts, CheckFramebufferStatus(GR_FRAMEBUFFER));
1116 if (status != GR_FRAMEBUFFER_COMPLETE) {
1117 GrPrintf("-- glCheckFramebufferStatus %x\n", status);
1118 }
1119 #endif
1120 fHWDrawState.fRenderTarget = fCurrDrawState.fRenderTarget;
1121 const GrIRect& vp = rt->viewport();
1122 fRenderTargetChanged = true;
1123 if (fHWBounds.fViewportRect != vp) {
1124 GR_GL(Viewport(vp.fLeft,
1125 vp.fBottom,
1126 vp.width(),
1127 -vp.height()));
1128 fHWBounds.fViewportRect = vp;
1129 }
1130 }
1131}
1132
1133GLenum gPrimitiveType2GLMode[] = {
1134 GL_TRIANGLES,
1135 GL_TRIANGLE_STRIP,
1136 GL_TRIANGLE_FAN,
1137 GL_POINTS,
1138 GL_LINES,
1139 GL_LINE_STRIP
1140};
1141
1142void GrGpuGL::drawIndexedHelper(PrimitiveType type,
1143 uint32_t startVertex,
1144 uint32_t startIndex,
1145 uint32_t vertexCount,
1146 uint32_t indexCount) {
1147 GrAssert((size_t)type < GR_ARRAY_COUNT(gPrimitiveType2GLMode));
1148
1149 GLvoid* indices = (GLvoid*)(sizeof(uint16_t) * startIndex);
1150 if (kReserved_GeometrySrcType == fGeometrySrc.fIndexSrc) {
1151 indices = (GLvoid*)((intptr_t)indices + (intptr_t)fIndices.get());
1152 } else if (kArray_GeometrySrcType == fGeometrySrc.fIndexSrc) {
1153 indices = (GLvoid*)((intptr_t)indices +
1154 (intptr_t)fGeometrySrc.fIndexArray);
1155 }
1156
1157 GR_GL(DrawElements(gPrimitiveType2GLMode[type], indexCount,
1158 GL_UNSIGNED_SHORT, indices));
1159}
1160
1161void GrGpuGL::drawNonIndexedHelper(PrimitiveType type,
1162 uint32_t startVertex,
1163 uint32_t vertexCount) {
1164 GrAssert((size_t)type < GR_ARRAY_COUNT(gPrimitiveType2GLMode));
1165
1166 GR_GL(DrawArrays(gPrimitiveType2GLMode[type], 0, vertexCount));
1167}
1168
1169#if !defined(SK_GL_HAS_COLOR4UB)
1170static inline GrFixed byte2fixed(unsigned value) {
1171 return (value + (value >> 7)) << 8;
1172}
1173#endif
1174
1175void GrGpuGL::resolveTextureRenderTarget(GrGLTexture* texture) {
1176 GrGLRenderTarget* rt = (GrGLRenderTarget*) texture->asRenderTarget();
1177
1178 if (NULL != rt && rt->needsResolve()) {
1179 GrAssert(kNone_MSFBO != fMSFBOType);
1180 GrAssert(rt->textureFBOID() != rt->renderFBOID());
1181 GR_GLEXT(fExts, BindFramebuffer(GR_READ_FRAMEBUFFER,
1182 rt->renderFBOID()));
1183 GR_GLEXT(fExts, BindFramebuffer(GR_DRAW_FRAMEBUFFER,
1184 rt->textureFBOID()));
1185 #if GR_COLLECT_STATS
1186 ++fStats.fRenderTargetChngCnt;
1187 #endif
1188 // make sure we go through set render target
1189 fHWDrawState.fRenderTarget = NULL;
1190
1191 GLint left = 0;
1192 GLint right = texture->contentWidth();
1193 // we will have rendered to the top of the FBO.
1194 GLint top = texture->allocHeight();
1195 GLint bottom = texture->allocHeight() - texture->contentHeight();
1196 if (kApple_MSFBO == fMSFBOType) {
1197 GR_GL(Enable(GL_SCISSOR_TEST));
1198 GR_GL(Scissor(left, bottom, right-left, top-bottom));
1199 GR_GLEXT(fExts, ResolveMultisampleFramebuffer());
1200 fHWBounds.fScissorRect.setEmpty();
1201 fHWBounds.fScissorEnabled = true;
1202 } else {
1203 GR_GLEXT(fExts, BlitFramebuffer(left, bottom, right, top,
1204 left, bottom, right, top,
1205 GL_COLOR_BUFFER_BIT, GL_NEAREST));
1206 }
1207 rt->setDirty(false);
1208
1209 }
1210}
1211
1212void GrGpuGL::flushStencil() {
1213
1214 // use stencil for clipping if clipping is enabled and the clip
1215 // has been written into the stencil.
1216 bool stencilClip = fClipState.fClipInStencil &&
1217 (kClip_StateBit & fCurrDrawState.fFlagBits);
1218 bool stencilChange =
1219 fWriteMaskChanged ||
1220 fHWStencilClip != stencilClip ||
1221 fHWDrawState.fStencilPass != fCurrDrawState.fStencilPass ||
1222 (kNone_StencilPass != fCurrDrawState.fStencilPass &&
1223 (StencilPass)kSetClip_StencilPass != fCurrDrawState.fStencilPass &&
1224 fHWDrawState.fReverseFill != fCurrDrawState.fReverseFill);
1225
1226 if (stencilChange) {
1227 GLint stencilBitCount;
1228 GLint clipStencilMask;
1229 GLint pathStencilMask;
reed@google.comac20fb92011-01-12 17:14:53 +00001230 GR_GL_GetIntegerv(GL_STENCIL_BITS, &stencilBitCount);
reed@google.comac10a2d2010-12-22 21:39:39 +00001231 GrAssert(stencilBitCount > 0 ||
1232 kNone_StencilPass == fCurrDrawState.fStencilPass);
1233 clipStencilMask = (1 << (stencilBitCount - 1));
1234 pathStencilMask = clipStencilMask - 1;
1235 switch (fCurrDrawState.fStencilPass) {
1236 case kNone_StencilPass:
1237 if (stencilClip) {
1238 GR_GL(Enable(GL_STENCIL_TEST));
1239 GR_GL(StencilFunc(GL_EQUAL,
1240 clipStencilMask,
1241 clipStencilMask));
1242 GR_GL(StencilOp(GL_KEEP, GL_KEEP, GL_KEEP));
1243 } else {
1244 GR_GL(Disable(GL_STENCIL_TEST));
1245 }
1246 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
1247 if (!fSingleStencilPassForWinding) {
1248 GR_GL(Disable(GL_CULL_FACE));
1249 }
1250 break;
1251 case kEvenOddStencil_StencilPass:
1252 GR_GL(Enable(GL_STENCIL_TEST));
1253 if (stencilClip) {
1254 GR_GL(StencilFunc(GL_EQUAL, clipStencilMask, clipStencilMask));
1255 } else {
1256 GR_GL(StencilFunc(GL_ALWAYS, 0x0, 0x0));
1257 }
1258 GR_GL(StencilMask(pathStencilMask));
1259 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
1260 GR_GL(StencilOp(GL_KEEP, GL_INVERT, GL_INVERT));
1261 GR_GL(ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE));
1262 if (!fSingleStencilPassForWinding) {
1263 GR_GL(Disable(GL_CULL_FACE));
1264 }
1265 break;
1266 case kEvenOddColor_StencilPass: {
1267 GR_GL(Enable(GL_STENCIL_TEST));
1268 GLint funcRef = 0;
1269 GLuint funcMask = pathStencilMask;
1270 if (stencilClip) {
1271 funcRef |= clipStencilMask;
1272 funcMask |= clipStencilMask;
1273 }
1274 if (!fCurrDrawState.fReverseFill) {
1275 funcRef |= pathStencilMask;
1276 }
bsalomon@google.com316f99232011-01-13 21:28:12 +00001277 GR_GL(StencilFunc(GL_EQUAL, funcRef, funcMask));
1278 GR_GL(StencilMask(pathStencilMask));
reed@google.comac10a2d2010-12-22 21:39:39 +00001279 GR_GL(StencilOp(GL_ZERO, GL_ZERO, GL_ZERO));
1280 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
1281 if (!fSingleStencilPassForWinding) {
1282 GR_GL(Disable(GL_CULL_FACE));
1283 }
1284 } break;
1285 case kWindingStencil1_StencilPass:
1286 GR_GL(Enable(GL_STENCIL_TEST));
1287 if (fHasStencilWrap) {
1288 if (stencilClip) {
1289 GR_GL(StencilFunc(GL_EQUAL,
1290 clipStencilMask,
1291 clipStencilMask));
1292 } else {
1293 GR_GL(StencilFunc(GL_ALWAYS, 0x0, 0x0));
1294 }
1295 if (fSingleStencilPassForWinding) {
1296 GR_GL(StencilOpSeparate(GL_FRONT, GL_KEEP,
1297 GL_INCR_WRAP, GL_INCR_WRAP));
1298 GR_GL(StencilOpSeparate(GL_BACK, GL_KEEP,
1299 GL_DECR_WRAP, GL_DECR_WRAP));
1300 } else {
1301 GR_GL(StencilOp(GL_KEEP, GL_INCR_WRAP, GL_INCR_WRAP));
1302 GR_GL(Enable(GL_CULL_FACE));
1303 GR_GL(CullFace(GL_BACK));
1304 }
1305 } else {
1306 // If we don't have wrap then we use the Func to detect
1307 // values that would wrap (0 on decr and mask on incr). We
1308 // make the func fail on these values and use the sfail op
1309 // to effectively wrap by inverting.
1310 // This applies whether we are doing a two-pass (front faces
1311 // followed by back faces) or a single pass (separate func/op)
1312
1313 // Note that in the case where we are also using stencil to
1314 // clip this means we will write into the path bits in clipped
1315 // out pixels. We still apply the clip bit in the color pass
1316 // stencil func so we don't draw color outside the clip.
1317 // We also will clear the stencil bits in clipped pixels by
1318 // using zero in the sfail op with write mask set to the
1319 // path mask.
1320 GR_GL(Enable(GL_STENCIL_TEST));
1321 if (fSingleStencilPassForWinding) {
1322 GR_GL(StencilFuncSeparate(GL_FRONT,
1323 GL_NOTEQUAL,
1324 pathStencilMask,
1325 pathStencilMask));
1326 GR_GL(StencilFuncSeparate(GL_BACK,
1327 GL_NOTEQUAL,
1328 0x0,
1329 pathStencilMask));
1330 GR_GL(StencilOpSeparate(GL_FRONT, GL_INVERT,
1331 GL_INCR, GL_INCR));
1332 GR_GL(StencilOpSeparate(GL_BACK, GL_INVERT,
1333 GL_DECR, GL_DECR));
1334 } else {
1335 GR_GL(StencilFunc(GL_NOTEQUAL,
1336 pathStencilMask,
1337 pathStencilMask));
1338 GR_GL(StencilOp(GL_INVERT, GL_INCR, GL_INCR));
1339 GR_GL(Enable(GL_CULL_FACE));
1340 GR_GL(CullFace(GL_BACK));
1341 }
1342 }
1343 GR_GL(StencilMask(pathStencilMask));
1344 GR_GL(ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE));
1345 break;
1346 case kWindingStencil2_StencilPass:
1347 GrAssert(!fSingleStencilPassForWinding);
1348 GR_GL(Enable(GL_STENCIL_TEST));
1349 if (fHasStencilWrap) {
1350 if (stencilClip) {
1351 GR_GL(StencilFunc(GL_EQUAL,
1352 clipStencilMask,
1353 clipStencilMask));
1354 } else {
1355 GR_GL(StencilFunc(GL_ALWAYS, 0x0, 0x0));
1356 }
1357 GR_GL(StencilOp(GL_DECR_WRAP, GL_DECR_WRAP, GL_DECR_WRAP));
1358 } else {
1359 GR_GL(StencilFunc(GL_NOTEQUAL, 0x0, pathStencilMask));
1360 GR_GL(StencilOp(GL_INVERT, GL_DECR, GL_DECR));
1361 }
1362 GR_GL(StencilMask(pathStencilMask));
1363 GR_GL(Enable(GL_CULL_FACE));
1364 GR_GL(CullFace(GL_FRONT));
1365 GR_GL(ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE));
1366 break;
1367 case kWindingColor_StencilPass: {
1368 GR_GL(Enable(GL_STENCIL_TEST));
1369 GLint funcRef = 0;
1370 GLuint funcMask = pathStencilMask;
1371 GLenum funcFunc;
1372 if (stencilClip) {
1373 funcRef |= clipStencilMask;
1374 funcMask |= clipStencilMask;
1375 }
1376 if (fCurrDrawState.fReverseFill) {
1377 funcFunc = GL_EQUAL;
1378 } else {
1379 funcFunc = GL_LESS;
1380 }
1381 GR_GL(StencilFunc(funcFunc, funcRef, funcMask));
1382 GR_GL(StencilMask(pathStencilMask));
1383 // must zero in sfail because winding w/o wrap will write
1384 // path stencil bits in clipped out pixels
1385 GR_GL(StencilOp(GL_ZERO, GL_ZERO, GL_ZERO));
1386 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
1387 if (!fSingleStencilPassForWinding) {
1388 GR_GL(Disable(GL_CULL_FACE));
1389 }
1390 } break;
1391 case kSetClip_StencilPass:
1392 GR_GL(Enable(GL_STENCIL_TEST));
1393 GR_GL(StencilFunc(GL_ALWAYS, clipStencilMask, clipStencilMask));
1394 GR_GL(StencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE));
1395 GR_GL(StencilMask(clipStencilMask));
1396 GR_GL(ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE));
1397 if (!fSingleStencilPassForWinding) {
1398 GR_GL(Disable(GL_CULL_FACE));
1399 }
1400 break;
1401 default:
1402 GrAssert(!"Unexpected stencil pass.");
1403 break;
1404
1405 }
1406 fHWDrawState.fStencilPass = fCurrDrawState.fStencilPass;
1407 fHWDrawState.fReverseFill = fCurrDrawState.fReverseFill;
1408 fWriteMaskChanged = false;
1409 fHWStencilClip = stencilClip;
1410 }
1411}
1412
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001413bool GrGpuGL::flushGLStateCommon(PrimitiveType type) {
1414
1415 // GrGpu::setupClipAndFlushState should have already checked this
1416 // and bailed if not true.
1417 GrAssert(NULL != fCurrDrawState.fRenderTarget);
reed@google.comac10a2d2010-12-22 21:39:39 +00001418
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001419 for (int s = 0; s < kNumStages; ++s) {
1420 bool usingTexture = VertexUsesStage(s, fGeometrySrc.fVertexLayout);
reed@google.comac10a2d2010-12-22 21:39:39 +00001421
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001422 // bind texture and set sampler state
1423 if (usingTexture) {
1424 GrGLTexture* nextTexture = (GrGLTexture*)fCurrDrawState.fTextures[s];
reed@google.comac10a2d2010-12-22 21:39:39 +00001425
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001426 if (NULL != nextTexture) {
bsalomon@google.com316f99232011-01-13 21:28:12 +00001427 // if we created a rt/tex and rendered to it without using a
1428 // texture and now we're texuring from the rt it will still be
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001429 // the last bound texture, but it needs resolving. So keep this
1430 // out of the "last != next" check.
1431 resolveTextureRenderTarget(nextTexture);
reed@google.comac10a2d2010-12-22 21:39:39 +00001432
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001433 if (fHWDrawState.fTextures[s] != nextTexture) {
1434 setTextureUnit(s);
1435 GR_GL(BindTexture(GL_TEXTURE_2D, nextTexture->textureID()));
1436 #if GR_COLLECT_STATS
1437 ++fStats.fTextureChngCnt;
1438 #endif
1439 //GrPrintf("---- bindtexture %d\n", nextTexture->textureID());
1440 fHWDrawState.fTextures[s] = nextTexture;
1441 }
bsalomon@google.com316f99232011-01-13 21:28:12 +00001442
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001443 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
bsalomon@google.com316f99232011-01-13 21:28:12 +00001444 const GrGLTexture::TexParams& oldTexParams =
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001445 nextTexture->getTexParams();
1446 GrGLTexture::TexParams newTexParams;
bsalomon@google.com316f99232011-01-13 21:28:12 +00001447
1448 newTexParams.fFilter = sampler.isFilter() ? GL_LINEAR :
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001449 GL_NEAREST;
bsalomon@google.com316f99232011-01-13 21:28:12 +00001450 newTexParams.fWrapS =
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001451 GrGLTexture::gWrapMode2GLWrap[sampler.getWrapX()];
bsalomon@google.com316f99232011-01-13 21:28:12 +00001452 newTexParams.fWrapT =
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001453 GrGLTexture::gWrapMode2GLWrap[sampler.getWrapY()];
reed@google.comac10a2d2010-12-22 21:39:39 +00001454
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001455 if (newTexParams.fFilter != oldTexParams.fFilter) {
1456 setTextureUnit(s);
bsalomon@google.com316f99232011-01-13 21:28:12 +00001457 GR_GL(TexParameteri(GL_TEXTURE_2D,
1458 GL_TEXTURE_MAG_FILTER,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001459 newTexParams.fFilter));
bsalomon@google.com316f99232011-01-13 21:28:12 +00001460 GR_GL(TexParameteri(GL_TEXTURE_2D,
1461 GL_TEXTURE_MIN_FILTER,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001462 newTexParams.fFilter));
1463 }
1464 if (newTexParams.fWrapS != oldTexParams.fWrapS) {
1465 setTextureUnit(s);
bsalomon@google.com316f99232011-01-13 21:28:12 +00001466 GR_GL(TexParameteri(GL_TEXTURE_2D,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001467 GL_TEXTURE_WRAP_S,
1468 newTexParams.fWrapS));
1469 }
1470 if (newTexParams.fWrapT != oldTexParams.fWrapT) {
1471 setTextureUnit(s);
bsalomon@google.com316f99232011-01-13 21:28:12 +00001472 GR_GL(TexParameteri(GL_TEXTURE_2D,
1473 GL_TEXTURE_WRAP_T,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001474 newTexParams.fWrapT));
1475 }
1476 nextTexture->setTexParams(newTexParams);
1477 } else {
1478 GrAssert(!"Rendering with texture vert flag set but no texture");
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001479 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +00001480 }
1481 }
1482 }
1483
1484 flushRenderTarget();
1485
1486 if ((fCurrDrawState.fFlagBits & kDither_StateBit) !=
1487 (fHWDrawState.fFlagBits & kDither_StateBit)) {
1488 if (fCurrDrawState.fFlagBits & kDither_StateBit) {
1489 GR_GL(Enable(GL_DITHER));
1490 } else {
1491 GR_GL(Disable(GL_DITHER));
1492 }
1493 }
1494
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001495#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +00001496 // ES doesn't support toggling GL_MULTISAMPLE and doesn't have
1497 // smooth lines.
1498 if (fRenderTargetChanged ||
1499 (fCurrDrawState.fFlagBits & kAntialias_StateBit) !=
1500 (fHWDrawState.fFlagBits & kAntialias_StateBit)) {
1501 GLint msaa = 0;
1502 // only perform query if we know MSAA is supported.
1503 // calling on non-MSAA target caused a crash in one environment,
1504 // though I don't think it should.
1505 if (!fAASamples[kHigh_AALevel]) {
reed@google.comac20fb92011-01-12 17:14:53 +00001506 GR_GL_GetIntegerv(GL_SAMPLE_BUFFERS, &msaa);
reed@google.comac10a2d2010-12-22 21:39:39 +00001507 }
1508 if (fCurrDrawState.fFlagBits & kAntialias_StateBit) {
1509 if (msaa) {
1510 GR_GL(Enable(GL_MULTISAMPLE));
1511 } else {
1512 GR_GL(Enable(GL_LINE_SMOOTH));
1513 }
1514 } else {
1515 if (msaa) {
1516 GR_GL(Disable(GL_MULTISAMPLE));
1517 }
1518 GR_GL(Disable(GL_LINE_SMOOTH));
1519 }
1520 }
1521#endif
1522
1523 bool blendOff = canDisableBlend();
1524 if (fHWBlendDisabled != blendOff) {
1525 if (blendOff) {
1526 GR_GL(Disable(GL_BLEND));
1527 } else {
1528 GR_GL(Enable(GL_BLEND));
1529 }
1530 fHWBlendDisabled = blendOff;
1531 }
1532
1533 if (!blendOff) {
1534 if (fHWDrawState.fSrcBlend != fCurrDrawState.fSrcBlend ||
1535 fHWDrawState.fDstBlend != fCurrDrawState.fDstBlend) {
1536 GR_GL(BlendFunc(gXfermodeCoeff2Blend[fCurrDrawState.fSrcBlend],
1537 gXfermodeCoeff2Blend[fCurrDrawState.fDstBlend]));
1538 fHWDrawState.fSrcBlend = fCurrDrawState.fSrcBlend;
1539 fHWDrawState.fDstBlend = fCurrDrawState.fDstBlend;
1540 }
1541 }
bsalomon@google.com316f99232011-01-13 21:28:12 +00001542
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001543#if GR_DEBUG
reed@google.comac10a2d2010-12-22 21:39:39 +00001544 // check for circular rendering
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001545 for (int s = 0; s < kNumStages; ++s) {
1546 GrAssert(!VertexUsesStage(s, fGeometrySrc.fVertexLayout) ||
1547 NULL == fCurrDrawState.fRenderTarget ||
1548 NULL == fCurrDrawState.fTextures[s] ||
bsalomon@google.com316f99232011-01-13 21:28:12 +00001549 fCurrDrawState.fTextures[s]->asRenderTarget() !=
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001550 fCurrDrawState.fRenderTarget);
1551 }
1552#endif
bsalomon@google.com316f99232011-01-13 21:28:12 +00001553
reed@google.comac10a2d2010-12-22 21:39:39 +00001554 flushStencil();
1555
1556 fHWDrawState.fFlagBits = fCurrDrawState.fFlagBits;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001557 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +00001558}
1559
1560void GrGpuGL::notifyVertexBufferBind(const GrGLVertexBuffer* buffer) {
1561 fHWGeometryState.fVertexBuffer = buffer;
1562}
1563
1564void GrGpuGL::notifyVertexBufferDelete(const GrGLVertexBuffer* buffer) {
1565 GrAssert(!(kBuffer_GeometrySrcType == fGeometrySrc.fVertexSrc &&
1566 buffer == fGeometrySrc.fVertexBuffer));
1567
1568 if (fHWGeometryState.fVertexBuffer == buffer) {
1569 // deleting bound buffer does implied bind to 0
1570 fHWGeometryState.fVertexBuffer = NULL;
1571 }
1572}
1573
1574void GrGpuGL::notifyIndexBufferBind(const GrGLIndexBuffer* buffer) {
1575 fGeometrySrc.fIndexBuffer = buffer;
1576}
1577
1578void GrGpuGL::notifyIndexBufferDelete(const GrGLIndexBuffer* buffer) {
1579 GrAssert(!(kBuffer_GeometrySrcType == fGeometrySrc.fIndexSrc &&
1580 buffer == fGeometrySrc.fIndexBuffer));
1581
1582 if (fHWGeometryState.fIndexBuffer == buffer) {
1583 // deleting bound buffer does implied bind to 0
1584 fHWGeometryState.fIndexBuffer = NULL;
1585 }
1586}
1587
reed@google.comac10a2d2010-12-22 21:39:39 +00001588void GrGpuGL::notifyRenderTargetDelete(GrRenderTarget* renderTarget) {
1589 GrAssert(NULL != renderTarget);
1590
1591 // if the bound FBO is destroyed we can't rely on the implicit bind to 0
1592 // a) we want the default RT which may not be FBO 0
1593 // b) we set more state than just FBO based on the RT
1594 // So trash the HW state to force an RT flush next time
1595 if (fCurrDrawState.fRenderTarget == renderTarget) {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001596 fCurrDrawState.fRenderTarget = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +00001597 }
1598 if (fHWDrawState.fRenderTarget == renderTarget) {
1599 fHWDrawState.fRenderTarget = NULL;
1600 }
1601 if (fClipState.fStencilClipTarget == renderTarget) {
1602 fClipState.fStencilClipTarget = NULL;
1603 }
1604}
1605
1606void GrGpuGL::notifyTextureDelete(GrGLTexture* texture) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001607 for (int s = 0; s < kNumStages; ++s) {
1608 if (fCurrDrawState.fTextures[s] == texture) {
1609 fCurrDrawState.fTextures[s] = NULL;
1610 }
1611 if (fHWDrawState.fTextures[s] == texture) {
1612 // deleting bound texture does implied bind to 0
1613 fHWDrawState.fTextures[s] = NULL;
1614 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001615 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001616}
1617
1618void GrGpuGL::notifyTextureRemoveRenderTarget(GrGLTexture* texture) {
1619 GrAssert(NULL != texture->asRenderTarget());
1620
1621 // if there is a pending resolve, perform it.
1622 resolveTextureRenderTarget(texture);
1623}
1624
1625bool GrGpuGL::canBeTexture(GrTexture::PixelConfig config,
1626 GLenum* internalFormat,
1627 GLenum* format,
1628 GLenum* type) {
1629 switch (config) {
1630 case GrTexture::kRGBA_8888_PixelConfig:
1631 case GrTexture::kRGBX_8888_PixelConfig: // todo: can we tell it our X?
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +00001632 *format = GR_GL_32BPP_COLOR_FORMAT;
reed@google.com63100f92011-01-18 21:32:14 +00001633#if GR_SUPPORT_GLES
1634 // according to GL_EXT_texture_format_BGRA8888 the *internal*
1635 // format for a BGRA is BGRA not RGBA (as on desktop)
1636 *internalFormat = GR_GL_32BPP_COLOR_FORMAT;
1637#else
1638 *internalFormat = GL_RGBA;
bsalomon@google.comed3a0682011-01-18 16:54:04 +00001639#endif
reed@google.comac10a2d2010-12-22 21:39:39 +00001640 *type = GL_UNSIGNED_BYTE;
1641 break;
1642 case GrTexture::kRGB_565_PixelConfig:
1643 *format = GL_RGB;
1644 *internalFormat = GL_RGB;
1645 *type = GL_UNSIGNED_SHORT_5_6_5;
1646 break;
1647 case GrTexture::kRGBA_4444_PixelConfig:
1648 *format = GL_RGBA;
1649 *internalFormat = GL_RGBA;
1650 *type = GL_UNSIGNED_SHORT_4_4_4_4;
1651 break;
1652 case GrTexture::kIndex_8_PixelConfig:
1653 if (this->supports8BitPalette()) {
1654 *format = GR_PALETTE8_RGBA8;
1655 *internalFormat = GR_PALETTE8_RGBA8;
1656 *type = GL_UNSIGNED_BYTE; // unused I think
1657 } else {
1658 return false;
1659 }
1660 break;
1661 case GrTexture::kAlpha_8_PixelConfig:
1662 *format = GL_ALPHA;
1663 *internalFormat = GL_ALPHA;
1664 *type = GL_UNSIGNED_BYTE;
1665 break;
1666 default:
1667 return false;
1668 }
1669 return true;
1670}
1671
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001672void GrGpuGL::setTextureUnit(int unit) {
1673 GrAssert(unit >= 0 && unit < kNumStages);
1674 if (fActiveTextureUnitIdx != unit) {
1675 GR_GL(ActiveTexture(GL_TEXTURE0 + unit));
1676 fActiveTextureUnitIdx = unit;
1677 }
1678}
bsalomon@google.com316f99232011-01-13 21:28:12 +00001679
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001680void GrGpuGL::setSpareTextureUnit() {
1681 if (fActiveTextureUnitIdx != (GL_TEXTURE0 + SPARE_TEX_UNIT)) {
1682 GR_GL(ActiveTexture(GL_TEXTURE0 + SPARE_TEX_UNIT));
1683 fActiveTextureUnitIdx = SPARE_TEX_UNIT;
1684 }
1685}
1686
reed@google.comac10a2d2010-12-22 21:39:39 +00001687/* On ES the internalFormat and format must match for TexImage and we use
1688 GL_RGB, GL_RGBA for color formats. We also generally like having the driver
1689 decide the internalFormat. However, on ES internalFormat for
1690 RenderBufferStorage* has to be a specific format (not a base format like
1691 GL_RGBA).
1692 */
1693bool GrGpuGL::fboInternalFormat(GrTexture::PixelConfig config, GLenum* format) {
1694 switch (config) {
1695 case GrTexture::kRGBA_8888_PixelConfig:
1696 case GrTexture::kRGBX_8888_PixelConfig:
1697 if (fRGBA8Renderbuffer) {
1698 *format = GR_RGBA8;
1699 return true;
1700 } else {
1701 return false;
1702 }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001703#if GR_SUPPORT_GLES // ES2 supports 565. ES1 supports it with FBO extension
1704 // desktop GL has no such internal format
reed@google.comac10a2d2010-12-22 21:39:39 +00001705 case GrTexture::kRGB_565_PixelConfig:
1706 *format = GR_RGB565;
1707 return true;
1708#endif
1709 case GrTexture::kRGBA_4444_PixelConfig:
1710 *format = GL_RGBA4;
1711 return true;
1712 default:
1713 return false;
1714 }
1715}