blob: f2a2a8f3b02729aaeec6ab34e06827616c6938f0 [file] [log] [blame]
reed@google.comac10a2d2010-12-22 21:39:39 +00001/*
bsalomon@google.com1da07462011-03-10 14:51:57 +00002 Copyright 2011 Google Inc.
reed@google.comac10a2d2010-12-22 21:39:39 +00003
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17#include "GrGpuGL.h"
18#include "GrMemory.h"
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +000019#if GR_WIN32_BUILD
20 // need to get wglGetProcAddress
21 #undef WIN32_LEAN_AND_MEAN
22 #define WIN32_LEAN_AND_MEAN 1
23 #include <windows.h>
24 #undef WIN32_LEAN_AND_MEAN
25#endif
26
reed@google.comac10a2d2010-12-22 21:39:39 +000027
28static const GLuint GR_MAX_GLUINT = ~0;
29static const GLint GR_INVAL_GLINT = ~0;
30
bsalomon@google.com316f99232011-01-13 21:28:12 +000031// we use a spare texture unit to avoid
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000032// mucking with the state of any of the stages.
bsalomon@google.com316f99232011-01-13 21:28:12 +000033static const int SPARE_TEX_UNIT = GrGpuGL::kNumStages;
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000034
reed@google.comac10a2d2010-12-22 21:39:39 +000035#define SKIP_CACHE_CHECK true
36
37static const GLenum gXfermodeCoeff2Blend[] = {
38 GL_ZERO,
39 GL_ONE,
40 GL_SRC_COLOR,
41 GL_ONE_MINUS_SRC_COLOR,
42 GL_DST_COLOR,
43 GL_ONE_MINUS_DST_COLOR,
44 GL_SRC_ALPHA,
45 GL_ONE_MINUS_SRC_ALPHA,
46 GL_DST_ALPHA,
47 GL_ONE_MINUS_DST_ALPHA,
bsalomon@google.com080773c2011-03-15 19:09:25 +000048 GL_CONSTANT_COLOR,
49 GL_ONE_MINUS_CONSTANT_COLOR,
50 GL_CONSTANT_ALPHA,
51 GL_ONE_MINUS_CONSTANT_ALPHA,
reed@google.comac10a2d2010-12-22 21:39:39 +000052};
53
bsalomon@google.com080773c2011-03-15 19:09:25 +000054bool GrGpuGL::BlendCoefReferencesConstant(GrBlendCoeff coeff) {
55 static const bool gCoeffReferencesBlendConst[] = {
56 false,
57 false,
58 false,
59 false,
60 false,
61 false,
62 false,
63 false,
64 false,
65 false,
66 true,
67 true,
68 true,
69 true,
70 };
71 return gCoeffReferencesBlendConst[coeff];
72 GR_STATIC_ASSERT(kBlendCoeffCount == GR_ARRAY_COUNT(gCoeffReferencesBlendConst));
73}
74
75GR_STATIC_ASSERT(0 == kZero_BlendCoeff);
76GR_STATIC_ASSERT(1 == kOne_BlendCoeff);
77GR_STATIC_ASSERT(2 == kSC_BlendCoeff);
78GR_STATIC_ASSERT(3 == kISC_BlendCoeff);
79GR_STATIC_ASSERT(4 == kDC_BlendCoeff);
80GR_STATIC_ASSERT(5 == kIDC_BlendCoeff);
81GR_STATIC_ASSERT(6 == kSA_BlendCoeff);
82GR_STATIC_ASSERT(7 == kISA_BlendCoeff);
83GR_STATIC_ASSERT(8 == kDA_BlendCoeff);
84GR_STATIC_ASSERT(9 == kIDA_BlendCoeff);
85GR_STATIC_ASSERT(10 == kConstC_BlendCoeff);
86GR_STATIC_ASSERT(11 == kIConstC_BlendCoeff);
87GR_STATIC_ASSERT(12 == kConstA_BlendCoeff);
88GR_STATIC_ASSERT(13 == kIConstA_BlendCoeff);
89
90GR_STATIC_ASSERT(kBlendCoeffCount == GR_ARRAY_COUNT(gXfermodeCoeff2Blend));
91
reed@google.comac10a2d2010-12-22 21:39:39 +000092///////////////////////////////////////////////////////////////////////////////
93
bsalomon@google.comd302f142011-03-03 13:54:13 +000094void GrGpuGL::AdjustTextureMatrix(const GrGLTexture* texture,
95 GrSamplerState::SampleMode mode,
bsalomon@google.comc6cf7232011-02-17 16:43:10 +000096 GrMatrix* matrix) {
97 GrAssert(NULL != texture);
98 GrAssert(NULL != matrix);
99 if (GR_Scalar1 != texture->contentScaleX() ||
100 GR_Scalar1 != texture->contentScaleY()) {
101 if (GrSamplerState::kRadial_SampleMode == mode) {
102 GrMatrix scale;
103 scale.setScale(texture->contentScaleX(), texture->contentScaleX());
104 matrix->postConcat(scale);
105 } else if (GrSamplerState::kNormal_SampleMode == mode) {
106 GrMatrix scale;
107 scale.setScale(texture->contentScaleX(), texture->contentScaleY());
108 matrix->postConcat(scale);
109 } else {
110 GrPrintf("We haven't handled NPOT adjustment for other sample modes!");
111 }
112 }
113 GrGLTexture::Orientation orientation = texture->orientation();
114 if (GrGLTexture::kBottomUp_Orientation == orientation) {
115 GrMatrix invY;
116 invY.setAll(GR_Scalar1, 0, 0,
117 0, -GR_Scalar1, GR_Scalar1,
118 0, 0, GrMatrix::I()[8]);
119 matrix->postConcat(invY);
120 } else {
121 GrAssert(GrGLTexture::kTopDown_Orientation == orientation);
122 }
123}
124
bsalomon@google.comd302f142011-03-03 13:54:13 +0000125bool GrGpuGL::TextureMatrixIsIdentity(const GrGLTexture* texture,
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000126 const GrSamplerState& sampler) {
127 GrAssert(NULL != texture);
128 if (!sampler.getMatrix().isIdentity()) {
129 return false;
130 }
131 if (GR_Scalar1 != texture->contentScaleX() ||
132 GR_Scalar1 != texture->contentScaleY()) {
133 return false;
134 }
135 GrGLTexture::Orientation orientation = texture->orientation();
136 if (GrGLTexture::kBottomUp_Orientation == orientation) {
137 return false;
138 } else {
139 GrAssert(GrGLTexture::kTopDown_Orientation == orientation);
140 }
141 return true;
142}
143
144///////////////////////////////////////////////////////////////////////////////
145
bsalomon@google.com42ab7ea2011-01-19 17:19:40 +0000146static bool gPrintStartupSpew;
147
twiz@google.com59a190b2011-03-14 21:23:01 +0000148static bool fbo_test(int w, int h) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000149
150 GLint savedFBO;
151 GLint savedTexUnit;
reed@google.com3d8de042011-01-20 02:18:00 +0000152 GR_GL_GetIntegerv(GL_ACTIVE_TEXTURE, &savedTexUnit);
153 GR_GL_GetIntegerv(GR_FRAMEBUFFER_BINDING, &savedFBO);
bsalomon@google.com316f99232011-01-13 21:28:12 +0000154
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000155 GR_GL(ActiveTexture(GL_TEXTURE0 + SPARE_TEX_UNIT));
bsalomon@google.com316f99232011-01-13 21:28:12 +0000156
reed@google.comac10a2d2010-12-22 21:39:39 +0000157 GLuint testFBO;
twiz@google.com59a190b2011-03-14 21:23:01 +0000158 GR_GL(GenFramebuffers(1, &testFBO));
159 GR_GL(BindFramebuffer(GR_FRAMEBUFFER, testFBO));
reed@google.comac10a2d2010-12-22 21:39:39 +0000160 GLuint testRTTex;
161 GR_GL(GenTextures(1, &testRTTex));
162 GR_GL(BindTexture(GL_TEXTURE_2D, testRTTex));
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000163 // some implementations require texture to be mip-map complete before
164 // FBO with level 0 bound as color attachment will be framebuffer complete.
165 GR_GL(TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
reed@google.comac10a2d2010-12-22 21:39:39 +0000166 GR_GL(TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h,
167 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL));
168 GR_GL(BindTexture(GL_TEXTURE_2D, 0));
twiz@google.com59a190b2011-03-14 21:23:01 +0000169 GR_GL(FramebufferTexture2D(GR_FRAMEBUFFER, GR_COLOR_ATTACHMENT0,
170 GL_TEXTURE_2D, testRTTex, 0));
171 GLenum status = GR_GL(CheckFramebufferStatus(GR_FRAMEBUFFER));
172 GR_GL(DeleteFramebuffers(1, &testFBO));
reed@google.comac10a2d2010-12-22 21:39:39 +0000173 GR_GL(DeleteTextures(1, &testRTTex));
bsalomon@google.com316f99232011-01-13 21:28:12 +0000174
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000175 GR_GL(ActiveTexture(savedTexUnit));
twiz@google.com59a190b2011-03-14 21:23:01 +0000176 GR_GL(BindFramebuffer(GR_FRAMEBUFFER, savedFBO));
bsalomon@google.com316f99232011-01-13 21:28:12 +0000177
reed@google.comac10a2d2010-12-22 21:39:39 +0000178 return status == GR_FRAMEBUFFER_COMPLETE;
179}
180
reed@google.comac10a2d2010-12-22 21:39:39 +0000181GrGpuGL::GrGpuGL() {
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000182
reed@google.comeeeb5a02010-12-23 15:12:59 +0000183 if (gPrintStartupSpew) {
184 GrPrintf("------------------------- create GrGpuGL %p --------------\n",
185 this);
twiz@google.com59a190b2011-03-14 21:23:01 +0000186 GrPrintf("------ VENDOR %s\n",
187 GrGLGetGLInterface()->fGetString(GL_VENDOR));
188 GrPrintf("------ RENDERER %s\n",
189 GrGLGetGLInterface()->fGetString(GL_RENDERER));
190 GrPrintf("------ VERSION %s\n",
191 GrGLGetGLInterface()->fGetString(GL_VERSION));
192 GrPrintf("------ EXTENSIONS\n %s \n",
193 GrGLGetGLInterface()->fGetString(GL_EXTENSIONS));
reed@google.comeeeb5a02010-12-23 15:12:59 +0000194 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000195
196 GrGLClearErr();
197
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000198 resetDirtyFlags();
bsalomon@google.com316f99232011-01-13 21:28:12 +0000199
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000200 GLint maxTextureUnits;
201 // check FS and fixed-function texture unit limits
202 // we only use textures in the fragment stage currently.
203 // checks are > to make sure we have a spare unit.
204#if GR_SUPPORT_GLDESKTOP || GR_SUPPORT_GLES2
reed@google.com3d8de042011-01-20 02:18:00 +0000205 GR_GL_GetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000206 GrAssert(maxTextureUnits > kNumStages);
207#endif
208#if GR_SUPPORT_GLDESKTOP || GR_SUPPORT_GLES1
reed@google.com3d8de042011-01-20 02:18:00 +0000209 GR_GL_GetIntegerv(GL_MAX_TEXTURE_UNITS, &maxTextureUnits);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000210 GrAssert(maxTextureUnits > kNumStages);
211#endif
bsalomon@google.com316f99232011-01-13 21:28:12 +0000212
reed@google.comac10a2d2010-12-22 21:39:39 +0000213 ////////////////////////////////////////////////////////////////////////////
214 // Check for supported features.
215
216 int major, minor;
217 gl_version(&major, &minor);
218
219 GLint numFormats;
reed@google.comac20fb92011-01-12 17:14:53 +0000220 GR_GL_GetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &numFormats);
reed@google.comac10a2d2010-12-22 21:39:39 +0000221 GrAutoSTMalloc<10, GLint> formats(numFormats);
reed@google.comac20fb92011-01-12 17:14:53 +0000222 GR_GL_GetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, formats);
reed@google.comac10a2d2010-12-22 21:39:39 +0000223 for (int i = 0; i < numFormats; ++i) {
224 if (formats[i] == GR_PALETTE8_RGBA8) {
225 f8bitPaletteSupport = true;
226 break;
227 }
228 }
reed@google.comeeeb5a02010-12-23 15:12:59 +0000229
230 if (gPrintStartupSpew) {
231 GrPrintf("Palette8 support: %s\n", (f8bitPaletteSupport ? "YES" : "NO"));
232 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000233
234 GR_STATIC_ASSERT(0 == kNone_AALevel);
235 GR_STATIC_ASSERT(1 == kLow_AALevel);
236 GR_STATIC_ASSERT(2 == kMed_AALevel);
237 GR_STATIC_ASSERT(3 == kHigh_AALevel);
238
239 memset(fAASamples, 0, sizeof(fAASamples));
240 fMSFBOType = kNone_MSFBO;
241 if (has_gl_extension("GL_IMG_multisampled_render_to_texture")) {
242 fMSFBOType = kIMG_MSFBO;
reed@google.comeeeb5a02010-12-23 15:12:59 +0000243 if (gPrintStartupSpew) {
244 GrPrintf("MSAA Support: IMG ES EXT.\n");
245 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000246 }
247 else if (has_gl_extension("GL_APPLE_framebuffer_multisample")) {
248 fMSFBOType = kApple_MSFBO;
reed@google.comeeeb5a02010-12-23 15:12:59 +0000249 if (gPrintStartupSpew) {
250 GrPrintf("MSAA Support: APPLE ES EXT.\n");
251 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000252 }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000253#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000254 else if ((major >= 3) ||
255 has_gl_extension("GL_ARB_framebuffer_object") ||
256 (has_gl_extension("GL_EXT_framebuffer_multisample") &&
257 has_gl_extension("GL_EXT_framebuffer_blit"))) {
258 fMSFBOType = kDesktop_MSFBO;
reed@google.comeeeb5a02010-12-23 15:12:59 +0000259 if (gPrintStartupSpew) {
260 GrPrintf("MSAA Support: DESKTOP\n");
261 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000262 }
263#endif
264 else {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000265 if (gPrintStartupSpew) {
266 GrPrintf("MSAA Support: NONE\n");
267 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000268 }
269
270 if (kNone_MSFBO != fMSFBOType) {
271 GLint maxSamples;
272 GLenum maxSampleGetter = (kIMG_MSFBO == fMSFBOType) ?
273 GR_MAX_SAMPLES_IMG :
274 GR_MAX_SAMPLES;
reed@google.comac20fb92011-01-12 17:14:53 +0000275 GR_GL_GetIntegerv(maxSampleGetter, &maxSamples);
reed@google.comac10a2d2010-12-22 21:39:39 +0000276 if (maxSamples > 1 ) {
277 fAASamples[kNone_AALevel] = 0;
278 fAASamples[kLow_AALevel] = GrMax(2,
279 GrFixedFloorToInt((GR_FixedHalf) *
280 maxSamples));
281 fAASamples[kMed_AALevel] = GrMax(2,
282 GrFixedFloorToInt(((GR_Fixed1*3)/4) *
283 maxSamples));
284 fAASamples[kHigh_AALevel] = maxSamples;
285 }
reed@google.comeeeb5a02010-12-23 15:12:59 +0000286 if (gPrintStartupSpew) {
287 GrPrintf("\tMax Samples: %d\n", maxSamples);
288 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000289 }
290
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000291#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000292 fHasStencilWrap = (major >= 2 || (major == 1 && minor >= 4)) ||
293 has_gl_extension("GL_EXT_stencil_wrap");
294#else
295 fHasStencilWrap = (major >= 2) || has_gl_extension("GL_OES_stencil_wrap");
296#endif
reed@google.comeeeb5a02010-12-23 15:12:59 +0000297 if (gPrintStartupSpew) {
298 GrPrintf("Stencil Wrap: %s\n", (fHasStencilWrap ? "YES" : "NO"));
299 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000300
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000301#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000302 // we could also look for GL_ATI_separate_stencil extension or
303 // GL_EXT_stencil_two_side but they use different function signatures
304 // than GL2.0+ (and than each other).
bsalomon@google.comd302f142011-03-03 13:54:13 +0000305 fTwoSidedStencilSupport = (major >= 2);
306 // supported on GL 1.4 and higher or by extension
307 fStencilWrapOpsSupport = (major > 1) ||
reed@google.comeca7d342011-03-04 19:33:13 +0000308 ((1 == major) && (minor >= 4)) ||
bsalomon@google.comd302f142011-03-03 13:54:13 +0000309 has_gl_extension("GL_EXT_stencil_wrap");
reed@google.comac10a2d2010-12-22 21:39:39 +0000310#else
311 // ES 2 has two sided stencil but 1.1 doesn't. There doesn't seem to be
312 // an ES1 extension.
bsalomon@google.comd302f142011-03-03 13:54:13 +0000313 fTwoSidedStencilSupport = (major >= 2);
314 // stencil wrap support is in ES2, ES1 requires extension.
315 fStencilWrapOpsSupport = (major > 1) ||
316 has_gl_extension("GL_OES_stencil_wrap");
317
reed@google.comac10a2d2010-12-22 21:39:39 +0000318#endif
reed@google.comeeeb5a02010-12-23 15:12:59 +0000319 if (gPrintStartupSpew) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000320 GrPrintf("Stencil Caps: TwoSide: %s, Wrap: %s\n",
321 (fTwoSidedStencilSupport ? "YES" : "NO"),
322 (fStencilWrapOpsSupport ? "YES" : "NO"));
reed@google.comeeeb5a02010-12-23 15:12:59 +0000323 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000324
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000325#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000326 fRGBA8Renderbuffer = true;
327#else
328 fRGBA8Renderbuffer = has_gl_extension("GL_OES_rgb8_rgba8");
329#endif
reed@google.comeeeb5a02010-12-23 15:12:59 +0000330 if (gPrintStartupSpew) {
331 GrPrintf("RGBA Renderbuffer: %s\n", (fRGBA8Renderbuffer ? "YES" : "NO"));
332 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000333
bsalomon@google.comed3a0682011-01-18 16:54:04 +0000334#if GR_SUPPORT_GLES
335 if (GR_GL_32BPP_COLOR_FORMAT == GR_BGRA) {
336 GrAssert(has_gl_extension("GL_EXT_texture_format_BGRA8888"));
337 }
338#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000339
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000340#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000341 fBufferLockSupport = true; // we require VBO support and the desktop VBO
342 // extension includes glMapBuffer.
343#else
344 fBufferLockSupport = has_gl_extension("GL_OES_mapbuffer");
345#endif
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000346
reed@google.comeeeb5a02010-12-23 15:12:59 +0000347 if (gPrintStartupSpew) {
348 GrPrintf("Map Buffer: %s\n", (fBufferLockSupport ? "YES" : "NO"));
349 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000350
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000351#if GR_SUPPORT_GLDESKTOP
bsalomon@google.com0748f212011-02-01 22:56:16 +0000352 if (major >= 2 || has_gl_extension("GL_ARB_texture_non_power_of_two")) {
353 fNPOTTextureTileSupport = true;
354 fNPOTTextureSupport = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000355 } else {
bsalomon@google.com0748f212011-02-01 22:56:16 +0000356 fNPOTTextureTileSupport = false;
357 fNPOTTextureSupport = false;
358 }
359#else
360 if (major >= 2) {
361 fNPOTTextureSupport = true;
362 fNPOTTextureTileSupport = has_gl_extension("GL_OES_texture_npot");
363 } else {
364 fNPOTTextureSupport = has_gl_extension("GL_APPLE_texture_2D_limited_npot");
365 fNPOTTextureTileSupport = false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000366 }
367#endif
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000368
reed@google.comac10a2d2010-12-22 21:39:39 +0000369 ////////////////////////////////////////////////////////////////////////////
370 // Experiments to determine limitations that can't be queried. TODO: Make
371 // these a preprocess that generate some compile time constants.
372
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000373 // sanity check to make sure we can at least create an FBO from a POT texture
bsalomon@google.com18908aa2011-02-07 14:51:55 +0000374
twiz@google.com59a190b2011-03-14 21:23:01 +0000375 bool simpleFBOSuccess = fbo_test(128, 128);
bsalomon@google.com0748f212011-02-01 22:56:16 +0000376 if (gPrintStartupSpew) {
377 if (!simpleFBOSuccess) {
378 GrPrintf("FBO Sanity Test: FAILED\n");
379 } else {
380 GrPrintf("FBO Sanity Test: PASSED\n");
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000381 }
382 }
bsalomon@google.com0748f212011-02-01 22:56:16 +0000383 GrAssert(simpleFBOSuccess);
reed@google.comac20fb92011-01-12 17:14:53 +0000384
reed@google.comac10a2d2010-12-22 21:39:39 +0000385 /* Experimentation has found that some GLs that support NPOT textures
386 do not support FBOs with a NPOT texture. They report "unsupported" FBO
387 status. I don't know how to explicitly query for this. Do an
388 experiment. Note they may support NPOT with a renderbuffer but not a
389 texture. Presumably, the implementation bloats the renderbuffer
390 internally to the next POT.
391 */
bsalomon@google.com0748f212011-02-01 22:56:16 +0000392 bool fNPOTRenderTargetSupport = false;
393 if (fNPOTTextureSupport) {
twiz@google.com59a190b2011-03-14 21:23:01 +0000394 fNPOTRenderTargetSupport = fbo_test(200, 200);
bsalomon@google.com0748f212011-02-01 22:56:16 +0000395 }
bsalomon@google.com18908aa2011-02-07 14:51:55 +0000396
bsalomon@google.com0748f212011-02-01 22:56:16 +0000397 if (gPrintStartupSpew) {
398 if (fNPOTTextureSupport) {
399 GrPrintf("NPOT textures supported\n");
400 if (fNPOTTextureTileSupport) {
401 GrPrintf("NPOT texture tiling supported\n");
402 } else {
403 GrPrintf("NPOT texture tiling NOT supported\n");
404 }
405 if (fNPOTRenderTargetSupport) {
406 GrPrintf("NPOT render targets supported\n");
407 } else {
408 GrPrintf("NPOT render targets NOT supported\n");
reed@google.comeeeb5a02010-12-23 15:12:59 +0000409 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000410 } else {
bsalomon@google.com0748f212011-02-01 22:56:16 +0000411 GrPrintf("NPOT textures NOT supported\n");
reed@google.comeeeb5a02010-12-23 15:12:59 +0000412 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000413 }
414
reed@google.comac10a2d2010-12-22 21:39:39 +0000415 /* The iPhone 4 has a restriction that for an FBO with texture color
416 attachment with height <= 8 then the width must be <= height. Here
417 we look for such a limitation.
418 */
419 fMinRenderTargetHeight = GR_INVAL_GLINT;
420 GLint maxRenderSize;
reed@google.comac20fb92011-01-12 17:14:53 +0000421 GR_GL_GetIntegerv(GR_MAX_RENDERBUFFER_SIZE, &maxRenderSize);
reed@google.comac10a2d2010-12-22 21:39:39 +0000422
reed@google.comeeeb5a02010-12-23 15:12:59 +0000423 if (gPrintStartupSpew) {
424 GrPrintf("Small height FBO texture experiments\n");
425 }
bsalomon@google.com0748f212011-02-01 22:56:16 +0000426
427 for (GLuint i = 1; i <= 256; fNPOTRenderTargetSupport ? ++i : i *= 2) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000428 GLuint w = maxRenderSize;
429 GLuint h = i;
twiz@google.com59a190b2011-03-14 21:23:01 +0000430 if (fbo_test(w, h)) {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000431 if (gPrintStartupSpew) {
432 GrPrintf("\t[%d, %d]: PASSED\n", w, h);
433 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000434 fMinRenderTargetHeight = i;
435 break;
436 } else {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000437 if (gPrintStartupSpew) {
438 GrPrintf("\t[%d, %d]: FAILED\n", w, h);
439 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000440 }
441 }
442 GrAssert(GR_INVAL_GLINT != fMinRenderTargetHeight);
443
reed@google.comeeeb5a02010-12-23 15:12:59 +0000444 if (gPrintStartupSpew) {
445 GrPrintf("Small width FBO texture experiments\n");
446 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000447 fMinRenderTargetWidth = GR_MAX_GLUINT;
bsalomon@google.com0748f212011-02-01 22:56:16 +0000448 for (GLuint i = 1; i <= 256; fNPOTRenderTargetSupport ? i *= 2 : ++i) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000449 GLuint w = i;
450 GLuint h = maxRenderSize;
twiz@google.com59a190b2011-03-14 21:23:01 +0000451 if (fbo_test(w, h)) {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000452 if (gPrintStartupSpew) {
453 GrPrintf("\t[%d, %d]: PASSED\n", w, h);
454 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000455 fMinRenderTargetWidth = i;
456 break;
457 } else {
reed@google.comeeeb5a02010-12-23 15:12:59 +0000458 if (gPrintStartupSpew) {
459 GrPrintf("\t[%d, %d]: FAILED\n", w, h);
460 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000461 }
462 }
463 GrAssert(GR_INVAL_GLINT != fMinRenderTargetWidth);
464
reed@google.com02a7e6c2011-01-28 21:21:49 +0000465 GR_GL_GetIntegerv(GL_MAX_TEXTURE_SIZE, &fMaxTextureDimension);
reed@google.comac10a2d2010-12-22 21:39:39 +0000466}
467
468GrGpuGL::~GrGpuGL() {
reed@google.comac10a2d2010-12-22 21:39:39 +0000469}
470
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000471void GrGpuGL::resetContext() {
472 // We detect cases when blending is effectively off
reed@google.comac10a2d2010-12-22 21:39:39 +0000473 fHWBlendDisabled = false;
474 GR_GL(Enable(GL_BLEND));
475
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000476 // we don't use the zb at all
477 GR_GL(Disable(GL_DEPTH_TEST));
478 GR_GL(DepthMask(GL_FALSE));
479
reed@google.comac10a2d2010-12-22 21:39:39 +0000480 GR_GL(Disable(GL_CULL_FACE));
bsalomon@google.comd302f142011-03-03 13:54:13 +0000481 GR_GL(FrontFace(GL_CCW));
482 fHWDrawState.fDrawFace = kBoth_DrawFace;
reed@google.comac10a2d2010-12-22 21:39:39 +0000483
484 GR_GL(Disable(GL_DITHER));
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000485#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000486 GR_GL(Disable(GL_LINE_SMOOTH));
487 GR_GL(Disable(GL_POINT_SMOOTH));
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000488 GR_GL(Disable(GL_MULTISAMPLE));
reed@google.comac10a2d2010-12-22 21:39:39 +0000489#endif
490
bsalomon@google.comd302f142011-03-03 13:54:13 +0000491 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
492 fHWDrawState.fFlagBits = 0;
493
reed@google.comac10a2d2010-12-22 21:39:39 +0000494 // we only ever use lines in hairline mode
495 GR_GL(LineWidth(1));
496
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000497 // invalid
498 fActiveTextureUnitIdx = -1;
reed@google.comac10a2d2010-12-22 21:39:39 +0000499
reed@google.comac10a2d2010-12-22 21:39:39 +0000500 // illegal values
bsalomon@google.comffca4002011-02-22 20:34:01 +0000501 fHWDrawState.fSrcBlend = (GrBlendCoeff)-1;
502 fHWDrawState.fDstBlend = (GrBlendCoeff)-1;
bsalomon@google.com080773c2011-03-15 19:09:25 +0000503
504 fHWDrawState.fBlendConstant = 0x00000000;
505 GR_GL(BlendColor(0,0,0,0));
506
reed@google.comac10a2d2010-12-22 21:39:39 +0000507 fHWDrawState.fColor = GrColor_ILLEGAL;
bsalomon@google.com316f99232011-01-13 21:28:12 +0000508
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000509 fHWDrawState.fViewMatrix = GrMatrix::InvalidMatrix();
bsalomon@google.com316f99232011-01-13 21:28:12 +0000510
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000511 for (int s = 0; s < kNumStages; ++s) {
512 fHWDrawState.fTextures[s] = NULL;
513 fHWDrawState.fSamplerStates[s].setRadial2Params(-GR_ScalarMax,
514 -GR_ScalarMax,
515 true);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000516
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000517 fHWDrawState.fSamplerStates[s].setMatrix(GrMatrix::InvalidMatrix());
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000518 }
bsalomon@google.com316f99232011-01-13 21:28:12 +0000519
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000520 fHWBounds.fScissorRect.invalidate();
reed@google.comac10a2d2010-12-22 21:39:39 +0000521 fHWBounds.fScissorEnabled = false;
522 GR_GL(Disable(GL_SCISSOR_TEST));
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000523 fHWBounds.fViewportRect.invalidate();
reed@google.comac10a2d2010-12-22 21:39:39 +0000524
bsalomon@google.comd302f142011-03-03 13:54:13 +0000525 fHWDrawState.fStencilSettings.invalidate();
reed@google.comac10a2d2010-12-22 21:39:39 +0000526 fHWStencilClip = false;
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000527 fClipState.fClipIsDirty = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000528
529 fHWGeometryState.fIndexBuffer = NULL;
530 fHWGeometryState.fVertexBuffer = NULL;
531 GR_GL(BindBuffer(GL_ARRAY_BUFFER, 0));
532 GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000533 fHWGeometryState.fArrayPtrsDirty = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000534
bsalomon@google.comd302f142011-03-03 13:54:13 +0000535 GR_GL(ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
reed@google.comac10a2d2010-12-22 21:39:39 +0000536 fHWDrawState.fRenderTarget = NULL;
537}
538
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000539GrRenderTarget* GrGpuGL::createPlatformRenderTargetHelper(
reed@google.comac10a2d2010-12-22 21:39:39 +0000540 intptr_t platformRenderTarget,
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000541 int stencilBits,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000542 int width,
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000543 int height) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000544 GrGLRenderTarget::GLRenderTargetIDs rtIDs;
545 rtIDs.fStencilRenderbufferID = 0;
546 rtIDs.fMSColorRenderbufferID = 0;
547 rtIDs.fTexFBOID = 0;
548 rtIDs.fOwnIDs = false;
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000549 GrGLIRect viewport;
reed@google.comac10a2d2010-12-22 21:39:39 +0000550
551 // viewport is in GL coords (top >= bottom)
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000552 viewport.fLeft = 0;
553 viewport.fBottom = 0;
554 viewport.fWidth = width;
555 viewport.fHeight = height;
reed@google.comac10a2d2010-12-22 21:39:39 +0000556
557 rtIDs.fRTFBOID = (GLuint)platformRenderTarget;
558 rtIDs.fTexFBOID = (GLuint)platformRenderTarget;
559
bsalomon@google.com1da07462011-03-10 14:51:57 +0000560 return new GrGLRenderTarget(rtIDs, NULL, stencilBits, viewport, NULL, this);
reed@google.comac10a2d2010-12-22 21:39:39 +0000561}
562
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000563GrRenderTarget* GrGpuGL::createRenderTargetFrom3DApiStateHelper() {
bsalomon@google.com42ab7ea2011-01-19 17:19:40 +0000564
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000565 GrGLRenderTarget::GLRenderTargetIDs rtIDs;
bsalomon@google.com42ab7ea2011-01-19 17:19:40 +0000566
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000567 GR_GL_GetIntegerv(GR_FRAMEBUFFER_BINDING, (GLint*)&rtIDs.fRTFBOID);
568 rtIDs.fTexFBOID = rtIDs.fRTFBOID;
569 rtIDs.fMSColorRenderbufferID = 0;
570 rtIDs.fStencilRenderbufferID = 0;
bsalomon@google.com42ab7ea2011-01-19 17:19:40 +0000571
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000572 GrGLIRect viewport;
573 viewport.setFromGLViewport();
574 GLuint stencilBits;
575 GR_GL_GetIntegerv(GL_STENCIL_BITS, (GLint*)&stencilBits);
576
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000577 rtIDs.fOwnIDs = false;
578
bsalomon@google.com1da07462011-03-10 14:51:57 +0000579 return new GrGLRenderTarget(rtIDs, NULL, stencilBits, viewport, NULL, this);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000580}
581
bsalomon@google.com5782d712011-01-21 21:03:59 +0000582///////////////////////////////////////////////////////////////////////////////
583
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000584static const GLuint UNKNOWN_BITS = ~0;
585
bsalomon@google.com3f3ffd62011-01-18 17:14:52 +0000586// defines stencil formats from more to less preferred
bsalomon@google.com5d18c382011-02-18 16:21:58 +0000587static const struct {
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000588 GLenum fEnum;
589 GLuint fBits;
590} gStencilFormats[] = {
591 {GR_STENCIL_INDEX8, 8},
reed@google.com63100f92011-01-18 21:32:14 +0000592
593#if GR_SUPPORT_GLDESKTOP
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000594 {GR_STENCIL_INDEX16, 16},
reed@google.com63100f92011-01-18 21:32:14 +0000595#endif
596
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000597 {GR_DEPTH24_STENCIL8, 8},
598 {GR_STENCIL_INDEX4, 4},
reed@google.com63100f92011-01-18 21:32:14 +0000599
600#if GR_SUPPORT_GLDESKTOP
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000601 {GL_STENCIL_INDEX, UNKNOWN_BITS},
602 {GR_DEPTH_STENCIL, UNKNOWN_BITS}
bsalomon@google.com3f3ffd62011-01-18 17:14:52 +0000603#endif
604};
605
606// good to set a break-point here to know when createTexture fails
607static GrTexture* return_null_texture() {
608// GrAssert(!"null texture");
609 return NULL;
610}
611
612#if GR_DEBUG
613static size_t as_size_t(int x) {
614 return x;
615}
616#endif
617
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000618GrTexture* GrGpuGL::createTextureHelper(const TextureDesc& desc,
619 const void* srcData,
620 size_t rowBytes) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000621
622#if GR_COLLECT_STATS
623 ++fStats.fTextureCreateCnt;
624#endif
reed@google.com1fcd51e2011-01-05 15:50:27 +0000625
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000626 setSpareTextureUnit();
bsalomon@google.com316f99232011-01-13 21:28:12 +0000627
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000628 static const GrGLTexture::TexParams DEFAULT_PARAMS = {
629 GL_NEAREST,
630 GL_CLAMP_TO_EDGE,
631 GL_CLAMP_TO_EDGE
632 };
reed@google.com1fcd51e2011-01-05 15:50:27 +0000633
reed@google.comac10a2d2010-12-22 21:39:39 +0000634 GrGLTexture::GLTextureDesc glDesc;
635 GLenum internalFormat;
636
637 glDesc.fContentWidth = desc.fWidth;
638 glDesc.fContentHeight = desc.fHeight;
639 glDesc.fAllocWidth = desc.fWidth;
640 glDesc.fAllocHeight = desc.fHeight;
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000641 glDesc.fStencilBits = 0;
reed@google.comac10a2d2010-12-22 21:39:39 +0000642 glDesc.fFormat = desc.fFormat;
643
644 bool renderTarget = 0 != (desc.fFlags & kRenderTarget_TextureFlag);
645 if (!canBeTexture(desc.fFormat,
646 &internalFormat,
647 &glDesc.fUploadFormat,
648 &glDesc.fUploadType)) {
649 return return_null_texture();
650 }
651
652 GrAssert(as_size_t(desc.fAALevel) < GR_ARRAY_COUNT(fAASamples));
653 GLint samples = fAASamples[desc.fAALevel];
654 if (kNone_MSFBO == fMSFBOType && desc.fAALevel != kNone_AALevel) {
655 GrPrintf("AA RT requested but not supported on this platform.");
656 }
657
658 GR_GL(GenTextures(1, &glDesc.fTextureID));
659 if (!glDesc.fTextureID) {
660 return return_null_texture();
661 }
662
663 glDesc.fUploadByteCount = GrTexture::BytesPerPixel(desc.fFormat);
664
665 /*
666 * check if our srcData has extra bytes past each row. If so, we need
667 * to trim those off here, since GL doesn't let us pass the rowBytes as
668 * a parameter to glTexImage2D
669 */
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000670#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000671 if (srcData) {
672 GR_GL(PixelStorei(GL_UNPACK_ROW_LENGTH,
673 rowBytes / glDesc.fUploadByteCount));
674 }
675#else
676 GrAutoSMalloc<128 * 128> trimStorage;
677 size_t trimRowBytes = desc.fWidth * glDesc.fUploadByteCount;
678 if (srcData && (trimRowBytes < rowBytes)) {
679 size_t trimSize = desc.fHeight * trimRowBytes;
680 trimStorage.realloc(trimSize);
681 // now copy the data into our new storage, skipping the trailing bytes
682 const char* src = (const char*)srcData;
683 char* dst = (char*)trimStorage.get();
684 for (uint32_t y = 0; y < desc.fHeight; y++) {
685 memcpy(dst, src, trimRowBytes);
686 src += rowBytes;
687 dst += trimRowBytes;
688 }
689 // now point srcData to our trimmed version
690 srcData = trimStorage.get();
691 }
692#endif
693
reed@google.comac10a2d2010-12-22 21:39:39 +0000694 if (renderTarget) {
bsalomon@google.com0748f212011-02-01 22:56:16 +0000695 if (!this->npotRenderTargetSupport()) {
696 glDesc.fAllocWidth = GrNextPow2(desc.fWidth);
697 glDesc.fAllocHeight = GrNextPow2(desc.fHeight);
698 }
699
reed@google.comac10a2d2010-12-22 21:39:39 +0000700 glDesc.fAllocWidth = GrMax<int>(fMinRenderTargetWidth,
701 glDesc.fAllocWidth);
702 glDesc.fAllocHeight = GrMax<int>(fMinRenderTargetHeight,
703 glDesc.fAllocHeight);
bsalomon@google.com0748f212011-02-01 22:56:16 +0000704 } else if (!this->npotTextureSupport()) {
705 glDesc.fAllocWidth = GrNextPow2(desc.fWidth);
706 glDesc.fAllocHeight = GrNextPow2(desc.fHeight);
reed@google.comac10a2d2010-12-22 21:39:39 +0000707 }
708
709 GR_GL(BindTexture(GL_TEXTURE_2D, glDesc.fTextureID));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000710 GR_GL(TexParameteri(GL_TEXTURE_2D,
711 GL_TEXTURE_MAG_FILTER,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000712 DEFAULT_PARAMS.fFilter));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000713 GR_GL(TexParameteri(GL_TEXTURE_2D,
714 GL_TEXTURE_MIN_FILTER,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000715 DEFAULT_PARAMS.fFilter));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000716 GR_GL(TexParameteri(GL_TEXTURE_2D,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000717 GL_TEXTURE_WRAP_S,
718 DEFAULT_PARAMS.fWrapS));
reed@google.com1fcd51e2011-01-05 15:50:27 +0000719 GR_GL(TexParameteri(GL_TEXTURE_2D,
720 GL_TEXTURE_WRAP_T,
bsalomon@google.comda96ea02010-12-23 16:53:57 +0000721 DEFAULT_PARAMS.fWrapT));
reed@google.comac10a2d2010-12-22 21:39:39 +0000722
723 GR_GL(PixelStorei(GL_UNPACK_ALIGNMENT, glDesc.fUploadByteCount));
724 if (GrTexture::kIndex_8_PixelConfig == desc.fFormat &&
725 supports8BitPalette()) {
726 // ES only supports CompressedTexImage2D, not CompressedTexSubimage2D
727 GrAssert(desc.fWidth == glDesc.fAllocWidth);
728 GrAssert(desc.fHeight == glDesc.fAllocHeight);
729 GLsizei imageSize = glDesc.fAllocWidth * glDesc.fAllocHeight +
730 kColorTableSize;
731 GR_GL(CompressedTexImage2D(GL_TEXTURE_2D, 0, glDesc.fUploadFormat,
732 glDesc.fAllocWidth, glDesc.fAllocHeight,
733 0, imageSize, srcData));
734 GrGL_RestoreResetRowLength();
735 } else {
736 if (NULL != srcData && (glDesc.fAllocWidth != desc.fWidth ||
737 glDesc.fAllocHeight != desc.fHeight)) {
738 GR_GL(TexImage2D(GL_TEXTURE_2D, 0, internalFormat,
739 glDesc.fAllocWidth, glDesc.fAllocHeight,
740 0, glDesc.fUploadFormat, glDesc.fUploadType, NULL));
741 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, desc.fWidth,
742 desc.fHeight, glDesc.fUploadFormat,
743 glDesc.fUploadType, srcData));
744 GrGL_RestoreResetRowLength();
745
746 uint32_t extraW = glDesc.fAllocWidth - desc.fWidth;
747 uint32_t extraH = glDesc.fAllocHeight - desc.fHeight;
748 uint32_t maxTexels = extraW * extraH;
749 maxTexels = GrMax(extraW * desc.fHeight, maxTexels);
750 maxTexels = GrMax(desc.fWidth * extraH, maxTexels);
751
752 GrAutoSMalloc<128*128> texels(glDesc.fUploadByteCount * maxTexels);
753
754 uint32_t rowSize = desc.fWidth * glDesc.fUploadByteCount;
755 if (extraH) {
756 uint8_t* lastRowStart = (uint8_t*) srcData +
757 (desc.fHeight - 1) * rowSize;
758 uint8_t* extraRowStart = (uint8_t*)texels.get();
759
760 for (uint32_t i = 0; i < extraH; ++i) {
761 memcpy(extraRowStart, lastRowStart, rowSize);
762 extraRowStart += rowSize;
763 }
764 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, 0, desc.fHeight, desc.fWidth,
765 extraH, glDesc.fUploadFormat, glDesc.fUploadType,
766 texels.get()));
767 }
768 if (extraW) {
769 uint8_t* edgeTexel = (uint8_t*)srcData + rowSize - glDesc.fUploadByteCount;
770 uint8_t* extraTexel = (uint8_t*)texels.get();
771 for (uint32_t j = 0; j < desc.fHeight; ++j) {
772 for (uint32_t i = 0; i < extraW; ++i) {
773 memcpy(extraTexel, edgeTexel, glDesc.fUploadByteCount);
774 extraTexel += glDesc.fUploadByteCount;
775 }
776 edgeTexel += rowSize;
777 }
778 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, desc.fWidth, 0, extraW,
779 desc.fHeight, glDesc.fUploadFormat,
780 glDesc.fUploadType, texels.get()));
781 }
782 if (extraW && extraH) {
783 uint8_t* cornerTexel = (uint8_t*)srcData + desc.fHeight * rowSize
784 - glDesc.fUploadByteCount;
785 uint8_t* extraTexel = (uint8_t*)texels.get();
786 for (uint32_t i = 0; i < extraW*extraH; ++i) {
787 memcpy(extraTexel, cornerTexel, glDesc.fUploadByteCount);
788 extraTexel += glDesc.fUploadByteCount;
789 }
790 GR_GL(TexSubImage2D(GL_TEXTURE_2D, 0, desc.fWidth, desc.fHeight,
791 extraW, extraH, glDesc.fUploadFormat,
792 glDesc.fUploadType, texels.get()));
793 }
794
795 } else {
796 GR_GL(TexImage2D(GL_TEXTURE_2D, 0, internalFormat, glDesc.fAllocWidth,
797 glDesc.fAllocHeight, 0, glDesc.fUploadFormat,
798 glDesc.fUploadType, srcData));
799 GrGL_RestoreResetRowLength();
800 }
801 }
802
803 glDesc.fOrientation = GrGLTexture::kTopDown_Orientation;
804
805 GrGLRenderTarget::GLRenderTargetIDs rtIDs;
806 rtIDs.fStencilRenderbufferID = 0;
807 rtIDs.fMSColorRenderbufferID = 0;
808 rtIDs.fRTFBOID = 0;
809 rtIDs.fTexFBOID = 0;
810 rtIDs.fOwnIDs = true;
811 GLenum msColorRenderbufferFormat = -1;
812
813 if (renderTarget) {
814#if GR_COLLECT_STATS
815 ++fStats.fRenderTargetCreateCnt;
816#endif
817 bool failed = true;
818 GLenum status;
819 GLint err;
820
821 // If need have both RT flag and srcData we have
822 // to invert the data before uploading because FBO
823 // will be rendered bottom up
824 GrAssert(NULL == srcData);
825 glDesc.fOrientation = GrGLTexture::kBottomUp_Orientation;
826
twiz@google.com59a190b2011-03-14 21:23:01 +0000827 GR_GL(GenFramebuffers(1, &rtIDs.fTexFBOID));
reed@google.comac10a2d2010-12-22 21:39:39 +0000828 GrAssert(rtIDs.fTexFBOID);
829
830 // If we are using multisampling and any extension other than the IMG
831 // one we will create two FBOs. We render to one and then resolve to
832 // the texture bound to the other. The IMG extension does an implicit
833 // resolve.
834 if (samples > 1 && kIMG_MSFBO != fMSFBOType && kNone_MSFBO != fMSFBOType) {
twiz@google.com59a190b2011-03-14 21:23:01 +0000835 GR_GL(GenFramebuffers(1, &rtIDs.fRTFBOID));
reed@google.comac10a2d2010-12-22 21:39:39 +0000836 GrAssert(0 != rtIDs.fRTFBOID);
twiz@google.com59a190b2011-03-14 21:23:01 +0000837 GR_GL(GenRenderbuffers(1, &rtIDs.fMSColorRenderbufferID));
reed@google.comac10a2d2010-12-22 21:39:39 +0000838 GrAssert(0 != rtIDs.fMSColorRenderbufferID);
839 if (!fboInternalFormat(desc.fFormat, &msColorRenderbufferFormat)) {
twiz@google.com59a190b2011-03-14 21:23:01 +0000840 GR_GL(DeleteRenderbuffers(1, &rtIDs.fMSColorRenderbufferID));
reed@google.comac10a2d2010-12-22 21:39:39 +0000841 GR_GL(DeleteTextures(1, &glDesc.fTextureID));
twiz@google.com59a190b2011-03-14 21:23:01 +0000842 GR_GL(DeleteFramebuffers(1, &rtIDs.fTexFBOID));
843 GR_GL(DeleteFramebuffers(1, &rtIDs.fRTFBOID));
reed@google.comac10a2d2010-12-22 21:39:39 +0000844 return return_null_texture();
845 }
846 } else {
847 rtIDs.fRTFBOID = rtIDs.fTexFBOID;
848 }
849 int attempts = 1;
850 if (!(kNoPathRendering_TextureFlag & desc.fFlags)) {
twiz@google.com59a190b2011-03-14 21:23:01 +0000851 GR_GL(GenRenderbuffers(1, &rtIDs.fStencilRenderbufferID));
reed@google.comac10a2d2010-12-22 21:39:39 +0000852 GrAssert(0 != rtIDs.fStencilRenderbufferID);
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000853 attempts = GR_ARRAY_COUNT(gStencilFormats);
reed@google.comac10a2d2010-12-22 21:39:39 +0000854 }
855
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000856 // someone suggested that some systems might require
bsalomon@google.com316f99232011-01-13 21:28:12 +0000857 // unbinding the texture before we call FramebufferTexture2D
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000858 // (seems unlikely)
reed@google.comac10a2d2010-12-22 21:39:39 +0000859 GR_GL(BindTexture(GL_TEXTURE_2D, 0));
reed@google.comac10a2d2010-12-22 21:39:39 +0000860
861 err = ~GL_NO_ERROR;
862 for (int i = 0; i < attempts; ++i) {
863 if (rtIDs.fStencilRenderbufferID) {
twiz@google.com59a190b2011-03-14 21:23:01 +0000864 GR_GL(BindRenderbuffer(GR_RENDERBUFFER,
865 rtIDs.fStencilRenderbufferID));
reed@google.comac10a2d2010-12-22 21:39:39 +0000866 if (samples > 1) {
twiz@google.com59a190b2011-03-14 21:23:01 +0000867 GR_GL_NO_ERR(RenderbufferStorageMultisample(
reed@google.comac10a2d2010-12-22 21:39:39 +0000868 GR_RENDERBUFFER,
869 samples,
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000870 gStencilFormats[i].fEnum,
reed@google.comac10a2d2010-12-22 21:39:39 +0000871 glDesc.fAllocWidth,
872 glDesc.fAllocHeight));
873 } else {
twiz@google.com59a190b2011-03-14 21:23:01 +0000874 GR_GL_NO_ERR(RenderbufferStorage(GR_RENDERBUFFER,
875 gStencilFormats[i].fEnum,
876 glDesc.fAllocWidth,
877 glDesc.fAllocHeight));
reed@google.comac10a2d2010-12-22 21:39:39 +0000878 }
879 err = glGetError();
880 if (err != GL_NO_ERROR) {
881 continue;
882 }
883 }
884 if (rtIDs.fRTFBOID != rtIDs.fTexFBOID) {
885 GrAssert(samples > 1);
twiz@google.com59a190b2011-03-14 21:23:01 +0000886 GR_GL(BindRenderbuffer(GR_RENDERBUFFER,
887 rtIDs.fMSColorRenderbufferID));
888 GR_GL_NO_ERR(RenderbufferStorageMultisample(
reed@google.comac10a2d2010-12-22 21:39:39 +0000889 GR_RENDERBUFFER,
890 samples,
891 msColorRenderbufferFormat,
892 glDesc.fAllocWidth,
893 glDesc.fAllocHeight));
894 err = glGetError();
895 if (err != GL_NO_ERROR) {
896 continue;
897 }
898 }
twiz@google.com59a190b2011-03-14 21:23:01 +0000899 GR_GL(BindFramebuffer(GR_FRAMEBUFFER, rtIDs.fTexFBOID));
reed@google.comac10a2d2010-12-22 21:39:39 +0000900
901#if GR_COLLECT_STATS
902 ++fStats.fRenderTargetChngCnt;
903#endif
904 if (kIMG_MSFBO == fMSFBOType && samples > 1) {
twiz@google.com59a190b2011-03-14 21:23:01 +0000905 GR_GL(FramebufferTexture2DMultisample(GR_FRAMEBUFFER,
906 GR_COLOR_ATTACHMENT0,
907 GL_TEXTURE_2D,
908 glDesc.fTextureID,
909 0,
910 samples));
reed@google.comac10a2d2010-12-22 21:39:39 +0000911
912 } else {
twiz@google.com59a190b2011-03-14 21:23:01 +0000913 GR_GL(FramebufferTexture2D(GR_FRAMEBUFFER,
914 GR_COLOR_ATTACHMENT0,
915 GL_TEXTURE_2D,
916 glDesc.fTextureID, 0));
reed@google.comac10a2d2010-12-22 21:39:39 +0000917 }
918 if (rtIDs.fRTFBOID != rtIDs.fTexFBOID) {
twiz@google.com59a190b2011-03-14 21:23:01 +0000919 GLenum status = GR_GL(CheckFramebufferStatus(GR_FRAMEBUFFER));
reed@google.comac10a2d2010-12-22 21:39:39 +0000920 if (status != GR_FRAMEBUFFER_COMPLETE) {
921 GrPrintf("-- glCheckFramebufferStatus %x %d %d\n",
922 status, desc.fWidth, desc.fHeight);
923 continue;
924 }
twiz@google.com59a190b2011-03-14 21:23:01 +0000925 GR_GL(BindFramebuffer(GR_FRAMEBUFFER, rtIDs.fRTFBOID));
reed@google.comac10a2d2010-12-22 21:39:39 +0000926 #if GR_COLLECT_STATS
927 ++fStats.fRenderTargetChngCnt;
928 #endif
twiz@google.com59a190b2011-03-14 21:23:01 +0000929 GR_GL(FramebufferRenderbuffer(GR_FRAMEBUFFER,
930 GR_COLOR_ATTACHMENT0,
931 GR_RENDERBUFFER,
932 rtIDs.fMSColorRenderbufferID));
reed@google.comac10a2d2010-12-22 21:39:39 +0000933
934 }
935 if (rtIDs.fStencilRenderbufferID) {
936 // bind the stencil to rt fbo if present, othewise the tex fbo
twiz@google.com59a190b2011-03-14 21:23:01 +0000937 GR_GL(FramebufferRenderbuffer(GR_FRAMEBUFFER,
938 GR_STENCIL_ATTACHMENT,
939 GR_RENDERBUFFER,
940 rtIDs.fStencilRenderbufferID));
reed@google.comac10a2d2010-12-22 21:39:39 +0000941 }
twiz@google.com59a190b2011-03-14 21:23:01 +0000942 status = GR_GL(CheckFramebufferStatus(GR_FRAMEBUFFER));
reed@google.comac10a2d2010-12-22 21:39:39 +0000943
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000944#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000945 // On some implementations you have to be bound as DEPTH_STENCIL.
946 // (Even binding to DEPTH and STENCIL separately with the same
947 // buffer doesn't work.)
948 if (rtIDs.fStencilRenderbufferID &&
949 status != GR_FRAMEBUFFER_COMPLETE) {
twiz@google.com59a190b2011-03-14 21:23:01 +0000950 GR_GL(FramebufferRenderbuffer(GR_FRAMEBUFFER,
951 GR_STENCIL_ATTACHMENT,
952 GR_RENDERBUFFER,
953 0));
954 GR_GL(FramebufferRenderbuffer(GR_FRAMEBUFFER,
955 GR_DEPTH_STENCIL_ATTACHMENT,
956 GR_RENDERBUFFER,
957 rtIDs.fStencilRenderbufferID));
958 status = GR_GL(CheckFramebufferStatus(GR_FRAMEBUFFER));
reed@google.comac10a2d2010-12-22 21:39:39 +0000959 }
960#endif
961 if (status != GR_FRAMEBUFFER_COMPLETE) {
962 GrPrintf("-- glCheckFramebufferStatus %x %d %d\n",
963 status, desc.fWidth, desc.fHeight);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000964#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +0000965 if (rtIDs.fStencilRenderbufferID) {
twiz@google.com59a190b2011-03-14 21:23:01 +0000966 GR_GL(FramebufferRenderbuffer(GR_FRAMEBUFFER,
967 GR_DEPTH_STENCIL_ATTACHMENT,
968 GR_RENDERBUFFER,
969 0));
reed@google.comac10a2d2010-12-22 21:39:39 +0000970 }
971#endif
972 continue;
973 }
974 // we're successful!
975 failed = false;
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000976 if (rtIDs.fStencilRenderbufferID) {
977 if (UNKNOWN_BITS == gStencilFormats[i].fBits) {
978 GR_GL_GetIntegerv(GL_STENCIL_BITS, (GLint*)&glDesc.fStencilBits);
979 } else {
980 glDesc.fStencilBits = gStencilFormats[i].fBits;
981 }
982 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000983 break;
984 }
985 if (failed) {
986 if (rtIDs.fStencilRenderbufferID) {
twiz@google.com59a190b2011-03-14 21:23:01 +0000987 GR_GL(DeleteRenderbuffers(1, &rtIDs.fStencilRenderbufferID));
reed@google.comac10a2d2010-12-22 21:39:39 +0000988 }
989 if (rtIDs.fMSColorRenderbufferID) {
twiz@google.com59a190b2011-03-14 21:23:01 +0000990 GR_GL(DeleteRenderbuffers(1, &rtIDs.fMSColorRenderbufferID));
reed@google.comac10a2d2010-12-22 21:39:39 +0000991 }
992 if (rtIDs.fRTFBOID != rtIDs.fTexFBOID) {
twiz@google.com59a190b2011-03-14 21:23:01 +0000993 GR_GL(DeleteFramebuffers(1, &rtIDs.fRTFBOID));
reed@google.comac10a2d2010-12-22 21:39:39 +0000994 }
995 if (rtIDs.fTexFBOID) {
twiz@google.com59a190b2011-03-14 21:23:01 +0000996 GR_GL(DeleteFramebuffers(1, &rtIDs.fTexFBOID));
reed@google.comac10a2d2010-12-22 21:39:39 +0000997 }
998 GR_GL(DeleteTextures(1, &glDesc.fTextureID));
999 return return_null_texture();
1000 }
1001 }
1002#ifdef TRACE_TEXTURE_CREATION
1003 GrPrintf("--- new texture [%d] size=(%d %d) bpp=%d\n",
1004 tex->fTextureID, width, height, tex->fUploadByteCount);
1005#endif
bsalomon@google.comda96ea02010-12-23 16:53:57 +00001006 GrGLTexture* tex = new GrGLTexture(glDesc, rtIDs, DEFAULT_PARAMS, this);
reed@google.comac10a2d2010-12-22 21:39:39 +00001007
1008 if (0 != rtIDs.fTexFBOID) {
1009 GrRenderTarget* rt = tex->asRenderTarget();
1010 // We've messed with FBO state but may not have set the correct viewport
1011 // so just dirty the rendertarget state to force a resend.
1012 fHWDrawState.fRenderTarget = NULL;
1013
1014 // clear the new stencil buffer if we have one
1015 if (!(desc.fFlags & kNoPathRendering_TextureFlag)) {
1016 GrRenderTarget* rtSave = fCurrDrawState.fRenderTarget;
1017 fCurrDrawState.fRenderTarget = rt;
1018 eraseStencil(0, ~0);
1019 fCurrDrawState.fRenderTarget = rtSave;
1020 }
1021 }
1022 return tex;
1023}
1024
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001025GrVertexBuffer* GrGpuGL::createVertexBufferHelper(uint32_t size, bool dynamic) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001026 GLuint id;
1027 GR_GL(GenBuffers(1, &id));
1028 if (id) {
1029 GR_GL(BindBuffer(GL_ARRAY_BUFFER, id));
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001030 fHWGeometryState.fArrayPtrsDirty = true;
reed@google.comac10a2d2010-12-22 21:39:39 +00001031 GrGLClearErr();
1032 // make sure driver can allocate memory for this buffer
1033 GR_GL_NO_ERR(BufferData(GL_ARRAY_BUFFER, size, NULL,
1034 dynamic ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW));
1035 if (glGetError() != GL_NO_ERROR) {
1036 GR_GL(DeleteBuffers(1, &id));
1037 // deleting bound buffer does implicit bind to 0
1038 fHWGeometryState.fVertexBuffer = NULL;
1039 return NULL;
1040 }
1041 GrGLVertexBuffer* vertexBuffer = new GrGLVertexBuffer(id, this,
1042 size, dynamic);
1043 fHWGeometryState.fVertexBuffer = vertexBuffer;
1044 return vertexBuffer;
1045 }
1046 return NULL;
1047}
1048
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001049GrIndexBuffer* GrGpuGL::createIndexBufferHelper(uint32_t size, bool dynamic) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001050 GLuint id;
1051 GR_GL(GenBuffers(1, &id));
1052 if (id) {
1053 GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, id));
1054 GrGLClearErr();
1055 // make sure driver can allocate memory for this buffer
1056 GR_GL_NO_ERR(BufferData(GL_ELEMENT_ARRAY_BUFFER, size, NULL,
1057 dynamic ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW));
1058 if (glGetError() != GL_NO_ERROR) {
1059 GR_GL(DeleteBuffers(1, &id));
1060 // deleting bound buffer does implicit bind to 0
1061 fHWGeometryState.fIndexBuffer = NULL;
1062 return NULL;
1063 }
1064 GrIndexBuffer* indexBuffer = new GrGLIndexBuffer(id, this,
1065 size, dynamic);
1066 fHWGeometryState.fIndexBuffer = indexBuffer;
1067 return indexBuffer;
1068 }
1069 return NULL;
1070}
1071
reed@google.comac10a2d2010-12-22 21:39:39 +00001072void GrGpuGL::flushScissor(const GrIRect* rect) {
1073 GrAssert(NULL != fCurrDrawState.fRenderTarget);
bsalomon@google.com8895a7a2011-02-18 16:09:55 +00001074 const GrGLIRect& vp =
bsalomon@google.comd302f142011-03-03 13:54:13 +00001075 ((GrGLRenderTarget*)fCurrDrawState.fRenderTarget)->getViewport();
reed@google.comac10a2d2010-12-22 21:39:39 +00001076
bsalomon@google.com8895a7a2011-02-18 16:09:55 +00001077 GrGLIRect scissor;
1078 if (NULL != rect) {
bsalomon@google.comd302f142011-03-03 13:54:13 +00001079 scissor.setRelativeTo(vp, rect->fLeft, rect->fTop,
bsalomon@google.com8895a7a2011-02-18 16:09:55 +00001080 rect->width(), rect->height());
1081 if (scissor.contains(vp)) {
1082 rect = NULL;
1083 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001084 }
1085
1086 if (NULL != rect) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001087 if (fHWBounds.fScissorRect != scissor) {
bsalomon@google.com8895a7a2011-02-18 16:09:55 +00001088 scissor.pushToGLScissor();
reed@google.comac10a2d2010-12-22 21:39:39 +00001089 fHWBounds.fScissorRect = scissor;
1090 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001091 if (!fHWBounds.fScissorEnabled) {
1092 GR_GL(Enable(GL_SCISSOR_TEST));
1093 fHWBounds.fScissorEnabled = true;
1094 }
1095 } else {
1096 if (fHWBounds.fScissorEnabled) {
1097 GR_GL(Disable(GL_SCISSOR_TEST));
1098 fHWBounds.fScissorEnabled = false;
1099 }
1100 }
1101}
1102
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001103void GrGpuGL::eraseColorHelper(GrColor color) {
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +00001104 if (NULL == fCurrDrawState.fRenderTarget) {
1105 return;
1106 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001107 flushRenderTarget();
1108 if (fHWBounds.fScissorEnabled) {
1109 GR_GL(Disable(GL_SCISSOR_TEST));
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +00001110 fHWBounds.fScissorEnabled = false;
reed@google.comac10a2d2010-12-22 21:39:39 +00001111 }
1112 GR_GL(ColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE));
bsalomon@google.comd302f142011-03-03 13:54:13 +00001113 fHWDrawState.fFlagBits &= ~kNoColorWrites_StateBit;
reed@google.comac10a2d2010-12-22 21:39:39 +00001114 GR_GL(ClearColor(GrColorUnpackR(color)/255.f,
1115 GrColorUnpackG(color)/255.f,
1116 GrColorUnpackB(color)/255.f,
1117 GrColorUnpackA(color)/255.f));
1118 GR_GL(Clear(GL_COLOR_BUFFER_BIT));
reed@google.comac10a2d2010-12-22 21:39:39 +00001119}
1120
1121void GrGpuGL::eraseStencil(uint32_t value, uint32_t mask) {
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +00001122 if (NULL == fCurrDrawState.fRenderTarget) {
1123 return;
1124 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001125 flushRenderTarget();
1126 if (fHWBounds.fScissorEnabled) {
1127 GR_GL(Disable(GL_SCISSOR_TEST));
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +00001128 fHWBounds.fScissorEnabled = false;
reed@google.comac10a2d2010-12-22 21:39:39 +00001129 }
1130 GR_GL(StencilMask(mask));
1131 GR_GL(ClearStencil(value));
1132 GR_GL(Clear(GL_STENCIL_BUFFER_BIT));
bsalomon@google.comd302f142011-03-03 13:54:13 +00001133 fHWDrawState.fStencilSettings.invalidate();
reed@google.comac10a2d2010-12-22 21:39:39 +00001134}
1135
bsalomon@google.comd302f142011-03-03 13:54:13 +00001136void GrGpuGL::eraseStencilClip(const GrIRect& rect) {
bsalomon@google.com8895a7a2011-02-18 16:09:55 +00001137 GrAssert(NULL != fCurrDrawState.fRenderTarget);
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +00001138#if 0
bsalomon@google.comd302f142011-03-03 13:54:13 +00001139 GLint stencilBitCount = fCurrDrawState.fRenderTarget->stencilBits();
reed@google.comac10a2d2010-12-22 21:39:39 +00001140 GrAssert(stencilBitCount > 0);
1141 GLint clipStencilMask = (1 << (stencilBitCount - 1));
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +00001142#else
1143 // we could just clear the clip bit but when we go through
1144 // angle a partial stencil mask will cause clears to be
1145 // turned into draws. Our contract on GrDrawTarget says that
1146 // changing the clip between stencil passes may or may not
1147 // zero the client's clip bits. So we just clear the whole thing.
1148 static const GLint clipStencilMask = ~0;
1149#endif
bsalomon@google.comd302f142011-03-03 13:54:13 +00001150 flushRenderTarget();
1151 flushScissor(&rect);
1152 GR_GL(StencilMask(clipStencilMask));
1153 GR_GL(ClearStencil(0));
1154 GR_GL(Clear(GL_STENCIL_BUFFER_BIT));
1155 fHWDrawState.fStencilSettings.invalidate();
reed@google.comac10a2d2010-12-22 21:39:39 +00001156}
1157
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001158void GrGpuGL::forceRenderTargetFlushHelper() {
reed@google.comac10a2d2010-12-22 21:39:39 +00001159 flushRenderTarget();
1160}
1161
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001162bool GrGpuGL::readPixelsHelper(int left, int top, int width, int height,
1163 GrTexture::PixelConfig config, void* buffer) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001164 GLenum internalFormat; // we don't use this for glReadPixels
1165 GLenum format;
1166 GLenum type;
1167 if (!this->canBeTexture(config, &internalFormat, &format, &type)) {
1168 return false;
1169 }
1170
bsalomon@google.com18908aa2011-02-07 14:51:55 +00001171 if (NULL == fCurrDrawState.fRenderTarget) {
1172 return false;
1173 }
1174 flushRenderTarget();
1175
bsalomon@google.comd302f142011-03-03 13:54:13 +00001176 const GrGLIRect& glvp = ((GrGLRenderTarget*)fCurrDrawState.fRenderTarget)->getViewport();
1177
bsalomon@google.com8895a7a2011-02-18 16:09:55 +00001178 // the read rect is viewport-relative
1179 GrGLIRect readRect;
1180 readRect.setRelativeTo(glvp, left, top, width, height);
1181 GR_GL(ReadPixels(readRect.fLeft, readRect.fBottom,
bsalomon@google.comd302f142011-03-03 13:54:13 +00001182 readRect.fWidth, readRect.fHeight,
bsalomon@google.com316f99232011-01-13 21:28:12 +00001183 format, type, buffer));
reed@google.comac10a2d2010-12-22 21:39:39 +00001184
1185 // now reverse the order of the rows, since GL's are bottom-to-top, but our
1186 // API presents top-to-bottom
1187 {
1188 size_t stride = width * GrTexture::BytesPerPixel(config);
1189 GrAutoMalloc rowStorage(stride);
1190 void* tmp = rowStorage.get();
1191
1192 const int halfY = height >> 1;
1193 char* top = reinterpret_cast<char*>(buffer);
1194 char* bottom = top + (height - 1) * stride;
1195 for (int y = 0; y < halfY; y++) {
1196 memcpy(tmp, top, stride);
1197 memcpy(top, bottom, stride);
1198 memcpy(bottom, tmp, stride);
1199 top += stride;
1200 bottom -= stride;
1201 }
1202 }
1203 return true;
1204}
1205
1206void GrGpuGL::flushRenderTarget() {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001207
1208 GrAssert(NULL != fCurrDrawState.fRenderTarget);
1209
reed@google.comac10a2d2010-12-22 21:39:39 +00001210 if (fHWDrawState.fRenderTarget != fCurrDrawState.fRenderTarget) {
1211 GrGLRenderTarget* rt = (GrGLRenderTarget*)fCurrDrawState.fRenderTarget;
twiz@google.com59a190b2011-03-14 21:23:01 +00001212 GR_GL(BindFramebuffer(GR_FRAMEBUFFER, rt->renderFBOID()));
reed@google.comac10a2d2010-12-22 21:39:39 +00001213 #if GR_COLLECT_STATS
1214 ++fStats.fRenderTargetChngCnt;
1215 #endif
1216 rt->setDirty(true);
1217 #if GR_DEBUG
twiz@google.com59a190b2011-03-14 21:23:01 +00001218 GLenum status = GR_GL(CheckFramebufferStatus(GR_FRAMEBUFFER));
reed@google.comac10a2d2010-12-22 21:39:39 +00001219 if (status != GR_FRAMEBUFFER_COMPLETE) {
1220 GrPrintf("-- glCheckFramebufferStatus %x\n", status);
1221 }
1222 #endif
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001223 fDirtyFlags.fRenderTargetChanged = true;
bsalomon@google.com8895a7a2011-02-18 16:09:55 +00001224 fHWDrawState.fRenderTarget = fCurrDrawState.fRenderTarget;
bsalomon@google.comd302f142011-03-03 13:54:13 +00001225 const GrGLIRect& vp = rt->getViewport();
bsalomon@google.com649a8622011-03-10 14:53:38 +00001226 if (fHWBounds.fViewportRect != vp) {
bsalomon@google.com8895a7a2011-02-18 16:09:55 +00001227 vp.pushToGLViewport();
reed@google.comac10a2d2010-12-22 21:39:39 +00001228 fHWBounds.fViewportRect = vp;
1229 }
1230 }
1231}
1232
1233GLenum gPrimitiveType2GLMode[] = {
1234 GL_TRIANGLES,
1235 GL_TRIANGLE_STRIP,
1236 GL_TRIANGLE_FAN,
1237 GL_POINTS,
1238 GL_LINES,
1239 GL_LINE_STRIP
1240};
1241
bsalomon@google.comd302f142011-03-03 13:54:13 +00001242#define SWAP_PER_DRAW 0
1243
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001244#if SWAP_PER_DRAW
bsalomon@google.comd302f142011-03-03 13:54:13 +00001245 #if GR_MAC_BUILD
1246 #include <AGL/agl.h>
1247 #elif GR_WIN32_BUILD
1248 void SwapBuf() {
1249 DWORD procID = GetCurrentProcessId();
1250 HWND hwnd = GetTopWindow(GetDesktopWindow());
1251 while(hwnd) {
1252 DWORD wndProcID = 0;
1253 GetWindowThreadProcessId(hwnd, &wndProcID);
1254 if(wndProcID == procID) {
1255 SwapBuffers(GetDC(hwnd));
1256 }
1257 hwnd = GetNextWindow(hwnd, GW_HWNDNEXT);
1258 }
1259 }
1260 #endif
1261#endif
1262
bsalomon@google.comffca4002011-02-22 20:34:01 +00001263void GrGpuGL::drawIndexedHelper(GrPrimitiveType type,
reed@google.comac10a2d2010-12-22 21:39:39 +00001264 uint32_t startVertex,
1265 uint32_t startIndex,
1266 uint32_t vertexCount,
1267 uint32_t indexCount) {
1268 GrAssert((size_t)type < GR_ARRAY_COUNT(gPrimitiveType2GLMode));
1269
1270 GLvoid* indices = (GLvoid*)(sizeof(uint16_t) * startIndex);
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001271
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001272 GrAssert(NULL != fHWGeometryState.fIndexBuffer);
1273 GrAssert(NULL != fHWGeometryState.fVertexBuffer);
1274
1275 // our setupGeometry better have adjusted this to zero since
1276 // DrawElements always draws from the begining of the arrays for idx 0.
1277 GrAssert(0 == startVertex);
reed@google.comac10a2d2010-12-22 21:39:39 +00001278
1279 GR_GL(DrawElements(gPrimitiveType2GLMode[type], indexCount,
1280 GL_UNSIGNED_SHORT, indices));
bsalomon@google.comd302f142011-03-03 13:54:13 +00001281#if SWAP_PER_DRAW
1282 glFlush();
1283 #if GR_MAC_BUILD
1284 aglSwapBuffers(aglGetCurrentContext());
1285 int set_a_break_pt_here = 9;
1286 aglSwapBuffers(aglGetCurrentContext());
1287 #elif GR_WIN32_BUILD
1288 SwapBuf();
1289 int set_a_break_pt_here = 9;
1290 SwapBuf();
1291 #endif
1292#endif
reed@google.comac10a2d2010-12-22 21:39:39 +00001293}
1294
bsalomon@google.comffca4002011-02-22 20:34:01 +00001295void GrGpuGL::drawNonIndexedHelper(GrPrimitiveType type,
reed@google.comac10a2d2010-12-22 21:39:39 +00001296 uint32_t startVertex,
1297 uint32_t vertexCount) {
1298 GrAssert((size_t)type < GR_ARRAY_COUNT(gPrimitiveType2GLMode));
1299
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001300 GrAssert(NULL != fHWGeometryState.fVertexBuffer);
1301
1302 // our setupGeometry better have adjusted this to zero.
1303 // DrawElements doesn't take an offset so we always adjus the startVertex.
1304 GrAssert(0 == startVertex);
1305
1306 // pass 0 for parameter first. We have to adjust gl*Pointer() to
1307 // account for startVertex in the DrawElements case. So we always
1308 // rely on setupGeometry to have accounted for startVertex.
reed@google.comac10a2d2010-12-22 21:39:39 +00001309 GR_GL(DrawArrays(gPrimitiveType2GLMode[type], 0, vertexCount));
bsalomon@google.comd302f142011-03-03 13:54:13 +00001310#if SWAP_PER_DRAW
1311 glFlush();
1312 #if GR_MAC_BUILD
1313 aglSwapBuffers(aglGetCurrentContext());
1314 int set_a_break_pt_here = 9;
1315 aglSwapBuffers(aglGetCurrentContext());
1316 #elif GR_WIN32_BUILD
1317 SwapBuf();
1318 int set_a_break_pt_here = 9;
1319 SwapBuf();
1320 #endif
1321#endif
reed@google.comac10a2d2010-12-22 21:39:39 +00001322}
1323
reed@google.comac10a2d2010-12-22 21:39:39 +00001324void GrGpuGL::resolveTextureRenderTarget(GrGLTexture* texture) {
1325 GrGLRenderTarget* rt = (GrGLRenderTarget*) texture->asRenderTarget();
1326
1327 if (NULL != rt && rt->needsResolve()) {
1328 GrAssert(kNone_MSFBO != fMSFBOType);
1329 GrAssert(rt->textureFBOID() != rt->renderFBOID());
twiz@google.com59a190b2011-03-14 21:23:01 +00001330 GR_GL(BindFramebuffer(GR_READ_FRAMEBUFFER,
reed@google.comac10a2d2010-12-22 21:39:39 +00001331 rt->renderFBOID()));
twiz@google.com59a190b2011-03-14 21:23:01 +00001332 GR_GL(BindFramebuffer(GR_DRAW_FRAMEBUFFER,
reed@google.comac10a2d2010-12-22 21:39:39 +00001333 rt->textureFBOID()));
1334 #if GR_COLLECT_STATS
1335 ++fStats.fRenderTargetChngCnt;
1336 #endif
1337 // make sure we go through set render target
1338 fHWDrawState.fRenderTarget = NULL;
1339
1340 GLint left = 0;
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001341 GLint right = texture->width();
reed@google.comac10a2d2010-12-22 21:39:39 +00001342 // we will have rendered to the top of the FBO.
1343 GLint top = texture->allocHeight();
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001344 GLint bottom = texture->allocHeight() - texture->height();
reed@google.comac10a2d2010-12-22 21:39:39 +00001345 if (kApple_MSFBO == fMSFBOType) {
1346 GR_GL(Enable(GL_SCISSOR_TEST));
1347 GR_GL(Scissor(left, bottom, right-left, top-bottom));
twiz@google.com59a190b2011-03-14 21:23:01 +00001348 GR_GL(ResolveMultisampleFramebuffer());
bsalomon@google.com8895a7a2011-02-18 16:09:55 +00001349 fHWBounds.fScissorRect.invalidate();
reed@google.comac10a2d2010-12-22 21:39:39 +00001350 fHWBounds.fScissorEnabled = true;
1351 } else {
twiz@google.com59a190b2011-03-14 21:23:01 +00001352 GR_GL(BlitFramebuffer(left, bottom, right, top,
reed@google.comac10a2d2010-12-22 21:39:39 +00001353 left, bottom, right, top,
1354 GL_COLOR_BUFFER_BIT, GL_NEAREST));
1355 }
1356 rt->setDirty(false);
1357
1358 }
1359}
1360
bsalomon@google.comd302f142011-03-03 13:54:13 +00001361static const GLenum grToGLStencilFunc[] = {
1362 GL_ALWAYS, // kAlways_StencilFunc
1363 GL_NEVER, // kNever_StencilFunc
1364 GL_GREATER, // kGreater_StencilFunc
1365 GL_GEQUAL, // kGEqual_StencilFunc
1366 GL_LESS, // kLess_StencilFunc
1367 GL_LEQUAL, // kLEqual_StencilFunc,
1368 GL_EQUAL, // kEqual_StencilFunc,
1369 GL_NOTEQUAL, // kNotEqual_StencilFunc,
1370};
1371GR_STATIC_ASSERT(GR_ARRAY_COUNT(grToGLStencilFunc) == kBasicStencilFuncCount);
1372GR_STATIC_ASSERT(0 == kAlways_StencilFunc);
1373GR_STATIC_ASSERT(1 == kNever_StencilFunc);
1374GR_STATIC_ASSERT(2 == kGreater_StencilFunc);
1375GR_STATIC_ASSERT(3 == kGEqual_StencilFunc);
1376GR_STATIC_ASSERT(4 == kLess_StencilFunc);
1377GR_STATIC_ASSERT(5 == kLEqual_StencilFunc);
1378GR_STATIC_ASSERT(6 == kEqual_StencilFunc);
1379GR_STATIC_ASSERT(7 == kNotEqual_StencilFunc);
1380
1381static const GLenum grToGLStencilOp[] = {
1382 GL_KEEP, // kKeep_StencilOp
1383 GL_REPLACE, // kReplace_StencilOp
1384 GL_INCR_WRAP, // kIncWrap_StencilOp
1385 GL_INCR, // kIncClamp_StencilOp
1386 GL_DECR_WRAP, // kDecWrap_StencilOp
1387 GL_DECR, // kDecClamp_StencilOp
1388 GL_ZERO, // kZero_StencilOp
1389 GL_INVERT, // kInvert_StencilOp
1390};
1391GR_STATIC_ASSERT(GR_ARRAY_COUNT(grToGLStencilOp) == kStencilOpCount);
1392GR_STATIC_ASSERT(0 == kKeep_StencilOp);
1393GR_STATIC_ASSERT(1 == kReplace_StencilOp);
1394GR_STATIC_ASSERT(2 == kIncWrap_StencilOp);
1395GR_STATIC_ASSERT(3 == kIncClamp_StencilOp);
1396GR_STATIC_ASSERT(4 == kDecWrap_StencilOp);
1397GR_STATIC_ASSERT(5 == kDecClamp_StencilOp);
1398GR_STATIC_ASSERT(6 == kZero_StencilOp);
1399GR_STATIC_ASSERT(7 == kInvert_StencilOp);
1400
reed@google.comac10a2d2010-12-22 21:39:39 +00001401void GrGpuGL::flushStencil() {
bsalomon@google.comd302f142011-03-03 13:54:13 +00001402 const GrStencilSettings* settings = &fCurrDrawState.fStencilSettings;
reed@google.comac10a2d2010-12-22 21:39:39 +00001403
1404 // use stencil for clipping if clipping is enabled and the clip
1405 // has been written into the stencil.
1406 bool stencilClip = fClipState.fClipInStencil &&
1407 (kClip_StateBit & fCurrDrawState.fFlagBits);
bsalomon@google.comd302f142011-03-03 13:54:13 +00001408 bool stencilChange = fHWStencilClip != stencilClip ||
1409 fHWDrawState.fStencilSettings != *settings ||
1410 ((fHWDrawState.fFlagBits & kModifyStencilClip_StateBit) !=
1411 (fCurrDrawState.fFlagBits & kModifyStencilClip_StateBit));
reed@google.comac10a2d2010-12-22 21:39:39 +00001412
1413 if (stencilChange) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001414
bsalomon@google.comd302f142011-03-03 13:54:13 +00001415 // we can't simultaneously perform stencil-clipping and modify the stencil clip
1416 GrAssert(!stencilClip || !(fCurrDrawState.fFlagBits & kModifyStencilClip_StateBit));
reed@google.comac10a2d2010-12-22 21:39:39 +00001417
bsalomon@google.comd302f142011-03-03 13:54:13 +00001418 if (settings->isDisabled()) {
1419 if (stencilClip) {
1420 settings = &gClipStencilSettings;
1421 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001422 }
bsalomon@google.comd302f142011-03-03 13:54:13 +00001423
1424 if (settings->isDisabled()) {
1425 GR_GL(Disable(GL_STENCIL_TEST));
1426 } else {
1427 GR_GL(Enable(GL_STENCIL_TEST));
1428 #if GR_DEBUG
1429 if (!fStencilWrapOpsSupport) {
1430 GrAssert(settings->fFrontPassOp != kIncWrap_StencilOp);
1431 GrAssert(settings->fFrontPassOp != kDecWrap_StencilOp);
1432 GrAssert(settings->fFrontFailOp != kIncWrap_StencilOp);
1433 GrAssert(settings->fBackFailOp != kDecWrap_StencilOp);
1434 GrAssert(settings->fBackPassOp != kIncWrap_StencilOp);
1435 GrAssert(settings->fBackPassOp != kDecWrap_StencilOp);
1436 GrAssert(settings->fBackFailOp != kIncWrap_StencilOp);
1437 GrAssert(settings->fFrontFailOp != kDecWrap_StencilOp);
1438 }
1439 #endif
1440 int stencilBits = fCurrDrawState.fRenderTarget->stencilBits();
1441 GrAssert(stencilBits ||
1442 (GrStencilSettings::gDisabled ==
1443 fCurrDrawState.fStencilSettings));
1444 GLuint clipStencilMask = 1 << (stencilBits - 1);
1445 GLuint userStencilMask = clipStencilMask - 1;
1446
1447 unsigned int frontRef = settings->fFrontFuncRef;
1448 unsigned int frontMask = settings->fFrontFuncMask;
1449 unsigned int frontWriteMask = settings->fFrontWriteMask;
1450 GLenum frontFunc;
1451
1452 if (fCurrDrawState.fFlagBits & kModifyStencilClip_StateBit) {
1453
1454 GrAssert(settings->fFrontFunc < kBasicStencilFuncCount);
1455 frontFunc = grToGLStencilFunc[settings->fFrontFunc];
1456 } else {
1457 frontFunc = grToGLStencilFunc[ConvertStencilFunc(stencilClip, settings->fFrontFunc)];
1458
1459 ConvertStencilFuncAndMask(settings->fFrontFunc,
1460 stencilClip,
1461 clipStencilMask,
1462 userStencilMask,
1463 &frontRef,
1464 &frontMask);
1465 frontWriteMask &= userStencilMask;
1466 }
1467 GrAssert(settings->fFrontFailOp >= 0 &&
1468 settings->fFrontFailOp < GR_ARRAY_COUNT(grToGLStencilOp));
1469 GrAssert(settings->fFrontPassOp >= 0 &&
1470 settings->fFrontPassOp < GR_ARRAY_COUNT(grToGLStencilOp));
1471 GrAssert(settings->fBackFailOp >= 0 &&
1472 settings->fBackFailOp < GR_ARRAY_COUNT(grToGLStencilOp));
1473 GrAssert(settings->fBackPassOp >= 0 &&
1474 settings->fBackPassOp < GR_ARRAY_COUNT(grToGLStencilOp));
1475 if (fTwoSidedStencilSupport) {
1476 GLenum backFunc;
1477
1478 unsigned int backRef = settings->fBackFuncRef;
1479 unsigned int backMask = settings->fBackFuncMask;
1480 unsigned int backWriteMask = settings->fBackWriteMask;
1481
1482
1483 if (fCurrDrawState.fFlagBits & kModifyStencilClip_StateBit) {
1484 GrAssert(settings->fBackFunc < kBasicStencilFuncCount);
1485 backFunc = grToGLStencilFunc[settings->fBackFunc];
1486 } else {
1487 backFunc = grToGLStencilFunc[ConvertStencilFunc(stencilClip, settings->fBackFunc)];
1488 ConvertStencilFuncAndMask(settings->fBackFunc,
1489 stencilClip,
1490 clipStencilMask,
1491 userStencilMask,
1492 &backRef,
1493 &backMask);
1494 backWriteMask &= userStencilMask;
1495 }
1496
1497 GR_GL(StencilFuncSeparate(GL_FRONT, frontFunc, frontRef, frontMask));
1498 GR_GL(StencilMaskSeparate(GL_FRONT, frontWriteMask));
1499 GR_GL(StencilFuncSeparate(GL_BACK, backFunc, backRef, backMask));
1500 GR_GL(StencilMaskSeparate(GL_BACK, backWriteMask));
1501 GR_GL(StencilOpSeparate(GL_FRONT, grToGLStencilOp[settings->fFrontFailOp],
1502 grToGLStencilOp[settings->fFrontPassOp],
1503 grToGLStencilOp[settings->fFrontPassOp]));
1504
1505 GR_GL(StencilOpSeparate(GL_BACK, grToGLStencilOp[settings->fBackFailOp],
1506 grToGLStencilOp[settings->fBackPassOp],
1507 grToGLStencilOp[settings->fBackPassOp]));
1508 } else {
1509 GR_GL(StencilFunc(frontFunc, frontRef, frontMask));
1510 GR_GL(StencilMask(frontWriteMask));
1511 GR_GL(StencilOp(grToGLStencilOp[settings->fFrontFailOp],
1512 grToGLStencilOp[settings->fFrontPassOp],
1513 grToGLStencilOp[settings->fFrontPassOp]));
1514 }
1515 }
1516 fHWDrawState.fStencilSettings = fCurrDrawState.fStencilSettings;
reed@google.comac10a2d2010-12-22 21:39:39 +00001517 fHWStencilClip = stencilClip;
1518 }
1519}
1520
bsalomon@google.comffca4002011-02-22 20:34:01 +00001521bool GrGpuGL::flushGLStateCommon(GrPrimitiveType type) {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001522
1523 // GrGpu::setupClipAndFlushState should have already checked this
1524 // and bailed if not true.
1525 GrAssert(NULL != fCurrDrawState.fRenderTarget);
reed@google.comac10a2d2010-12-22 21:39:39 +00001526
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001527 for (int s = 0; s < kNumStages; ++s) {
1528 bool usingTexture = VertexUsesStage(s, fGeometrySrc.fVertexLayout);
reed@google.comac10a2d2010-12-22 21:39:39 +00001529
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001530 // bind texture and set sampler state
1531 if (usingTexture) {
1532 GrGLTexture* nextTexture = (GrGLTexture*)fCurrDrawState.fTextures[s];
reed@google.comac10a2d2010-12-22 21:39:39 +00001533
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001534 if (NULL != nextTexture) {
bsalomon@google.com316f99232011-01-13 21:28:12 +00001535 // if we created a rt/tex and rendered to it without using a
1536 // texture and now we're texuring from the rt it will still be
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001537 // the last bound texture, but it needs resolving. So keep this
1538 // out of the "last != next" check.
1539 resolveTextureRenderTarget(nextTexture);
reed@google.comac10a2d2010-12-22 21:39:39 +00001540
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001541 if (fHWDrawState.fTextures[s] != nextTexture) {
1542 setTextureUnit(s);
1543 GR_GL(BindTexture(GL_TEXTURE_2D, nextTexture->textureID()));
1544 #if GR_COLLECT_STATS
1545 ++fStats.fTextureChngCnt;
1546 #endif
1547 //GrPrintf("---- bindtexture %d\n", nextTexture->textureID());
1548 fHWDrawState.fTextures[s] = nextTexture;
1549 }
bsalomon@google.com316f99232011-01-13 21:28:12 +00001550
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001551 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
bsalomon@google.com316f99232011-01-13 21:28:12 +00001552 const GrGLTexture::TexParams& oldTexParams =
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001553 nextTexture->getTexParams();
1554 GrGLTexture::TexParams newTexParams;
bsalomon@google.com316f99232011-01-13 21:28:12 +00001555
1556 newTexParams.fFilter = sampler.isFilter() ? GL_LINEAR :
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001557 GL_NEAREST;
bsalomon@google.com316f99232011-01-13 21:28:12 +00001558 newTexParams.fWrapS =
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001559 GrGLTexture::gWrapMode2GLWrap[sampler.getWrapX()];
bsalomon@google.com316f99232011-01-13 21:28:12 +00001560 newTexParams.fWrapT =
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001561 GrGLTexture::gWrapMode2GLWrap[sampler.getWrapY()];
reed@google.comac10a2d2010-12-22 21:39:39 +00001562
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001563 if (newTexParams.fFilter != oldTexParams.fFilter) {
1564 setTextureUnit(s);
bsalomon@google.com316f99232011-01-13 21:28:12 +00001565 GR_GL(TexParameteri(GL_TEXTURE_2D,
1566 GL_TEXTURE_MAG_FILTER,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001567 newTexParams.fFilter));
bsalomon@google.com316f99232011-01-13 21:28:12 +00001568 GR_GL(TexParameteri(GL_TEXTURE_2D,
1569 GL_TEXTURE_MIN_FILTER,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001570 newTexParams.fFilter));
1571 }
1572 if (newTexParams.fWrapS != oldTexParams.fWrapS) {
1573 setTextureUnit(s);
bsalomon@google.com316f99232011-01-13 21:28:12 +00001574 GR_GL(TexParameteri(GL_TEXTURE_2D,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001575 GL_TEXTURE_WRAP_S,
1576 newTexParams.fWrapS));
1577 }
1578 if (newTexParams.fWrapT != oldTexParams.fWrapT) {
1579 setTextureUnit(s);
bsalomon@google.com316f99232011-01-13 21:28:12 +00001580 GR_GL(TexParameteri(GL_TEXTURE_2D,
1581 GL_TEXTURE_WRAP_T,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001582 newTexParams.fWrapT));
1583 }
1584 nextTexture->setTexParams(newTexParams);
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001585
1586 // The texture matrix has to compensate for texture width/height
1587 // and NPOT-embedded-in-POT
1588 fDirtyFlags.fTextureChangedMask |= (1 << s);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001589 } else {
1590 GrAssert(!"Rendering with texture vert flag set but no texture");
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001591 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +00001592 }
1593 }
1594 }
1595
1596 flushRenderTarget();
1597
1598 if ((fCurrDrawState.fFlagBits & kDither_StateBit) !=
1599 (fHWDrawState.fFlagBits & kDither_StateBit)) {
1600 if (fCurrDrawState.fFlagBits & kDither_StateBit) {
1601 GR_GL(Enable(GL_DITHER));
1602 } else {
1603 GR_GL(Disable(GL_DITHER));
1604 }
1605 }
1606
bsalomon@google.comd302f142011-03-03 13:54:13 +00001607 if ((fCurrDrawState.fFlagBits & kNoColorWrites_StateBit) !=
1608 (fHWDrawState.fFlagBits & kNoColorWrites_StateBit)) {
1609 GLenum mask;
1610 if (fCurrDrawState.fFlagBits & kNoColorWrites_StateBit) {
1611 mask = GL_FALSE;
1612 } else {
1613 mask = GL_TRUE;
1614 }
1615 GR_GL(ColorMask(mask, mask, mask, mask));
1616 }
1617
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001618#if GR_SUPPORT_GLDESKTOP
reed@google.comac10a2d2010-12-22 21:39:39 +00001619 // ES doesn't support toggling GL_MULTISAMPLE and doesn't have
1620 // smooth lines.
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001621 if (fDirtyFlags.fRenderTargetChanged ||
reed@google.comac10a2d2010-12-22 21:39:39 +00001622 (fCurrDrawState.fFlagBits & kAntialias_StateBit) !=
1623 (fHWDrawState.fFlagBits & kAntialias_StateBit)) {
1624 GLint msaa = 0;
1625 // only perform query if we know MSAA is supported.
1626 // calling on non-MSAA target caused a crash in one environment,
1627 // though I don't think it should.
reed@google.coma09368c2011-02-24 21:42:29 +00001628 if (fAASamples[kHigh_AALevel]) {
reed@google.comac20fb92011-01-12 17:14:53 +00001629 GR_GL_GetIntegerv(GL_SAMPLE_BUFFERS, &msaa);
reed@google.comac10a2d2010-12-22 21:39:39 +00001630 }
1631 if (fCurrDrawState.fFlagBits & kAntialias_StateBit) {
1632 if (msaa) {
1633 GR_GL(Enable(GL_MULTISAMPLE));
1634 } else {
1635 GR_GL(Enable(GL_LINE_SMOOTH));
1636 }
1637 } else {
1638 if (msaa) {
1639 GR_GL(Disable(GL_MULTISAMPLE));
1640 }
1641 GR_GL(Disable(GL_LINE_SMOOTH));
1642 }
1643 }
1644#endif
1645
1646 bool blendOff = canDisableBlend();
1647 if (fHWBlendDisabled != blendOff) {
1648 if (blendOff) {
1649 GR_GL(Disable(GL_BLEND));
1650 } else {
1651 GR_GL(Enable(GL_BLEND));
1652 }
1653 fHWBlendDisabled = blendOff;
1654 }
1655
1656 if (!blendOff) {
1657 if (fHWDrawState.fSrcBlend != fCurrDrawState.fSrcBlend ||
1658 fHWDrawState.fDstBlend != fCurrDrawState.fDstBlend) {
1659 GR_GL(BlendFunc(gXfermodeCoeff2Blend[fCurrDrawState.fSrcBlend],
1660 gXfermodeCoeff2Blend[fCurrDrawState.fDstBlend]));
1661 fHWDrawState.fSrcBlend = fCurrDrawState.fSrcBlend;
1662 fHWDrawState.fDstBlend = fCurrDrawState.fDstBlend;
1663 }
bsalomon@google.com080773c2011-03-15 19:09:25 +00001664 if ((BlendCoefReferencesConstant(fCurrDrawState.fSrcBlend) ||
1665 BlendCoefReferencesConstant(fCurrDrawState.fDstBlend)) &&
1666 fHWDrawState.fBlendConstant != fCurrDrawState.fBlendConstant) {
1667
1668 float c[] = {
1669 GrColorUnpackR(fCurrDrawState.fBlendConstant) / 255.f,
1670 GrColorUnpackG(fCurrDrawState.fBlendConstant) / 255.f,
1671 GrColorUnpackB(fCurrDrawState.fBlendConstant) / 255.f,
1672 GrColorUnpackA(fCurrDrawState.fBlendConstant) / 255.f
1673 };
1674 GR_GL(BlendColor(c[0], c[1], c[2], c[3]));
1675 fHWDrawState.fBlendConstant = fCurrDrawState.fBlendConstant;
1676 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001677 }
bsalomon@google.com316f99232011-01-13 21:28:12 +00001678
bsalomon@google.comd302f142011-03-03 13:54:13 +00001679 if (fHWDrawState.fDrawFace != fCurrDrawState.fDrawFace) {
1680 switch (fCurrDrawState.fDrawFace) {
1681 case kCCW_DrawFace:
1682 glEnable(GL_CULL_FACE);
1683 GR_GL(CullFace(GL_BACK));
1684 break;
1685 case kCW_DrawFace:
1686 GR_GL(Enable(GL_CULL_FACE));
1687 GR_GL(CullFace(GL_FRONT));
1688 break;
1689 case kBoth_DrawFace:
1690 GR_GL(Disable(GL_CULL_FACE));
1691 break;
1692 default:
1693 GrCrash("Unknown draw face.");
1694 }
1695 fHWDrawState.fDrawFace = fCurrDrawState.fDrawFace;
1696 }
1697
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001698#if GR_DEBUG
reed@google.comac10a2d2010-12-22 21:39:39 +00001699 // check for circular rendering
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001700 for (int s = 0; s < kNumStages; ++s) {
1701 GrAssert(!VertexUsesStage(s, fGeometrySrc.fVertexLayout) ||
1702 NULL == fCurrDrawState.fRenderTarget ||
1703 NULL == fCurrDrawState.fTextures[s] ||
bsalomon@google.com316f99232011-01-13 21:28:12 +00001704 fCurrDrawState.fTextures[s]->asRenderTarget() !=
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001705 fCurrDrawState.fRenderTarget);
1706 }
1707#endif
bsalomon@google.com316f99232011-01-13 21:28:12 +00001708
reed@google.comac10a2d2010-12-22 21:39:39 +00001709 flushStencil();
1710
bsalomon@google.comd302f142011-03-03 13:54:13 +00001711 // flushStencil may look at the private state bits, so keep it before this.
reed@google.comac10a2d2010-12-22 21:39:39 +00001712 fHWDrawState.fFlagBits = fCurrDrawState.fFlagBits;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001713 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +00001714}
1715
1716void GrGpuGL::notifyVertexBufferBind(const GrGLVertexBuffer* buffer) {
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001717 if (fHWGeometryState.fVertexBuffer != buffer) {
1718 fHWGeometryState.fArrayPtrsDirty = true;
1719 fHWGeometryState.fVertexBuffer = buffer;
1720 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001721}
1722
1723void GrGpuGL::notifyVertexBufferDelete(const GrGLVertexBuffer* buffer) {
1724 GrAssert(!(kBuffer_GeometrySrcType == fGeometrySrc.fVertexSrc &&
1725 buffer == fGeometrySrc.fVertexBuffer));
1726
1727 if (fHWGeometryState.fVertexBuffer == buffer) {
1728 // deleting bound buffer does implied bind to 0
1729 fHWGeometryState.fVertexBuffer = NULL;
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001730 fHWGeometryState.fArrayPtrsDirty = true;
reed@google.comac10a2d2010-12-22 21:39:39 +00001731 }
1732}
1733
1734void GrGpuGL::notifyIndexBufferBind(const GrGLIndexBuffer* buffer) {
1735 fGeometrySrc.fIndexBuffer = buffer;
1736}
1737
1738void GrGpuGL::notifyIndexBufferDelete(const GrGLIndexBuffer* buffer) {
1739 GrAssert(!(kBuffer_GeometrySrcType == fGeometrySrc.fIndexSrc &&
1740 buffer == fGeometrySrc.fIndexBuffer));
1741
1742 if (fHWGeometryState.fIndexBuffer == buffer) {
1743 // deleting bound buffer does implied bind to 0
1744 fHWGeometryState.fIndexBuffer = NULL;
1745 }
1746}
1747
reed@google.comac10a2d2010-12-22 21:39:39 +00001748void GrGpuGL::notifyRenderTargetDelete(GrRenderTarget* renderTarget) {
1749 GrAssert(NULL != renderTarget);
reed@google.comac10a2d2010-12-22 21:39:39 +00001750 if (fCurrDrawState.fRenderTarget == renderTarget) {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001751 fCurrDrawState.fRenderTarget = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +00001752 }
1753 if (fHWDrawState.fRenderTarget == renderTarget) {
1754 fHWDrawState.fRenderTarget = NULL;
1755 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001756}
1757
1758void GrGpuGL::notifyTextureDelete(GrGLTexture* texture) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001759 for (int s = 0; s < kNumStages; ++s) {
1760 if (fCurrDrawState.fTextures[s] == texture) {
1761 fCurrDrawState.fTextures[s] = NULL;
1762 }
1763 if (fHWDrawState.fTextures[s] == texture) {
1764 // deleting bound texture does implied bind to 0
1765 fHWDrawState.fTextures[s] = NULL;
1766 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001767 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001768}
1769
reed@google.comac10a2d2010-12-22 21:39:39 +00001770bool GrGpuGL::canBeTexture(GrTexture::PixelConfig config,
1771 GLenum* internalFormat,
1772 GLenum* format,
1773 GLenum* type) {
1774 switch (config) {
1775 case GrTexture::kRGBA_8888_PixelConfig:
1776 case GrTexture::kRGBX_8888_PixelConfig: // todo: can we tell it our X?
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +00001777 *format = GR_GL_32BPP_COLOR_FORMAT;
reed@google.com63100f92011-01-18 21:32:14 +00001778#if GR_SUPPORT_GLES
1779 // according to GL_EXT_texture_format_BGRA8888 the *internal*
1780 // format for a BGRA is BGRA not RGBA (as on desktop)
1781 *internalFormat = GR_GL_32BPP_COLOR_FORMAT;
1782#else
1783 *internalFormat = GL_RGBA;
bsalomon@google.comed3a0682011-01-18 16:54:04 +00001784#endif
reed@google.comac10a2d2010-12-22 21:39:39 +00001785 *type = GL_UNSIGNED_BYTE;
1786 break;
1787 case GrTexture::kRGB_565_PixelConfig:
1788 *format = GL_RGB;
1789 *internalFormat = GL_RGB;
1790 *type = GL_UNSIGNED_SHORT_5_6_5;
1791 break;
1792 case GrTexture::kRGBA_4444_PixelConfig:
1793 *format = GL_RGBA;
1794 *internalFormat = GL_RGBA;
1795 *type = GL_UNSIGNED_SHORT_4_4_4_4;
1796 break;
1797 case GrTexture::kIndex_8_PixelConfig:
1798 if (this->supports8BitPalette()) {
1799 *format = GR_PALETTE8_RGBA8;
1800 *internalFormat = GR_PALETTE8_RGBA8;
1801 *type = GL_UNSIGNED_BYTE; // unused I think
1802 } else {
1803 return false;
1804 }
1805 break;
1806 case GrTexture::kAlpha_8_PixelConfig:
1807 *format = GL_ALPHA;
1808 *internalFormat = GL_ALPHA;
1809 *type = GL_UNSIGNED_BYTE;
1810 break;
1811 default:
1812 return false;
1813 }
1814 return true;
1815}
1816
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001817void GrGpuGL::setTextureUnit(int unit) {
1818 GrAssert(unit >= 0 && unit < kNumStages);
1819 if (fActiveTextureUnitIdx != unit) {
1820 GR_GL(ActiveTexture(GL_TEXTURE0 + unit));
1821 fActiveTextureUnitIdx = unit;
1822 }
1823}
bsalomon@google.com316f99232011-01-13 21:28:12 +00001824
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001825void GrGpuGL::setSpareTextureUnit() {
1826 if (fActiveTextureUnitIdx != (GL_TEXTURE0 + SPARE_TEX_UNIT)) {
1827 GR_GL(ActiveTexture(GL_TEXTURE0 + SPARE_TEX_UNIT));
1828 fActiveTextureUnitIdx = SPARE_TEX_UNIT;
1829 }
1830}
1831
reed@google.comac10a2d2010-12-22 21:39:39 +00001832/* On ES the internalFormat and format must match for TexImage and we use
1833 GL_RGB, GL_RGBA for color formats. We also generally like having the driver
1834 decide the internalFormat. However, on ES internalFormat for
1835 RenderBufferStorage* has to be a specific format (not a base format like
1836 GL_RGBA).
1837 */
1838bool GrGpuGL::fboInternalFormat(GrTexture::PixelConfig config, GLenum* format) {
1839 switch (config) {
1840 case GrTexture::kRGBA_8888_PixelConfig:
1841 case GrTexture::kRGBX_8888_PixelConfig:
1842 if (fRGBA8Renderbuffer) {
1843 *format = GR_RGBA8;
1844 return true;
1845 } else {
1846 return false;
1847 }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001848#if GR_SUPPORT_GLES // ES2 supports 565. ES1 supports it with FBO extension
1849 // desktop GL has no such internal format
reed@google.comac10a2d2010-12-22 21:39:39 +00001850 case GrTexture::kRGB_565_PixelConfig:
1851 *format = GR_RGB565;
1852 return true;
1853#endif
1854 case GrTexture::kRGBA_4444_PixelConfig:
1855 *format = GL_RGBA4;
1856 return true;
1857 default:
1858 return false;
1859 }
1860}
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001861
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001862void GrGpuGL::resetDirtyFlags() {
1863 Gr_bzero(&fDirtyFlags, sizeof(fDirtyFlags));
1864}
1865
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001866void GrGpuGL::setBuffers(bool indexed,
1867 int* extraVertexOffset,
1868 int* extraIndexOffset) {
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001869
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001870 GrAssert(NULL != extraVertexOffset);
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001871
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001872 GrGLVertexBuffer* vbuf;
1873 switch (fGeometrySrc.fVertexSrc) {
1874 case kBuffer_GeometrySrcType:
1875 *extraVertexOffset = 0;
1876 vbuf = (GrGLVertexBuffer*) fGeometrySrc.fVertexBuffer;
1877 break;
1878 case kArray_GeometrySrcType:
1879 case kReserved_GeometrySrcType:
1880 finalizeReservedVertices();
1881 *extraVertexOffset = fCurrPoolStartVertex;
1882 vbuf = (GrGLVertexBuffer*) fCurrPoolVertexBuffer;
1883 break;
1884 default:
1885 vbuf = NULL; // suppress warning
1886 GrCrash("Unknown geometry src type!");
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001887 }
1888
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001889 GrAssert(NULL != vbuf);
1890 GrAssert(!vbuf->isLocked());
1891 if (fHWGeometryState.fVertexBuffer != vbuf) {
1892 GR_GL(BindBuffer(GL_ARRAY_BUFFER, vbuf->bufferID()));
1893 fHWGeometryState.fArrayPtrsDirty = true;
1894 fHWGeometryState.fVertexBuffer = vbuf;
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001895 }
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001896
1897 if (indexed) {
1898 GrAssert(NULL != extraIndexOffset);
1899
1900 GrGLIndexBuffer* ibuf;
1901 switch (fGeometrySrc.fIndexSrc) {
1902 case kBuffer_GeometrySrcType:
1903 *extraIndexOffset = 0;
1904 ibuf = (GrGLIndexBuffer*)fGeometrySrc.fIndexBuffer;
1905 break;
1906 case kArray_GeometrySrcType:
1907 case kReserved_GeometrySrcType:
1908 finalizeReservedIndices();
1909 *extraIndexOffset = fCurrPoolStartIndex;
1910 ibuf = (GrGLIndexBuffer*) fCurrPoolIndexBuffer;
1911 break;
1912 default:
1913 ibuf = NULL; // suppress warning
1914 GrCrash("Unknown geometry src type!");
1915 }
1916
1917 GrAssert(NULL != ibuf);
1918 GrAssert(!ibuf->isLocked());
1919 if (fHWGeometryState.fIndexBuffer != ibuf) {
1920 GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibuf->bufferID()));
1921 fHWGeometryState.fIndexBuffer = ibuf;
1922 }
1923 }
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001924}