blob: 1dbc5fbb7e8fb60d1ff314746b334f0b3bf15272 [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) {
1022 flushRenderTarget();
1023 if (fHWBounds.fScissorEnabled) {
1024 GR_GL(Disable(GL_SCISSOR_TEST));
1025 }
1026 GR_GL(ColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE));
1027 GR_GL(ClearColor(GrColorUnpackR(color)/255.f,
1028 GrColorUnpackG(color)/255.f,
1029 GrColorUnpackB(color)/255.f,
1030 GrColorUnpackA(color)/255.f));
1031 GR_GL(Clear(GL_COLOR_BUFFER_BIT));
1032 fHWBounds.fScissorEnabled = false;
1033 fWriteMaskChanged = true;
1034}
1035
1036void GrGpuGL::eraseStencil(uint32_t value, uint32_t mask) {
1037 flushRenderTarget();
1038 if (fHWBounds.fScissorEnabled) {
1039 GR_GL(Disable(GL_SCISSOR_TEST));
1040 }
1041 GR_GL(StencilMask(mask));
1042 GR_GL(ClearStencil(value));
1043 GR_GL(Clear(GL_STENCIL_BUFFER_BIT));
1044 fHWBounds.fScissorEnabled = false;
1045 fWriteMaskChanged = true;
1046}
1047
1048void GrGpuGL::eraseStencilClip() {
1049 GLint stencilBitCount;
reed@google.comac20fb92011-01-12 17:14:53 +00001050 GR_GL_GetIntegerv(GL_STENCIL_BITS, &stencilBitCount);
reed@google.comac10a2d2010-12-22 21:39:39 +00001051 GrAssert(stencilBitCount > 0);
1052 GLint clipStencilMask = (1 << (stencilBitCount - 1));
1053 eraseStencil(0, clipStencilMask);
1054}
1055
1056void GrGpuGL::forceRenderTargetFlush() {
1057 flushRenderTarget();
1058}
1059
1060bool GrGpuGL::readPixels(int left, int top, int width, int height,
1061 GrTexture::PixelConfig config, void* buffer) {
1062 GLenum internalFormat; // we don't use this for glReadPixels
1063 GLenum format;
1064 GLenum type;
1065 if (!this->canBeTexture(config, &internalFormat, &format, &type)) {
1066 return false;
1067 }
1068
1069 GrAssert(NULL != fCurrDrawState.fRenderTarget);
1070 const GrIRect& vp = ((GrGLRenderTarget*)fCurrDrawState.fRenderTarget)->viewport();
1071
1072 // Brian says that viewport rects are already upside down (grrrrr)
bsalomon@google.com316f99232011-01-13 21:28:12 +00001073 GR_GL(ReadPixels(left, -vp.height() - top - height, width, height,
1074 format, type, buffer));
reed@google.comac10a2d2010-12-22 21:39:39 +00001075
1076 // now reverse the order of the rows, since GL's are bottom-to-top, but our
1077 // API presents top-to-bottom
1078 {
1079 size_t stride = width * GrTexture::BytesPerPixel(config);
1080 GrAutoMalloc rowStorage(stride);
1081 void* tmp = rowStorage.get();
1082
1083 const int halfY = height >> 1;
1084 char* top = reinterpret_cast<char*>(buffer);
1085 char* bottom = top + (height - 1) * stride;
1086 for (int y = 0; y < halfY; y++) {
1087 memcpy(tmp, top, stride);
1088 memcpy(top, bottom, stride);
1089 memcpy(bottom, tmp, stride);
1090 top += stride;
1091 bottom -= stride;
1092 }
1093 }
1094 return true;
1095}
1096
1097void GrGpuGL::flushRenderTarget() {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001098
1099 GrAssert(NULL != fCurrDrawState.fRenderTarget);
1100
reed@google.comac10a2d2010-12-22 21:39:39 +00001101 if (fHWDrawState.fRenderTarget != fCurrDrawState.fRenderTarget) {
1102 GrGLRenderTarget* rt = (GrGLRenderTarget*)fCurrDrawState.fRenderTarget;
1103 GR_GLEXT(fExts, BindFramebuffer(GR_FRAMEBUFFER, rt->renderFBOID()));
1104 #if GR_COLLECT_STATS
1105 ++fStats.fRenderTargetChngCnt;
1106 #endif
1107 rt->setDirty(true);
1108 #if GR_DEBUG
1109 GLenum status = GR_GLEXT(fExts, CheckFramebufferStatus(GR_FRAMEBUFFER));
1110 if (status != GR_FRAMEBUFFER_COMPLETE) {
1111 GrPrintf("-- glCheckFramebufferStatus %x\n", status);
1112 }
1113 #endif
1114 fHWDrawState.fRenderTarget = fCurrDrawState.fRenderTarget;
1115 const GrIRect& vp = rt->viewport();
1116 fRenderTargetChanged = true;
1117 if (fHWBounds.fViewportRect != vp) {
1118 GR_GL(Viewport(vp.fLeft,
1119 vp.fBottom,
1120 vp.width(),
1121 -vp.height()));
1122 fHWBounds.fViewportRect = vp;
1123 }
1124 }
1125}
1126
1127GLenum gPrimitiveType2GLMode[] = {
1128 GL_TRIANGLES,
1129 GL_TRIANGLE_STRIP,
1130 GL_TRIANGLE_FAN,
1131 GL_POINTS,
1132 GL_LINES,
1133 GL_LINE_STRIP
1134};
1135
1136void GrGpuGL::drawIndexedHelper(PrimitiveType type,
1137 uint32_t startVertex,
1138 uint32_t startIndex,
1139 uint32_t vertexCount,
1140 uint32_t indexCount) {
1141 GrAssert((size_t)type < GR_ARRAY_COUNT(gPrimitiveType2GLMode));
1142
1143 GLvoid* indices = (GLvoid*)(sizeof(uint16_t) * startIndex);
1144 if (kReserved_GeometrySrcType == fGeometrySrc.fIndexSrc) {
1145 indices = (GLvoid*)((intptr_t)indices + (intptr_t)fIndices.get());
1146 } else if (kArray_GeometrySrcType == fGeometrySrc.fIndexSrc) {
1147 indices = (GLvoid*)((intptr_t)indices +
1148 (intptr_t)fGeometrySrc.fIndexArray);
1149 }
1150
1151 GR_GL(DrawElements(gPrimitiveType2GLMode[type], indexCount,
1152 GL_UNSIGNED_SHORT, indices));
1153}
1154
1155void GrGpuGL::drawNonIndexedHelper(PrimitiveType type,
1156 uint32_t startVertex,
1157 uint32_t vertexCount) {
1158 GrAssert((size_t)type < GR_ARRAY_COUNT(gPrimitiveType2GLMode));
1159
1160 GR_GL(DrawArrays(gPrimitiveType2GLMode[type], 0, vertexCount));
1161}
1162
1163#if !defined(SK_GL_HAS_COLOR4UB)
1164static inline GrFixed byte2fixed(unsigned value) {
1165 return (value + (value >> 7)) << 8;
1166}
1167#endif
1168
1169void GrGpuGL::resolveTextureRenderTarget(GrGLTexture* texture) {
1170 GrGLRenderTarget* rt = (GrGLRenderTarget*) texture->asRenderTarget();
1171
1172 if (NULL != rt && rt->needsResolve()) {
1173 GrAssert(kNone_MSFBO != fMSFBOType);
1174 GrAssert(rt->textureFBOID() != rt->renderFBOID());
1175 GR_GLEXT(fExts, BindFramebuffer(GR_READ_FRAMEBUFFER,
1176 rt->renderFBOID()));
1177 GR_GLEXT(fExts, BindFramebuffer(GR_DRAW_FRAMEBUFFER,
1178 rt->textureFBOID()));
1179 #if GR_COLLECT_STATS
1180 ++fStats.fRenderTargetChngCnt;
1181 #endif
1182 // make sure we go through set render target
1183 fHWDrawState.fRenderTarget = NULL;
1184
1185 GLint left = 0;
1186 GLint right = texture->contentWidth();
1187 // we will have rendered to the top of the FBO.
1188 GLint top = texture->allocHeight();
1189 GLint bottom = texture->allocHeight() - texture->contentHeight();
1190 if (kApple_MSFBO == fMSFBOType) {
1191 GR_GL(Enable(GL_SCISSOR_TEST));
1192 GR_GL(Scissor(left, bottom, right-left, top-bottom));
1193 GR_GLEXT(fExts, ResolveMultisampleFramebuffer());
1194 fHWBounds.fScissorRect.setEmpty();
1195 fHWBounds.fScissorEnabled = true;
1196 } else {
1197 GR_GLEXT(fExts, BlitFramebuffer(left, bottom, right, top,
1198 left, bottom, right, top,
1199 GL_COLOR_BUFFER_BIT, GL_NEAREST));
1200 }
1201 rt->setDirty(false);
1202
1203 }
1204}
1205
1206void GrGpuGL::flushStencil() {
1207
1208 // use stencil for clipping if clipping is enabled and the clip
1209 // has been written into the stencil.
1210 bool stencilClip = fClipState.fClipInStencil &&
1211 (kClip_StateBit & fCurrDrawState.fFlagBits);
1212 bool stencilChange =
1213 fWriteMaskChanged ||
1214 fHWStencilClip != stencilClip ||
1215 fHWDrawState.fStencilPass != fCurrDrawState.fStencilPass ||
1216 (kNone_StencilPass != fCurrDrawState.fStencilPass &&
1217 (StencilPass)kSetClip_StencilPass != fCurrDrawState.fStencilPass &&
1218 fHWDrawState.fReverseFill != fCurrDrawState.fReverseFill);
1219
1220 if (stencilChange) {
1221 GLint stencilBitCount;
1222 GLint clipStencilMask;
1223 GLint pathStencilMask;
reed@google.comac20fb92011-01-12 17:14:53 +00001224 GR_GL_GetIntegerv(GL_STENCIL_BITS, &stencilBitCount);
reed@google.comac10a2d2010-12-22 21:39:39 +00001225 GrAssert(stencilBitCount > 0 ||
1226 kNone_StencilPass == fCurrDrawState.fStencilPass);
1227 clipStencilMask = (1 << (stencilBitCount - 1));
1228 pathStencilMask = clipStencilMask - 1;
1229 switch (fCurrDrawState.fStencilPass) {
1230 case kNone_StencilPass:
1231 if (stencilClip) {
1232 GR_GL(Enable(GL_STENCIL_TEST));
1233 GR_GL(StencilFunc(GL_EQUAL,
1234 clipStencilMask,
1235 clipStencilMask));
1236 GR_GL(StencilOp(GL_KEEP, GL_KEEP, GL_KEEP));
1237 } else {
1238 GR_GL(Disable(GL_STENCIL_TEST));
1239 }
1240 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
1241 if (!fSingleStencilPassForWinding) {
1242 GR_GL(Disable(GL_CULL_FACE));
1243 }
1244 break;
1245 case kEvenOddStencil_StencilPass:
1246 GR_GL(Enable(GL_STENCIL_TEST));
1247 if (stencilClip) {
1248 GR_GL(StencilFunc(GL_EQUAL, clipStencilMask, clipStencilMask));
1249 } else {
1250 GR_GL(StencilFunc(GL_ALWAYS, 0x0, 0x0));
1251 }
1252 GR_GL(StencilMask(pathStencilMask));
1253 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
1254 GR_GL(StencilOp(GL_KEEP, GL_INVERT, GL_INVERT));
1255 GR_GL(ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE));
1256 if (!fSingleStencilPassForWinding) {
1257 GR_GL(Disable(GL_CULL_FACE));
1258 }
1259 break;
1260 case kEvenOddColor_StencilPass: {
1261 GR_GL(Enable(GL_STENCIL_TEST));
1262 GLint funcRef = 0;
1263 GLuint funcMask = pathStencilMask;
1264 if (stencilClip) {
1265 funcRef |= clipStencilMask;
1266 funcMask |= clipStencilMask;
1267 }
1268 if (!fCurrDrawState.fReverseFill) {
1269 funcRef |= pathStencilMask;
1270 }
bsalomon@google.com316f99232011-01-13 21:28:12 +00001271 GR_GL(StencilFunc(GL_EQUAL, funcRef, funcMask));
1272 GR_GL(StencilMask(pathStencilMask));
reed@google.comac10a2d2010-12-22 21:39:39 +00001273 GR_GL(StencilOp(GL_ZERO, GL_ZERO, GL_ZERO));
1274 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
1275 if (!fSingleStencilPassForWinding) {
1276 GR_GL(Disable(GL_CULL_FACE));
1277 }
1278 } break;
1279 case kWindingStencil1_StencilPass:
1280 GR_GL(Enable(GL_STENCIL_TEST));
1281 if (fHasStencilWrap) {
1282 if (stencilClip) {
1283 GR_GL(StencilFunc(GL_EQUAL,
1284 clipStencilMask,
1285 clipStencilMask));
1286 } else {
1287 GR_GL(StencilFunc(GL_ALWAYS, 0x0, 0x0));
1288 }
1289 if (fSingleStencilPassForWinding) {
1290 GR_GL(StencilOpSeparate(GL_FRONT, GL_KEEP,
1291 GL_INCR_WRAP, GL_INCR_WRAP));
1292 GR_GL(StencilOpSeparate(GL_BACK, GL_KEEP,
1293 GL_DECR_WRAP, GL_DECR_WRAP));
1294 } else {
1295 GR_GL(StencilOp(GL_KEEP, GL_INCR_WRAP, GL_INCR_WRAP));
1296 GR_GL(Enable(GL_CULL_FACE));
1297 GR_GL(CullFace(GL_BACK));
1298 }
1299 } else {
1300 // If we don't have wrap then we use the Func to detect
1301 // values that would wrap (0 on decr and mask on incr). We
1302 // make the func fail on these values and use the sfail op
1303 // to effectively wrap by inverting.
1304 // This applies whether we are doing a two-pass (front faces
1305 // followed by back faces) or a single pass (separate func/op)
1306
1307 // Note that in the case where we are also using stencil to
1308 // clip this means we will write into the path bits in clipped
1309 // out pixels. We still apply the clip bit in the color pass
1310 // stencil func so we don't draw color outside the clip.
1311 // We also will clear the stencil bits in clipped pixels by
1312 // using zero in the sfail op with write mask set to the
1313 // path mask.
1314 GR_GL(Enable(GL_STENCIL_TEST));
1315 if (fSingleStencilPassForWinding) {
1316 GR_GL(StencilFuncSeparate(GL_FRONT,
1317 GL_NOTEQUAL,
1318 pathStencilMask,
1319 pathStencilMask));
1320 GR_GL(StencilFuncSeparate(GL_BACK,
1321 GL_NOTEQUAL,
1322 0x0,
1323 pathStencilMask));
1324 GR_GL(StencilOpSeparate(GL_FRONT, GL_INVERT,
1325 GL_INCR, GL_INCR));
1326 GR_GL(StencilOpSeparate(GL_BACK, GL_INVERT,
1327 GL_DECR, GL_DECR));
1328 } else {
1329 GR_GL(StencilFunc(GL_NOTEQUAL,
1330 pathStencilMask,
1331 pathStencilMask));
1332 GR_GL(StencilOp(GL_INVERT, GL_INCR, GL_INCR));
1333 GR_GL(Enable(GL_CULL_FACE));
1334 GR_GL(CullFace(GL_BACK));
1335 }
1336 }
1337 GR_GL(StencilMask(pathStencilMask));
1338 GR_GL(ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE));
1339 break;
1340 case kWindingStencil2_StencilPass:
1341 GrAssert(!fSingleStencilPassForWinding);
1342 GR_GL(Enable(GL_STENCIL_TEST));
1343 if (fHasStencilWrap) {
1344 if (stencilClip) {
1345 GR_GL(StencilFunc(GL_EQUAL,
1346 clipStencilMask,
1347 clipStencilMask));
1348 } else {
1349 GR_GL(StencilFunc(GL_ALWAYS, 0x0, 0x0));
1350 }
1351 GR_GL(StencilOp(GL_DECR_WRAP, GL_DECR_WRAP, GL_DECR_WRAP));
1352 } else {
1353 GR_GL(StencilFunc(GL_NOTEQUAL, 0x0, pathStencilMask));
1354 GR_GL(StencilOp(GL_INVERT, GL_DECR, GL_DECR));
1355 }
1356 GR_GL(StencilMask(pathStencilMask));
1357 GR_GL(Enable(GL_CULL_FACE));
1358 GR_GL(CullFace(GL_FRONT));
1359 GR_GL(ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE));
1360 break;
1361 case kWindingColor_StencilPass: {
1362 GR_GL(Enable(GL_STENCIL_TEST));
1363 GLint funcRef = 0;
1364 GLuint funcMask = pathStencilMask;
1365 GLenum funcFunc;
1366 if (stencilClip) {
1367 funcRef |= clipStencilMask;
1368 funcMask |= clipStencilMask;
1369 }
1370 if (fCurrDrawState.fReverseFill) {
1371 funcFunc = GL_EQUAL;
1372 } else {
1373 funcFunc = GL_LESS;
1374 }
1375 GR_GL(StencilFunc(funcFunc, funcRef, funcMask));
1376 GR_GL(StencilMask(pathStencilMask));
1377 // must zero in sfail because winding w/o wrap will write
1378 // path stencil bits in clipped out pixels
1379 GR_GL(StencilOp(GL_ZERO, GL_ZERO, GL_ZERO));
1380 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
1381 if (!fSingleStencilPassForWinding) {
1382 GR_GL(Disable(GL_CULL_FACE));
1383 }
1384 } break;
1385 case kSetClip_StencilPass:
1386 GR_GL(Enable(GL_STENCIL_TEST));
1387 GR_GL(StencilFunc(GL_ALWAYS, clipStencilMask, clipStencilMask));
1388 GR_GL(StencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE));
1389 GR_GL(StencilMask(clipStencilMask));
1390 GR_GL(ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE));
1391 if (!fSingleStencilPassForWinding) {
1392 GR_GL(Disable(GL_CULL_FACE));
1393 }
1394 break;
1395 default:
1396 GrAssert(!"Unexpected stencil pass.");
1397 break;
1398
1399 }
1400 fHWDrawState.fStencilPass = fCurrDrawState.fStencilPass;
1401 fHWDrawState.fReverseFill = fCurrDrawState.fReverseFill;
1402 fWriteMaskChanged = false;
1403 fHWStencilClip = stencilClip;
1404 }
1405}
1406
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001407bool GrGpuGL::flushGLStateCommon(PrimitiveType type) {
1408
1409 // GrGpu::setupClipAndFlushState should have already checked this
1410 // and bailed if not true.
1411 GrAssert(NULL != fCurrDrawState.fRenderTarget);
reed@google.comac10a2d2010-12-22 21:39:39 +00001412
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001413 for (int s = 0; s < kNumStages; ++s) {
1414 bool usingTexture = VertexUsesStage(s, fGeometrySrc.fVertexLayout);
reed@google.comac10a2d2010-12-22 21:39:39 +00001415
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001416 // bind texture and set sampler state
1417 if (usingTexture) {
1418 GrGLTexture* nextTexture = (GrGLTexture*)fCurrDrawState.fTextures[s];
reed@google.comac10a2d2010-12-22 21:39:39 +00001419
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001420 if (NULL != nextTexture) {
bsalomon@google.com316f99232011-01-13 21:28:12 +00001421 // if we created a rt/tex and rendered to it without using a
1422 // texture and now we're texuring from the rt it will still be
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001423 // the last bound texture, but it needs resolving. So keep this
1424 // out of the "last != next" check.
1425 resolveTextureRenderTarget(nextTexture);
reed@google.comac10a2d2010-12-22 21:39:39 +00001426
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001427 if (fHWDrawState.fTextures[s] != nextTexture) {
1428 setTextureUnit(s);
1429 GR_GL(BindTexture(GL_TEXTURE_2D, nextTexture->textureID()));
1430 #if GR_COLLECT_STATS
1431 ++fStats.fTextureChngCnt;
1432 #endif
1433 //GrPrintf("---- bindtexture %d\n", nextTexture->textureID());
1434 fHWDrawState.fTextures[s] = nextTexture;
1435 }
bsalomon@google.com316f99232011-01-13 21:28:12 +00001436
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001437 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
bsalomon@google.com316f99232011-01-13 21:28:12 +00001438 const GrGLTexture::TexParams& oldTexParams =
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001439 nextTexture->getTexParams();
1440 GrGLTexture::TexParams newTexParams;
bsalomon@google.com316f99232011-01-13 21:28:12 +00001441
1442 newTexParams.fFilter = sampler.isFilter() ? GL_LINEAR :
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001443 GL_NEAREST;
bsalomon@google.com316f99232011-01-13 21:28:12 +00001444 newTexParams.fWrapS =
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001445 GrGLTexture::gWrapMode2GLWrap[sampler.getWrapX()];
bsalomon@google.com316f99232011-01-13 21:28:12 +00001446 newTexParams.fWrapT =
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001447 GrGLTexture::gWrapMode2GLWrap[sampler.getWrapY()];
reed@google.comac10a2d2010-12-22 21:39:39 +00001448
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001449 if (newTexParams.fFilter != oldTexParams.fFilter) {
1450 setTextureUnit(s);
bsalomon@google.com316f99232011-01-13 21:28:12 +00001451 GR_GL(TexParameteri(GL_TEXTURE_2D,
1452 GL_TEXTURE_MAG_FILTER,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001453 newTexParams.fFilter));
bsalomon@google.com316f99232011-01-13 21:28:12 +00001454 GR_GL(TexParameteri(GL_TEXTURE_2D,
1455 GL_TEXTURE_MIN_FILTER,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001456 newTexParams.fFilter));
1457 }
1458 if (newTexParams.fWrapS != oldTexParams.fWrapS) {
1459 setTextureUnit(s);
bsalomon@google.com316f99232011-01-13 21:28:12 +00001460 GR_GL(TexParameteri(GL_TEXTURE_2D,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001461 GL_TEXTURE_WRAP_S,
1462 newTexParams.fWrapS));
1463 }
1464 if (newTexParams.fWrapT != oldTexParams.fWrapT) {
1465 setTextureUnit(s);
bsalomon@google.com316f99232011-01-13 21:28:12 +00001466 GR_GL(TexParameteri(GL_TEXTURE_2D,
1467 GL_TEXTURE_WRAP_T,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001468 newTexParams.fWrapT));
1469 }
1470 nextTexture->setTexParams(newTexParams);
1471 } else {
1472 GrAssert(!"Rendering with texture vert flag set but no texture");
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001473 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +00001474 }
1475 }
1476 }
1477
1478 flushRenderTarget();
1479
1480 if ((fCurrDrawState.fFlagBits & kDither_StateBit) !=
1481 (fHWDrawState.fFlagBits & kDither_StateBit)) {
1482 if (fCurrDrawState.fFlagBits & kDither_StateBit) {
1483 GR_GL(Enable(GL_DITHER));
1484 } else {
1485 GR_GL(Disable(GL_DITHER));
1486 }
1487 }
1488
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001489#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +00001490 // ES doesn't support toggling GL_MULTISAMPLE and doesn't have
1491 // smooth lines.
1492 if (fRenderTargetChanged ||
1493 (fCurrDrawState.fFlagBits & kAntialias_StateBit) !=
1494 (fHWDrawState.fFlagBits & kAntialias_StateBit)) {
1495 GLint msaa = 0;
1496 // only perform query if we know MSAA is supported.
1497 // calling on non-MSAA target caused a crash in one environment,
1498 // though I don't think it should.
1499 if (!fAASamples[kHigh_AALevel]) {
reed@google.comac20fb92011-01-12 17:14:53 +00001500 GR_GL_GetIntegerv(GL_SAMPLE_BUFFERS, &msaa);
reed@google.comac10a2d2010-12-22 21:39:39 +00001501 }
1502 if (fCurrDrawState.fFlagBits & kAntialias_StateBit) {
1503 if (msaa) {
1504 GR_GL(Enable(GL_MULTISAMPLE));
1505 } else {
1506 GR_GL(Enable(GL_LINE_SMOOTH));
1507 }
1508 } else {
1509 if (msaa) {
1510 GR_GL(Disable(GL_MULTISAMPLE));
1511 }
1512 GR_GL(Disable(GL_LINE_SMOOTH));
1513 }
1514 }
1515#endif
1516
1517 bool blendOff = canDisableBlend();
1518 if (fHWBlendDisabled != blendOff) {
1519 if (blendOff) {
1520 GR_GL(Disable(GL_BLEND));
1521 } else {
1522 GR_GL(Enable(GL_BLEND));
1523 }
1524 fHWBlendDisabled = blendOff;
1525 }
1526
1527 if (!blendOff) {
1528 if (fHWDrawState.fSrcBlend != fCurrDrawState.fSrcBlend ||
1529 fHWDrawState.fDstBlend != fCurrDrawState.fDstBlend) {
1530 GR_GL(BlendFunc(gXfermodeCoeff2Blend[fCurrDrawState.fSrcBlend],
1531 gXfermodeCoeff2Blend[fCurrDrawState.fDstBlend]));
1532 fHWDrawState.fSrcBlend = fCurrDrawState.fSrcBlend;
1533 fHWDrawState.fDstBlend = fCurrDrawState.fDstBlend;
1534 }
1535 }
bsalomon@google.com316f99232011-01-13 21:28:12 +00001536
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001537#if GR_DEBUG
reed@google.comac10a2d2010-12-22 21:39:39 +00001538 // check for circular rendering
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001539 for (int s = 0; s < kNumStages; ++s) {
1540 GrAssert(!VertexUsesStage(s, fGeometrySrc.fVertexLayout) ||
1541 NULL == fCurrDrawState.fRenderTarget ||
1542 NULL == fCurrDrawState.fTextures[s] ||
bsalomon@google.com316f99232011-01-13 21:28:12 +00001543 fCurrDrawState.fTextures[s]->asRenderTarget() !=
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001544 fCurrDrawState.fRenderTarget);
1545 }
1546#endif
bsalomon@google.com316f99232011-01-13 21:28:12 +00001547
reed@google.comac10a2d2010-12-22 21:39:39 +00001548 flushStencil();
1549
1550 fHWDrawState.fFlagBits = fCurrDrawState.fFlagBits;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001551 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +00001552}
1553
1554void GrGpuGL::notifyVertexBufferBind(const GrGLVertexBuffer* buffer) {
1555 fHWGeometryState.fVertexBuffer = buffer;
1556}
1557
1558void GrGpuGL::notifyVertexBufferDelete(const GrGLVertexBuffer* buffer) {
1559 GrAssert(!(kBuffer_GeometrySrcType == fGeometrySrc.fVertexSrc &&
1560 buffer == fGeometrySrc.fVertexBuffer));
1561
1562 if (fHWGeometryState.fVertexBuffer == buffer) {
1563 // deleting bound buffer does implied bind to 0
1564 fHWGeometryState.fVertexBuffer = NULL;
1565 }
1566}
1567
1568void GrGpuGL::notifyIndexBufferBind(const GrGLIndexBuffer* buffer) {
1569 fGeometrySrc.fIndexBuffer = buffer;
1570}
1571
1572void GrGpuGL::notifyIndexBufferDelete(const GrGLIndexBuffer* buffer) {
1573 GrAssert(!(kBuffer_GeometrySrcType == fGeometrySrc.fIndexSrc &&
1574 buffer == fGeometrySrc.fIndexBuffer));
1575
1576 if (fHWGeometryState.fIndexBuffer == buffer) {
1577 // deleting bound buffer does implied bind to 0
1578 fHWGeometryState.fIndexBuffer = NULL;
1579 }
1580}
1581
reed@google.comac10a2d2010-12-22 21:39:39 +00001582void GrGpuGL::notifyRenderTargetDelete(GrRenderTarget* renderTarget) {
1583 GrAssert(NULL != renderTarget);
1584
1585 // if the bound FBO is destroyed we can't rely on the implicit bind to 0
1586 // a) we want the default RT which may not be FBO 0
1587 // b) we set more state than just FBO based on the RT
1588 // So trash the HW state to force an RT flush next time
1589 if (fCurrDrawState.fRenderTarget == renderTarget) {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001590 fCurrDrawState.fRenderTarget = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +00001591 }
1592 if (fHWDrawState.fRenderTarget == renderTarget) {
1593 fHWDrawState.fRenderTarget = NULL;
1594 }
1595 if (fClipState.fStencilClipTarget == renderTarget) {
1596 fClipState.fStencilClipTarget = NULL;
1597 }
1598}
1599
1600void GrGpuGL::notifyTextureDelete(GrGLTexture* texture) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001601 for (int s = 0; s < kNumStages; ++s) {
1602 if (fCurrDrawState.fTextures[s] == texture) {
1603 fCurrDrawState.fTextures[s] = NULL;
1604 }
1605 if (fHWDrawState.fTextures[s] == texture) {
1606 // deleting bound texture does implied bind to 0
1607 fHWDrawState.fTextures[s] = NULL;
1608 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001609 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001610}
1611
1612void GrGpuGL::notifyTextureRemoveRenderTarget(GrGLTexture* texture) {
1613 GrAssert(NULL != texture->asRenderTarget());
1614
1615 // if there is a pending resolve, perform it.
1616 resolveTextureRenderTarget(texture);
1617}
1618
1619bool GrGpuGL::canBeTexture(GrTexture::PixelConfig config,
1620 GLenum* internalFormat,
1621 GLenum* format,
1622 GLenum* type) {
1623 switch (config) {
1624 case GrTexture::kRGBA_8888_PixelConfig:
1625 case GrTexture::kRGBX_8888_PixelConfig: // todo: can we tell it our X?
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +00001626 *format = GR_GL_32BPP_COLOR_FORMAT;
reed@google.com63100f92011-01-18 21:32:14 +00001627#if GR_SUPPORT_GLES
1628 // according to GL_EXT_texture_format_BGRA8888 the *internal*
1629 // format for a BGRA is BGRA not RGBA (as on desktop)
1630 *internalFormat = GR_GL_32BPP_COLOR_FORMAT;
1631#else
1632 *internalFormat = GL_RGBA;
bsalomon@google.comed3a0682011-01-18 16:54:04 +00001633#endif
reed@google.comac10a2d2010-12-22 21:39:39 +00001634 *type = GL_UNSIGNED_BYTE;
1635 break;
1636 case GrTexture::kRGB_565_PixelConfig:
1637 *format = GL_RGB;
1638 *internalFormat = GL_RGB;
1639 *type = GL_UNSIGNED_SHORT_5_6_5;
1640 break;
1641 case GrTexture::kRGBA_4444_PixelConfig:
1642 *format = GL_RGBA;
1643 *internalFormat = GL_RGBA;
1644 *type = GL_UNSIGNED_SHORT_4_4_4_4;
1645 break;
1646 case GrTexture::kIndex_8_PixelConfig:
1647 if (this->supports8BitPalette()) {
1648 *format = GR_PALETTE8_RGBA8;
1649 *internalFormat = GR_PALETTE8_RGBA8;
1650 *type = GL_UNSIGNED_BYTE; // unused I think
1651 } else {
1652 return false;
1653 }
1654 break;
1655 case GrTexture::kAlpha_8_PixelConfig:
1656 *format = GL_ALPHA;
1657 *internalFormat = GL_ALPHA;
1658 *type = GL_UNSIGNED_BYTE;
1659 break;
1660 default:
1661 return false;
1662 }
1663 return true;
1664}
1665
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001666void GrGpuGL::setTextureUnit(int unit) {
1667 GrAssert(unit >= 0 && unit < kNumStages);
1668 if (fActiveTextureUnitIdx != unit) {
1669 GR_GL(ActiveTexture(GL_TEXTURE0 + unit));
1670 fActiveTextureUnitIdx = unit;
1671 }
1672}
bsalomon@google.com316f99232011-01-13 21:28:12 +00001673
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001674void GrGpuGL::setSpareTextureUnit() {
1675 if (fActiveTextureUnitIdx != (GL_TEXTURE0 + SPARE_TEX_UNIT)) {
1676 GR_GL(ActiveTexture(GL_TEXTURE0 + SPARE_TEX_UNIT));
1677 fActiveTextureUnitIdx = SPARE_TEX_UNIT;
1678 }
1679}
1680
reed@google.comac10a2d2010-12-22 21:39:39 +00001681/* On ES the internalFormat and format must match for TexImage and we use
1682 GL_RGB, GL_RGBA for color formats. We also generally like having the driver
1683 decide the internalFormat. However, on ES internalFormat for
1684 RenderBufferStorage* has to be a specific format (not a base format like
1685 GL_RGBA).
1686 */
1687bool GrGpuGL::fboInternalFormat(GrTexture::PixelConfig config, GLenum* format) {
1688 switch (config) {
1689 case GrTexture::kRGBA_8888_PixelConfig:
1690 case GrTexture::kRGBX_8888_PixelConfig:
1691 if (fRGBA8Renderbuffer) {
1692 *format = GR_RGBA8;
1693 return true;
1694 } else {
1695 return false;
1696 }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001697#if GR_SUPPORT_GLES // ES2 supports 565. ES1 supports it with FBO extension
1698 // desktop GL has no such internal format
reed@google.comac10a2d2010-12-22 21:39:39 +00001699 case GrTexture::kRGB_565_PixelConfig:
1700 *format = GR_RGB565;
1701 return true;
1702#endif
1703 case GrTexture::kRGBA_4444_PixelConfig:
1704 *format = GL_RGBA4;
1705 return true;
1706 default:
1707 return false;
1708 }
1709}