1 : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * the Mozilla Foundation.
19 : * Portions created by the Initial Developer are Copyright (C) 2009
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Vladimir Vukicevic <vladimir@pobox.com>
24 : * Mark Steele <mwsteele@gmail.com>
25 : * Bas Schouten <bschouten@mozilla.com>
26 : * Jeff Gilbert <jgilbert@mozilla.com>
27 : *
28 : * Alternatively, the contents of this file may be used under the terms of
29 : * either the GNU General Public License Version 2 or later (the "GPL"), or
30 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
31 : * in which case the provisions of the GPL or the LGPL are applicable instead
32 : * of those above. If you wish to allow use of your version of this file only
33 : * under the terms of either the GPL or the LGPL, and not to allow others to
34 : * use your version of this file under the terms of the MPL, indicate your
35 : * decision by deleting the provisions above and replace them with the notice
36 : * and other provisions required by the GPL or the LGPL. If you do not delete
37 : * the provisions above, a recipient may use your version of this file under
38 : * the terms of any one of the MPL, the GPL or the LGPL.
39 : *
40 : * ***** END LICENSE BLOCK ***** */
41 :
42 :
43 : #include <string.h>
44 : #include <stdio.h>
45 :
46 : #include "prlink.h"
47 : #include "prenv.h"
48 :
49 : #include "nsThreadUtils.h"
50 :
51 : #include "gfxPlatform.h"
52 : #include "GLContext.h"
53 : #include "GLContextProvider.h"
54 :
55 : #include "gfxCrashReporterUtils.h"
56 : #include "gfxUtils.h"
57 :
58 : #include "mozilla/Util.h" // for DebugOnly
59 :
60 : namespace mozilla {
61 : namespace gl {
62 :
63 : #ifdef DEBUG
64 : PRUintn GLContext::sCurrentGLContextTLS = -1;
65 : #endif
66 :
67 : PRUint32 GLContext::sDebugMode = 0;
68 :
69 : // define this here since it's global to GLContextProvider, not any
70 : // specific implementation
71 1464 : const ContextFormat ContextFormat::BasicRGBA32Format(ContextFormat::BasicRGBA32);
72 :
73 : #define MAX_SYMBOL_LENGTH 128
74 : #define MAX_SYMBOL_NAMES 5
75 :
76 : // should match the order of GLExtensions
77 : static const char *sExtensionNames[] = {
78 : "GL_EXT_framebuffer_object",
79 : "GL_ARB_framebuffer_object",
80 : "GL_ARB_texture_rectangle",
81 : "GL_EXT_bgra",
82 : "GL_EXT_texture_format_BGRA8888",
83 : "GL_OES_depth24",
84 : "GL_OES_depth32",
85 : "GL_OES_stencil8",
86 : "GL_OES_texture_npot",
87 : "GL_OES_depth_texture",
88 : "GL_OES_packed_depth_stencil",
89 : "GL_IMG_read_format",
90 : "GL_EXT_read_format_bgra",
91 : "GL_APPLE_client_storage",
92 : "GL_ARB_texture_non_power_of_two",
93 : "GL_ARB_pixel_buffer_object",
94 : "GL_ARB_ES2_compatibility",
95 : "GL_OES_texture_float",
96 : "GL_ARB_texture_float",
97 : "GL_EXT_unpack_subimage",
98 : "GL_OES_standard_derivatives",
99 : "GL_EXT_texture_filter_anisotropic",
100 : "GL_EXT_framebuffer_blit",
101 : "GL_ANGLE_framebuffer_blit",
102 : "GL_EXT_framebuffer_multisample",
103 : "GL_ANGLE_framebuffer_multisample",
104 : "GL_OES_rgb8_rgba8",
105 : "GL_ARB_robustness",
106 : "GL_EXT_robustness",
107 : NULL
108 : };
109 :
110 : bool
111 0 : LibrarySymbolLoader::OpenLibrary(const char *library)
112 : {
113 : PRLibSpec lspec;
114 0 : lspec.type = PR_LibSpec_Pathname;
115 0 : lspec.value.pathname = library;
116 :
117 0 : mLibrary = PR_LoadLibraryWithFlags(lspec, PR_LD_LAZY | PR_LD_LOCAL);
118 0 : if (!mLibrary)
119 0 : return false;
120 :
121 0 : return true;
122 : }
123 :
124 : bool
125 0 : LibrarySymbolLoader::LoadSymbols(SymLoadStruct *firstStruct, bool tryplatform, const char *prefix)
126 : {
127 0 : return LoadSymbols(mLibrary, firstStruct, tryplatform ? mLookupFunc : nsnull, prefix);
128 : }
129 :
130 : PRFuncPtr
131 0 : LibrarySymbolLoader::LookupSymbol(PRLibrary *lib,
132 : const char *sym,
133 : PlatformLookupFunction lookupFunction)
134 : {
135 0 : PRFuncPtr res = 0;
136 :
137 : // try finding it in the library directly, if we have one
138 0 : if (lib) {
139 0 : res = PR_FindFunctionSymbol(lib, sym);
140 : }
141 :
142 : // then try looking it up via the lookup symbol
143 0 : if (!res && lookupFunction) {
144 0 : res = lookupFunction(sym);
145 : }
146 :
147 : // finally just try finding it in the process
148 0 : if (!res) {
149 : PRLibrary *leakedLibRef;
150 0 : res = PR_FindFunctionSymbolAndLibrary(sym, &leakedLibRef);
151 : }
152 :
153 0 : return res;
154 : }
155 :
156 : bool
157 0 : LibrarySymbolLoader::LoadSymbols(PRLibrary *lib,
158 : SymLoadStruct *firstStruct,
159 : PlatformLookupFunction lookupFunction,
160 : const char *prefix)
161 : {
162 : char sbuf[MAX_SYMBOL_LENGTH * 2];
163 0 : int failCount = 0;
164 :
165 0 : SymLoadStruct *ss = firstStruct;
166 0 : while (ss->symPointer) {
167 0 : *ss->symPointer = 0;
168 :
169 0 : for (int i = 0; i < MAX_SYMBOL_NAMES; i++) {
170 0 : if (ss->symNames[i] == nsnull)
171 0 : break;
172 :
173 0 : const char *s = ss->symNames[i];
174 0 : if (prefix && *prefix != 0) {
175 0 : strcpy(sbuf, prefix);
176 0 : strcat(sbuf, ss->symNames[i]);
177 0 : s = sbuf;
178 : }
179 :
180 0 : PRFuncPtr p = LookupSymbol(lib, s, lookupFunction);
181 0 : if (p) {
182 0 : *ss->symPointer = p;
183 0 : break;
184 : }
185 : }
186 :
187 0 : if (*ss->symPointer == 0) {
188 0 : fprintf (stderr, "Can't find symbol '%s'\n", ss->symNames[0]);
189 0 : failCount++;
190 : }
191 :
192 0 : ss++;
193 : }
194 :
195 0 : return failCount == 0 ? true : false;
196 : }
197 :
198 : /*
199 : * XXX - we should really know the ARB/EXT variants of these
200 : * instead of only handling the symbol if it's exposed directly.
201 : */
202 :
203 : bool
204 0 : GLContext::InitWithPrefix(const char *prefix, bool trygl)
205 : {
206 0 : ScopedGfxFeatureReporter reporter("GL Context");
207 :
208 0 : if (mInitialized) {
209 0 : reporter.SetSuccessful();
210 0 : return true;
211 : }
212 :
213 : SymLoadStruct symbols[] = {
214 : { (PRFuncPtr*) &mSymbols.fActiveTexture, { "ActiveTexture", "ActiveTextureARB", NULL } },
215 : { (PRFuncPtr*) &mSymbols.fAttachShader, { "AttachShader", "AttachShaderARB", NULL } },
216 : { (PRFuncPtr*) &mSymbols.fBindAttribLocation, { "BindAttribLocation", "BindAttribLocationARB", NULL } },
217 : { (PRFuncPtr*) &mSymbols.fBindBuffer, { "BindBuffer", "BindBufferARB", NULL } },
218 : { (PRFuncPtr*) &mSymbols.fBindTexture, { "BindTexture", "BindTextureARB", NULL } },
219 : { (PRFuncPtr*) &mSymbols.fBlendColor, { "BlendColor", NULL } },
220 : { (PRFuncPtr*) &mSymbols.fBlendEquation, { "BlendEquation", NULL } },
221 : { (PRFuncPtr*) &mSymbols.fBlendEquationSeparate, { "BlendEquationSeparate", "BlendEquationSeparateEXT", NULL } },
222 : { (PRFuncPtr*) &mSymbols.fBlendFunc, { "BlendFunc", NULL } },
223 : { (PRFuncPtr*) &mSymbols.fBlendFuncSeparate, { "BlendFuncSeparate", "BlendFuncSeparateEXT", NULL } },
224 : { (PRFuncPtr*) &mSymbols.fBufferData, { "BufferData", NULL } },
225 : { (PRFuncPtr*) &mSymbols.fBufferSubData, { "BufferSubData", NULL } },
226 : { (PRFuncPtr*) &mSymbols.fClear, { "Clear", NULL } },
227 : { (PRFuncPtr*) &mSymbols.fClearColor, { "ClearColor", NULL } },
228 : { (PRFuncPtr*) &mSymbols.fClearStencil, { "ClearStencil", NULL } },
229 : { (PRFuncPtr*) &mSymbols.fColorMask, { "ColorMask", NULL } },
230 : { (PRFuncPtr*) &mSymbols.fCullFace, { "CullFace", NULL } },
231 : { (PRFuncPtr*) &mSymbols.fDetachShader, { "DetachShader", "DetachShaderARB", NULL } },
232 : { (PRFuncPtr*) &mSymbols.fDepthFunc, { "DepthFunc", NULL } },
233 : { (PRFuncPtr*) &mSymbols.fDepthMask, { "DepthMask", NULL } },
234 : { (PRFuncPtr*) &mSymbols.fDisable, { "Disable", NULL } },
235 : { (PRFuncPtr*) &mSymbols.fDisableVertexAttribArray, { "DisableVertexAttribArray", "DisableVertexAttribArrayARB", NULL } },
236 : { (PRFuncPtr*) &mSymbols.fDrawArrays, { "DrawArrays", NULL } },
237 : { (PRFuncPtr*) &mSymbols.fDrawElements, { "DrawElements", NULL } },
238 : { (PRFuncPtr*) &mSymbols.fEnable, { "Enable", NULL } },
239 : { (PRFuncPtr*) &mSymbols.fEnableVertexAttribArray, { "EnableVertexAttribArray", "EnableVertexAttribArrayARB", NULL } },
240 : { (PRFuncPtr*) &mSymbols.fFinish, { "Finish", NULL } },
241 : { (PRFuncPtr*) &mSymbols.fFlush, { "Flush", NULL } },
242 : { (PRFuncPtr*) &mSymbols.fFrontFace, { "FrontFace", NULL } },
243 : { (PRFuncPtr*) &mSymbols.fGetActiveAttrib, { "GetActiveAttrib", "GetActiveAttribARB", NULL } },
244 : { (PRFuncPtr*) &mSymbols.fGetActiveUniform, { "GetActiveUniform", "GetActiveUniformARB", NULL } },
245 : { (PRFuncPtr*) &mSymbols.fGetAttachedShaders, { "GetAttachedShaders", "GetAttachedShadersARB", NULL } },
246 : { (PRFuncPtr*) &mSymbols.fGetAttribLocation, { "GetAttribLocation", "GetAttribLocationARB", NULL } },
247 : { (PRFuncPtr*) &mSymbols.fGetIntegerv, { "GetIntegerv", NULL } },
248 : { (PRFuncPtr*) &mSymbols.fGetFloatv, { "GetFloatv", NULL } },
249 : { (PRFuncPtr*) &mSymbols.fGetBooleanv, { "GetBooleanv", NULL } },
250 : { (PRFuncPtr*) &mSymbols.fGetBufferParameteriv, { "GetBufferParameteriv", "GetBufferParameterivARB", NULL } },
251 : { (PRFuncPtr*) &mSymbols.fGetError, { "GetError", NULL } },
252 : { (PRFuncPtr*) &mSymbols.fGetProgramiv, { "GetProgramiv", "GetProgramivARB", NULL } },
253 : { (PRFuncPtr*) &mSymbols.fGetProgramInfoLog, { "GetProgramInfoLog", "GetProgramInfoLogARB", NULL } },
254 : { (PRFuncPtr*) &mSymbols.fTexParameteri, { "TexParameteri", NULL } },
255 : { (PRFuncPtr*) &mSymbols.fTexParameterf, { "TexParameterf", NULL } },
256 : { (PRFuncPtr*) &mSymbols.fGetString, { "GetString", NULL } },
257 : { (PRFuncPtr*) &mSymbols.fGetTexParameterfv, { "GetTexParameterfv", NULL } },
258 : { (PRFuncPtr*) &mSymbols.fGetTexParameteriv, { "GetTexParameteriv", NULL } },
259 : { (PRFuncPtr*) &mSymbols.fGetUniformfv, { "GetUniformfv", "GetUniformfvARB", NULL } },
260 : { (PRFuncPtr*) &mSymbols.fGetUniformiv, { "GetUniformiv", "GetUniformivARB", NULL } },
261 : { (PRFuncPtr*) &mSymbols.fGetUniformLocation, { "GetUniformLocation", "GetUniformLocationARB", NULL } },
262 : { (PRFuncPtr*) &mSymbols.fGetVertexAttribfv, { "GetVertexAttribfv", "GetVertexAttribfvARB", NULL } },
263 : { (PRFuncPtr*) &mSymbols.fGetVertexAttribiv, { "GetVertexAttribiv", "GetVertexAttribivARB", NULL } },
264 : { (PRFuncPtr*) &mSymbols.fHint, { "Hint", NULL } },
265 : { (PRFuncPtr*) &mSymbols.fIsBuffer, { "IsBuffer", "IsBufferARB", NULL } },
266 : { (PRFuncPtr*) &mSymbols.fIsEnabled, { "IsEnabled", NULL } },
267 : { (PRFuncPtr*) &mSymbols.fIsProgram, { "IsProgram", "IsProgramARB", NULL } },
268 : { (PRFuncPtr*) &mSymbols.fIsShader, { "IsShader", "IsShaderARB", NULL } },
269 : { (PRFuncPtr*) &mSymbols.fIsTexture, { "IsTexture", "IsTextureARB", NULL } },
270 : { (PRFuncPtr*) &mSymbols.fLineWidth, { "LineWidth", NULL } },
271 : { (PRFuncPtr*) &mSymbols.fLinkProgram, { "LinkProgram", "LinkProgramARB", NULL } },
272 : { (PRFuncPtr*) &mSymbols.fPixelStorei, { "PixelStorei", NULL } },
273 : { (PRFuncPtr*) &mSymbols.fPolygonOffset, { "PolygonOffset", NULL } },
274 : { (PRFuncPtr*) &mSymbols.fReadPixels, { "ReadPixels", NULL } },
275 : { (PRFuncPtr*) &mSymbols.fSampleCoverage, { "SampleCoverage", NULL } },
276 : { (PRFuncPtr*) &mSymbols.fScissor, { "Scissor", NULL } },
277 : { (PRFuncPtr*) &mSymbols.fStencilFunc, { "StencilFunc", NULL } },
278 : { (PRFuncPtr*) &mSymbols.fStencilFuncSeparate, { "StencilFuncSeparate", "StencilFuncSeparateEXT", NULL } },
279 : { (PRFuncPtr*) &mSymbols.fStencilMask, { "StencilMask", NULL } },
280 : { (PRFuncPtr*) &mSymbols.fStencilMaskSeparate, { "StencilMaskSeparate", "StencilMaskSeparateEXT", NULL } },
281 : { (PRFuncPtr*) &mSymbols.fStencilOp, { "StencilOp", NULL } },
282 : { (PRFuncPtr*) &mSymbols.fStencilOpSeparate, { "StencilOpSeparate", "StencilOpSeparateEXT", NULL } },
283 : { (PRFuncPtr*) &mSymbols.fTexImage2D, { "TexImage2D", NULL } },
284 : { (PRFuncPtr*) &mSymbols.fTexSubImage2D, { "TexSubImage2D", NULL } },
285 : { (PRFuncPtr*) &mSymbols.fUniform1f, { "Uniform1f", NULL } },
286 : { (PRFuncPtr*) &mSymbols.fUniform1fv, { "Uniform1fv", NULL } },
287 : { (PRFuncPtr*) &mSymbols.fUniform1i, { "Uniform1i", NULL } },
288 : { (PRFuncPtr*) &mSymbols.fUniform1iv, { "Uniform1iv", NULL } },
289 : { (PRFuncPtr*) &mSymbols.fUniform2f, { "Uniform2f", NULL } },
290 : { (PRFuncPtr*) &mSymbols.fUniform2fv, { "Uniform2fv", NULL } },
291 : { (PRFuncPtr*) &mSymbols.fUniform2i, { "Uniform2i", NULL } },
292 : { (PRFuncPtr*) &mSymbols.fUniform2iv, { "Uniform2iv", NULL } },
293 : { (PRFuncPtr*) &mSymbols.fUniform3f, { "Uniform3f", NULL } },
294 : { (PRFuncPtr*) &mSymbols.fUniform3fv, { "Uniform3fv", NULL } },
295 : { (PRFuncPtr*) &mSymbols.fUniform3i, { "Uniform3i", NULL } },
296 : { (PRFuncPtr*) &mSymbols.fUniform3iv, { "Uniform3iv", NULL } },
297 : { (PRFuncPtr*) &mSymbols.fUniform4f, { "Uniform4f", NULL } },
298 : { (PRFuncPtr*) &mSymbols.fUniform4fv, { "Uniform4fv", NULL } },
299 : { (PRFuncPtr*) &mSymbols.fUniform4i, { "Uniform4i", NULL } },
300 : { (PRFuncPtr*) &mSymbols.fUniform4iv, { "Uniform4iv", NULL } },
301 : { (PRFuncPtr*) &mSymbols.fUniformMatrix2fv, { "UniformMatrix2fv", NULL } },
302 : { (PRFuncPtr*) &mSymbols.fUniformMatrix3fv, { "UniformMatrix3fv", NULL } },
303 : { (PRFuncPtr*) &mSymbols.fUniformMatrix4fv, { "UniformMatrix4fv", NULL } },
304 : { (PRFuncPtr*) &mSymbols.fUseProgram, { "UseProgram", NULL } },
305 : { (PRFuncPtr*) &mSymbols.fValidateProgram, { "ValidateProgram", NULL } },
306 : { (PRFuncPtr*) &mSymbols.fVertexAttribPointer, { "VertexAttribPointer", NULL } },
307 : { (PRFuncPtr*) &mSymbols.fVertexAttrib1f, { "VertexAttrib1f", NULL } },
308 : { (PRFuncPtr*) &mSymbols.fVertexAttrib2f, { "VertexAttrib2f", NULL } },
309 : { (PRFuncPtr*) &mSymbols.fVertexAttrib3f, { "VertexAttrib3f", NULL } },
310 : { (PRFuncPtr*) &mSymbols.fVertexAttrib4f, { "VertexAttrib4f", NULL } },
311 : { (PRFuncPtr*) &mSymbols.fVertexAttrib1fv, { "VertexAttrib1fv", NULL } },
312 : { (PRFuncPtr*) &mSymbols.fVertexAttrib2fv, { "VertexAttrib2fv", NULL } },
313 : { (PRFuncPtr*) &mSymbols.fVertexAttrib3fv, { "VertexAttrib3fv", NULL } },
314 : { (PRFuncPtr*) &mSymbols.fVertexAttrib4fv, { "VertexAttrib4fv", NULL } },
315 : { (PRFuncPtr*) &mSymbols.fViewport, { "Viewport", NULL } },
316 : { (PRFuncPtr*) &mSymbols.fCompileShader, { "CompileShader", NULL } },
317 : { (PRFuncPtr*) &mSymbols.fCopyTexImage2D, { "CopyTexImage2D", NULL } },
318 : { (PRFuncPtr*) &mSymbols.fCopyTexSubImage2D, { "CopyTexSubImage2D", NULL } },
319 : { (PRFuncPtr*) &mSymbols.fGetShaderiv, { "GetShaderiv", NULL } },
320 : { (PRFuncPtr*) &mSymbols.fGetShaderInfoLog, { "GetShaderInfoLog", NULL } },
321 : { (PRFuncPtr*) &mSymbols.fGetShaderSource, { "GetShaderSource", NULL } },
322 : { (PRFuncPtr*) &mSymbols.fShaderSource, { "ShaderSource", NULL } },
323 : { (PRFuncPtr*) &mSymbols.fVertexAttribPointer, { "VertexAttribPointer", NULL } },
324 : { (PRFuncPtr*) &mSymbols.fBindFramebuffer, { "BindFramebuffer", "BindFramebufferEXT", NULL } },
325 : { (PRFuncPtr*) &mSymbols.fBindRenderbuffer, { "BindRenderbuffer", "BindRenderbufferEXT", NULL } },
326 : { (PRFuncPtr*) &mSymbols.fCheckFramebufferStatus, { "CheckFramebufferStatus", "CheckFramebufferStatusEXT", NULL } },
327 : { (PRFuncPtr*) &mSymbols.fFramebufferRenderbuffer, { "FramebufferRenderbuffer", "FramebufferRenderbufferEXT", NULL } },
328 : { (PRFuncPtr*) &mSymbols.fFramebufferTexture2D, { "FramebufferTexture2D", "FramebufferTexture2DEXT", NULL } },
329 : { (PRFuncPtr*) &mSymbols.fGenerateMipmap, { "GenerateMipmap", "GenerateMipmapEXT", NULL } },
330 : { (PRFuncPtr*) &mSymbols.fGetFramebufferAttachmentParameteriv, { "GetFramebufferAttachmentParameteriv", "GetFramebufferAttachmentParameterivEXT", NULL } },
331 : { (PRFuncPtr*) &mSymbols.fGetRenderbufferParameteriv, { "GetRenderbufferParameteriv", "GetRenderbufferParameterivEXT", NULL } },
332 : { (PRFuncPtr*) &mSymbols.fIsFramebuffer, { "IsFramebuffer", "IsFramebufferEXT", NULL } },
333 : { (PRFuncPtr*) &mSymbols.fIsRenderbuffer, { "IsRenderbuffer", "IsRenderbufferEXT", NULL } },
334 : { (PRFuncPtr*) &mSymbols.fRenderbufferStorage, { "RenderbufferStorage", "RenderbufferStorageEXT", NULL } },
335 :
336 : { (PRFuncPtr*) &mSymbols.fGenBuffers, { "GenBuffers", "GenBuffersARB", NULL } },
337 : { (PRFuncPtr*) &mSymbols.fGenTextures, { "GenTextures", NULL } },
338 : { (PRFuncPtr*) &mSymbols.fCreateProgram, { "CreateProgram", "CreateProgramARB", NULL } },
339 : { (PRFuncPtr*) &mSymbols.fCreateShader, { "CreateShader", "CreateShaderARB", NULL } },
340 : { (PRFuncPtr*) &mSymbols.fGenFramebuffers, { "GenFramebuffers", "GenFramebuffersEXT", NULL } },
341 : { (PRFuncPtr*) &mSymbols.fGenRenderbuffers, { "GenRenderbuffers", "GenRenderbuffersEXT", NULL } },
342 :
343 : { (PRFuncPtr*) &mSymbols.fDeleteBuffers, { "DeleteBuffers", "DeleteBuffersARB", NULL } },
344 : { (PRFuncPtr*) &mSymbols.fDeleteTextures, { "DeleteTextures", "DeleteTexturesARB", NULL } },
345 : { (PRFuncPtr*) &mSymbols.fDeleteProgram, { "DeleteProgram", "DeleteProgramARB", NULL } },
346 : { (PRFuncPtr*) &mSymbols.fDeleteShader, { "DeleteShader", "DeleteShaderARB", NULL } },
347 : { (PRFuncPtr*) &mSymbols.fDeleteFramebuffers, { "DeleteFramebuffers", "DeleteFramebuffersEXT", NULL } },
348 : { (PRFuncPtr*) &mSymbols.fDeleteRenderbuffers, { "DeleteRenderbuffers", "DeleteRenderbuffersEXT", NULL } },
349 :
350 : { NULL, { NULL } },
351 :
352 0 : };
353 :
354 0 : mInitialized = LoadSymbols(&symbols[0], trygl, prefix);
355 :
356 : // Load OpenGL ES 2.0 symbols, or desktop if we aren't using ES 2.
357 0 : if (mInitialized) {
358 0 : if (mIsGLES2) {
359 : SymLoadStruct symbols_ES2[] = {
360 : { (PRFuncPtr*) &mSymbols.fGetShaderPrecisionFormat, { "GetShaderPrecisionFormat", NULL } },
361 : { (PRFuncPtr*) &mSymbols.fClearDepthf, { "ClearDepthf", NULL } },
362 : { (PRFuncPtr*) &mSymbols.fDepthRangef, { "DepthRangef", NULL } },
363 : { NULL, { NULL } },
364 0 : };
365 :
366 0 : if (!LoadSymbols(&symbols_ES2[0], trygl, prefix)) {
367 0 : NS_RUNTIMEABORT("OpenGL ES 2.0 supported, but symbols could not be loaded.");
368 0 : mInitialized = false;
369 : }
370 : } else {
371 : SymLoadStruct symbols_desktop[] = {
372 : { (PRFuncPtr*) &mSymbols.fClearDepth, { "ClearDepth", NULL } },
373 : { (PRFuncPtr*) &mSymbols.fDepthRange, { "DepthRange", NULL } },
374 : { (PRFuncPtr*) &mSymbols.fReadBuffer, { "ReadBuffer", NULL } },
375 : { (PRFuncPtr*) &mSymbols.fMapBuffer, { "MapBuffer", NULL } },
376 : { (PRFuncPtr*) &mSymbols.fUnmapBuffer, { "UnmapBuffer", NULL } },
377 : { NULL, { NULL } },
378 0 : };
379 :
380 0 : if (!LoadSymbols(&symbols_desktop[0], trygl, prefix)) {
381 0 : NS_RUNTIMEABORT("Desktop symbols failed to load.");
382 0 : mInitialized = false;
383 : }
384 : }
385 : }
386 :
387 : const char *glVendorString;
388 : const char *glRendererString;
389 :
390 0 : if (mInitialized) {
391 0 : glVendorString = (const char *)fGetString(LOCAL_GL_VENDOR);
392 : const char *vendorMatchStrings[VendorOther] = {
393 : "Intel",
394 : "NVIDIA",
395 : "ATI",
396 : "Qualcomm"
397 0 : };
398 0 : mVendor = VendorOther;
399 0 : for (int i = 0; i < VendorOther; ++i) {
400 0 : if (DoesStringMatch(glVendorString, vendorMatchStrings[i])) {
401 0 : mVendor = i;
402 0 : break;
403 : }
404 : }
405 :
406 0 : glRendererString = (const char *)fGetString(LOCAL_GL_RENDERER);
407 : const char *rendererMatchStrings[RendererOther] = {
408 : "Adreno 200"
409 0 : };
410 0 : mRenderer = RendererOther;
411 0 : for (int i = 0; i < RendererOther; ++i) {
412 0 : if (DoesStringMatch(glRendererString, rendererMatchStrings[i])) {
413 0 : mRenderer = i;
414 0 : break;
415 : }
416 : }
417 : }
418 :
419 0 : if (mInitialized) {
420 : #ifdef DEBUG
421 : static bool once = false;
422 0 : if (!once) {
423 : const char *vendors[VendorOther] = {
424 : "Intel",
425 : "NVIDIA",
426 : "ATI",
427 : "Qualcomm"
428 0 : };
429 :
430 0 : once = true;
431 0 : if (mVendor < VendorOther) {
432 : printf_stderr("OpenGL vendor ('%s') recognized as: %s\n",
433 0 : glVendorString, vendors[mVendor]);
434 : } else {
435 0 : printf_stderr("OpenGL vendor ('%s') unrecognized\n", glVendorString);
436 : }
437 : }
438 : #endif
439 :
440 0 : InitExtensions();
441 :
442 0 : NS_ASSERTION(!IsExtensionSupported(GLContext::ARB_pixel_buffer_object) ||
443 : (mSymbols.fMapBuffer && mSymbols.fUnmapBuffer),
444 : "ARB_pixel_buffer_object supported without glMapBuffer/UnmapBuffer being available!");
445 :
446 0 : if (SupportsRobustness()) {
447 0 : if (IsExtensionSupported(ARB_robustness)) {
448 : SymLoadStruct robustnessSymbols[] = {
449 : { (PRFuncPtr*) &mSymbols.fGetGraphicsResetStatus, { "GetGraphicsResetStatusARB", NULL } },
450 : { NULL, { NULL } },
451 0 : };
452 :
453 0 : if (!LoadSymbols(&robustnessSymbols[0], trygl, prefix)) {
454 0 : NS_RUNTIMEABORT("GL supports ARB_robustness without supplying GetGraphicsResetStatusARB.");
455 0 : mInitialized = false;
456 : } else {
457 0 : mHasRobustness = true;
458 : }
459 0 : } else if (IsExtensionSupported(EXT_robustness)) {
460 : SymLoadStruct robustnessSymbols[] = {
461 : { (PRFuncPtr*) &mSymbols.fGetGraphicsResetStatus, { "GetGraphicsResetStatusEXT", NULL } },
462 : { NULL, { NULL } },
463 0 : };
464 :
465 0 : if (!LoadSymbols(&robustnessSymbols[0], trygl, prefix)) {
466 0 : NS_RUNTIMEABORT("GL supports EGL_robustness without supplying GetGraphicsResetStatusEXT.");
467 0 : mInitialized = false;
468 : } else {
469 0 : mHasRobustness = true;
470 : }
471 : }
472 : }
473 :
474 : // Check for aux symbols based on extensions
475 0 : if (IsExtensionSupported(GLContext::ANGLE_framebuffer_blit) ||
476 0 : IsExtensionSupported(GLContext::EXT_framebuffer_blit)) {
477 : SymLoadStruct auxSymbols[] = {
478 : { (PRFuncPtr*) &mSymbols.fBlitFramebuffer, { "BlitFramebuffer", "BlitFramebufferEXT", "BlitFramebufferANGLE", NULL } },
479 : { NULL, { NULL } },
480 0 : };
481 0 : if (!LoadSymbols(&auxSymbols[0], trygl, prefix)) {
482 0 : NS_RUNTIMEABORT("GL supports framebuffer_blit without supplying glBlitFramebuffer");
483 0 : mInitialized = false;
484 : }
485 : }
486 :
487 0 : if (IsExtensionSupported(GLContext::ANGLE_framebuffer_multisample) ||
488 0 : IsExtensionSupported(GLContext::EXT_framebuffer_multisample)) {
489 : SymLoadStruct auxSymbols[] = {
490 : { (PRFuncPtr*) &mSymbols.fRenderbufferStorageMultisample, { "RenderbufferStorageMultisample", "RenderbufferStorageMultisampleEXT", "RenderbufferStorageMultisampleANGLE", NULL } },
491 : { NULL, { NULL } },
492 0 : };
493 0 : if (!LoadSymbols(&auxSymbols[0], trygl, prefix)) {
494 0 : NS_RUNTIMEABORT("GL supports framebuffer_multisample without supplying glRenderbufferStorageMultisample");
495 0 : mInitialized = false;
496 : }
497 : }
498 :
499 : // Load developer symbols, don't fail if we can't find them.
500 : SymLoadStruct auxSymbols[] = {
501 : { (PRFuncPtr*) &mSymbols.fGetTexImage, { "GetTexImage", NULL } },
502 : { (PRFuncPtr*) &mSymbols.fGetTexLevelParameteriv, { "GetTexLevelParameteriv", NULL } },
503 : { NULL, { NULL } },
504 0 : };
505 0 : LoadSymbols(&auxSymbols[0], trygl, prefix);
506 : }
507 :
508 0 : if (mInitialized) {
509 : GLint v[4];
510 :
511 0 : fGetIntegerv(LOCAL_GL_SCISSOR_BOX, v);
512 0 : mScissorStack.AppendElement(nsIntRect(v[0], v[1], v[2], v[3]));
513 :
514 0 : fGetIntegerv(LOCAL_GL_VIEWPORT, v);
515 0 : mViewportStack.AppendElement(nsIntRect(v[0], v[1], v[2], v[3]));
516 :
517 0 : fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
518 0 : fGetIntegerv(LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE, &mMaxCubeMapTextureSize);
519 0 : fGetIntegerv(LOCAL_GL_MAX_RENDERBUFFER_SIZE, &mMaxRenderbufferSize);
520 :
521 : #ifdef XP_MACOSX
522 : if (mVendor == VendorIntel) {
523 : // see bug 737182 for 2D textures, bug 684822 for cube map textures.
524 : mMaxTextureSize = NS_MIN(mMaxTextureSize, 4096);
525 : mMaxCubeMapTextureSize = NS_MIN(mMaxCubeMapTextureSize, 512);
526 : // for good measure, we align renderbuffers on what we do for 2D textures
527 : mMaxRenderbufferSize = NS_MIN(mMaxRenderbufferSize, 4096);
528 : }
529 : #endif
530 :
531 0 : mMaxTextureImageSize = mMaxTextureSize;
532 :
533 0 : UpdateActualFormat();
534 : }
535 :
536 : #ifdef DEBUG
537 0 : if (PR_GetEnv("MOZ_GL_DEBUG"))
538 0 : sDebugMode |= DebugEnabled;
539 :
540 : // enables extra verbose output, informing of the start and finish of every GL call.
541 : // useful e.g. to record information to investigate graphics system crashes/lockups
542 0 : if (PR_GetEnv("MOZ_GL_DEBUG_VERBOSE"))
543 0 : sDebugMode |= DebugTrace;
544 :
545 : // aborts on GL error. Can be useful to debug quicker code that is known not to generate any GL error in principle.
546 0 : if (PR_GetEnv("MOZ_GL_DEBUG_ABORT_ON_ERROR"))
547 0 : sDebugMode |= DebugAbortOnError;
548 : #endif
549 :
550 0 : if (mInitialized)
551 0 : reporter.SetSuccessful();
552 : else {
553 : // if initialization fails, ensure all symbols are zero, to avoid hard-to-understand bugs
554 0 : mSymbols.Zero();
555 0 : NS_WARNING("InitWithPrefix failed!");
556 : }
557 :
558 0 : return mInitialized;
559 : }
560 :
561 : void
562 0 : GLContext::InitExtensions()
563 : {
564 0 : MakeCurrent();
565 0 : const GLubyte *extensions = fGetString(LOCAL_GL_EXTENSIONS);
566 0 : if (!extensions)
567 0 : return;
568 :
569 0 : char *exts = strdup((char *)extensions);
570 :
571 : #ifdef DEBUG
572 : static bool once = false;
573 : #else
574 : const bool once = true;
575 : #endif
576 :
577 0 : if (!once) {
578 0 : printf_stderr("GL extensions: %s\n", exts);
579 : }
580 :
581 0 : char *s = exts;
582 0 : bool done = false;
583 0 : while (!done) {
584 0 : char *space = strchr(s, ' ');
585 0 : if (space) {
586 0 : *space = '\0';
587 : } else {
588 0 : done = true;
589 : }
590 :
591 0 : for (int i = 0; sExtensionNames[i]; ++i) {
592 0 : if (strcmp(s, sExtensionNames[i]) == 0) {
593 0 : if (!once) {
594 0 : printf_stderr("Found extension %s\n", s);
595 : }
596 0 : mAvailableExtensions[i] = 1;
597 : }
598 : }
599 :
600 0 : s = space+1;
601 : }
602 :
603 0 : free(exts);
604 :
605 : #ifdef DEBUG
606 0 : once = true;
607 : #endif
608 : }
609 :
610 : bool
611 0 : GLContext::IsExtensionSupported(const char *extension)
612 : {
613 0 : return ListHasExtension(fGetString(LOCAL_GL_EXTENSIONS), extension);
614 : }
615 :
616 : bool
617 0 : GLContext::CanUploadSubTextures()
618 : {
619 : // There are certain GPUs that we don't want to use glTexSubImage2D on
620 : // because that function can be very slow and/or buggy
621 :
622 0 : return !(Renderer() == RendererAdreno200);
623 : }
624 :
625 : // Common code for checking for both GL extensions and GLX extensions.
626 : bool
627 0 : GLContext::ListHasExtension(const GLubyte *extensions, const char *extension)
628 : {
629 : // fix bug 612572 - we were crashing as we were calling this function with extensions==null
630 0 : if (extensions == nsnull || extension == nsnull)
631 0 : return false;
632 :
633 : const GLubyte *start;
634 : GLubyte *where, *terminator;
635 :
636 : /* Extension names should not have spaces. */
637 0 : where = (GLubyte *) strchr(extension, ' ');
638 0 : if (where || *extension == '\0')
639 0 : return false;
640 :
641 : /*
642 : * It takes a bit of care to be fool-proof about parsing the
643 : * OpenGL extensions string. Don't be fooled by sub-strings,
644 : * etc.
645 : */
646 0 : start = extensions;
647 0 : for (;;) {
648 0 : where = (GLubyte *) strstr((const char *) start, extension);
649 0 : if (!where) {
650 : break;
651 : }
652 0 : terminator = where + strlen(extension);
653 0 : if (where == start || *(where - 1) == ' ') {
654 0 : if (*terminator == ' ' || *terminator == '\0') {
655 0 : return true;
656 : }
657 : }
658 0 : start = terminator;
659 : }
660 0 : return false;
661 : }
662 :
663 : already_AddRefed<TextureImage>
664 0 : GLContext::CreateTextureImage(const nsIntSize& aSize,
665 : TextureImage::ContentType aContentType,
666 : GLenum aWrapMode,
667 : bool aUseNearestFilter)
668 : {
669 0 : MakeCurrent();
670 :
671 : GLuint texture;
672 0 : fGenTextures(1, &texture);
673 :
674 0 : fActiveTexture(LOCAL_GL_TEXTURE0);
675 0 : fBindTexture(LOCAL_GL_TEXTURE_2D, texture);
676 :
677 0 : GLint texfilter = aUseNearestFilter ? LOCAL_GL_NEAREST : LOCAL_GL_LINEAR;
678 0 : fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, texfilter);
679 0 : fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, texfilter);
680 0 : fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, aWrapMode);
681 0 : fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, aWrapMode);
682 :
683 0 : return CreateBasicTextureImage(texture, aSize, aWrapMode, aContentType, this);
684 : }
685 :
686 0 : void GLContext::ApplyFilterToBoundTexture(gfxPattern::GraphicsFilter aFilter)
687 : {
688 0 : if (aFilter == gfxPattern::FILTER_NEAREST) {
689 0 : fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_NEAREST);
690 0 : fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_NEAREST);
691 : } else {
692 0 : if (aFilter != gfxPattern::FILTER_GOOD) {
693 0 : NS_WARNING("Unsupported filter type!");
694 : }
695 0 : fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR);
696 0 : fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR);
697 : }
698 0 : }
699 :
700 0 : BasicTextureImage::~BasicTextureImage()
701 : {
702 0 : GLContext *ctx = mGLContext;
703 0 : if (ctx->IsDestroyed() || !NS_IsMainThread()) {
704 0 : ctx = ctx->GetSharedContext();
705 : }
706 :
707 : // If we have a context, then we need to delete the texture;
708 : // if we don't have a context (either real or shared),
709 : // then they went away when the contex was deleted, because it
710 : // was the only one that had access to it.
711 0 : if (ctx && !ctx->IsDestroyed()) {
712 0 : mGLContext->MakeCurrent();
713 0 : mGLContext->fDeleteTextures(1, &mTexture);
714 : }
715 0 : }
716 :
717 : gfxASurface*
718 0 : BasicTextureImage::BeginUpdate(nsIntRegion& aRegion)
719 : {
720 0 : NS_ASSERTION(!mUpdateSurface, "BeginUpdate() without EndUpdate()?");
721 :
722 : // determine the region the client will need to repaint
723 0 : if (mGLContext->CanUploadSubTextures()) {
724 0 : GetUpdateRegion(aRegion);
725 : } else {
726 0 : aRegion = nsIntRect(nsIntPoint(0, 0), mSize);
727 : }
728 :
729 0 : mUpdateRegion = aRegion;
730 :
731 0 : nsIntRect rgnSize = mUpdateRegion.GetBounds();
732 0 : if (!nsIntRect(nsIntPoint(0, 0), mSize).Contains(rgnSize)) {
733 0 : NS_ERROR("update outside of image");
734 0 : return NULL;
735 : }
736 :
737 : ImageFormat format =
738 0 : (GetContentType() == gfxASurface::CONTENT_COLOR) ?
739 0 : gfxASurface::ImageFormatRGB24 : gfxASurface::ImageFormatARGB32;
740 : mUpdateSurface =
741 0 : GetSurfaceForUpdate(gfxIntSize(rgnSize.width, rgnSize.height), format);
742 :
743 0 : if (!mUpdateSurface || mUpdateSurface->CairoStatus()) {
744 0 : mUpdateSurface = NULL;
745 0 : return NULL;
746 : }
747 :
748 0 : mUpdateSurface->SetDeviceOffset(gfxPoint(-rgnSize.x, -rgnSize.y));
749 :
750 0 : return mUpdateSurface;
751 : }
752 :
753 : void
754 0 : BasicTextureImage::GetUpdateRegion(nsIntRegion& aForRegion)
755 : {
756 : // if the texture hasn't been initialized yet, or something important
757 : // changed, we need to recreate our backing surface and force the
758 : // client to paint everything
759 0 : if (mTextureState != Valid)
760 0 : aForRegion = nsIntRect(nsIntPoint(0, 0), mSize);
761 0 : }
762 :
763 : void
764 0 : BasicTextureImage::EndUpdate()
765 : {
766 0 : NS_ASSERTION(!!mUpdateSurface, "EndUpdate() without BeginUpdate()?");
767 :
768 : // FIXME: this is the slow boat. Make me fast (with GLXPixmap?).
769 :
770 : // Undo the device offset that BeginUpdate set; doesn't much matter for us here,
771 : // but important if we ever do anything directly with the surface.
772 0 : mUpdateSurface->SetDeviceOffset(gfxPoint(0, 0));
773 :
774 0 : bool relative = FinishedSurfaceUpdate();
775 :
776 : mShaderType =
777 : mGLContext->UploadSurfaceToTexture(mUpdateSurface,
778 : mUpdateRegion,
779 : mTexture,
780 : mTextureState == Created,
781 : mUpdateOffset,
782 0 : relative);
783 0 : FinishedSurfaceUpload();
784 :
785 0 : mUpdateSurface = nsnull;
786 0 : mTextureState = Valid;
787 0 : }
788 :
789 : void
790 0 : BasicTextureImage::BindTexture(GLenum aTextureUnit)
791 : {
792 0 : mGLContext->fActiveTexture(aTextureUnit);
793 0 : mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
794 0 : mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
795 0 : }
796 :
797 : void
798 0 : BasicTextureImage::ApplyFilter()
799 : {
800 0 : mGLContext->ApplyFilterToBoundTexture(mFilter);
801 0 : }
802 :
803 :
804 : already_AddRefed<gfxASurface>
805 0 : BasicTextureImage::GetSurfaceForUpdate(const gfxIntSize& aSize, ImageFormat aFmt)
806 : {
807 0 : return gfxPlatform::GetPlatform()->
808 0 : CreateOffscreenSurface(aSize, gfxASurface::ContentFromFormat(aFmt));
809 : }
810 :
811 : bool
812 0 : BasicTextureImage::FinishedSurfaceUpdate()
813 : {
814 0 : return false;
815 : }
816 :
817 : void
818 0 : BasicTextureImage::FinishedSurfaceUpload()
819 : {
820 0 : }
821 :
822 : bool
823 0 : BasicTextureImage::DirectUpdate(gfxASurface* aSurf, const nsIntRegion& aRegion, const nsIntPoint& aFrom /* = nsIntPoint(0, 0) */)
824 : {
825 0 : nsIntRect bounds = aRegion.GetBounds();
826 0 : nsIntRegion region;
827 0 : if (mTextureState != Valid) {
828 0 : bounds = nsIntRect(0, 0, mSize.width, mSize.height);
829 0 : region = nsIntRegion(bounds);
830 : } else {
831 0 : region = aRegion;
832 : }
833 :
834 : mShaderType =
835 : mGLContext->UploadSurfaceToTexture(aSurf,
836 : region,
837 : mTexture,
838 : mTextureState == Created,
839 : bounds.TopLeft() + aFrom,
840 0 : false);
841 0 : mTextureState = Valid;
842 0 : return true;
843 : }
844 :
845 : void
846 0 : BasicTextureImage::Resize(const nsIntSize& aSize)
847 : {
848 0 : NS_ASSERTION(!mUpdateSurface, "Resize() while in update?");
849 :
850 0 : mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
851 :
852 : mGLContext->fTexImage2D(LOCAL_GL_TEXTURE_2D,
853 : 0,
854 : LOCAL_GL_RGBA,
855 : aSize.width,
856 : aSize.height,
857 : 0,
858 : LOCAL_GL_RGBA,
859 : LOCAL_GL_UNSIGNED_BYTE,
860 0 : NULL);
861 :
862 0 : mTextureState = Allocated;
863 0 : mSize = aSize;
864 0 : }
865 :
866 0 : TiledTextureImage::TiledTextureImage(GLContext* aGL,
867 : nsIntSize aSize,
868 : TextureImage::ContentType aContentType,
869 : bool aUseNearestFilter)
870 : : TextureImage(aSize, LOCAL_GL_CLAMP_TO_EDGE, aContentType, aUseNearestFilter)
871 : , mCurrentImage(0)
872 : , mInUpdate(false)
873 : , mGL(aGL)
874 : , mUseNearestFilter(aUseNearestFilter)
875 0 : , mTextureState(Created)
876 : {
877 0 : mTileSize = mGL->GetMaxTextureSize();
878 0 : if (aSize != nsIntSize(0,0)) {
879 0 : Resize(aSize);
880 : }
881 0 : }
882 :
883 0 : TiledTextureImage::~TiledTextureImage()
884 : {
885 0 : }
886 :
887 : bool
888 0 : TiledTextureImage::DirectUpdate(gfxASurface* aSurf, const nsIntRegion& aRegion, const nsIntPoint& aFrom /* = nsIntPoint(0, 0) */)
889 : {
890 0 : nsIntRegion region;
891 :
892 0 : if (mTextureState != Valid) {
893 0 : nsIntRect bounds = nsIntRect(0, 0, mSize.width, mSize.height);
894 0 : region = nsIntRegion(bounds);
895 : } else {
896 0 : region = aRegion;
897 : }
898 :
899 0 : bool result = true;
900 0 : for (unsigned i = 0; i < mImages.Length(); i++) {
901 0 : int xPos = (i % mColumns) * mTileSize;
902 0 : int yPos = (i / mColumns) * mTileSize;
903 0 : nsIntRegion tileRegion;
904 0 : nsIntRect tileRect = nsIntRect(nsIntPoint(xPos, yPos), mImages[i]->GetSize());
905 0 : tileRegion.And(region, tileRect); // intersect with tile
906 0 : if (tileRegion.IsEmpty())
907 0 : continue;
908 0 : if (mGL->CanUploadSubTextures()) {
909 0 : tileRegion.MoveBy(-xPos, -yPos); // translate into tile local space
910 : } else {
911 : // If sub-textures are unsupported, expand to tile boundaries
912 0 : tileRect.x = tileRect.y = 0;
913 0 : tileRegion = nsIntRegion(tileRect);
914 : }
915 0 : result &= mImages[i]->DirectUpdate(aSurf,
916 : tileRegion,
917 0 : aFrom + nsIntPoint(xPos, yPos));
918 : }
919 0 : mShaderType = mImages[0]->GetShaderProgramType();
920 0 : mTextureState = Valid;
921 0 : return result;
922 : }
923 :
924 : void
925 0 : TiledTextureImage::GetUpdateRegion(nsIntRegion& aForRegion)
926 : {
927 0 : if (mTextureState != Valid) {
928 : // if the texture hasn't been initialized yet, or something important
929 : // changed, we need to recreate our backing surface and force the
930 : // client to paint everything
931 0 : aForRegion = nsIntRect(nsIntPoint(0, 0), mSize);
932 0 : return;
933 : }
934 :
935 0 : nsIntRegion newRegion;
936 :
937 : // We need to query each texture with the region it will be drawing and
938 : // set aForRegion to be the combination of all of these regions
939 0 : for (unsigned i = 0; i < mImages.Length(); i++) {
940 0 : int xPos = (i % mColumns) * mTileSize;
941 0 : int yPos = (i / mColumns) * mTileSize;
942 0 : nsIntRect imageRect = nsIntRect(nsIntRect(nsIntPoint(xPos,yPos), mImages[i]->GetSize()));
943 :
944 0 : if (aForRegion.Intersects(imageRect)) {
945 : // Make a copy of the region
946 0 : nsIntRegion subRegion;
947 0 : subRegion.And(aForRegion, imageRect);
948 : // Translate it into tile-space
949 0 : subRegion.MoveBy(-xPos, -yPos);
950 : // Query region
951 0 : mImages[i]->GetUpdateRegion(subRegion);
952 : // Translate back
953 0 : subRegion.MoveBy(xPos, yPos);
954 : // Add to the accumulated region
955 0 : newRegion.Or(newRegion, subRegion);
956 : }
957 : }
958 :
959 0 : aForRegion = newRegion;
960 : }
961 :
962 : gfxASurface*
963 0 : TiledTextureImage::BeginUpdate(nsIntRegion& aRegion)
964 : {
965 0 : NS_ASSERTION(!mInUpdate, "nested update");
966 0 : mInUpdate = true;
967 :
968 : // Note, we don't call GetUpdateRegion here as if the updated region is
969 : // fully contained in a single tile, we get to avoid iterating through
970 : // the tiles again (and a little copying).
971 0 : if (mTextureState != Valid)
972 : {
973 : // if the texture hasn't been initialized yet, or something important
974 : // changed, we need to recreate our backing surface and force the
975 : // client to paint everything
976 0 : aRegion = nsIntRect(nsIntPoint(0, 0), mSize);
977 : }
978 :
979 0 : nsIntRect bounds = aRegion.GetBounds();
980 :
981 0 : for (unsigned i = 0; i < mImages.Length(); i++) {
982 0 : int xPos = (i % mColumns) * mTileSize;
983 0 : int yPos = (i / mColumns) * mTileSize;
984 0 : nsIntRegion imageRegion = nsIntRegion(nsIntRect(nsIntPoint(xPos,yPos), mImages[i]->GetSize()));
985 :
986 : // a single Image can handle this update request
987 0 : if (imageRegion.Contains(aRegion)) {
988 : // adjust for tile offset
989 0 : aRegion.MoveBy(-xPos, -yPos);
990 : // forward the actual call
991 0 : nsRefPtr<gfxASurface> surface = mImages[i]->BeginUpdate(aRegion);
992 : // caller expects container space
993 0 : aRegion.MoveBy(xPos, yPos);
994 : // Correct the device offset
995 0 : gfxPoint offset = surface->GetDeviceOffset();
996 : surface->SetDeviceOffset(gfxPoint(offset.x - xPos,
997 0 : offset.y - yPos));
998 : // we don't have a temp surface
999 0 : mUpdateSurface = nsnull;
1000 : // remember which image to EndUpdate
1001 0 : mCurrentImage = i;
1002 0 : return surface.get();
1003 : }
1004 : }
1005 :
1006 : // Get the real updated region, taking into account the capabilities of
1007 : // each TextureImage tile
1008 0 : GetUpdateRegion(aRegion);
1009 0 : mUpdateRegion = aRegion;
1010 0 : bounds = aRegion.GetBounds();
1011 :
1012 : // update covers multiple Images - create a temp surface to paint in
1013 : gfxASurface::gfxImageFormat format =
1014 0 : (GetContentType() == gfxASurface::CONTENT_COLOR) ?
1015 0 : gfxASurface::ImageFormatRGB24 : gfxASurface::ImageFormatARGB32;
1016 0 : mUpdateSurface = gfxPlatform::GetPlatform()->
1017 0 : CreateOffscreenSurface(gfxIntSize(bounds.width, bounds.height), gfxASurface::ContentFromFormat(format));
1018 0 : mUpdateSurface->SetDeviceOffset(gfxPoint(-bounds.x, -bounds.y));
1019 :
1020 0 : return mUpdateSurface;
1021 : }
1022 :
1023 : void
1024 0 : TiledTextureImage::EndUpdate()
1025 : {
1026 0 : NS_ASSERTION(mInUpdate, "EndUpdate not in update");
1027 0 : if (!mUpdateSurface) { // update was to a single TextureImage
1028 0 : mImages[mCurrentImage]->EndUpdate();
1029 0 : mInUpdate = false;
1030 0 : mTextureState = Valid;
1031 0 : mShaderType = mImages[mCurrentImage]->GetShaderProgramType();
1032 0 : return;
1033 : }
1034 :
1035 : // upload tiles from temp surface
1036 0 : for (unsigned i = 0; i < mImages.Length(); i++) {
1037 0 : int xPos = (i % mColumns) * mTileSize;
1038 0 : int yPos = (i / mColumns) * mTileSize;
1039 0 : nsIntRect imageRect = nsIntRect(nsIntPoint(xPos,yPos), mImages[i]->GetSize());
1040 :
1041 0 : nsIntRegion subregion;
1042 0 : subregion.And(mUpdateRegion, imageRect);
1043 0 : if (subregion.IsEmpty())
1044 0 : continue;
1045 0 : subregion.MoveBy(-xPos, -yPos); // Tile-local space
1046 : // copy tile from temp surface
1047 0 : gfxASurface* surf = mImages[i]->BeginUpdate(subregion);
1048 0 : nsRefPtr<gfxContext> ctx = new gfxContext(surf);
1049 0 : gfxUtils::ClipToRegion(ctx, subregion);
1050 0 : ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
1051 0 : ctx->SetSource(mUpdateSurface, gfxPoint(-xPos, -yPos));
1052 0 : ctx->Paint();
1053 0 : mImages[i]->EndUpdate();
1054 : }
1055 :
1056 0 : mUpdateSurface = nsnull;
1057 0 : mInUpdate = false;
1058 0 : mShaderType = mImages[0]->GetShaderProgramType();
1059 0 : mTextureState = Valid;
1060 : }
1061 :
1062 0 : void TiledTextureImage::BeginTileIteration()
1063 : {
1064 0 : mCurrentImage = 0;
1065 0 : }
1066 :
1067 0 : bool TiledTextureImage::NextTile()
1068 : {
1069 0 : if (mCurrentImage + 1 < mImages.Length()) {
1070 0 : mCurrentImage++;
1071 0 : return true;
1072 : }
1073 0 : return false;
1074 : }
1075 :
1076 0 : nsIntRect TiledTextureImage::GetTileRect()
1077 : {
1078 0 : nsIntRect rect = mImages[mCurrentImage]->GetTileRect();
1079 0 : unsigned int xPos = (mCurrentImage % mColumns) * mTileSize;
1080 0 : unsigned int yPos = (mCurrentImage / mColumns) * mTileSize;
1081 0 : rect.MoveBy(xPos, yPos);
1082 : return rect;
1083 : }
1084 :
1085 : void
1086 0 : TiledTextureImage::BindTexture(GLenum aTextureUnit)
1087 : {
1088 0 : mImages[mCurrentImage]->BindTexture(aTextureUnit);
1089 0 : }
1090 :
1091 : void
1092 0 : TiledTextureImage::ApplyFilter()
1093 : {
1094 0 : mGL->ApplyFilterToBoundTexture(mFilter);
1095 0 : }
1096 :
1097 : /*
1098 : * simple resize, just discards everything. we can be more clever just
1099 : * adding or discarding tiles, but do we want this?
1100 : */
1101 0 : void TiledTextureImage::Resize(const nsIntSize& aSize)
1102 : {
1103 0 : if (mSize == aSize && mTextureState != Created) {
1104 0 : return;
1105 : }
1106 0 : mSize = aSize;
1107 0 : mImages.Clear();
1108 : // calculate rows and columns, rounding up
1109 0 : mColumns = (aSize.width + mTileSize - 1) / mTileSize;
1110 0 : mRows = (aSize.height + mTileSize - 1) / mTileSize;
1111 :
1112 0 : for (unsigned int row = 0; row < mRows; row++) {
1113 0 : for (unsigned int col = 0; col < mColumns; col++) {
1114 : nsIntSize size( // use tilesize first, then the remainder
1115 : (col+1) * mTileSize > (unsigned int)aSize.width ? aSize.width % mTileSize : mTileSize,
1116 0 : (row+1) * mTileSize > (unsigned int)aSize.height ? aSize.height % mTileSize : mTileSize);
1117 : nsRefPtr<TextureImage> teximg =
1118 0 : mGL->TileGenFunc(size, mContentType, mUseNearestFilter);
1119 0 : mImages.AppendElement(teximg.forget());
1120 : }
1121 : }
1122 0 : mTextureState = Allocated;
1123 : }
1124 :
1125 0 : PRUint32 TiledTextureImage::GetTileCount()
1126 : {
1127 0 : return mImages.Length();
1128 : }
1129 :
1130 : bool
1131 0 : GLContext::ResizeOffscreenFBO(const gfxIntSize& aSize, const bool aUseReadFBO, const bool aDisableAA)
1132 : {
1133 0 : if (!IsOffscreenSizeAllowed(aSize))
1134 0 : return false;
1135 :
1136 0 : MakeCurrent();
1137 :
1138 0 : const bool alpha = mCreationFormat.alpha > 0;
1139 0 : const int depth = mCreationFormat.depth;
1140 0 : const int stencil = mCreationFormat.stencil;
1141 0 : int samples = mCreationFormat.samples;
1142 :
1143 0 : GLint maxSamples = 0;
1144 0 : if (SupportsFramebufferMultisample() && !aDisableAA)
1145 0 : fGetIntegerv(LOCAL_GL_MAX_SAMPLES, &maxSamples);
1146 :
1147 0 : samples = NS_MIN(samples, maxSamples);
1148 :
1149 0 : const bool useDrawMSFBO = (samples > 0);
1150 :
1151 0 : if (!useDrawMSFBO && !aUseReadFBO) {
1152 : // Early out, as no FBO resize work is necessary.
1153 0 : return true;
1154 : }
1155 :
1156 0 : GLuint curBoundFramebufferDraw = 0;
1157 0 : GLuint curBoundFramebufferRead = 0;
1158 0 : GLuint curBoundRenderbuffer = 0;
1159 0 : GLuint curBoundTexture = 0;
1160 :
1161 : GLint viewport[4];
1162 :
1163 : const bool useDepthStencil =
1164 0 : !mIsGLES2 || IsExtensionSupported(OES_packed_depth_stencil);
1165 :
1166 : // save a few things for later restoring
1167 0 : curBoundFramebufferDraw = GetUserBoundDrawFBO();
1168 0 : curBoundFramebufferRead = GetUserBoundReadFBO();
1169 0 : fGetIntegerv(LOCAL_GL_RENDERBUFFER_BINDING, (GLint*) &curBoundRenderbuffer);
1170 0 : fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, (GLint*) &curBoundTexture);
1171 0 : fGetIntegerv(LOCAL_GL_VIEWPORT, viewport);
1172 :
1173 : // the context format of what we're defining
1174 : // This becomes mActualFormat on success
1175 0 : ContextFormat cf(mCreationFormat);
1176 :
1177 : // Create everything we need for the resize, so if it fails, we haven't broken anything
1178 : // If successful, these new resized objects will replace their associated member vars in GLContext
1179 0 : GLuint newOffscreenDrawFBO = 0;
1180 0 : GLuint newOffscreenReadFBO = 0;
1181 0 : GLuint newOffscreenTexture = 0;
1182 0 : GLuint newOffscreenColorRB = 0;
1183 0 : GLuint newOffscreenDepthRB = 0;
1184 0 : GLuint newOffscreenStencilRB = 0;
1185 :
1186 : // Create the buffers and texture
1187 0 : if (aUseReadFBO) {
1188 0 : fGenFramebuffers(1, &newOffscreenReadFBO);
1189 0 : fGenTextures(1, &newOffscreenTexture);
1190 : }
1191 :
1192 0 : if (useDrawMSFBO) {
1193 0 : fGenFramebuffers(1, &newOffscreenDrawFBO);
1194 0 : fGenRenderbuffers(1, &newOffscreenColorRB);
1195 : } else {
1196 0 : newOffscreenDrawFBO = newOffscreenReadFBO;
1197 : }
1198 :
1199 0 : if (depth && stencil && useDepthStencil) {
1200 0 : fGenRenderbuffers(1, &newOffscreenDepthRB);
1201 : } else {
1202 0 : if (depth) {
1203 0 : fGenRenderbuffers(1, &newOffscreenDepthRB);
1204 : }
1205 :
1206 0 : if (stencil) {
1207 0 : fGenRenderbuffers(1, &newOffscreenStencilRB);
1208 : }
1209 : }
1210 :
1211 : // Allocate texture
1212 0 : if (aUseReadFBO) {
1213 0 : fBindTexture(LOCAL_GL_TEXTURE_2D, newOffscreenTexture);
1214 0 : fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR);
1215 0 : fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR);
1216 0 : fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
1217 0 : fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
1218 :
1219 0 : if (alpha) {
1220 : fTexImage2D(LOCAL_GL_TEXTURE_2D,
1221 : 0,
1222 : LOCAL_GL_RGBA,
1223 : aSize.width, aSize.height,
1224 : 0,
1225 : LOCAL_GL_RGBA,
1226 : LOCAL_GL_UNSIGNED_BYTE,
1227 0 : NULL);
1228 :
1229 0 : cf.red = cf.green = cf.blue = cf.alpha = 8;
1230 : } else {
1231 : fTexImage2D(LOCAL_GL_TEXTURE_2D,
1232 : 0,
1233 : LOCAL_GL_RGB,
1234 : aSize.width, aSize.height,
1235 : 0,
1236 : LOCAL_GL_RGB,
1237 : #ifdef XP_WIN
1238 : LOCAL_GL_UNSIGNED_BYTE,
1239 : #else
1240 : mIsGLES2 ? LOCAL_GL_UNSIGNED_SHORT_5_6_5
1241 : : LOCAL_GL_UNSIGNED_BYTE,
1242 : #endif
1243 0 : NULL);
1244 :
1245 : #ifdef XP_WIN
1246 : cf.red = cf.green = cf.blue = 8;
1247 : #else
1248 0 : cf.red = 5;
1249 0 : cf.green = 6;
1250 0 : cf.blue = 5;
1251 : #endif
1252 0 : cf.alpha = 0;
1253 : }
1254 : }
1255 0 : cf.samples = samples;
1256 :
1257 : // Allocate color buffer
1258 0 : if (useDrawMSFBO) {
1259 : GLenum colorFormat;
1260 0 : if (!mIsGLES2 || IsExtensionSupported(OES_rgb8_rgba8))
1261 0 : colorFormat = alpha ? LOCAL_GL_RGBA8 : LOCAL_GL_RGB8;
1262 : else
1263 0 : colorFormat = alpha ? LOCAL_GL_RGBA4 : LOCAL_GL_RGB565;
1264 :
1265 0 : fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, newOffscreenColorRB);
1266 : fRenderbufferStorageMultisample(LOCAL_GL_RENDERBUFFER,
1267 : samples,
1268 : colorFormat,
1269 0 : aSize.width, aSize.height);
1270 : }
1271 :
1272 : // Allocate depth and stencil buffers
1273 0 : if (depth && stencil && useDepthStencil) {
1274 0 : fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, newOffscreenDepthRB);
1275 0 : if (useDrawMSFBO) {
1276 : fRenderbufferStorageMultisample(LOCAL_GL_RENDERBUFFER,
1277 : samples,
1278 : LOCAL_GL_DEPTH24_STENCIL8,
1279 0 : aSize.width, aSize.height);
1280 : } else {
1281 : fRenderbufferStorage(LOCAL_GL_RENDERBUFFER,
1282 : LOCAL_GL_DEPTH24_STENCIL8,
1283 0 : aSize.width, aSize.height);
1284 : }
1285 0 : cf.depth = 24;
1286 0 : cf.stencil = 8;
1287 : } else {
1288 0 : if (depth) {
1289 : GLenum depthType;
1290 0 : if (mIsGLES2) {
1291 0 : if (IsExtensionSupported(OES_depth32)) {
1292 0 : depthType = LOCAL_GL_DEPTH_COMPONENT32;
1293 0 : cf.depth = 32;
1294 0 : } else if (IsExtensionSupported(OES_depth24)) {
1295 0 : depthType = LOCAL_GL_DEPTH_COMPONENT24;
1296 0 : cf.depth = 24;
1297 : } else {
1298 0 : depthType = LOCAL_GL_DEPTH_COMPONENT16;
1299 0 : cf.depth = 16;
1300 : }
1301 : } else {
1302 0 : depthType = LOCAL_GL_DEPTH_COMPONENT24;
1303 0 : cf.depth = 24;
1304 : }
1305 :
1306 0 : fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, newOffscreenDepthRB);
1307 0 : if (useDrawMSFBO) {
1308 : fRenderbufferStorageMultisample(LOCAL_GL_RENDERBUFFER,
1309 : samples,
1310 : depthType,
1311 0 : aSize.width, aSize.height);
1312 : } else {
1313 : fRenderbufferStorage(LOCAL_GL_RENDERBUFFER,
1314 : depthType,
1315 0 : aSize.width, aSize.height);
1316 : }
1317 : }
1318 :
1319 0 : if (stencil) {
1320 0 : fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, newOffscreenStencilRB);
1321 0 : if (useDrawMSFBO) {
1322 : fRenderbufferStorageMultisample(LOCAL_GL_RENDERBUFFER,
1323 : samples,
1324 : LOCAL_GL_STENCIL_INDEX8,
1325 0 : aSize.width, aSize.height);
1326 : } else {
1327 : fRenderbufferStorage(LOCAL_GL_RENDERBUFFER,
1328 : LOCAL_GL_STENCIL_INDEX8,
1329 0 : aSize.width, aSize.height);
1330 : }
1331 0 : cf.stencil = 8;
1332 : }
1333 : }
1334 :
1335 : // Now assemble the FBO
1336 0 : BindInternalFBO(newOffscreenDrawFBO); // If we're not using a separate draw FBO, this will be the read FBO
1337 0 : if (useDrawMSFBO) {
1338 : fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
1339 : LOCAL_GL_COLOR_ATTACHMENT0,
1340 : LOCAL_GL_RENDERBUFFER,
1341 0 : newOffscreenColorRB);
1342 : }
1343 :
1344 0 : if (depth && stencil && useDepthStencil) {
1345 : fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
1346 : LOCAL_GL_DEPTH_ATTACHMENT,
1347 : LOCAL_GL_RENDERBUFFER,
1348 0 : newOffscreenDepthRB);
1349 : fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
1350 : LOCAL_GL_STENCIL_ATTACHMENT,
1351 : LOCAL_GL_RENDERBUFFER,
1352 0 : newOffscreenDepthRB);
1353 : } else {
1354 0 : if (depth) {
1355 : fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
1356 : LOCAL_GL_DEPTH_ATTACHMENT,
1357 : LOCAL_GL_RENDERBUFFER,
1358 0 : newOffscreenDepthRB);
1359 : }
1360 :
1361 0 : if (stencil) {
1362 : fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
1363 : LOCAL_GL_STENCIL_ATTACHMENT,
1364 : LOCAL_GL_RENDERBUFFER,
1365 0 : newOffscreenStencilRB);
1366 : }
1367 : }
1368 :
1369 0 : if (aUseReadFBO) {
1370 0 : BindInternalFBO(newOffscreenReadFBO);
1371 : fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
1372 : LOCAL_GL_COLOR_ATTACHMENT0,
1373 : LOCAL_GL_TEXTURE_2D,
1374 : newOffscreenTexture,
1375 0 : 0);
1376 : }
1377 :
1378 : // We should be all resized. Check for framebuffer completeness.
1379 : GLenum status;
1380 0 : bool framebuffersComplete = true;
1381 :
1382 0 : BindInternalFBO(newOffscreenDrawFBO);
1383 0 : status = fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
1384 0 : if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
1385 0 : NS_WARNING("DrawFBO: Incomplete");
1386 : #ifdef DEBUG
1387 0 : printf_stderr("Framebuffer status: %X\n", status);
1388 : #endif
1389 0 : framebuffersComplete = false;
1390 : }
1391 :
1392 0 : BindInternalFBO(newOffscreenReadFBO);
1393 0 : status = fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
1394 0 : if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
1395 0 : NS_WARNING("ReadFBO: Incomplete");
1396 : #ifdef DEBUG
1397 0 : printf_stderr("Framebuffer status: %X\n", status);
1398 : #endif
1399 0 : framebuffersComplete = false;
1400 : }
1401 :
1402 0 : if (!framebuffersComplete) {
1403 0 : NS_WARNING("Error resizing offscreen framebuffer -- framebuffer(s) not complete");
1404 :
1405 : // Clean up the mess
1406 0 : fDeleteFramebuffers(1, &newOffscreenDrawFBO);
1407 0 : fDeleteFramebuffers(1, &newOffscreenReadFBO);
1408 0 : fDeleteTextures(1, &newOffscreenTexture);
1409 0 : fDeleteRenderbuffers(1, &newOffscreenColorRB);
1410 0 : fDeleteRenderbuffers(1, &newOffscreenDepthRB);
1411 0 : fDeleteRenderbuffers(1, &newOffscreenStencilRB);
1412 :
1413 0 : BindUserDrawFBO(curBoundFramebufferDraw);
1414 0 : BindUserReadFBO(curBoundFramebufferRead);
1415 0 : fBindTexture(LOCAL_GL_TEXTURE_2D, curBoundTexture);
1416 0 : fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, curBoundRenderbuffer);
1417 0 : fViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
1418 :
1419 0 : return false;
1420 : }
1421 :
1422 : // Success, so delete the old and busted
1423 0 : fDeleteFramebuffers(1, &mOffscreenDrawFBO);
1424 0 : fDeleteFramebuffers(1, &mOffscreenReadFBO);
1425 0 : fDeleteTextures(1, &mOffscreenTexture);
1426 0 : fDeleteRenderbuffers(1, &mOffscreenColorRB);
1427 0 : fDeleteRenderbuffers(1, &mOffscreenDepthRB);
1428 0 : fDeleteRenderbuffers(1, &mOffscreenStencilRB);
1429 :
1430 : // Update currently bound references if we're changing what they were point to
1431 : // This way we don't rebind to old buffers when we're done here
1432 0 : if (curBoundFramebufferDraw == mOffscreenDrawFBO)
1433 0 : curBoundFramebufferDraw = newOffscreenDrawFBO;
1434 0 : if (curBoundFramebufferRead == mOffscreenReadFBO)
1435 0 : curBoundFramebufferRead = newOffscreenReadFBO;
1436 0 : if (curBoundTexture == mOffscreenTexture)
1437 0 : curBoundTexture = newOffscreenTexture;
1438 0 : if (curBoundRenderbuffer == mOffscreenColorRB)
1439 0 : curBoundRenderbuffer = newOffscreenColorRB;
1440 0 : else if (curBoundRenderbuffer == mOffscreenDepthRB)
1441 0 : curBoundRenderbuffer = newOffscreenDepthRB;
1442 0 : else if (curBoundRenderbuffer == mOffscreenStencilRB)
1443 0 : curBoundRenderbuffer = newOffscreenStencilRB;
1444 :
1445 : // Replace with the new hotness
1446 0 : mOffscreenDrawFBO = newOffscreenDrawFBO;
1447 0 : mOffscreenReadFBO = newOffscreenReadFBO;
1448 0 : mOffscreenTexture = newOffscreenTexture;
1449 0 : mOffscreenColorRB = newOffscreenColorRB;
1450 0 : mOffscreenDepthRB = newOffscreenDepthRB;
1451 0 : mOffscreenStencilRB = newOffscreenStencilRB;
1452 :
1453 0 : mOffscreenSize = aSize;
1454 0 : mOffscreenActualSize = aSize;
1455 :
1456 0 : mActualFormat = cf;
1457 :
1458 : #ifdef DEBUG
1459 0 : if (DebugMode()) {
1460 : printf_stderr("Resized %dx%d offscreen FBO: r: %d g: %d b: %d a: %d depth: %d stencil: %d samples: %d\n",
1461 : mOffscreenActualSize.width, mOffscreenActualSize.height,
1462 : mActualFormat.red, mActualFormat.green, mActualFormat.blue, mActualFormat.alpha,
1463 0 : mActualFormat.depth, mActualFormat.stencil, mActualFormat.samples);
1464 : }
1465 : #endif
1466 :
1467 : // We're good, and the framebuffer is already attached.
1468 : // Now restore the GL state back to what it was before the resize took place.
1469 : // If the user was using fb 0, this will bind the offscreen framebuffer we
1470 : // just created.
1471 0 : BindUserDrawFBO(curBoundFramebufferDraw);
1472 0 : BindUserReadFBO(curBoundFramebufferRead);
1473 0 : fBindTexture(LOCAL_GL_TEXTURE_2D, curBoundTexture);
1474 0 : fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, curBoundRenderbuffer);
1475 0 : fViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
1476 :
1477 : // Make sure we know that the buffers are new and thus dirty:
1478 0 : ForceDirtyFBOs();
1479 :
1480 0 : return true;
1481 : }
1482 :
1483 : void
1484 0 : GLContext::DeleteOffscreenFBO()
1485 : {
1486 0 : fDeleteFramebuffers(1, &mOffscreenDrawFBO);
1487 0 : fDeleteFramebuffers(1, &mOffscreenReadFBO);
1488 0 : fDeleteTextures(1, &mOffscreenTexture);
1489 0 : fDeleteRenderbuffers(1, &mOffscreenColorRB);
1490 0 : fDeleteRenderbuffers(1, &mOffscreenDepthRB);
1491 0 : fDeleteRenderbuffers(1, &mOffscreenStencilRB);
1492 :
1493 0 : mOffscreenDrawFBO = 0;
1494 0 : mOffscreenReadFBO = 0;
1495 0 : mOffscreenTexture = 0;
1496 0 : mOffscreenColorRB = 0;
1497 0 : mOffscreenDepthRB = 0;
1498 0 : mOffscreenStencilRB = 0;
1499 0 : }
1500 :
1501 : void
1502 0 : GLContext::ClearSafely()
1503 : {
1504 : // bug 659349 --- we must be very careful here: clearing a GL framebuffer is nontrivial, relies on a lot of state,
1505 : // and in the case of the backbuffer of a WebGL context, state is exposed to scripts.
1506 : //
1507 : // The code here is taken from WebGLContext::ForceClearFramebufferWithDefaultValues, but I didn't find a good way of
1508 : // sharing code with it. WebGL's code is somewhat performance-critical as it is typically called on every frame, so
1509 : // WebGL keeps track of GL state to avoid having to query it everytime, and also tries to only do work for actually
1510 : // present buffers (e.g. stencil buffer). Doing that here seems like premature optimization,
1511 : // as ClearSafely() is called only when e.g. a canvas is resized, not on every animation frame.
1512 :
1513 : realGLboolean scissorTestEnabled;
1514 : realGLboolean ditherEnabled;
1515 : realGLboolean colorWriteMask[4];
1516 : realGLboolean depthWriteMask;
1517 : GLint stencilWriteMaskFront, stencilWriteMaskBack;
1518 : GLfloat colorClearValue[4];
1519 : GLfloat depthClearValue;
1520 : GLint stencilClearValue;
1521 :
1522 : // save current GL state
1523 0 : fGetBooleanv(LOCAL_GL_SCISSOR_TEST, &scissorTestEnabled);
1524 0 : fGetBooleanv(LOCAL_GL_DITHER, &ditherEnabled);
1525 0 : fGetBooleanv(LOCAL_GL_COLOR_WRITEMASK, colorWriteMask);
1526 0 : fGetBooleanv(LOCAL_GL_DEPTH_WRITEMASK, &depthWriteMask);
1527 0 : fGetIntegerv(LOCAL_GL_STENCIL_WRITEMASK, &stencilWriteMaskFront);
1528 0 : fGetIntegerv(LOCAL_GL_STENCIL_BACK_WRITEMASK, &stencilWriteMaskBack);
1529 0 : fGetFloatv(LOCAL_GL_COLOR_CLEAR_VALUE, colorClearValue);
1530 0 : fGetFloatv(LOCAL_GL_DEPTH_CLEAR_VALUE, &depthClearValue);
1531 0 : fGetIntegerv(LOCAL_GL_STENCIL_CLEAR_VALUE, &stencilClearValue);
1532 :
1533 : // prepare GL state for clearing
1534 0 : fDisable(LOCAL_GL_SCISSOR_TEST);
1535 0 : fDisable(LOCAL_GL_DITHER);
1536 0 : PushViewportRect(nsIntRect(0, 0, mOffscreenSize.width, mOffscreenSize.height));
1537 :
1538 0 : fColorMask(1, 1, 1, 1);
1539 0 : fClearColor(0.f, 0.f, 0.f, 0.f);
1540 :
1541 0 : fDepthMask(1);
1542 0 : fClearDepth(1.0f);
1543 :
1544 0 : fStencilMask(0xffffffff);
1545 0 : fClearStencil(0);
1546 :
1547 : // do clear
1548 : fClear(LOCAL_GL_COLOR_BUFFER_BIT |
1549 : LOCAL_GL_DEPTH_BUFFER_BIT |
1550 0 : LOCAL_GL_STENCIL_BUFFER_BIT);
1551 :
1552 : // restore GL state after clearing
1553 0 : fColorMask(colorWriteMask[0],
1554 0 : colorWriteMask[1],
1555 0 : colorWriteMask[2],
1556 0 : colorWriteMask[3]);
1557 : fClearColor(colorClearValue[0],
1558 : colorClearValue[1],
1559 : colorClearValue[2],
1560 0 : colorClearValue[3]);
1561 :
1562 0 : fDepthMask(depthWriteMask);
1563 0 : fClearDepth(depthClearValue);
1564 :
1565 0 : fStencilMaskSeparate(LOCAL_GL_FRONT, stencilWriteMaskFront);
1566 0 : fStencilMaskSeparate(LOCAL_GL_BACK, stencilWriteMaskBack);
1567 0 : fClearStencil(stencilClearValue);
1568 :
1569 0 : PopViewportRect();
1570 :
1571 0 : if (ditherEnabled)
1572 0 : fEnable(LOCAL_GL_DITHER);
1573 : else
1574 0 : fDisable(LOCAL_GL_DITHER);
1575 :
1576 0 : if (scissorTestEnabled)
1577 0 : fEnable(LOCAL_GL_SCISSOR_TEST);
1578 : else
1579 0 : fDisable(LOCAL_GL_SCISSOR_TEST);
1580 :
1581 0 : }
1582 :
1583 : void
1584 0 : GLContext::UpdateActualFormat()
1585 : {
1586 0 : ContextFormat nf;
1587 :
1588 0 : fGetIntegerv(LOCAL_GL_RED_BITS, (GLint*) &nf.red);
1589 0 : fGetIntegerv(LOCAL_GL_GREEN_BITS, (GLint*) &nf.green);
1590 0 : fGetIntegerv(LOCAL_GL_BLUE_BITS, (GLint*) &nf.blue);
1591 0 : fGetIntegerv(LOCAL_GL_ALPHA_BITS, (GLint*) &nf.alpha);
1592 0 : fGetIntegerv(LOCAL_GL_DEPTH_BITS, (GLint*) &nf.depth);
1593 0 : fGetIntegerv(LOCAL_GL_STENCIL_BITS, (GLint*) &nf.stencil);
1594 :
1595 0 : mActualFormat = nf;
1596 0 : }
1597 :
1598 : void
1599 0 : GLContext::MarkDestroyed()
1600 : {
1601 0 : if (IsDestroyed())
1602 0 : return;
1603 :
1604 0 : MakeCurrent();
1605 0 : DeleteOffscreenFBO();
1606 :
1607 0 : fDeleteProgram(mBlitProgram);
1608 0 : mBlitProgram = 0;
1609 0 : fDeleteFramebuffers(1, &mBlitFramebuffer);
1610 0 : mBlitFramebuffer = 0;
1611 :
1612 0 : mSymbols.Zero();
1613 : }
1614 :
1615 0 : static void SwapRAndBComponents(gfxImageSurface* aSurf)
1616 : {
1617 0 : gfxIntSize size = aSurf->GetSize();
1618 0 : for (int j = 0; j < size.height; ++j) {
1619 0 : PRUint32 *row = (PRUint32*) (aSurf->Data() + aSurf->Stride() * j);
1620 0 : for (int i = 0; i < size.width; ++i) {
1621 0 : *row = (*row & 0xff00ff00) | ((*row & 0xff) << 16) | ((*row & 0xff0000) >> 16);
1622 0 : row++;
1623 : }
1624 : }
1625 0 : }
1626 :
1627 0 : static already_AddRefed<gfxImageSurface> YInvertImageSurface(gfxImageSurface* aSurf)
1628 : {
1629 0 : gfxIntSize size = aSurf->GetSize();
1630 0 : nsRefPtr<gfxImageSurface> temp = new gfxImageSurface(size, aSurf->Format());
1631 0 : nsRefPtr<gfxContext> ctx = new gfxContext(temp);
1632 0 : ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
1633 0 : ctx->Scale(1.0, -1.0);
1634 0 : ctx->Translate(-gfxPoint(0.0, size.height));
1635 0 : ctx->SetSource(aSurf);
1636 0 : ctx->Paint();
1637 0 : return temp.forget();
1638 : }
1639 :
1640 : already_AddRefed<gfxImageSurface>
1641 0 : GLContext::GetTexImage(GLuint aTexture, bool aYInvert, ShaderProgramType aShader)
1642 : {
1643 0 : MakeCurrent();
1644 0 : fFinish();
1645 0 : fActiveTexture(LOCAL_GL_TEXTURE0);
1646 0 : fBindTexture(LOCAL_GL_TEXTURE_2D, aTexture);
1647 :
1648 0 : gfxIntSize size;
1649 0 : fGetTexLevelParameteriv(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_TEXTURE_WIDTH, &size.width);
1650 0 : fGetTexLevelParameteriv(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_TEXTURE_HEIGHT, &size.height);
1651 :
1652 0 : nsRefPtr<gfxImageSurface> surf = new gfxImageSurface(size, gfxASurface::ImageFormatARGB32);
1653 0 : if (!surf || surf->CairoStatus()) {
1654 0 : return NULL;
1655 : }
1656 :
1657 0 : PRUint32 currentPackAlignment = 0;
1658 0 : fGetIntegerv(LOCAL_GL_PACK_ALIGNMENT, (GLint*)¤tPackAlignment);
1659 0 : if (currentPackAlignment != 4) {
1660 0 : fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, 4);
1661 : }
1662 0 : fGetTexImage(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, surf->Data());
1663 0 : if (currentPackAlignment != 4) {
1664 0 : fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, currentPackAlignment);
1665 : }
1666 :
1667 0 : if (aShader == RGBALayerProgramType || aShader == RGBXLayerProgramType) {
1668 0 : SwapRAndBComponents(surf);
1669 : }
1670 :
1671 0 : if (aYInvert) {
1672 0 : surf = YInvertImageSurface(surf);
1673 : }
1674 0 : return surf.forget();
1675 : }
1676 :
1677 : already_AddRefed<gfxImageSurface>
1678 0 : GLContext::ReadTextureImage(GLuint aTexture,
1679 : const gfxIntSize& aSize,
1680 : GLenum aTextureFormat,
1681 : bool aYInvert)
1682 : {
1683 0 : MakeCurrent();
1684 :
1685 0 : nsRefPtr<gfxImageSurface> isurf;
1686 :
1687 : GLint oldrb, oldfb, oldprog, oldPackAlignment;
1688 : GLint success;
1689 :
1690 0 : GLuint rb = 0, fb = 0;
1691 0 : GLuint vs = 0, fs = 0, prog = 0;
1692 :
1693 : const char *vShader =
1694 : "attribute vec4 aVertex;\n"
1695 : "attribute vec2 aTexCoord;\n"
1696 : "varying vec2 vTexCoord;\n"
1697 0 : "void main() { gl_Position = aVertex; vTexCoord = aTexCoord; }";
1698 : const char *fShader =
1699 : "#ifdef GL_ES\n"
1700 : "precision mediump float;\n"
1701 : "#endif\n"
1702 : "varying vec2 vTexCoord;\n"
1703 : "uniform sampler2D uTexture;\n"
1704 0 : "void main() { gl_FragColor = texture2D(uTexture, vTexCoord); }";
1705 :
1706 : float verts[4*4] = {
1707 : -1.0f, -1.0f, 0.0f, 1.0f,
1708 : 1.0f, -1.0f, 0.0f, 1.0f,
1709 : -1.0f, 1.0f, 0.0f, 1.0f,
1710 : 1.0f, 1.0f, 0.0f, 1.0f
1711 0 : };
1712 :
1713 : float texcoords[2*4] = {
1714 : 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f
1715 0 : };
1716 :
1717 0 : fGetIntegerv(LOCAL_GL_RENDERBUFFER_BINDING, &oldrb);
1718 0 : fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, &oldfb);
1719 0 : fGetIntegerv(LOCAL_GL_CURRENT_PROGRAM, &oldprog);
1720 0 : fGetIntegerv(LOCAL_GL_PACK_ALIGNMENT, &oldPackAlignment);
1721 :
1722 0 : PushViewportRect(nsIntRect(0, 0, aSize.width, aSize.height));
1723 :
1724 0 : fGenRenderbuffers(1, &rb);
1725 0 : fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, rb);
1726 : fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, LOCAL_GL_RGBA,
1727 0 : aSize.width, aSize.height);
1728 :
1729 0 : fGenFramebuffers(1, &fb);
1730 0 : fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, fb);
1731 : fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0,
1732 0 : LOCAL_GL_RENDERBUFFER, rb);
1733 :
1734 0 : if (fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER) !=
1735 : LOCAL_GL_FRAMEBUFFER_COMPLETE)
1736 : {
1737 0 : goto cleanup;
1738 : }
1739 :
1740 0 : vs = fCreateShader(LOCAL_GL_VERTEX_SHADER);
1741 0 : fs = fCreateShader(LOCAL_GL_FRAGMENT_SHADER);
1742 0 : fShaderSource(vs, 1, (const GLchar**) &vShader, NULL);
1743 0 : fShaderSource(fs, 1, (const GLchar**) &fShader, NULL);
1744 0 : fCompileShader(vs);
1745 0 : fCompileShader(fs);
1746 0 : prog = fCreateProgram();
1747 0 : fAttachShader(prog, vs);
1748 0 : fAttachShader(prog, fs);
1749 0 : fBindAttribLocation(prog, 0, "aVertex");
1750 0 : fBindAttribLocation(prog, 1, "aTexCoord");
1751 0 : fLinkProgram(prog);
1752 :
1753 0 : fGetProgramiv(prog, LOCAL_GL_LINK_STATUS, &success);
1754 0 : if (!success) {
1755 0 : goto cleanup;
1756 : }
1757 :
1758 0 : fUseProgram(prog);
1759 :
1760 0 : fEnableVertexAttribArray(0);
1761 0 : fEnableVertexAttribArray(1);
1762 :
1763 0 : fVertexAttribPointer(0, 4, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, verts);
1764 0 : fVertexAttribPointer(1, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, texcoords);
1765 :
1766 0 : fActiveTexture(LOCAL_GL_TEXTURE0);
1767 0 : fBindTexture(LOCAL_GL_TEXTURE_2D, aTexture);
1768 :
1769 0 : fUniform1i(fGetUniformLocation(prog, "uTexture"), 0);
1770 :
1771 0 : fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
1772 :
1773 0 : fDisableVertexAttribArray(1);
1774 0 : fDisableVertexAttribArray(0);
1775 :
1776 0 : isurf = new gfxImageSurface(aSize, gfxASurface::ImageFormatARGB32);
1777 0 : if (!isurf || isurf->CairoStatus()) {
1778 0 : isurf = nsnull;
1779 0 : goto cleanup;
1780 : }
1781 :
1782 0 : if (oldPackAlignment != 4)
1783 0 : fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, 4);
1784 :
1785 : fReadPixels(0, 0, aSize.width, aSize.height,
1786 : LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE,
1787 0 : isurf->Data());
1788 :
1789 0 : SwapRAndBComponents(isurf);
1790 :
1791 0 : if (oldPackAlignment != 4)
1792 0 : fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, oldPackAlignment);
1793 :
1794 0 : if (aYInvert) {
1795 0 : isurf = YInvertImageSurface(isurf);
1796 : }
1797 :
1798 : cleanup:
1799 : // note that deleting 0 has no effect in any of these calls
1800 0 : fDeleteRenderbuffers(1, &rb);
1801 0 : fDeleteFramebuffers(1, &fb);
1802 0 : fDeleteShader(vs);
1803 0 : fDeleteShader(fs);
1804 0 : fDeleteProgram(prog);
1805 :
1806 0 : fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, oldrb);
1807 0 : fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, oldfb);
1808 0 : fUseProgram(oldprog);
1809 :
1810 0 : PopViewportRect();
1811 :
1812 0 : return isurf.forget();
1813 : }
1814 :
1815 : static void
1816 0 : GetOptimalReadFormats(GLContext* gl, GLenum& format, GLenum& type) {
1817 0 : if (gl->IsGLES2()) {
1818 0 : bool has_BGRA_UByte = false;
1819 0 : if (gl->IsExtensionSupported(gl::GLContext::EXT_bgra)) {
1820 0 : has_BGRA_UByte = true;
1821 0 : } else if (gl->IsExtensionSupported(gl::GLContext::EXT_read_format_bgra) ||
1822 0 : gl->IsExtensionSupported(gl::GLContext::IMG_read_format)) {
1823 : // Note that these extensions are not required to query this value.
1824 : // However, we should never get back BGRA unless one of these is supported.
1825 0 : GLint auxFormat = 0;
1826 0 : GLint auxType = 0;
1827 :
1828 0 : gl->fGetIntegerv(LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT, &auxFormat);
1829 0 : gl->fGetIntegerv(LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE, &auxType);
1830 :
1831 0 : if (auxFormat == LOCAL_GL_BGRA && auxType == LOCAL_GL_UNSIGNED_BYTE)
1832 0 : has_BGRA_UByte = true;
1833 : }
1834 :
1835 0 : format = has_BGRA_UByte ? LOCAL_GL_BGRA : LOCAL_GL_RGBA;
1836 0 : type = LOCAL_GL_UNSIGNED_BYTE;
1837 : } else {
1838 : // defaults for desktop
1839 0 : format = LOCAL_GL_BGRA;
1840 0 : type = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV;
1841 : }
1842 0 : }
1843 :
1844 : void
1845 0 : GLContext::ReadPixelsIntoImageSurface(GLint aX, GLint aY,
1846 : GLsizei aWidth, GLsizei aHeight,
1847 : gfxImageSurface *aDest)
1848 : {
1849 0 : MakeCurrent();
1850 :
1851 0 : if (aDest->Format() != gfxASurface::ImageFormatARGB32 &&
1852 0 : aDest->Format() != gfxASurface::ImageFormatRGB24)
1853 : {
1854 0 : NS_WARNING("ReadPixelsIntoImageSurface called with invalid image format");
1855 0 : return;
1856 : }
1857 :
1858 0 : if (aDest->Width() != aWidth ||
1859 0 : aDest->Height() != aHeight ||
1860 0 : aDest->Stride() != aWidth * 4)
1861 : {
1862 0 : NS_WARNING("ReadPixelsIntoImageSurface called with wrong size or stride surface");
1863 0 : return;
1864 : }
1865 :
1866 0 : GLint currentPackAlignment = 0;
1867 0 : fGetIntegerv(LOCAL_GL_PACK_ALIGNMENT, ¤tPackAlignment);
1868 :
1869 0 : if (currentPackAlignment != 4)
1870 0 : fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, 4);
1871 :
1872 : GLenum format;
1873 : GLenum datatype;
1874 :
1875 0 : GetOptimalReadFormats(this, format, datatype);
1876 :
1877 : fReadPixels(0, 0, aWidth, aHeight,
1878 : format, datatype,
1879 0 : aDest->Data());
1880 :
1881 : // Output should be in BGRA, so swap if RGBA
1882 0 : if (format == LOCAL_GL_RGBA) {
1883 : // swap B and R bytes
1884 0 : for (int j = 0; j < aHeight; ++j) {
1885 0 : PRUint32 *row = (PRUint32*) (aDest->Data() + aDest->Stride() * j);
1886 0 : for (int i = 0; i < aWidth; ++i) {
1887 0 : *row = (*row & 0xff00ff00) | ((*row & 0xff) << 16) | ((*row & 0xff0000) >> 16);
1888 0 : row++;
1889 : }
1890 : }
1891 : }
1892 :
1893 0 : if (currentPackAlignment != 4)
1894 0 : fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, currentPackAlignment);
1895 : }
1896 :
1897 : void
1898 0 : GLContext::BlitTextureImage(TextureImage *aSrc, const nsIntRect& aSrcRect,
1899 : TextureImage *aDst, const nsIntRect& aDstRect)
1900 : {
1901 0 : NS_ASSERTION(!aSrc->InUpdate(), "Source texture is in update!");
1902 0 : NS_ASSERTION(!aDst->InUpdate(), "Destination texture is in update!");
1903 :
1904 0 : if (aSrcRect.IsEmpty() || aDstRect.IsEmpty())
1905 0 : return;
1906 :
1907 : // only save/restore this stuff on Qualcomm Adreno, to work
1908 : // around an apparent bug
1909 0 : int savedFb = 0;
1910 0 : if (mVendor == VendorQualcomm) {
1911 0 : fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, &savedFb);
1912 : }
1913 :
1914 0 : fDisable(LOCAL_GL_SCISSOR_TEST);
1915 0 : fDisable(LOCAL_GL_BLEND);
1916 :
1917 : // 2.0 means scale up by two
1918 0 : float blitScaleX = float(aDstRect.width) / float(aSrcRect.width);
1919 0 : float blitScaleY = float(aDstRect.height) / float(aSrcRect.height);
1920 :
1921 : // We start iterating over all destination tiles
1922 0 : aDst->BeginTileIteration();
1923 0 : do {
1924 : // calculate portion of the tile that is going to be painted to
1925 0 : nsIntRect dstSubRect;
1926 0 : nsIntRect dstTextureRect = aDst->GetTileRect();
1927 0 : dstSubRect.IntersectRect(aDstRect, dstTextureRect);
1928 :
1929 : // this tile is not part of the destination rectangle aDstRect
1930 0 : if (dstSubRect.IsEmpty())
1931 0 : continue;
1932 :
1933 : // (*) transform the rect of this tile into the rectangle defined by aSrcRect...
1934 0 : nsIntRect dstInSrcRect(dstSubRect);
1935 0 : dstInSrcRect.MoveBy(-aDstRect.TopLeft());
1936 : // ...which might be of different size, hence scale accordingly
1937 0 : dstInSrcRect.ScaleRoundOut(1.0f / blitScaleX, 1.0f / blitScaleY);
1938 0 : dstInSrcRect.MoveBy(aSrcRect.TopLeft());
1939 :
1940 0 : SetBlitFramebufferForDestTexture(aDst->GetTextureID());
1941 0 : UseBlitProgram();
1942 :
1943 0 : aSrc->BeginTileIteration();
1944 : // now iterate over all tiles in the source Image...
1945 0 : do {
1946 : // calculate portion of the source tile that is in the source rect
1947 0 : nsIntRect srcSubRect;
1948 0 : nsIntRect srcTextureRect = aSrc->GetTileRect();
1949 0 : srcSubRect.IntersectRect(aSrcRect, srcTextureRect);
1950 :
1951 : // this tile is not part of the source rect
1952 0 : if (srcSubRect.IsEmpty()) {
1953 0 : continue;
1954 : }
1955 : // calculate intersection of source rect with destination rect
1956 0 : srcSubRect.IntersectRect(srcSubRect, dstInSrcRect);
1957 : // this tile does not overlap the current destination tile
1958 0 : if (srcSubRect.IsEmpty()) {
1959 0 : continue;
1960 : }
1961 : // We now have the intersection of
1962 : // the current source tile
1963 : // and the desired source rectangle
1964 : // and the destination tile
1965 : // and the desired destination rectange
1966 : // in destination space.
1967 : // We need to transform this back into destination space, inverting the transform from (*)
1968 0 : nsIntRect srcSubInDstRect(srcSubRect);
1969 0 : srcSubInDstRect.MoveBy(-aSrcRect.TopLeft());
1970 0 : srcSubInDstRect.ScaleRoundOut(blitScaleX, blitScaleY);
1971 0 : srcSubInDstRect.MoveBy(aDstRect.TopLeft());
1972 :
1973 : // we transform these rectangles to be relative to the current src and dst tiles, respectively
1974 0 : nsIntSize srcSize = srcTextureRect.Size();
1975 0 : nsIntSize dstSize = dstTextureRect.Size();
1976 0 : srcSubRect.MoveBy(-srcTextureRect.x, -srcTextureRect.y);
1977 0 : srcSubInDstRect.MoveBy(-dstTextureRect.x, -dstTextureRect.y);
1978 :
1979 0 : float dx0 = 2.0 * float(srcSubInDstRect.x) / float(dstSize.width) - 1.0;
1980 0 : float dy0 = 2.0 * float(srcSubInDstRect.y) / float(dstSize.height) - 1.0;
1981 0 : float dx1 = 2.0 * float(srcSubInDstRect.x + srcSubInDstRect.width) / float(dstSize.width) - 1.0;
1982 0 : float dy1 = 2.0 * float(srcSubInDstRect.y + srcSubInDstRect.height) / float(dstSize.height) - 1.0;
1983 0 : PushViewportRect(nsIntRect(0, 0, dstSize.width, dstSize.height));
1984 :
1985 0 : RectTriangles rects;
1986 0 : if (aSrc->GetWrapMode() == LOCAL_GL_REPEAT) {
1987 : rects.addRect(/* dest rectangle */
1988 : dx0, dy0, dx1, dy1,
1989 : /* tex coords */
1990 : srcSubRect.x / float(srcSize.width),
1991 : srcSubRect.y / float(srcSize.height),
1992 0 : srcSubRect.XMost() / float(srcSize.width),
1993 0 : srcSubRect.YMost() / float(srcSize.height));
1994 : } else {
1995 0 : DecomposeIntoNoRepeatTriangles(srcSubRect, srcSize, rects);
1996 :
1997 : // now put the coords into the d[xy]0 .. d[xy]1 coordinate space
1998 : // from the 0..1 that it comes out of decompose
1999 0 : RectTriangles::vert_coord* v = (RectTriangles::vert_coord*)rects.vertexPointer();
2000 :
2001 0 : for (unsigned int i = 0; i < rects.elements(); ++i) {
2002 0 : v[i].x = (v[i].x * (dx1 - dx0)) + dx0;
2003 0 : v[i].y = (v[i].y * (dy1 - dy0)) + dy0;
2004 : }
2005 : }
2006 :
2007 0 : TextureImage::ScopedBindTexture texBind(aSrc, LOCAL_GL_TEXTURE0);
2008 :
2009 0 : fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
2010 :
2011 0 : fVertexAttribPointer(0, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, rects.vertexPointer());
2012 0 : fVertexAttribPointer(1, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, rects.texCoordPointer());
2013 :
2014 0 : fEnableVertexAttribArray(0);
2015 0 : fEnableVertexAttribArray(1);
2016 :
2017 0 : fDrawArrays(LOCAL_GL_TRIANGLES, 0, rects.elements());
2018 :
2019 0 : fDisableVertexAttribArray(0);
2020 0 : fDisableVertexAttribArray(1);
2021 :
2022 0 : PopViewportRect();
2023 0 : } while (aSrc->NextTile());
2024 0 : } while (aDst->NextTile());
2025 :
2026 0 : fVertexAttribPointer(0, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, NULL);
2027 0 : fVertexAttribPointer(1, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, NULL);
2028 :
2029 : // unbind the previous texture from the framebuffer
2030 0 : SetBlitFramebufferForDestTexture(0);
2031 :
2032 : // then put back the previous framebuffer, and don't
2033 : // enable stencil if it wasn't enabled on entry to work
2034 : // around Adreno 200 bug that causes us to crash if
2035 : // we enable scissor test while the current FBO is invalid
2036 : // (which it will be, once we assign texture 0 to the color
2037 : // attachment)
2038 0 : if (mVendor == VendorQualcomm) {
2039 0 : fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, savedFb);
2040 : }
2041 :
2042 0 : fEnable(LOCAL_GL_SCISSOR_TEST);
2043 0 : fEnable(LOCAL_GL_BLEND);
2044 : }
2045 :
2046 : static unsigned int
2047 0 : DataOffset(gfxImageSurface *aSurf, const nsIntPoint &aPoint)
2048 : {
2049 0 : unsigned int data = aPoint.y * aSurf->Stride();
2050 0 : data += aPoint.x * gfxASurface::BytePerPixelFromFormat(aSurf->Format());
2051 0 : return data;
2052 : }
2053 :
2054 : ShaderProgramType
2055 0 : GLContext::UploadSurfaceToTexture(gfxASurface *aSurface,
2056 : const nsIntRegion& aDstRegion,
2057 : GLuint& aTexture,
2058 : bool aOverwrite,
2059 : const nsIntPoint& aSrcPoint,
2060 : bool aPixelBuffer)
2061 : {
2062 0 : bool textureInited = aOverwrite ? false : true;
2063 0 : MakeCurrent();
2064 0 : fActiveTexture(LOCAL_GL_TEXTURE0);
2065 :
2066 0 : if (!aTexture) {
2067 0 : fGenTextures(1, &aTexture);
2068 0 : fBindTexture(LOCAL_GL_TEXTURE_2D, aTexture);
2069 : fTexParameteri(LOCAL_GL_TEXTURE_2D,
2070 : LOCAL_GL_TEXTURE_MIN_FILTER,
2071 0 : LOCAL_GL_LINEAR);
2072 : fTexParameteri(LOCAL_GL_TEXTURE_2D,
2073 : LOCAL_GL_TEXTURE_MAG_FILTER,
2074 0 : LOCAL_GL_LINEAR);
2075 : fTexParameteri(LOCAL_GL_TEXTURE_2D,
2076 : LOCAL_GL_TEXTURE_WRAP_S,
2077 0 : LOCAL_GL_CLAMP_TO_EDGE);
2078 : fTexParameteri(LOCAL_GL_TEXTURE_2D,
2079 : LOCAL_GL_TEXTURE_WRAP_T,
2080 0 : LOCAL_GL_CLAMP_TO_EDGE);
2081 0 : textureInited = false;
2082 : } else {
2083 0 : fBindTexture(LOCAL_GL_TEXTURE_2D, aTexture);
2084 : }
2085 :
2086 0 : nsIntRegion paintRegion;
2087 0 : if (!textureInited) {
2088 0 : paintRegion = nsIntRegion(aDstRegion.GetBounds());
2089 : } else {
2090 0 : paintRegion = aDstRegion;
2091 : }
2092 :
2093 0 : nsRefPtr<gfxImageSurface> imageSurface = aSurface->GetAsImageSurface();
2094 0 : unsigned char* data = NULL;
2095 :
2096 0 : if (!imageSurface ||
2097 0 : (imageSurface->Format() != gfxASurface::ImageFormatARGB32 &&
2098 0 : imageSurface->Format() != gfxASurface::ImageFormatRGB24 &&
2099 0 : imageSurface->Format() != gfxASurface::ImageFormatRGB16_565 &&
2100 0 : imageSurface->Format() != gfxASurface::ImageFormatA8)) {
2101 : // We can't get suitable pixel data for the surface, make a copy
2102 0 : nsIntRect bounds = aDstRegion.GetBounds();
2103 : imageSurface =
2104 : new gfxImageSurface(gfxIntSize(bounds.width, bounds.height),
2105 0 : gfxASurface::ImageFormatARGB32);
2106 :
2107 0 : nsRefPtr<gfxContext> context = new gfxContext(imageSurface);
2108 :
2109 0 : context->Translate(-gfxPoint(aSrcPoint.x, aSrcPoint.y));
2110 0 : context->SetSource(aSurface);
2111 0 : context->Paint();
2112 0 : data = imageSurface->Data();
2113 0 : NS_ASSERTION(!aPixelBuffer,
2114 : "Must be using an image compatible surface with pixel buffers!");
2115 : } else {
2116 : // If a pixel buffer is bound the data pointer parameter is relative
2117 : // to the start of the data block.
2118 0 : if (!aPixelBuffer) {
2119 0 : data = imageSurface->Data();
2120 : }
2121 0 : data += DataOffset(imageSurface, aSrcPoint);
2122 : }
2123 :
2124 : GLenum format;
2125 : GLenum internalformat;
2126 : GLenum type;
2127 0 : PRInt32 pixelSize = gfxASurface::BytePerPixelFromFormat(imageSurface->Format());
2128 : ShaderProgramType shader;
2129 :
2130 0 : switch (imageSurface->Format()) {
2131 : case gfxASurface::ImageFormatARGB32:
2132 0 : format = LOCAL_GL_RGBA;
2133 0 : type = LOCAL_GL_UNSIGNED_BYTE;
2134 0 : shader = BGRALayerProgramType;
2135 0 : break;
2136 : case gfxASurface::ImageFormatRGB24:
2137 : // Treat RGB24 surfaces as RGBA32 except for the shader
2138 : // program used.
2139 0 : format = LOCAL_GL_RGBA;
2140 0 : type = LOCAL_GL_UNSIGNED_BYTE;
2141 0 : shader = BGRXLayerProgramType;
2142 0 : break;
2143 : case gfxASurface::ImageFormatRGB16_565:
2144 0 : format = LOCAL_GL_RGB;
2145 0 : type = LOCAL_GL_UNSIGNED_SHORT_5_6_5;
2146 0 : shader = RGBALayerProgramType;
2147 0 : break;
2148 : case gfxASurface::ImageFormatA8:
2149 0 : format = LOCAL_GL_LUMINANCE;
2150 0 : type = LOCAL_GL_UNSIGNED_BYTE;
2151 : // We don't have a specific luminance shader
2152 0 : shader = ShaderProgramType(0);
2153 0 : break;
2154 : default:
2155 0 : NS_ASSERTION(false, "Unhandled image surface format!");
2156 0 : format = 0;
2157 0 : type = 0;
2158 0 : shader = ShaderProgramType(0);
2159 : }
2160 :
2161 0 : PRInt32 stride = imageSurface->Stride();
2162 :
2163 : #ifndef USE_GLES2
2164 0 : internalformat = LOCAL_GL_RGBA;
2165 : #else
2166 : internalformat = format;
2167 : #endif
2168 :
2169 0 : nsIntRegionRectIterator iter(paintRegion);
2170 : const nsIntRect *iterRect;
2171 :
2172 : // Top left point of the region's bounding rectangle.
2173 0 : nsIntPoint topLeft = paintRegion.GetBounds().TopLeft();
2174 :
2175 0 : while ((iterRect = iter.Next())) {
2176 : // The inital data pointer is at the top left point of the region's
2177 : // bounding rectangle. We need to find the offset of this rect
2178 : // within the region and adjust the data pointer accordingly.
2179 : unsigned char *rectData =
2180 0 : data + DataOffset(imageSurface, iterRect->TopLeft() - topLeft);
2181 :
2182 0 : NS_ASSERTION(textureInited || (iterRect->x == 0 && iterRect->y == 0),
2183 : "Must be uploading to the origin when we don't have an existing texture");
2184 :
2185 0 : if (textureInited && CanUploadSubTextures()) {
2186 : TexSubImage2D(LOCAL_GL_TEXTURE_2D,
2187 : 0,
2188 : iterRect->x,
2189 : iterRect->y,
2190 : iterRect->width,
2191 : iterRect->height,
2192 : stride,
2193 : pixelSize,
2194 : format,
2195 : type,
2196 0 : rectData);
2197 : } else {
2198 : TexImage2D(LOCAL_GL_TEXTURE_2D,
2199 : 0,
2200 : internalformat,
2201 : iterRect->width,
2202 : iterRect->height,
2203 : stride,
2204 : pixelSize,
2205 : 0,
2206 : format,
2207 : type,
2208 0 : rectData);
2209 : }
2210 :
2211 : }
2212 :
2213 0 : return shader;
2214 : }
2215 :
2216 0 : static GLint GetAddressAlignment(ptrdiff_t aAddress)
2217 : {
2218 0 : if (!(aAddress & 0x7)) {
2219 0 : return 8;
2220 0 : } else if (!(aAddress & 0x3)) {
2221 0 : return 4;
2222 0 : } else if (!(aAddress & 0x1)) {
2223 0 : return 2;
2224 : } else {
2225 0 : return 1;
2226 : }
2227 : }
2228 :
2229 : void
2230 0 : GLContext::TexImage2D(GLenum target, GLint level, GLint internalformat,
2231 : GLsizei width, GLsizei height, GLsizei stride,
2232 : GLint pixelsize, GLint border, GLenum format,
2233 : GLenum type, const GLvoid *pixels)
2234 : {
2235 : #ifdef USE_GLES2
2236 :
2237 : NS_ASSERTION(format == internalformat,
2238 : "format and internalformat not the same for glTexImage2D on GLES2");
2239 :
2240 : if (stride == width * pixelsize) {
2241 : fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT,
2242 : NS_MIN(GetAddressAlignment((ptrdiff_t)pixels),
2243 : GetAddressAlignment((ptrdiff_t)stride)));
2244 : fTexImage2D(target,
2245 : border,
2246 : internalformat,
2247 : width,
2248 : height,
2249 : border,
2250 : format,
2251 : type,
2252 : pixels);
2253 : fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4);
2254 : } else {
2255 : // Use GLES-specific workarounds for GL_UNPACK_ROW_LENGTH; these are
2256 : // implemented in TexSubImage2D.
2257 : fTexImage2D(target,
2258 : border,
2259 : internalformat,
2260 : width,
2261 : height,
2262 : border,
2263 : format,
2264 : type,
2265 : NULL);
2266 : TexSubImage2D(target,
2267 : level,
2268 : 0,
2269 : 0,
2270 : width,
2271 : height,
2272 : stride,
2273 : pixelsize,
2274 : format,
2275 : type,
2276 : pixels);
2277 : }
2278 : #else
2279 : fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT,
2280 0 : NS_MIN(GetAddressAlignment((ptrdiff_t)pixels),
2281 0 : GetAddressAlignment((ptrdiff_t)stride)));
2282 0 : int rowLength = stride/pixelsize;
2283 0 : fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, rowLength);
2284 : fTexImage2D(target,
2285 : level,
2286 : internalformat,
2287 : width,
2288 : height,
2289 : border,
2290 : format,
2291 : type,
2292 0 : pixels);
2293 0 : fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, 0);
2294 0 : fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4);
2295 : #endif
2296 0 : }
2297 :
2298 : void
2299 0 : GLContext::TexSubImage2D(GLenum target, GLint level,
2300 : GLint xoffset, GLint yoffset,
2301 : GLsizei width, GLsizei height, GLsizei stride,
2302 : GLint pixelsize, GLenum format,
2303 : GLenum type, const GLvoid* pixels)
2304 : {
2305 : #ifdef USE_GLES2
2306 : if (stride == width * pixelsize) {
2307 : fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT,
2308 : NS_MIN(GetAddressAlignment((ptrdiff_t)pixels),
2309 : GetAddressAlignment((ptrdiff_t)stride)));
2310 : fTexSubImage2D(target,
2311 : level,
2312 : xoffset,
2313 : yoffset,
2314 : width,
2315 : height,
2316 : format,
2317 : type,
2318 : pixels);
2319 : fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4);
2320 : } else if (IsExtensionSupported(EXT_unpack_subimage)) {
2321 : TexSubImage2DWithUnpackSubimageGLES(target, level, xoffset, yoffset,
2322 : width, height, stride,
2323 : pixelsize, format, type, pixels);
2324 :
2325 : } else {
2326 : TexSubImage2DWithoutUnpackSubimage(target, level, xoffset, yoffset,
2327 : width, height, stride,
2328 : pixelsize, format, type, pixels);
2329 : }
2330 : #else
2331 : fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT,
2332 0 : NS_MIN(GetAddressAlignment((ptrdiff_t)pixels),
2333 0 : GetAddressAlignment((ptrdiff_t)stride)));
2334 0 : int rowLength = stride/pixelsize;
2335 0 : fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, rowLength);
2336 : fTexSubImage2D(target,
2337 : level,
2338 : xoffset,
2339 : yoffset,
2340 : width,
2341 : height,
2342 : format,
2343 : type,
2344 0 : pixels);
2345 0 : fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, 0);
2346 0 : fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4);
2347 : #endif
2348 0 : }
2349 :
2350 : void
2351 0 : GLContext::TexSubImage2DWithUnpackSubimageGLES(GLenum target, GLint level,
2352 : GLint xoffset, GLint yoffset,
2353 : GLsizei width, GLsizei height,
2354 : GLsizei stride, GLint pixelsize,
2355 : GLenum format, GLenum type,
2356 : const GLvoid* pixels)
2357 : {
2358 : fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT,
2359 0 : NS_MIN(GetAddressAlignment((ptrdiff_t)pixels),
2360 0 : GetAddressAlignment((ptrdiff_t)stride)));
2361 : // When using GL_UNPACK_ROW_LENGTH, we need to work around a Tegra
2362 : // driver crash where the driver apparently tries to read
2363 : // (stride - width * pixelsize) bytes past the end of the last input
2364 : // row. We only upload the first height-1 rows using GL_UNPACK_ROW_LENGTH,
2365 : // and then we upload the final row separately. See bug 697990.
2366 0 : int rowLength = stride/pixelsize;
2367 0 : fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, rowLength);
2368 : fTexSubImage2D(target,
2369 : level,
2370 : xoffset,
2371 : yoffset,
2372 : width,
2373 : height-1,
2374 : format,
2375 : type,
2376 0 : pixels);
2377 0 : fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, 0);
2378 : fTexSubImage2D(target,
2379 : level,
2380 : xoffset,
2381 : yoffset+height-1,
2382 : width,
2383 : 1,
2384 : format,
2385 : type,
2386 0 : (const unsigned char *)pixels+(height-1)*stride);
2387 0 : fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4);
2388 0 : }
2389 :
2390 : void
2391 0 : GLContext::TexSubImage2DWithoutUnpackSubimage(GLenum target, GLint level,
2392 : GLint xoffset, GLint yoffset,
2393 : GLsizei width, GLsizei height,
2394 : GLsizei stride, GLint pixelsize,
2395 : GLenum format, GLenum type,
2396 : const GLvoid* pixels)
2397 : {
2398 : // Not using the whole row of texture data and GL_UNPACK_ROW_LENGTH
2399 : // isn't supported. We make a copy of the texture data we're using,
2400 : // such that we're using the whole row of data in the copy. This turns
2401 : // out to be more efficient than uploading row-by-row; see bug 698197.
2402 0 : unsigned char *newPixels = new unsigned char[width*height*pixelsize];
2403 0 : unsigned char *rowDest = newPixels;
2404 0 : const unsigned char *rowSource = (const unsigned char *)pixels;
2405 0 : for (int h = 0; h < height; h++) {
2406 0 : memcpy(rowDest, rowSource, width*pixelsize);
2407 0 : rowDest += width*pixelsize;
2408 0 : rowSource += stride;
2409 : }
2410 :
2411 0 : stride = width*pixelsize;
2412 : fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT,
2413 0 : NS_MIN(GetAddressAlignment((ptrdiff_t)newPixels),
2414 0 : GetAddressAlignment((ptrdiff_t)stride)));
2415 : fTexSubImage2D(target,
2416 : level,
2417 : xoffset,
2418 : yoffset,
2419 : width,
2420 : height,
2421 : format,
2422 : type,
2423 0 : newPixels);
2424 0 : delete [] newPixels;
2425 0 : fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4);
2426 0 : }
2427 :
2428 : void
2429 0 : GLContext::RectTriangles::addRect(GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1,
2430 : GLfloat tx0, GLfloat ty0, GLfloat tx1, GLfloat ty1)
2431 : {
2432 : vert_coord v;
2433 0 : v.x = x0; v.y = y0;
2434 0 : vertexCoords.AppendElement(v);
2435 0 : v.x = x1; v.y = y0;
2436 0 : vertexCoords.AppendElement(v);
2437 0 : v.x = x0; v.y = y1;
2438 0 : vertexCoords.AppendElement(v);
2439 :
2440 0 : v.x = x0; v.y = y1;
2441 0 : vertexCoords.AppendElement(v);
2442 0 : v.x = x1; v.y = y0;
2443 0 : vertexCoords.AppendElement(v);
2444 0 : v.x = x1; v.y = y1;
2445 0 : vertexCoords.AppendElement(v);
2446 :
2447 : tex_coord t;
2448 0 : t.u = tx0; t.v = ty0;
2449 0 : texCoords.AppendElement(t);
2450 0 : t.u = tx1; t.v = ty0;
2451 0 : texCoords.AppendElement(t);
2452 0 : t.u = tx0; t.v = ty1;
2453 0 : texCoords.AppendElement(t);
2454 :
2455 0 : t.u = tx0; t.v = ty1;
2456 0 : texCoords.AppendElement(t);
2457 0 : t.u = tx1; t.v = ty0;
2458 0 : texCoords.AppendElement(t);
2459 0 : t.u = tx1; t.v = ty1;
2460 0 : texCoords.AppendElement(t);
2461 0 : }
2462 :
2463 : static GLfloat
2464 0 : WrapTexCoord(GLfloat v)
2465 : {
2466 : // fmodf gives negative results for negative numbers;
2467 : // that is, fmodf(0.75, 1.0) == 0.75, but
2468 : // fmodf(-0.75, 1.0) == -0.75. For the negative case,
2469 : // the result we need is 0.25, so we add 1.0f.
2470 0 : if (v < 0.0f) {
2471 0 : return 1.0f + fmodf(v, 1.0f);
2472 : }
2473 :
2474 0 : return fmodf(v, 1.0f);
2475 : }
2476 :
2477 : void
2478 0 : GLContext::DecomposeIntoNoRepeatTriangles(const nsIntRect& aTexCoordRect,
2479 : const nsIntSize& aTexSize,
2480 : RectTriangles& aRects)
2481 : {
2482 : // normalize this
2483 0 : nsIntRect tcr(aTexCoordRect);
2484 0 : while (tcr.x > aTexSize.width)
2485 0 : tcr.x -= aTexSize.width;
2486 0 : while (tcr.y > aTexSize.height)
2487 0 : tcr.y -= aTexSize.height;
2488 :
2489 : // Compute top left and bottom right tex coordinates
2490 : GLfloat tl[2] =
2491 : { GLfloat(tcr.x) / GLfloat(aTexSize.width),
2492 0 : GLfloat(tcr.y) / GLfloat(aTexSize.height) };
2493 : GLfloat br[2] =
2494 0 : { GLfloat(tcr.XMost()) / GLfloat(aTexSize.width),
2495 0 : GLfloat(tcr.YMost()) / GLfloat(aTexSize.height) };
2496 :
2497 : // then check if we wrap in either the x or y axis; if we do,
2498 : // then also use fmod to figure out the "true" non-wrapping
2499 : // texture coordinates.
2500 :
2501 0 : bool xwrap = false, ywrap = false;
2502 0 : if (tcr.x < 0 || tcr.x > aTexSize.width ||
2503 0 : tcr.XMost() < 0 || tcr.XMost() > aTexSize.width)
2504 : {
2505 0 : xwrap = true;
2506 0 : tl[0] = WrapTexCoord(tl[0]);
2507 0 : br[0] = WrapTexCoord(br[0]);
2508 : }
2509 :
2510 0 : if (tcr.y < 0 || tcr.y > aTexSize.height ||
2511 0 : tcr.YMost() < 0 || tcr.YMost() > aTexSize.height)
2512 : {
2513 0 : ywrap = true;
2514 0 : tl[1] = WrapTexCoord(tl[1]);
2515 0 : br[1] = WrapTexCoord(br[1]);
2516 : }
2517 :
2518 0 : NS_ASSERTION(tl[0] >= 0.0f && tl[0] <= 1.0f &&
2519 : tl[1] >= 0.0f && tl[1] <= 1.0f &&
2520 : br[0] >= 0.0f && br[0] <= 1.0f &&
2521 : br[1] >= 0.0f && br[1] <= 1.0f,
2522 : "Somehow generated invalid texture coordinates");
2523 :
2524 : // If xwrap is false, the texture will be sampled from tl[0]
2525 : // .. br[0]. If xwrap is true, then it will be split into tl[0]
2526 : // .. 1.0, and 0.0 .. br[0]. Same for the Y axis. The
2527 : // destination rectangle is also split appropriately, according
2528 : // to the calculated xmid/ymid values.
2529 :
2530 : // There isn't a 1:1 mapping between tex coords and destination coords;
2531 : // when computing midpoints, we have to take that into account. We
2532 : // need to map the texture coords, which are (in the wrap case):
2533 : // |tl->1| and |0->br| to the |0->1| range of the vertex coords. So
2534 : // we have the length (1-tl)+(br) that needs to map into 0->1.
2535 : // These are only valid if there is wrap involved, they won't be used
2536 : // otherwise.
2537 0 : GLfloat xlen = (1.0f - tl[0]) + br[0];
2538 0 : GLfloat ylen = (1.0f - tl[1]) + br[1];
2539 :
2540 0 : NS_ASSERTION(!xwrap || xlen > 0.0f, "xlen isn't > 0, what's going on?");
2541 0 : NS_ASSERTION(!ywrap || ylen > 0.0f, "ylen isn't > 0, what's going on?");
2542 0 : NS_ASSERTION(aTexCoordRect.width <= aTexSize.width &&
2543 : aTexCoordRect.height <= aTexSize.height, "tex coord rect would cause tiling!");
2544 :
2545 0 : if (!xwrap && !ywrap) {
2546 : aRects.addRect(0.0f, 0.0f, 1.0f, 1.0f,
2547 0 : tl[0], tl[1], br[0], br[1]);
2548 0 : } else if (!xwrap && ywrap) {
2549 0 : GLfloat ymid = (1.0f - tl[1]) / ylen;
2550 : aRects.addRect(0.0f, 0.0f,
2551 : 1.0f, ymid,
2552 : tl[0], tl[1],
2553 0 : br[0], 1.0f);
2554 : aRects.addRect(0.0f, ymid,
2555 : 1.0f, 1.0f,
2556 : tl[0], 0.0f,
2557 0 : br[0], br[1]);
2558 0 : } else if (xwrap && !ywrap) {
2559 0 : GLfloat xmid = (1.0f - tl[0]) / xlen;
2560 : aRects.addRect(0.0f, 0.0f,
2561 : xmid, 1.0f,
2562 : tl[0], tl[1],
2563 0 : 1.0f, br[1]);
2564 : aRects.addRect(xmid, 0.0f,
2565 : 1.0f, 1.0f,
2566 : 0.0f, tl[1],
2567 0 : br[0], br[1]);
2568 : } else {
2569 0 : GLfloat xmid = (1.0f - tl[0]) / xlen;
2570 0 : GLfloat ymid = (1.0f - tl[1]) / ylen;
2571 : aRects.addRect(0.0f, 0.0f,
2572 : xmid, ymid,
2573 : tl[0], tl[1],
2574 0 : 1.0f, 1.0f);
2575 : aRects.addRect(xmid, 0.0f,
2576 : 1.0f, ymid,
2577 : 0.0f, tl[1],
2578 0 : br[0], 1.0f);
2579 : aRects.addRect(0.0f, ymid,
2580 : xmid, 1.0f,
2581 : tl[0], 0.0f,
2582 0 : 1.0f, br[1]);
2583 : aRects.addRect(xmid, ymid,
2584 : 1.0f, 1.0f,
2585 : 0.0f, 0.0f,
2586 0 : br[0], br[1]);
2587 : }
2588 0 : }
2589 :
2590 : void
2591 0 : GLContext::UseBlitProgram()
2592 : {
2593 0 : if (mBlitProgram) {
2594 0 : fUseProgram(mBlitProgram);
2595 0 : return;
2596 : }
2597 :
2598 0 : mBlitProgram = fCreateProgram();
2599 :
2600 : GLuint shaders[2];
2601 0 : shaders[0] = fCreateShader(LOCAL_GL_VERTEX_SHADER);
2602 0 : shaders[1] = fCreateShader(LOCAL_GL_FRAGMENT_SHADER);
2603 :
2604 : const char *blitVSSrc =
2605 : "attribute vec2 aVertex;"
2606 : "attribute vec2 aTexCoord;"
2607 : "varying vec2 vTexCoord;"
2608 : "void main() {"
2609 : " vTexCoord = aTexCoord;"
2610 : " gl_Position = vec4(aVertex, 0.0, 1.0);"
2611 0 : "}";
2612 : const char *blitFSSrc = "#ifdef GL_ES\nprecision mediump float;\n#endif\n"
2613 : "uniform sampler2D uSrcTexture;"
2614 : "varying vec2 vTexCoord;"
2615 : "void main() {"
2616 : " gl_FragColor = texture2D(uSrcTexture, vTexCoord);"
2617 0 : "}";
2618 :
2619 0 : fShaderSource(shaders[0], 1, (const GLchar**) &blitVSSrc, NULL);
2620 0 : fShaderSource(shaders[1], 1, (const GLchar**) &blitFSSrc, NULL);
2621 :
2622 0 : for (int i = 0; i < 2; ++i) {
2623 0 : GLint success, len = 0;
2624 :
2625 0 : fCompileShader(shaders[i]);
2626 0 : fGetShaderiv(shaders[i], LOCAL_GL_COMPILE_STATUS, &success);
2627 0 : NS_ASSERTION(success, "Shader compilation failed!");
2628 :
2629 0 : if (!success) {
2630 0 : nsCAutoString log;
2631 0 : fGetShaderiv(shaders[i], LOCAL_GL_INFO_LOG_LENGTH, (GLint*) &len);
2632 0 : log.SetCapacity(len);
2633 0 : fGetShaderInfoLog(shaders[i], len, (GLint*) &len, (char*) log.BeginWriting());
2634 0 : log.SetLength(len);
2635 :
2636 0 : printf_stderr("Shader %d compilation failed:\n%s\n", log.get());
2637 : return;
2638 : }
2639 :
2640 0 : fAttachShader(mBlitProgram, shaders[i]);
2641 0 : fDeleteShader(shaders[i]);
2642 : }
2643 :
2644 0 : fBindAttribLocation(mBlitProgram, 0, "aVertex");
2645 0 : fBindAttribLocation(mBlitProgram, 1, "aTexCoord");
2646 :
2647 0 : fLinkProgram(mBlitProgram);
2648 :
2649 0 : GLint success, len = 0;
2650 0 : fGetProgramiv(mBlitProgram, LOCAL_GL_LINK_STATUS, &success);
2651 0 : NS_ASSERTION(success, "Shader linking failed!");
2652 :
2653 0 : if (!success) {
2654 0 : nsCAutoString log;
2655 0 : fGetProgramiv(mBlitProgram, LOCAL_GL_INFO_LOG_LENGTH, (GLint*) &len);
2656 0 : log.SetCapacity(len);
2657 0 : fGetProgramInfoLog(mBlitProgram, len, (GLint*) &len, (char*) log.BeginWriting());
2658 0 : log.SetLength(len);
2659 :
2660 0 : printf_stderr("Program linking failed:\n%s\n", log.get());
2661 : return;
2662 : }
2663 :
2664 0 : fUseProgram(mBlitProgram);
2665 0 : fUniform1i(fGetUniformLocation(mBlitProgram, "uSrcTexture"), 0);
2666 : }
2667 :
2668 : void
2669 0 : GLContext::SetBlitFramebufferForDestTexture(GLuint aTexture)
2670 : {
2671 0 : if (!mBlitFramebuffer) {
2672 0 : fGenFramebuffers(1, &mBlitFramebuffer);
2673 : }
2674 :
2675 0 : fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mBlitFramebuffer);
2676 : fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
2677 : LOCAL_GL_COLOR_ATTACHMENT0,
2678 : LOCAL_GL_TEXTURE_2D,
2679 : aTexture,
2680 0 : 0);
2681 :
2682 0 : GLenum result = fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
2683 0 : if (aTexture && (result != LOCAL_GL_FRAMEBUFFER_COMPLETE)) {
2684 0 : nsCAutoString msg;
2685 0 : msg.Append("Framebuffer not complete -- error 0x");
2686 0 : msg.AppendInt(result, 16);
2687 : // Note: if you are hitting this, it is likely that
2688 : // your texture is not texture complete -- that is, you
2689 : // allocated a texture name, but didn't actually define its
2690 : // size via a call to TexImage2D.
2691 0 : NS_RUNTIMEABORT(msg.get());
2692 : }
2693 0 : }
2694 :
2695 : #ifdef DEBUG
2696 :
2697 : void
2698 0 : GLContext::CreatedProgram(GLContext *aOrigin, GLuint aName)
2699 : {
2700 0 : mTrackedPrograms.AppendElement(NamedResource(aOrigin, aName));
2701 0 : }
2702 :
2703 : void
2704 0 : GLContext::CreatedShader(GLContext *aOrigin, GLuint aName)
2705 : {
2706 0 : mTrackedShaders.AppendElement(NamedResource(aOrigin, aName));
2707 0 : }
2708 :
2709 : void
2710 0 : GLContext::CreatedBuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames)
2711 : {
2712 0 : for (GLsizei i = 0; i < aCount; ++i) {
2713 0 : mTrackedBuffers.AppendElement(NamedResource(aOrigin, aNames[i]));
2714 : }
2715 0 : }
2716 :
2717 : void
2718 0 : GLContext::CreatedTextures(GLContext *aOrigin, GLsizei aCount, GLuint *aNames)
2719 : {
2720 0 : for (GLsizei i = 0; i < aCount; ++i) {
2721 0 : mTrackedTextures.AppendElement(NamedResource(aOrigin, aNames[i]));
2722 : }
2723 0 : }
2724 :
2725 : void
2726 0 : GLContext::CreatedFramebuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames)
2727 : {
2728 0 : for (GLsizei i = 0; i < aCount; ++i) {
2729 0 : mTrackedFramebuffers.AppendElement(NamedResource(aOrigin, aNames[i]));
2730 : }
2731 0 : }
2732 :
2733 : void
2734 0 : GLContext::CreatedRenderbuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames)
2735 : {
2736 0 : for (GLsizei i = 0; i < aCount; ++i) {
2737 0 : mTrackedRenderbuffers.AppendElement(NamedResource(aOrigin, aNames[i]));
2738 : }
2739 0 : }
2740 :
2741 : static void
2742 0 : RemoveNamesFromArray(GLContext *aOrigin, GLsizei aCount, GLuint *aNames, nsTArray<GLContext::NamedResource>& aArray)
2743 : {
2744 0 : for (GLsizei j = 0; j < aCount; ++j) {
2745 0 : GLuint name = aNames[j];
2746 : // name 0 can be ignored
2747 0 : if (name == 0)
2748 0 : continue;
2749 :
2750 0 : bool found = false;
2751 0 : for (PRUint32 i = 0; i < aArray.Length(); ++i) {
2752 0 : if (aArray[i].name == name) {
2753 0 : aArray.RemoveElementAt(i);
2754 0 : found = true;
2755 0 : break;
2756 : }
2757 : }
2758 : }
2759 0 : }
2760 :
2761 : void
2762 0 : GLContext::DeletedProgram(GLContext *aOrigin, GLuint aName)
2763 : {
2764 0 : RemoveNamesFromArray(aOrigin, 1, &aName, mTrackedPrograms);
2765 0 : }
2766 :
2767 : void
2768 0 : GLContext::DeletedShader(GLContext *aOrigin, GLuint aName)
2769 : {
2770 0 : RemoveNamesFromArray(aOrigin, 1, &aName, mTrackedShaders);
2771 0 : }
2772 :
2773 : void
2774 0 : GLContext::DeletedBuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames)
2775 : {
2776 0 : RemoveNamesFromArray(aOrigin, aCount, aNames, mTrackedBuffers);
2777 0 : }
2778 :
2779 : void
2780 0 : GLContext::DeletedTextures(GLContext *aOrigin, GLsizei aCount, GLuint *aNames)
2781 : {
2782 0 : RemoveNamesFromArray(aOrigin, aCount, aNames, mTrackedTextures);
2783 0 : }
2784 :
2785 : void
2786 0 : GLContext::DeletedFramebuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames)
2787 : {
2788 0 : RemoveNamesFromArray(aOrigin, aCount, aNames, mTrackedFramebuffers);
2789 0 : }
2790 :
2791 : void
2792 0 : GLContext::DeletedRenderbuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames)
2793 : {
2794 0 : RemoveNamesFromArray(aOrigin, aCount, aNames, mTrackedRenderbuffers);
2795 0 : }
2796 :
2797 : static void
2798 0 : MarkContextDestroyedInArray(GLContext *aContext, nsTArray<GLContext::NamedResource>& aArray)
2799 : {
2800 0 : for (PRUint32 i = 0; i < aArray.Length(); ++i) {
2801 0 : if (aArray[i].origin == aContext)
2802 0 : aArray[i].originDeleted = true;
2803 : }
2804 0 : }
2805 :
2806 : void
2807 0 : GLContext::SharedContextDestroyed(GLContext *aChild)
2808 : {
2809 0 : MarkContextDestroyedInArray(aChild, mTrackedPrograms);
2810 0 : MarkContextDestroyedInArray(aChild, mTrackedShaders);
2811 0 : MarkContextDestroyedInArray(aChild, mTrackedTextures);
2812 0 : MarkContextDestroyedInArray(aChild, mTrackedFramebuffers);
2813 0 : MarkContextDestroyedInArray(aChild, mTrackedRenderbuffers);
2814 0 : MarkContextDestroyedInArray(aChild, mTrackedBuffers);
2815 0 : }
2816 :
2817 : static void
2818 0 : ReportArrayContents(const nsTArray<GLContext::NamedResource>& aArray)
2819 : {
2820 0 : nsTArray<GLContext::NamedResource> copy(aArray);
2821 0 : copy.Sort();
2822 :
2823 0 : GLContext *lastContext = NULL;
2824 0 : for (PRUint32 i = 0; i < copy.Length(); ++i) {
2825 0 : if (lastContext != copy[i].origin) {
2826 0 : if (lastContext)
2827 0 : printf_stderr("\n");
2828 0 : printf_stderr(" [%p - %s] ", copy[i].origin, copy[i].originDeleted ? "deleted" : "live");
2829 0 : lastContext = copy[i].origin;
2830 : }
2831 0 : printf_stderr("%d ", copy[i].name);
2832 : }
2833 0 : printf_stderr("\n");
2834 0 : }
2835 :
2836 : void
2837 0 : GLContext::ReportOutstandingNames()
2838 : {
2839 0 : printf_stderr("== GLContext %p ==\n", this);
2840 0 : printf_stderr("Outstanding Textures:\n");
2841 0 : ReportArrayContents(mTrackedTextures);
2842 0 : printf_stderr("Outstanding Buffers:\n");
2843 0 : ReportArrayContents(mTrackedBuffers);
2844 0 : printf_stderr("Outstanding Programs:\n");
2845 0 : ReportArrayContents(mTrackedPrograms);
2846 0 : printf_stderr("Outstanding Shaders:\n");
2847 0 : ReportArrayContents(mTrackedShaders);
2848 0 : printf_stderr("Outstanding Framebuffers:\n");
2849 0 : ReportArrayContents(mTrackedFramebuffers);
2850 0 : printf_stderr("Outstanding Renderbuffers:\n");
2851 0 : ReportArrayContents(mTrackedRenderbuffers);
2852 0 : }
2853 :
2854 : #endif /* DEBUG */
2855 :
2856 : } /* namespace gl */
2857 4392 : } /* namespace mozilla */
|