blob: 0198481c9d7c4306f2c2743ced78e08b344096b6 [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;
61 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
114 GR_GL(GetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextureUnits));
115 GrAssert(maxTextureUnits > kNumStages);
116#endif
117#if GR_SUPPORT_GLDESKTOP || GR_SUPPORT_GLES1
118 GR_GL(GetIntegerv(GL_MAX_TEXTURE_UNITS, &maxTextureUnits));
119 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;
418 fHWDrawState.fPointSize = -1;
bsalomon@google.com316f99232011-01-13 21:28:12 +0000419
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000420 fHWDrawState.fViewMatrix.setScale(GR_ScalarMax, GR_ScalarMax); // illegal
bsalomon@google.com316f99232011-01-13 21:28:12 +0000421
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000422 for (int s = 0; s < kNumStages; ++s) {
423 fHWDrawState.fTextures[s] = NULL;
424 fHWDrawState.fSamplerStates[s].setRadial2Params(-GR_ScalarMax,
425 -GR_ScalarMax,
426 true);
bsalomon@google.com316f99232011-01-13 21:28:12 +0000427 fHWDrawState.fTextureMatrices[s].setScale(GR_ScalarMax, GR_ScalarMax);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000428 }
bsalomon@google.com316f99232011-01-13 21:28:12 +0000429
reed@google.comac10a2d2010-12-22 21:39:39 +0000430 GR_GL(Scissor(0,0,0,0));
431 fHWBounds.fScissorRect.setLTRB(0,0,0,0);
432 fHWBounds.fScissorEnabled = false;
433 GR_GL(Disable(GL_SCISSOR_TEST));
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000434 fHWBounds.fViewportRect.setLTRB(-1,-1,-1,-1);
reed@google.comac10a2d2010-12-22 21:39:39 +0000435
reed@google.comac10a2d2010-12-22 21:39:39 +0000436 // disabling the stencil test also disables
437 // stencil buffer writes
438 GR_GL(Disable(GL_STENCIL_TEST));
439 GR_GL(StencilMask(0xffffffff));
440 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
441 fHWDrawState.fReverseFill = false;
442 fHWDrawState.fStencilPass = kNone_StencilPass;
443 fHWStencilClip = false;
444
445 fHWGeometryState.fIndexBuffer = NULL;
446 fHWGeometryState.fVertexBuffer = NULL;
447 GR_GL(BindBuffer(GL_ARRAY_BUFFER, 0));
448 GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
449
450 fHWDrawState.fRenderTarget = NULL;
451}
452
453void GrGpuGL::resetContext() {
454 INHERITED::resetContext();
455 resetContextHelper();
456}
457
reed@google.comac10a2d2010-12-22 21:39:39 +0000458GrRenderTarget* GrGpuGL::createPlatformRenderTarget(
459 intptr_t platformRenderTarget,
460 int width, int height) {
461 GrGLRenderTarget::GLRenderTargetIDs rtIDs;
462 rtIDs.fStencilRenderbufferID = 0;
463 rtIDs.fMSColorRenderbufferID = 0;
464 rtIDs.fTexFBOID = 0;
465 rtIDs.fOwnIDs = false;
466
467 GrIRect viewport;
468
469 // viewport is in GL coords (top >= bottom)
470 viewport.setLTRB(0, height, width, 0);
471
472 rtIDs.fRTFBOID = (GLuint)platformRenderTarget;
473 rtIDs.fTexFBOID = (GLuint)platformRenderTarget;
474
475 GrGLRenderTarget* rt = new GrGLRenderTarget(rtIDs, viewport, NULL, this);
476
477 return rt;
478}
479
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000480GrRenderTarget* GrGpuGL::createRenderTargetFrom3DApiState() {
bsalomon@google.com42ab7ea2011-01-19 17:19:40 +0000481
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000482 GrGLRenderTarget::GLRenderTargetIDs rtIDs;
bsalomon@google.com42ab7ea2011-01-19 17:19:40 +0000483
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000484 GR_GL_GetIntegerv(GR_FRAMEBUFFER_BINDING, (GLint*)&rtIDs.fRTFBOID);
485 rtIDs.fTexFBOID = rtIDs.fRTFBOID;
486 rtIDs.fMSColorRenderbufferID = 0;
487 rtIDs.fStencilRenderbufferID = 0;
bsalomon@google.com42ab7ea2011-01-19 17:19:40 +0000488
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000489 GLint vp[4];
490 GR_GL_GetIntegerv(GL_VIEWPORT, vp);
491 GrIRect viewportRect;
492 viewportRect.setLTRB(vp[0],
493 vp[1] + vp[3],
494 vp[0] + vp[2],
495 vp[1]);
496 rtIDs.fOwnIDs = false;
497
498 return new GrGLRenderTarget(rtIDs,
499 viewportRect,
500 NULL,
501 this);
502}
503
bsalomon@google.com3f3ffd62011-01-18 17:14:52 +0000504// defines stencil formats from more to less preferred
reed@google.com63100f92011-01-18 21:32:14 +0000505GLenum GR_GL_STENCIL_FORMAT_ARRAY[] = {
506 GR_STENCIL_INDEX8,
507
508#if GR_SUPPORT_GLDESKTOP
509 GR_STENCIL_INDEX16,
510#endif
511
512 GR_DEPTH24_STENCIL8,
513 GR_STENCIL_INDEX4,
514
515#if GR_SUPPORT_GLDESKTOP
bsalomon@google.com3f3ffd62011-01-18 17:14:52 +0000516 GL_STENCIL_INDEX,
517 GR_DEPTH_STENCIL,
518#endif
519};
520
521// good to set a break-point here to know when createTexture fails
522static GrTexture* return_null_texture() {
523// GrAssert(!"null texture");
524 return NULL;
525}
526
527#if GR_DEBUG
528static size_t as_size_t(int x) {
529 return x;
530}
531#endif
532
reed@google.comac10a2d2010-12-22 21:39:39 +0000533GrTexture* GrGpuGL::createTexture(const TextureDesc& desc,
534 const void* srcData, size_t rowBytes) {
535
536#if GR_COLLECT_STATS
537 ++fStats.fTextureCreateCnt;
538#endif
reed@google.com1fcd51e2011-01-05 15:50:27 +0000539
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000540 setSpareTextureUnit();
bsalomon@google.com316f99232011-01-13 21:28:12 +0000541
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000542 static const GrGLTexture::TexParams DEFAULT_PARAMS = {
543 GL_NEAREST,
544 GL_CLAMP_TO_EDGE,
545 GL_CLAMP_TO_EDGE
546 };
reed@google.com1fcd51e2011-01-05 15:50:27 +0000547
reed@google.comac10a2d2010-12-22 21:39:39 +0000548 GrGLTexture::GLTextureDesc glDesc;
549 GLenum internalFormat;
550
551 glDesc.fContentWidth = desc.fWidth;
552 glDesc.fContentHeight = desc.fHeight;
553 glDesc.fAllocWidth = desc.fWidth;
554 glDesc.fAllocHeight = desc.fHeight;
555 glDesc.fFormat = desc.fFormat;
556
557 bool renderTarget = 0 != (desc.fFlags & kRenderTarget_TextureFlag);
558 if (!canBeTexture(desc.fFormat,
559 &internalFormat,
560 &glDesc.fUploadFormat,
561 &glDesc.fUploadType)) {
562 return return_null_texture();
563 }
564
565 GrAssert(as_size_t(desc.fAALevel) < GR_ARRAY_COUNT(fAASamples));
566 GLint samples = fAASamples[desc.fAALevel];
567 if (kNone_MSFBO == fMSFBOType && desc.fAALevel != kNone_AALevel) {
568 GrPrintf("AA RT requested but not supported on this platform.");
569 }
570
571 GR_GL(GenTextures(1, &glDesc.fTextureID));
572 if (!glDesc.fTextureID) {
573 return return_null_texture();
574 }
575
576 glDesc.fUploadByteCount = GrTexture::BytesPerPixel(desc.fFormat);
577
578 /*
579 * check if our srcData has extra bytes past each row. If so, we need
580 * to trim those off here, since GL doesn't let us pass the rowBytes as
581 * a parameter to glTexImage2D
582 */
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000583#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000584 if (srcData) {
585 GR_GL(PixelStorei(GL_UNPACK_ROW_LENGTH,
586 rowBytes / glDesc.fUploadByteCount));
587 }
588#else
589 GrAutoSMalloc<128 * 128> trimStorage;
590 size_t trimRowBytes = desc.fWidth * glDesc.fUploadByteCount;
591 if (srcData && (trimRowBytes < rowBytes)) {
592 size_t trimSize = desc.fHeight * trimRowBytes;
593 trimStorage.realloc(trimSize);
594 // now copy the data into our new storage, skipping the trailing bytes
595 const char* src = (const char*)srcData;
596 char* dst = (char*)trimStorage.get();
597 for (uint32_t y = 0; y < desc.fHeight; y++) {
598 memcpy(dst, src, trimRowBytes);
599 src += rowBytes;
600 dst += trimRowBytes;
601 }
602 // now point srcData to our trimmed version
603 srcData = trimStorage.get();
604 }
605#endif
606
607 if (fNPOTTextureSupport < kNonRendertarget_NPOTTextureType ||
608 (fNPOTTextureSupport == kNonRendertarget_NPOTTextureType &&
609 renderTarget)) {
610 glDesc.fAllocWidth = GrNextPow2(desc.fWidth);
611 glDesc.fAllocHeight = GrNextPow2(desc.fHeight);
612 }
613
614 if (renderTarget) {
615 glDesc.fAllocWidth = GrMax<int>(fMinRenderTargetWidth,
616 glDesc.fAllocWidth);
617 glDesc.fAllocHeight = GrMax<int>(fMinRenderTargetHeight,
618 glDesc.fAllocHeight);
619 }
620
621 GR_GL(BindTexture(GL_TEXTURE_2D, glDesc.fTextureID));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000622 GR_GL(TexParameteri(GL_TEXTURE_2D,
623 GL_TEXTURE_MAG_FILTER,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000624 DEFAULT_PARAMS.fFilter));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000625 GR_GL(TexParameteri(GL_TEXTURE_2D,
626 GL_TEXTURE_MIN_FILTER,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000627 DEFAULT_PARAMS.fFilter));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000628 GR_GL(TexParameteri(GL_TEXTURE_2D,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000629 GL_TEXTURE_WRAP_S,
630 DEFAULT_PARAMS.fWrapS));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000631 GR_GL(TexParameteri(GL_TEXTURE_2D,
632 GL_TEXTURE_WRAP_T,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000633 DEFAULT_PARAMS.fWrapT));
reed@google.comac10a2d2010-12-22 21:39:39 +0000634
635 GR_GL(PixelStorei(GL_UNPACK_ALIGNMENT, glDesc.fUploadByteCount));
636 if (GrTexture::kIndex_8_PixelConfig == desc.fFormat &&
637 supports8BitPalette()) {
638 // ES only supports CompressedTexImage2D, not CompressedTexSubimage2D
639 GrAssert(desc.fWidth == glDesc.fAllocWidth);
640 GrAssert(desc.fHeight == glDesc.fAllocHeight);
641 GLsizei imageSize = glDesc.fAllocWidth * glDesc.fAllocHeight +
642 kColorTableSize;
643 GR_GL(CompressedTexImage2D(GL_TEXTURE_2D, 0, glDesc.fUploadFormat,
644 glDesc.fAllocWidth, glDesc.fAllocHeight,
645 0, imageSize, srcData));
646 GrGL_RestoreResetRowLength();
647 } else {
648 if (NULL != srcData && (glDesc.fAllocWidth != desc.fWidth ||
649 glDesc.fAllocHeight != desc.fHeight)) {
650 GR_GL(TexImage2D(GL_TEXTURE_2D, 0, internalFormat,
651 glDesc.fAllocWidth, glDesc.fAllocHeight,
652 0, glDesc.fUploadFormat, glDesc.fUploadType, NULL));
653 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, desc.fWidth,
654 desc.fHeight, glDesc.fUploadFormat,
655 glDesc.fUploadType, srcData));
656 GrGL_RestoreResetRowLength();
657
658 uint32_t extraW = glDesc.fAllocWidth - desc.fWidth;
659 uint32_t extraH = glDesc.fAllocHeight - desc.fHeight;
660 uint32_t maxTexels = extraW * extraH;
661 maxTexels = GrMax(extraW * desc.fHeight, maxTexels);
662 maxTexels = GrMax(desc.fWidth * extraH, maxTexels);
663
664 GrAutoSMalloc<128*128> texels(glDesc.fUploadByteCount * maxTexels);
665
666 uint32_t rowSize = desc.fWidth * glDesc.fUploadByteCount;
667 if (extraH) {
668 uint8_t* lastRowStart = (uint8_t*) srcData +
669 (desc.fHeight - 1) * rowSize;
670 uint8_t* extraRowStart = (uint8_t*)texels.get();
671
672 for (uint32_t i = 0; i < extraH; ++i) {
673 memcpy(extraRowStart, lastRowStart, rowSize);
674 extraRowStart += rowSize;
675 }
676 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, 0, desc.fHeight, desc.fWidth,
677 extraH, glDesc.fUploadFormat, glDesc.fUploadType,
678 texels.get()));
679 }
680 if (extraW) {
681 uint8_t* edgeTexel = (uint8_t*)srcData + rowSize - glDesc.fUploadByteCount;
682 uint8_t* extraTexel = (uint8_t*)texels.get();
683 for (uint32_t j = 0; j < desc.fHeight; ++j) {
684 for (uint32_t i = 0; i < extraW; ++i) {
685 memcpy(extraTexel, edgeTexel, glDesc.fUploadByteCount);
686 extraTexel += glDesc.fUploadByteCount;
687 }
688 edgeTexel += rowSize;
689 }
690 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, desc.fWidth, 0, extraW,
691 desc.fHeight, glDesc.fUploadFormat,
692 glDesc.fUploadType, texels.get()));
693 }
694 if (extraW && extraH) {
695 uint8_t* cornerTexel = (uint8_t*)srcData + desc.fHeight * rowSize
696 - glDesc.fUploadByteCount;
697 uint8_t* extraTexel = (uint8_t*)texels.get();
698 for (uint32_t i = 0; i < extraW*extraH; ++i) {
699 memcpy(extraTexel, cornerTexel, glDesc.fUploadByteCount);
700 extraTexel += glDesc.fUploadByteCount;
701 }
702 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, desc.fWidth, desc.fHeight,
703 extraW, extraH, glDesc.fUploadFormat,
704 glDesc.fUploadType, texels.get()));
705 }
706
707 } else {
708 GR_GL(TexImage2D(GL_TEXTURE_2D, 0, internalFormat, glDesc.fAllocWidth,
709 glDesc.fAllocHeight, 0, glDesc.fUploadFormat,
710 glDesc.fUploadType, srcData));
711 GrGL_RestoreResetRowLength();
712 }
713 }
714
715 glDesc.fOrientation = GrGLTexture::kTopDown_Orientation;
716
717 GrGLRenderTarget::GLRenderTargetIDs rtIDs;
718 rtIDs.fStencilRenderbufferID = 0;
719 rtIDs.fMSColorRenderbufferID = 0;
720 rtIDs.fRTFBOID = 0;
721 rtIDs.fTexFBOID = 0;
722 rtIDs.fOwnIDs = true;
723 GLenum msColorRenderbufferFormat = -1;
724
725 if (renderTarget) {
726#if GR_COLLECT_STATS
727 ++fStats.fRenderTargetCreateCnt;
728#endif
729 bool failed = true;
730 GLenum status;
731 GLint err;
732
733 // If need have both RT flag and srcData we have
734 // to invert the data before uploading because FBO
735 // will be rendered bottom up
736 GrAssert(NULL == srcData);
737 glDesc.fOrientation = GrGLTexture::kBottomUp_Orientation;
738
739 GR_GLEXT(fExts, GenFramebuffers(1, &rtIDs.fTexFBOID));
740 GrAssert(rtIDs.fTexFBOID);
741
742 // If we are using multisampling and any extension other than the IMG
743 // one we will create two FBOs. We render to one and then resolve to
744 // the texture bound to the other. The IMG extension does an implicit
745 // resolve.
746 if (samples > 1 && kIMG_MSFBO != fMSFBOType && kNone_MSFBO != fMSFBOType) {
747 GR_GLEXT(fExts, GenFramebuffers(1, &rtIDs.fRTFBOID));
748 GrAssert(0 != rtIDs.fRTFBOID);
749 GR_GLEXT(fExts, GenRenderbuffers(1, &rtIDs.fMSColorRenderbufferID));
750 GrAssert(0 != rtIDs.fMSColorRenderbufferID);
751 if (!fboInternalFormat(desc.fFormat, &msColorRenderbufferFormat)) {
752 GR_GLEXT(fExts,
753 DeleteRenderbuffers(1, &rtIDs.fMSColorRenderbufferID));
754 GR_GL(DeleteTextures(1, &glDesc.fTextureID));
755 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fTexFBOID));
756 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fRTFBOID));
reed@google.comac10a2d2010-12-22 21:39:39 +0000757 return return_null_texture();
758 }
759 } else {
760 rtIDs.fRTFBOID = rtIDs.fTexFBOID;
761 }
762 int attempts = 1;
763 if (!(kNoPathRendering_TextureFlag & desc.fFlags)) {
764 GR_GLEXT(fExts, GenRenderbuffers(1, &rtIDs.fStencilRenderbufferID));
765 GrAssert(0 != rtIDs.fStencilRenderbufferID);
766 attempts = GR_ARRAY_COUNT(GR_GL_STENCIL_FORMAT_ARRAY);
767 }
768
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000769 // someone suggested that some systems might require
bsalomon@google.com316f99232011-01-13 21:28:12 +0000770 // unbinding the texture before we call FramebufferTexture2D
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000771 // (seems unlikely)
reed@google.comac10a2d2010-12-22 21:39:39 +0000772 GR_GL(BindTexture(GL_TEXTURE_2D, 0));
reed@google.comac10a2d2010-12-22 21:39:39 +0000773
774 err = ~GL_NO_ERROR;
775 for (int i = 0; i < attempts; ++i) {
776 if (rtIDs.fStencilRenderbufferID) {
777 GR_GLEXT(fExts, BindRenderbuffer(GR_RENDERBUFFER,
778 rtIDs.fStencilRenderbufferID));
779 if (samples > 1) {
780 GR_GLEXT_NO_ERR(fExts, RenderbufferStorageMultisample(
781 GR_RENDERBUFFER,
782 samples,
783 GR_GL_STENCIL_FORMAT_ARRAY[i],
784 glDesc.fAllocWidth,
785 glDesc.fAllocHeight));
786 } else {
787 GR_GLEXT_NO_ERR(fExts, RenderbufferStorage(
788 GR_RENDERBUFFER,
789 GR_GL_STENCIL_FORMAT_ARRAY[i],
790 glDesc.fAllocWidth,
791 glDesc.fAllocHeight));
792 }
793 err = glGetError();
794 if (err != GL_NO_ERROR) {
795 continue;
796 }
797 }
798 if (rtIDs.fRTFBOID != rtIDs.fTexFBOID) {
799 GrAssert(samples > 1);
800 GR_GLEXT(fExts, BindRenderbuffer(GR_RENDERBUFFER,
801 rtIDs.fMSColorRenderbufferID));
802 GR_GLEXT_NO_ERR(fExts, RenderbufferStorageMultisample(
803 GR_RENDERBUFFER,
804 samples,
805 msColorRenderbufferFormat,
806 glDesc.fAllocWidth,
807 glDesc.fAllocHeight));
808 err = glGetError();
809 if (err != GL_NO_ERROR) {
810 continue;
811 }
812 }
813 GR_GLEXT(fExts, BindFramebuffer(GR_FRAMEBUFFER, rtIDs.fTexFBOID));
814
815#if GR_COLLECT_STATS
816 ++fStats.fRenderTargetChngCnt;
817#endif
818 if (kIMG_MSFBO == fMSFBOType && samples > 1) {
819 GR_GLEXT(fExts, FramebufferTexture2DMultisample(
820 GR_FRAMEBUFFER,
821 GR_COLOR_ATTACHMENT0,
822 GL_TEXTURE_2D,
823 glDesc.fTextureID,
824 0,
825 samples));
826
827 } else {
828 GR_GLEXT(fExts, FramebufferTexture2D(GR_FRAMEBUFFER,
829 GR_COLOR_ATTACHMENT0,
830 GL_TEXTURE_2D,
831 glDesc.fTextureID, 0));
832 }
833 if (rtIDs.fRTFBOID != rtIDs.fTexFBOID) {
834 GLenum status = GR_GLEXT(fExts,
835 CheckFramebufferStatus(GR_FRAMEBUFFER));
836 if (status != GR_FRAMEBUFFER_COMPLETE) {
837 GrPrintf("-- glCheckFramebufferStatus %x %d %d\n",
838 status, desc.fWidth, desc.fHeight);
839 continue;
840 }
841 GR_GLEXT(fExts, BindFramebuffer(GR_FRAMEBUFFER, rtIDs.fRTFBOID));
842 #if GR_COLLECT_STATS
843 ++fStats.fRenderTargetChngCnt;
844 #endif
845 GR_GLEXT(fExts, FramebufferRenderbuffer(GR_FRAMEBUFFER,
846 GR_COLOR_ATTACHMENT0,
847 GR_RENDERBUFFER,
848 rtIDs.fMSColorRenderbufferID));
849
850 }
851 if (rtIDs.fStencilRenderbufferID) {
852 // bind the stencil to rt fbo if present, othewise the tex fbo
853 GR_GLEXT(fExts, FramebufferRenderbuffer(GR_FRAMEBUFFER,
854 GR_STENCIL_ATTACHMENT,
bsalomon@google.com316f99232011-01-13 21:28:12 +0000855 GR_RENDERBUFFER,
reed@google.comac10a2d2010-12-22 21:39:39 +0000856 rtIDs.fStencilRenderbufferID));
857 }
858 status = GR_GLEXT(fExts, CheckFramebufferStatus(GR_FRAMEBUFFER));
859
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000860#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000861 // On some implementations you have to be bound as DEPTH_STENCIL.
862 // (Even binding to DEPTH and STENCIL separately with the same
863 // buffer doesn't work.)
864 if (rtIDs.fStencilRenderbufferID &&
865 status != GR_FRAMEBUFFER_COMPLETE) {
866 GR_GLEXT(fExts, FramebufferRenderbuffer(GR_FRAMEBUFFER,
867 GR_STENCIL_ATTACHMENT,
868 GR_RENDERBUFFER,
869 0));
870 GR_GLEXT(fExts,
871 FramebufferRenderbuffer(GR_FRAMEBUFFER,
872 GR_DEPTH_STENCIL_ATTACHMENT,
873 GR_RENDERBUFFER,
874 rtIDs.fStencilRenderbufferID));
875 status = GR_GLEXT(fExts, CheckFramebufferStatus(GR_FRAMEBUFFER));
876 }
877#endif
878 if (status != GR_FRAMEBUFFER_COMPLETE) {
879 GrPrintf("-- glCheckFramebufferStatus %x %d %d\n",
880 status, desc.fWidth, desc.fHeight);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000881#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000882 if (rtIDs.fStencilRenderbufferID) {
883 GR_GLEXT(fExts, FramebufferRenderbuffer(GR_FRAMEBUFFER,
884 GR_DEPTH_STENCIL_ATTACHMENT,
885 GR_RENDERBUFFER,
886 0));
887 }
888#endif
889 continue;
890 }
891 // we're successful!
892 failed = false;
893 break;
894 }
895 if (failed) {
896 if (rtIDs.fStencilRenderbufferID) {
897 GR_GLEXT(fExts,
898 DeleteRenderbuffers(1, &rtIDs.fStencilRenderbufferID));
899 }
900 if (rtIDs.fMSColorRenderbufferID) {
901 GR_GLEXT(fExts,
902 DeleteRenderbuffers(1, &rtIDs.fMSColorRenderbufferID));
903 }
904 if (rtIDs.fRTFBOID != rtIDs.fTexFBOID) {
905 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fRTFBOID));
906 }
907 if (rtIDs.fTexFBOID) {
908 GR_GLEXT(fExts, DeleteFramebuffers(1, &rtIDs.fTexFBOID));
909 }
910 GR_GL(DeleteTextures(1, &glDesc.fTextureID));
911 return return_null_texture();
912 }
913 }
914#ifdef TRACE_TEXTURE_CREATION
915 GrPrintf("--- new texture [%d] size=(%d %d) bpp=%d\n",
916 tex->fTextureID, width, height, tex->fUploadByteCount);
917#endif
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000918 GrGLTexture* tex = new GrGLTexture(glDesc, rtIDs, DEFAULT_PARAMS, this);
reed@google.comac10a2d2010-12-22 21:39:39 +0000919
920 if (0 != rtIDs.fTexFBOID) {
921 GrRenderTarget* rt = tex->asRenderTarget();
922 // We've messed with FBO state but may not have set the correct viewport
923 // so just dirty the rendertarget state to force a resend.
924 fHWDrawState.fRenderTarget = NULL;
925
926 // clear the new stencil buffer if we have one
927 if (!(desc.fFlags & kNoPathRendering_TextureFlag)) {
928 GrRenderTarget* rtSave = fCurrDrawState.fRenderTarget;
929 fCurrDrawState.fRenderTarget = rt;
930 eraseStencil(0, ~0);
931 fCurrDrawState.fRenderTarget = rtSave;
932 }
933 }
934 return tex;
935}
936
reed@google.comac10a2d2010-12-22 21:39:39 +0000937GrVertexBuffer* GrGpuGL::createVertexBuffer(uint32_t size, bool dynamic) {
938 GLuint id;
939 GR_GL(GenBuffers(1, &id));
940 if (id) {
941 GR_GL(BindBuffer(GL_ARRAY_BUFFER, id));
942 GrGLClearErr();
943 // make sure driver can allocate memory for this buffer
944 GR_GL_NO_ERR(BufferData(GL_ARRAY_BUFFER, size, NULL,
945 dynamic ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW));
946 if (glGetError() != GL_NO_ERROR) {
947 GR_GL(DeleteBuffers(1, &id));
948 // deleting bound buffer does implicit bind to 0
949 fHWGeometryState.fVertexBuffer = NULL;
950 return NULL;
951 }
952 GrGLVertexBuffer* vertexBuffer = new GrGLVertexBuffer(id, this,
953 size, dynamic);
954 fHWGeometryState.fVertexBuffer = vertexBuffer;
955 return vertexBuffer;
956 }
957 return NULL;
958}
959
960GrIndexBuffer* GrGpuGL::createIndexBuffer(uint32_t size, bool dynamic) {
961 GLuint id;
962 GR_GL(GenBuffers(1, &id));
963 if (id) {
964 GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, id));
965 GrGLClearErr();
966 // make sure driver can allocate memory for this buffer
967 GR_GL_NO_ERR(BufferData(GL_ELEMENT_ARRAY_BUFFER, size, NULL,
968 dynamic ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW));
969 if (glGetError() != GL_NO_ERROR) {
970 GR_GL(DeleteBuffers(1, &id));
971 // deleting bound buffer does implicit bind to 0
972 fHWGeometryState.fIndexBuffer = NULL;
973 return NULL;
974 }
975 GrIndexBuffer* indexBuffer = new GrGLIndexBuffer(id, this,
976 size, dynamic);
977 fHWGeometryState.fIndexBuffer = indexBuffer;
978 return indexBuffer;
979 }
980 return NULL;
981}
982
reed@google.comac10a2d2010-12-22 21:39:39 +0000983void GrGpuGL::flushScissor(const GrIRect* rect) {
984 GrAssert(NULL != fCurrDrawState.fRenderTarget);
985 const GrIRect& vp =
986 ((GrGLRenderTarget*)fCurrDrawState.fRenderTarget)->viewport();
987
988 if (NULL != rect &&
989 rect->contains(vp)) {
990 rect = NULL;
991 }
992
993 if (NULL != rect) {
994 GrIRect scissor;
995 // viewport is already in GL coords
996 // create a scissor in GL coords (top > bottom)
997 scissor.setLTRB(vp.fLeft + rect->fLeft,
998 vp.fTop - rect->fTop,
999 vp.fLeft + rect->fRight,
1000 vp.fTop - rect->fBottom);
1001
1002 if (fHWBounds.fScissorRect != scissor) {
1003 GR_GL(Scissor(scissor.fLeft, scissor.fBottom,
1004 scissor.width(), -scissor.height()));
1005 fHWBounds.fScissorRect = scissor;
1006 }
1007
1008 if (!fHWBounds.fScissorEnabled) {
1009 GR_GL(Enable(GL_SCISSOR_TEST));
1010 fHWBounds.fScissorEnabled = true;
1011 }
1012 } else {
1013 if (fHWBounds.fScissorEnabled) {
1014 GR_GL(Disable(GL_SCISSOR_TEST));
1015 fHWBounds.fScissorEnabled = false;
1016 }
1017 }
1018}
1019
reed@google.comac10a2d2010-12-22 21:39:39 +00001020void GrGpuGL::eraseColor(GrColor color) {
1021 flushRenderTarget();
1022 if (fHWBounds.fScissorEnabled) {
1023 GR_GL(Disable(GL_SCISSOR_TEST));
1024 }
1025 GR_GL(ColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE));
1026 GR_GL(ClearColor(GrColorUnpackR(color)/255.f,
1027 GrColorUnpackG(color)/255.f,
1028 GrColorUnpackB(color)/255.f,
1029 GrColorUnpackA(color)/255.f));
1030 GR_GL(Clear(GL_COLOR_BUFFER_BIT));
1031 fHWBounds.fScissorEnabled = false;
1032 fWriteMaskChanged = true;
1033}
1034
1035void GrGpuGL::eraseStencil(uint32_t value, uint32_t mask) {
1036 flushRenderTarget();
1037 if (fHWBounds.fScissorEnabled) {
1038 GR_GL(Disable(GL_SCISSOR_TEST));
1039 }
1040 GR_GL(StencilMask(mask));
1041 GR_GL(ClearStencil(value));
1042 GR_GL(Clear(GL_STENCIL_BUFFER_BIT));
1043 fHWBounds.fScissorEnabled = false;
1044 fWriteMaskChanged = true;
1045}
1046
1047void GrGpuGL::eraseStencilClip() {
1048 GLint stencilBitCount;
reed@google.comac20fb92011-01-12 17:14:53 +00001049 GR_GL_GetIntegerv(GL_STENCIL_BITS, &stencilBitCount);
reed@google.comac10a2d2010-12-22 21:39:39 +00001050 GrAssert(stencilBitCount > 0);
1051 GLint clipStencilMask = (1 << (stencilBitCount - 1));
1052 eraseStencil(0, clipStencilMask);
1053}
1054
1055void GrGpuGL::forceRenderTargetFlush() {
1056 flushRenderTarget();
1057}
1058
1059bool GrGpuGL::readPixels(int left, int top, int width, int height,
1060 GrTexture::PixelConfig config, void* buffer) {
1061 GLenum internalFormat; // we don't use this for glReadPixels
1062 GLenum format;
1063 GLenum type;
1064 if (!this->canBeTexture(config, &internalFormat, &format, &type)) {
1065 return false;
1066 }
1067
1068 GrAssert(NULL != fCurrDrawState.fRenderTarget);
1069 const GrIRect& vp = ((GrGLRenderTarget*)fCurrDrawState.fRenderTarget)->viewport();
1070
1071 // Brian says that viewport rects are already upside down (grrrrr)
bsalomon@google.com316f99232011-01-13 21:28:12 +00001072 GR_GL(ReadPixels(left, -vp.height() - top - height, width, height,
1073 format, type, buffer));
reed@google.comac10a2d2010-12-22 21:39:39 +00001074
1075 // now reverse the order of the rows, since GL's are bottom-to-top, but our
1076 // API presents top-to-bottom
1077 {
1078 size_t stride = width * GrTexture::BytesPerPixel(config);
1079 GrAutoMalloc rowStorage(stride);
1080 void* tmp = rowStorage.get();
1081
1082 const int halfY = height >> 1;
1083 char* top = reinterpret_cast<char*>(buffer);
1084 char* bottom = top + (height - 1) * stride;
1085 for (int y = 0; y < halfY; y++) {
1086 memcpy(tmp, top, stride);
1087 memcpy(top, bottom, stride);
1088 memcpy(bottom, tmp, stride);
1089 top += stride;
1090 bottom -= stride;
1091 }
1092 }
1093 return true;
1094}
1095
1096void GrGpuGL::flushRenderTarget() {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001097
1098 GrAssert(NULL != fCurrDrawState.fRenderTarget);
1099
reed@google.comac10a2d2010-12-22 21:39:39 +00001100 if (fHWDrawState.fRenderTarget != fCurrDrawState.fRenderTarget) {
1101 GrGLRenderTarget* rt = (GrGLRenderTarget*)fCurrDrawState.fRenderTarget;
1102 GR_GLEXT(fExts, BindFramebuffer(GR_FRAMEBUFFER, rt->renderFBOID()));
1103 #if GR_COLLECT_STATS
1104 ++fStats.fRenderTargetChngCnt;
1105 #endif
1106 rt->setDirty(true);
1107 #if GR_DEBUG
1108 GLenum status = GR_GLEXT(fExts, CheckFramebufferStatus(GR_FRAMEBUFFER));
1109 if (status != GR_FRAMEBUFFER_COMPLETE) {
1110 GrPrintf("-- glCheckFramebufferStatus %x\n", status);
1111 }
1112 #endif
1113 fHWDrawState.fRenderTarget = fCurrDrawState.fRenderTarget;
1114 const GrIRect& vp = rt->viewport();
1115 fRenderTargetChanged = true;
1116 if (fHWBounds.fViewportRect != vp) {
1117 GR_GL(Viewport(vp.fLeft,
1118 vp.fBottom,
1119 vp.width(),
1120 -vp.height()));
1121 fHWBounds.fViewportRect = vp;
1122 }
1123 }
1124}
1125
1126GLenum gPrimitiveType2GLMode[] = {
1127 GL_TRIANGLES,
1128 GL_TRIANGLE_STRIP,
1129 GL_TRIANGLE_FAN,
1130 GL_POINTS,
1131 GL_LINES,
1132 GL_LINE_STRIP
1133};
1134
1135void GrGpuGL::drawIndexedHelper(PrimitiveType type,
1136 uint32_t startVertex,
1137 uint32_t startIndex,
1138 uint32_t vertexCount,
1139 uint32_t indexCount) {
1140 GrAssert((size_t)type < GR_ARRAY_COUNT(gPrimitiveType2GLMode));
1141
1142 GLvoid* indices = (GLvoid*)(sizeof(uint16_t) * startIndex);
1143 if (kReserved_GeometrySrcType == fGeometrySrc.fIndexSrc) {
1144 indices = (GLvoid*)((intptr_t)indices + (intptr_t)fIndices.get());
1145 } else if (kArray_GeometrySrcType == fGeometrySrc.fIndexSrc) {
1146 indices = (GLvoid*)((intptr_t)indices +
1147 (intptr_t)fGeometrySrc.fIndexArray);
1148 }
1149
1150 GR_GL(DrawElements(gPrimitiveType2GLMode[type], indexCount,
1151 GL_UNSIGNED_SHORT, indices));
1152}
1153
1154void GrGpuGL::drawNonIndexedHelper(PrimitiveType type,
1155 uint32_t startVertex,
1156 uint32_t vertexCount) {
1157 GrAssert((size_t)type < GR_ARRAY_COUNT(gPrimitiveType2GLMode));
1158
1159 GR_GL(DrawArrays(gPrimitiveType2GLMode[type], 0, vertexCount));
1160}
1161
1162#if !defined(SK_GL_HAS_COLOR4UB)
1163static inline GrFixed byte2fixed(unsigned value) {
1164 return (value + (value >> 7)) << 8;
1165}
1166#endif
1167
1168void GrGpuGL::resolveTextureRenderTarget(GrGLTexture* texture) {
1169 GrGLRenderTarget* rt = (GrGLRenderTarget*) texture->asRenderTarget();
1170
1171 if (NULL != rt && rt->needsResolve()) {
1172 GrAssert(kNone_MSFBO != fMSFBOType);
1173 GrAssert(rt->textureFBOID() != rt->renderFBOID());
1174 GR_GLEXT(fExts, BindFramebuffer(GR_READ_FRAMEBUFFER,
1175 rt->renderFBOID()));
1176 GR_GLEXT(fExts, BindFramebuffer(GR_DRAW_FRAMEBUFFER,
1177 rt->textureFBOID()));
1178 #if GR_COLLECT_STATS
1179 ++fStats.fRenderTargetChngCnt;
1180 #endif
1181 // make sure we go through set render target
1182 fHWDrawState.fRenderTarget = NULL;
1183
1184 GLint left = 0;
1185 GLint right = texture->contentWidth();
1186 // we will have rendered to the top of the FBO.
1187 GLint top = texture->allocHeight();
1188 GLint bottom = texture->allocHeight() - texture->contentHeight();
1189 if (kApple_MSFBO == fMSFBOType) {
1190 GR_GL(Enable(GL_SCISSOR_TEST));
1191 GR_GL(Scissor(left, bottom, right-left, top-bottom));
1192 GR_GLEXT(fExts, ResolveMultisampleFramebuffer());
1193 fHWBounds.fScissorRect.setEmpty();
1194 fHWBounds.fScissorEnabled = true;
1195 } else {
1196 GR_GLEXT(fExts, BlitFramebuffer(left, bottom, right, top,
1197 left, bottom, right, top,
1198 GL_COLOR_BUFFER_BIT, GL_NEAREST));
1199 }
1200 rt->setDirty(false);
1201
1202 }
1203}
1204
1205void GrGpuGL::flushStencil() {
1206
1207 // use stencil for clipping if clipping is enabled and the clip
1208 // has been written into the stencil.
1209 bool stencilClip = fClipState.fClipInStencil &&
1210 (kClip_StateBit & fCurrDrawState.fFlagBits);
1211 bool stencilChange =
1212 fWriteMaskChanged ||
1213 fHWStencilClip != stencilClip ||
1214 fHWDrawState.fStencilPass != fCurrDrawState.fStencilPass ||
1215 (kNone_StencilPass != fCurrDrawState.fStencilPass &&
1216 (StencilPass)kSetClip_StencilPass != fCurrDrawState.fStencilPass &&
1217 fHWDrawState.fReverseFill != fCurrDrawState.fReverseFill);
1218
1219 if (stencilChange) {
1220 GLint stencilBitCount;
1221 GLint clipStencilMask;
1222 GLint pathStencilMask;
reed@google.comac20fb92011-01-12 17:14:53 +00001223 GR_GL_GetIntegerv(GL_STENCIL_BITS, &stencilBitCount);
reed@google.comac10a2d2010-12-22 21:39:39 +00001224 GrAssert(stencilBitCount > 0 ||
1225 kNone_StencilPass == fCurrDrawState.fStencilPass);
1226 clipStencilMask = (1 << (stencilBitCount - 1));
1227 pathStencilMask = clipStencilMask - 1;
1228 switch (fCurrDrawState.fStencilPass) {
1229 case kNone_StencilPass:
1230 if (stencilClip) {
1231 GR_GL(Enable(GL_STENCIL_TEST));
1232 GR_GL(StencilFunc(GL_EQUAL,
1233 clipStencilMask,
1234 clipStencilMask));
1235 GR_GL(StencilOp(GL_KEEP, GL_KEEP, GL_KEEP));
1236 } else {
1237 GR_GL(Disable(GL_STENCIL_TEST));
1238 }
1239 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
1240 if (!fSingleStencilPassForWinding) {
1241 GR_GL(Disable(GL_CULL_FACE));
1242 }
1243 break;
1244 case kEvenOddStencil_StencilPass:
1245 GR_GL(Enable(GL_STENCIL_TEST));
1246 if (stencilClip) {
1247 GR_GL(StencilFunc(GL_EQUAL, clipStencilMask, clipStencilMask));
1248 } else {
1249 GR_GL(StencilFunc(GL_ALWAYS, 0x0, 0x0));
1250 }
1251 GR_GL(StencilMask(pathStencilMask));
1252 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
1253 GR_GL(StencilOp(GL_KEEP, GL_INVERT, GL_INVERT));
1254 GR_GL(ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE));
1255 if (!fSingleStencilPassForWinding) {
1256 GR_GL(Disable(GL_CULL_FACE));
1257 }
1258 break;
1259 case kEvenOddColor_StencilPass: {
1260 GR_GL(Enable(GL_STENCIL_TEST));
1261 GLint funcRef = 0;
1262 GLuint funcMask = pathStencilMask;
1263 if (stencilClip) {
1264 funcRef |= clipStencilMask;
1265 funcMask |= clipStencilMask;
1266 }
1267 if (!fCurrDrawState.fReverseFill) {
1268 funcRef |= pathStencilMask;
1269 }
bsalomon@google.com316f99232011-01-13 21:28:12 +00001270 GR_GL(StencilFunc(GL_EQUAL, funcRef, funcMask));
1271 GR_GL(StencilMask(pathStencilMask));
reed@google.comac10a2d2010-12-22 21:39:39 +00001272 GR_GL(StencilOp(GL_ZERO, GL_ZERO, GL_ZERO));
1273 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
1274 if (!fSingleStencilPassForWinding) {
1275 GR_GL(Disable(GL_CULL_FACE));
1276 }
1277 } break;
1278 case kWindingStencil1_StencilPass:
1279 GR_GL(Enable(GL_STENCIL_TEST));
1280 if (fHasStencilWrap) {
1281 if (stencilClip) {
1282 GR_GL(StencilFunc(GL_EQUAL,
1283 clipStencilMask,
1284 clipStencilMask));
1285 } else {
1286 GR_GL(StencilFunc(GL_ALWAYS, 0x0, 0x0));
1287 }
1288 if (fSingleStencilPassForWinding) {
1289 GR_GL(StencilOpSeparate(GL_FRONT, GL_KEEP,
1290 GL_INCR_WRAP, GL_INCR_WRAP));
1291 GR_GL(StencilOpSeparate(GL_BACK, GL_KEEP,
1292 GL_DECR_WRAP, GL_DECR_WRAP));
1293 } else {
1294 GR_GL(StencilOp(GL_KEEP, GL_INCR_WRAP, GL_INCR_WRAP));
1295 GR_GL(Enable(GL_CULL_FACE));
1296 GR_GL(CullFace(GL_BACK));
1297 }
1298 } else {
1299 // If we don't have wrap then we use the Func to detect
1300 // values that would wrap (0 on decr and mask on incr). We
1301 // make the func fail on these values and use the sfail op
1302 // to effectively wrap by inverting.
1303 // This applies whether we are doing a two-pass (front faces
1304 // followed by back faces) or a single pass (separate func/op)
1305
1306 // Note that in the case where we are also using stencil to
1307 // clip this means we will write into the path bits in clipped
1308 // out pixels. We still apply the clip bit in the color pass
1309 // stencil func so we don't draw color outside the clip.
1310 // We also will clear the stencil bits in clipped pixels by
1311 // using zero in the sfail op with write mask set to the
1312 // path mask.
1313 GR_GL(Enable(GL_STENCIL_TEST));
1314 if (fSingleStencilPassForWinding) {
1315 GR_GL(StencilFuncSeparate(GL_FRONT,
1316 GL_NOTEQUAL,
1317 pathStencilMask,
1318 pathStencilMask));
1319 GR_GL(StencilFuncSeparate(GL_BACK,
1320 GL_NOTEQUAL,
1321 0x0,
1322 pathStencilMask));
1323 GR_GL(StencilOpSeparate(GL_FRONT, GL_INVERT,
1324 GL_INCR, GL_INCR));
1325 GR_GL(StencilOpSeparate(GL_BACK, GL_INVERT,
1326 GL_DECR, GL_DECR));
1327 } else {
1328 GR_GL(StencilFunc(GL_NOTEQUAL,
1329 pathStencilMask,
1330 pathStencilMask));
1331 GR_GL(StencilOp(GL_INVERT, GL_INCR, GL_INCR));
1332 GR_GL(Enable(GL_CULL_FACE));
1333 GR_GL(CullFace(GL_BACK));
1334 }
1335 }
1336 GR_GL(StencilMask(pathStencilMask));
1337 GR_GL(ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE));
1338 break;
1339 case kWindingStencil2_StencilPass:
1340 GrAssert(!fSingleStencilPassForWinding);
1341 GR_GL(Enable(GL_STENCIL_TEST));
1342 if (fHasStencilWrap) {
1343 if (stencilClip) {
1344 GR_GL(StencilFunc(GL_EQUAL,
1345 clipStencilMask,
1346 clipStencilMask));
1347 } else {
1348 GR_GL(StencilFunc(GL_ALWAYS, 0x0, 0x0));
1349 }
1350 GR_GL(StencilOp(GL_DECR_WRAP, GL_DECR_WRAP, GL_DECR_WRAP));
1351 } else {
1352 GR_GL(StencilFunc(GL_NOTEQUAL, 0x0, pathStencilMask));
1353 GR_GL(StencilOp(GL_INVERT, GL_DECR, GL_DECR));
1354 }
1355 GR_GL(StencilMask(pathStencilMask));
1356 GR_GL(Enable(GL_CULL_FACE));
1357 GR_GL(CullFace(GL_FRONT));
1358 GR_GL(ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE));
1359 break;
1360 case kWindingColor_StencilPass: {
1361 GR_GL(Enable(GL_STENCIL_TEST));
1362 GLint funcRef = 0;
1363 GLuint funcMask = pathStencilMask;
1364 GLenum funcFunc;
1365 if (stencilClip) {
1366 funcRef |= clipStencilMask;
1367 funcMask |= clipStencilMask;
1368 }
1369 if (fCurrDrawState.fReverseFill) {
1370 funcFunc = GL_EQUAL;
1371 } else {
1372 funcFunc = GL_LESS;
1373 }
1374 GR_GL(StencilFunc(funcFunc, funcRef, funcMask));
1375 GR_GL(StencilMask(pathStencilMask));
1376 // must zero in sfail because winding w/o wrap will write
1377 // path stencil bits in clipped out pixels
1378 GR_GL(StencilOp(GL_ZERO, GL_ZERO, GL_ZERO));
1379 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
1380 if (!fSingleStencilPassForWinding) {
1381 GR_GL(Disable(GL_CULL_FACE));
1382 }
1383 } break;
1384 case kSetClip_StencilPass:
1385 GR_GL(Enable(GL_STENCIL_TEST));
1386 GR_GL(StencilFunc(GL_ALWAYS, clipStencilMask, clipStencilMask));
1387 GR_GL(StencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE));
1388 GR_GL(StencilMask(clipStencilMask));
1389 GR_GL(ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE));
1390 if (!fSingleStencilPassForWinding) {
1391 GR_GL(Disable(GL_CULL_FACE));
1392 }
1393 break;
1394 default:
1395 GrAssert(!"Unexpected stencil pass.");
1396 break;
1397
1398 }
1399 fHWDrawState.fStencilPass = fCurrDrawState.fStencilPass;
1400 fHWDrawState.fReverseFill = fCurrDrawState.fReverseFill;
1401 fWriteMaskChanged = false;
1402 fHWStencilClip = stencilClip;
1403 }
1404}
1405
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001406bool GrGpuGL::flushGLStateCommon(PrimitiveType type) {
1407
1408 // GrGpu::setupClipAndFlushState should have already checked this
1409 // and bailed if not true.
1410 GrAssert(NULL != fCurrDrawState.fRenderTarget);
reed@google.comac10a2d2010-12-22 21:39:39 +00001411
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001412 for (int s = 0; s < kNumStages; ++s) {
1413 bool usingTexture = VertexUsesStage(s, fGeometrySrc.fVertexLayout);
reed@google.comac10a2d2010-12-22 21:39:39 +00001414
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001415 // bind texture and set sampler state
1416 if (usingTexture) {
1417 GrGLTexture* nextTexture = (GrGLTexture*)fCurrDrawState.fTextures[s];
reed@google.comac10a2d2010-12-22 21:39:39 +00001418
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001419 if (NULL != nextTexture) {
bsalomon@google.com316f99232011-01-13 21:28:12 +00001420 // if we created a rt/tex and rendered to it without using a
1421 // texture and now we're texuring from the rt it will still be
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001422 // the last bound texture, but it needs resolving. So keep this
1423 // out of the "last != next" check.
1424 resolveTextureRenderTarget(nextTexture);
reed@google.comac10a2d2010-12-22 21:39:39 +00001425
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001426 if (fHWDrawState.fTextures[s] != nextTexture) {
1427 setTextureUnit(s);
1428 GR_GL(BindTexture(GL_TEXTURE_2D, nextTexture->textureID()));
1429 #if GR_COLLECT_STATS
1430 ++fStats.fTextureChngCnt;
1431 #endif
1432 //GrPrintf("---- bindtexture %d\n", nextTexture->textureID());
1433 fHWDrawState.fTextures[s] = nextTexture;
1434 }
bsalomon@google.com316f99232011-01-13 21:28:12 +00001435
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001436 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
bsalomon@google.com316f99232011-01-13 21:28:12 +00001437 const GrGLTexture::TexParams& oldTexParams =
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001438 nextTexture->getTexParams();
1439 GrGLTexture::TexParams newTexParams;
bsalomon@google.com316f99232011-01-13 21:28:12 +00001440
1441 newTexParams.fFilter = sampler.isFilter() ? GL_LINEAR :
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001442 GL_NEAREST;
bsalomon@google.com316f99232011-01-13 21:28:12 +00001443 newTexParams.fWrapS =
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001444 GrGLTexture::gWrapMode2GLWrap[sampler.getWrapX()];
bsalomon@google.com316f99232011-01-13 21:28:12 +00001445 newTexParams.fWrapT =
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001446 GrGLTexture::gWrapMode2GLWrap[sampler.getWrapY()];
reed@google.comac10a2d2010-12-22 21:39:39 +00001447
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001448 if (newTexParams.fFilter != oldTexParams.fFilter) {
1449 setTextureUnit(s);
bsalomon@google.com316f99232011-01-13 21:28:12 +00001450 GR_GL(TexParameteri(GL_TEXTURE_2D,
1451 GL_TEXTURE_MAG_FILTER,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001452 newTexParams.fFilter));
bsalomon@google.com316f99232011-01-13 21:28:12 +00001453 GR_GL(TexParameteri(GL_TEXTURE_2D,
1454 GL_TEXTURE_MIN_FILTER,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001455 newTexParams.fFilter));
1456 }
1457 if (newTexParams.fWrapS != oldTexParams.fWrapS) {
1458 setTextureUnit(s);
bsalomon@google.com316f99232011-01-13 21:28:12 +00001459 GR_GL(TexParameteri(GL_TEXTURE_2D,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001460 GL_TEXTURE_WRAP_S,
1461 newTexParams.fWrapS));
1462 }
1463 if (newTexParams.fWrapT != oldTexParams.fWrapT) {
1464 setTextureUnit(s);
bsalomon@google.com316f99232011-01-13 21:28:12 +00001465 GR_GL(TexParameteri(GL_TEXTURE_2D,
1466 GL_TEXTURE_WRAP_T,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001467 newTexParams.fWrapT));
1468 }
1469 nextTexture->setTexParams(newTexParams);
1470 } else {
1471 GrAssert(!"Rendering with texture vert flag set but no texture");
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001472 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +00001473 }
1474 }
1475 }
1476
1477 flushRenderTarget();
1478
1479 if ((fCurrDrawState.fFlagBits & kDither_StateBit) !=
1480 (fHWDrawState.fFlagBits & kDither_StateBit)) {
1481 if (fCurrDrawState.fFlagBits & kDither_StateBit) {
1482 GR_GL(Enable(GL_DITHER));
1483 } else {
1484 GR_GL(Disable(GL_DITHER));
1485 }
1486 }
1487
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001488#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +00001489 // ES doesn't support toggling GL_MULTISAMPLE and doesn't have
1490 // smooth lines.
1491 if (fRenderTargetChanged ||
1492 (fCurrDrawState.fFlagBits & kAntialias_StateBit) !=
1493 (fHWDrawState.fFlagBits & kAntialias_StateBit)) {
1494 GLint msaa = 0;
1495 // only perform query if we know MSAA is supported.
1496 // calling on non-MSAA target caused a crash in one environment,
1497 // though I don't think it should.
1498 if (!fAASamples[kHigh_AALevel]) {
reed@google.comac20fb92011-01-12 17:14:53 +00001499 GR_GL_GetIntegerv(GL_SAMPLE_BUFFERS, &msaa);
reed@google.comac10a2d2010-12-22 21:39:39 +00001500 }
1501 if (fCurrDrawState.fFlagBits & kAntialias_StateBit) {
1502 if (msaa) {
1503 GR_GL(Enable(GL_MULTISAMPLE));
1504 } else {
1505 GR_GL(Enable(GL_LINE_SMOOTH));
1506 }
1507 } else {
1508 if (msaa) {
1509 GR_GL(Disable(GL_MULTISAMPLE));
1510 }
1511 GR_GL(Disable(GL_LINE_SMOOTH));
1512 }
1513 }
1514#endif
1515
1516 bool blendOff = canDisableBlend();
1517 if (fHWBlendDisabled != blendOff) {
1518 if (blendOff) {
1519 GR_GL(Disable(GL_BLEND));
1520 } else {
1521 GR_GL(Enable(GL_BLEND));
1522 }
1523 fHWBlendDisabled = blendOff;
1524 }
1525
1526 if (!blendOff) {
1527 if (fHWDrawState.fSrcBlend != fCurrDrawState.fSrcBlend ||
1528 fHWDrawState.fDstBlend != fCurrDrawState.fDstBlend) {
1529 GR_GL(BlendFunc(gXfermodeCoeff2Blend[fCurrDrawState.fSrcBlend],
1530 gXfermodeCoeff2Blend[fCurrDrawState.fDstBlend]));
1531 fHWDrawState.fSrcBlend = fCurrDrawState.fSrcBlend;
1532 fHWDrawState.fDstBlend = fCurrDrawState.fDstBlend;
1533 }
1534 }
bsalomon@google.com316f99232011-01-13 21:28:12 +00001535
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001536#if GR_DEBUG
reed@google.comac10a2d2010-12-22 21:39:39 +00001537 // check for circular rendering
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001538 for (int s = 0; s < kNumStages; ++s) {
1539 GrAssert(!VertexUsesStage(s, fGeometrySrc.fVertexLayout) ||
1540 NULL == fCurrDrawState.fRenderTarget ||
1541 NULL == fCurrDrawState.fTextures[s] ||
bsalomon@google.com316f99232011-01-13 21:28:12 +00001542 fCurrDrawState.fTextures[s]->asRenderTarget() !=
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001543 fCurrDrawState.fRenderTarget);
1544 }
1545#endif
bsalomon@google.com316f99232011-01-13 21:28:12 +00001546
reed@google.comac10a2d2010-12-22 21:39:39 +00001547 flushStencil();
1548
1549 fHWDrawState.fFlagBits = fCurrDrawState.fFlagBits;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001550 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +00001551}
1552
1553void GrGpuGL::notifyVertexBufferBind(const GrGLVertexBuffer* buffer) {
1554 fHWGeometryState.fVertexBuffer = buffer;
1555}
1556
1557void GrGpuGL::notifyVertexBufferDelete(const GrGLVertexBuffer* buffer) {
1558 GrAssert(!(kBuffer_GeometrySrcType == fGeometrySrc.fVertexSrc &&
1559 buffer == fGeometrySrc.fVertexBuffer));
1560
1561 if (fHWGeometryState.fVertexBuffer == buffer) {
1562 // deleting bound buffer does implied bind to 0
1563 fHWGeometryState.fVertexBuffer = NULL;
1564 }
1565}
1566
1567void GrGpuGL::notifyIndexBufferBind(const GrGLIndexBuffer* buffer) {
1568 fGeometrySrc.fIndexBuffer = buffer;
1569}
1570
1571void GrGpuGL::notifyIndexBufferDelete(const GrGLIndexBuffer* buffer) {
1572 GrAssert(!(kBuffer_GeometrySrcType == fGeometrySrc.fIndexSrc &&
1573 buffer == fGeometrySrc.fIndexBuffer));
1574
1575 if (fHWGeometryState.fIndexBuffer == buffer) {
1576 // deleting bound buffer does implied bind to 0
1577 fHWGeometryState.fIndexBuffer = NULL;
1578 }
1579}
1580
reed@google.comac10a2d2010-12-22 21:39:39 +00001581void GrGpuGL::notifyRenderTargetDelete(GrRenderTarget* renderTarget) {
1582 GrAssert(NULL != renderTarget);
1583
1584 // if the bound FBO is destroyed we can't rely on the implicit bind to 0
1585 // a) we want the default RT which may not be FBO 0
1586 // b) we set more state than just FBO based on the RT
1587 // So trash the HW state to force an RT flush next time
1588 if (fCurrDrawState.fRenderTarget == renderTarget) {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001589 fCurrDrawState.fRenderTarget = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +00001590 }
1591 if (fHWDrawState.fRenderTarget == renderTarget) {
1592 fHWDrawState.fRenderTarget = NULL;
1593 }
1594 if (fClipState.fStencilClipTarget == renderTarget) {
1595 fClipState.fStencilClipTarget = NULL;
1596 }
1597}
1598
1599void GrGpuGL::notifyTextureDelete(GrGLTexture* texture) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001600 for (int s = 0; s < kNumStages; ++s) {
1601 if (fCurrDrawState.fTextures[s] == texture) {
1602 fCurrDrawState.fTextures[s] = NULL;
1603 }
1604 if (fHWDrawState.fTextures[s] == texture) {
1605 // deleting bound texture does implied bind to 0
1606 fHWDrawState.fTextures[s] = NULL;
1607 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001608 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001609}
1610
1611void GrGpuGL::notifyTextureRemoveRenderTarget(GrGLTexture* texture) {
1612 GrAssert(NULL != texture->asRenderTarget());
1613
1614 // if there is a pending resolve, perform it.
1615 resolveTextureRenderTarget(texture);
1616}
1617
1618bool GrGpuGL::canBeTexture(GrTexture::PixelConfig config,
1619 GLenum* internalFormat,
1620 GLenum* format,
1621 GLenum* type) {
1622 switch (config) {
1623 case GrTexture::kRGBA_8888_PixelConfig:
1624 case GrTexture::kRGBX_8888_PixelConfig: // todo: can we tell it our X?
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +00001625 *format = GR_GL_32BPP_COLOR_FORMAT;
reed@google.com63100f92011-01-18 21:32:14 +00001626#if GR_SUPPORT_GLES
1627 // according to GL_EXT_texture_format_BGRA8888 the *internal*
1628 // format for a BGRA is BGRA not RGBA (as on desktop)
1629 *internalFormat = GR_GL_32BPP_COLOR_FORMAT;
1630#else
1631 *internalFormat = GL_RGBA;
bsalomon@google.comed3a0682011-01-18 16:54:04 +00001632#endif
reed@google.comac10a2d2010-12-22 21:39:39 +00001633 *type = GL_UNSIGNED_BYTE;
1634 break;
1635 case GrTexture::kRGB_565_PixelConfig:
1636 *format = GL_RGB;
1637 *internalFormat = GL_RGB;
1638 *type = GL_UNSIGNED_SHORT_5_6_5;
1639 break;
1640 case GrTexture::kRGBA_4444_PixelConfig:
1641 *format = GL_RGBA;
1642 *internalFormat = GL_RGBA;
1643 *type = GL_UNSIGNED_SHORT_4_4_4_4;
1644 break;
1645 case GrTexture::kIndex_8_PixelConfig:
1646 if (this->supports8BitPalette()) {
1647 *format = GR_PALETTE8_RGBA8;
1648 *internalFormat = GR_PALETTE8_RGBA8;
1649 *type = GL_UNSIGNED_BYTE; // unused I think
1650 } else {
1651 return false;
1652 }
1653 break;
1654 case GrTexture::kAlpha_8_PixelConfig:
1655 *format = GL_ALPHA;
1656 *internalFormat = GL_ALPHA;
1657 *type = GL_UNSIGNED_BYTE;
1658 break;
1659 default:
1660 return false;
1661 }
1662 return true;
1663}
1664
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001665void GrGpuGL::setTextureUnit(int unit) {
1666 GrAssert(unit >= 0 && unit < kNumStages);
1667 if (fActiveTextureUnitIdx != unit) {
1668 GR_GL(ActiveTexture(GL_TEXTURE0 + unit));
1669 fActiveTextureUnitIdx = unit;
1670 }
1671}
bsalomon@google.com316f99232011-01-13 21:28:12 +00001672
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001673void GrGpuGL::setSpareTextureUnit() {
1674 if (fActiveTextureUnitIdx != (GL_TEXTURE0 + SPARE_TEX_UNIT)) {
1675 GR_GL(ActiveTexture(GL_TEXTURE0 + SPARE_TEX_UNIT));
1676 fActiveTextureUnitIdx = SPARE_TEX_UNIT;
1677 }
1678}
1679
reed@google.comac10a2d2010-12-22 21:39:39 +00001680/* On ES the internalFormat and format must match for TexImage and we use
1681 GL_RGB, GL_RGBA for color formats. We also generally like having the driver
1682 decide the internalFormat. However, on ES internalFormat for
1683 RenderBufferStorage* has to be a specific format (not a base format like
1684 GL_RGBA).
1685 */
1686bool GrGpuGL::fboInternalFormat(GrTexture::PixelConfig config, GLenum* format) {
1687 switch (config) {
1688 case GrTexture::kRGBA_8888_PixelConfig:
1689 case GrTexture::kRGBX_8888_PixelConfig:
1690 if (fRGBA8Renderbuffer) {
1691 *format = GR_RGBA8;
1692 return true;
1693 } else {
1694 return false;
1695 }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001696#if GR_SUPPORT_GLES // ES2 supports 565. ES1 supports it with FBO extension
1697 // desktop GL has no such internal format
reed@google.comac10a2d2010-12-22 21:39:39 +00001698 case GrTexture::kRGB_565_PixelConfig:
1699 *format = GR_RGB565;
1700 return true;
1701#endif
1702 case GrTexture::kRGBA_4444_PixelConfig:
1703 *format = GL_RGBA4;
1704 return true;
1705 default:
1706 return false;
1707 }
1708}