1 : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
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 Corporation code.
16 : *
17 : * The Initial Developer of the Original Code is Mozilla Foundation.
18 : * Portions created by the Initial Developer are Copyright (C) 2009
19 : * the Initial Developer. All Rights Reserved.
20 : *
21 : * Contributor(s):
22 : * Bas Schouten <bschouten@mozilla.org>
23 : * Frederic Plourde <frederic.plourde@collabora.co.uk>
24 : * Vladimir Vukicevic <vladimir@pobox.com>
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either the GNU General Public License Version 2 or later (the "GPL"), or
28 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : #include "mozilla/layers/PLayers.h"
41 :
42 : /* This must occur *after* layers/PLayers.h to avoid typedefs conflicts. */
43 : #include "mozilla/Util.h"
44 :
45 : #include "LayerManagerOGL.h"
46 : #include "ThebesLayerOGL.h"
47 : #include "ContainerLayerOGL.h"
48 : #include "ImageLayerOGL.h"
49 : #include "ColorLayerOGL.h"
50 : #include "CanvasLayerOGL.h"
51 : #include "mozilla/TimeStamp.h"
52 : #include "mozilla/Preferences.h"
53 :
54 : #include "LayerManagerOGLShaders.h"
55 :
56 : #include "gfxContext.h"
57 : #include "gfxUtils.h"
58 : #include "gfxPlatform.h"
59 : #include "nsIWidget.h"
60 :
61 : #include "GLContext.h"
62 : #include "GLContextProvider.h"
63 :
64 : #include "nsIServiceManager.h"
65 : #include "nsIConsoleService.h"
66 :
67 : #include "gfxCrashReporterUtils.h"
68 :
69 : #include "sampler.h"
70 :
71 : namespace mozilla {
72 : namespace layers {
73 :
74 : using namespace mozilla::gl;
75 :
76 : #ifdef CHECK_CURRENT_PROGRAM
77 : int LayerManagerOGLProgram::sCurrentProgramKey = 0;
78 : #endif
79 :
80 : /**
81 : * LayerManagerOGL
82 : */
83 0 : LayerManagerOGL::LayerManagerOGL(nsIWidget *aWidget)
84 : : mWidget(aWidget)
85 : , mWidgetSize(-1, -1)
86 : , mBackBufferFBO(0)
87 : , mBackBufferTexture(0)
88 : , mBackBufferSize(-1, -1)
89 0 : , mHasBGRA(0)
90 : {
91 0 : }
92 :
93 0 : LayerManagerOGL::~LayerManagerOGL()
94 : {
95 0 : Destroy();
96 0 : }
97 :
98 : void
99 0 : LayerManagerOGL::Destroy()
100 : {
101 0 : if (!mDestroyed) {
102 0 : if (mRoot) {
103 0 : RootLayer()->Destroy();
104 : }
105 0 : mRoot = nsnull;
106 :
107 0 : CleanupResources();
108 :
109 0 : mDestroyed = true;
110 : }
111 0 : }
112 :
113 : void
114 0 : LayerManagerOGL::CleanupResources()
115 : {
116 0 : if (!mGLContext)
117 0 : return;
118 :
119 0 : if (mRoot) {
120 0 : RootLayer()->CleanupResources();
121 : }
122 :
123 0 : nsRefPtr<GLContext> ctx = mGLContext->GetSharedContext();
124 0 : if (!ctx) {
125 0 : ctx = mGLContext;
126 : }
127 :
128 0 : ctx->MakeCurrent();
129 :
130 0 : for (unsigned int i = 0; i < mPrograms.Length(); ++i)
131 0 : delete mPrograms[i];
132 0 : mPrograms.Clear();
133 :
134 0 : ctx->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
135 :
136 0 : if (mBackBufferFBO) {
137 0 : ctx->fDeleteFramebuffers(1, &mBackBufferFBO);
138 0 : mBackBufferFBO = 0;
139 : }
140 :
141 0 : if (mBackBufferTexture) {
142 0 : ctx->fDeleteTextures(1, &mBackBufferTexture);
143 0 : mBackBufferTexture = 0;
144 : }
145 :
146 0 : if (mQuadVBO) {
147 0 : ctx->fDeleteBuffers(1, &mQuadVBO);
148 0 : mQuadVBO = 0;
149 : }
150 :
151 0 : mGLContext = nsnull;
152 : }
153 :
154 : already_AddRefed<mozilla::gl::GLContext>
155 0 : LayerManagerOGL::CreateContext()
156 : {
157 0 : nsRefPtr<GLContext> context;
158 :
159 : #ifdef XP_WIN
160 : if (PR_GetEnv("MOZ_LAYERS_PREFER_EGL")) {
161 : printf_stderr("Trying GL layers...\n");
162 : context = gl::GLContextProviderEGL::CreateForWindow(mWidget);
163 : }
164 : #endif
165 :
166 0 : if (!context)
167 0 : context = gl::GLContextProvider::CreateForWindow(mWidget);
168 :
169 0 : if (!context) {
170 0 : NS_WARNING("Failed to create LayerManagerOGL context");
171 : }
172 0 : return context.forget();
173 : }
174 :
175 : bool
176 0 : LayerManagerOGL::Initialize(nsRefPtr<GLContext> aContext, bool force)
177 : {
178 0 : ScopedGfxFeatureReporter reporter("GL Layers", force);
179 :
180 : // Do not allow double intiailization
181 0 : NS_ABORT_IF_FALSE(mGLContext == nsnull, "Don't reiniailize layer managers");
182 :
183 0 : if (!aContext)
184 0 : return false;
185 :
186 0 : mGLContext = aContext;
187 0 : mGLContext->SetFlipped(true);
188 :
189 0 : MakeCurrent();
190 :
191 : mHasBGRA =
192 0 : mGLContext->IsExtensionSupported(gl::GLContext::EXT_texture_format_BGRA8888) ||
193 0 : mGLContext->IsExtensionSupported(gl::GLContext::EXT_bgra);
194 :
195 : mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
196 0 : LOCAL_GL_ONE, LOCAL_GL_ONE);
197 0 : mGLContext->fEnable(LOCAL_GL_BLEND);
198 :
199 : // We unfortunately can't do generic initialization here, since the
200 : // concrete type actually matters. This macro generates the
201 : // initialization using a concrete type and index.
202 : #define SHADER_PROGRAM(penum, ptype, vsstr, fsstr) do { \
203 : NS_ASSERTION(programIndex++ == penum, "out of order shader initialization!"); \
204 : ptype *p = new ptype(mGLContext); \
205 : if (!p->Initialize(vsstr, fsstr)) { \
206 : delete p; \
207 : return false; \
208 : } \
209 : mPrograms.AppendElement(p); \
210 : } while (0)
211 :
212 :
213 : // NOTE: Order matters here, and should be in the same order as the
214 : // ProgramType enum!
215 : #ifdef DEBUG
216 0 : GLint programIndex = 0;
217 : #endif
218 :
219 : /* Layer programs */
220 0 : SHADER_PROGRAM(RGBALayerProgramType, ColorTextureLayerProgram,
221 : sLayerVS, sRGBATextureLayerFS);
222 0 : SHADER_PROGRAM(BGRALayerProgramType, ColorTextureLayerProgram,
223 : sLayerVS, sBGRATextureLayerFS);
224 0 : SHADER_PROGRAM(RGBXLayerProgramType, ColorTextureLayerProgram,
225 : sLayerVS, sRGBXTextureLayerFS);
226 0 : SHADER_PROGRAM(BGRXLayerProgramType, ColorTextureLayerProgram,
227 : sLayerVS, sBGRXTextureLayerFS);
228 0 : SHADER_PROGRAM(RGBARectLayerProgramType, ColorTextureLayerProgram,
229 : sLayerVS, sRGBARectTextureLayerFS);
230 0 : SHADER_PROGRAM(ColorLayerProgramType, SolidColorLayerProgram,
231 : sLayerVS, sSolidColorLayerFS);
232 0 : SHADER_PROGRAM(YCbCrLayerProgramType, YCbCrTextureLayerProgram,
233 : sLayerVS, sYCbCrTextureLayerFS);
234 0 : SHADER_PROGRAM(ComponentAlphaPass1ProgramType, ComponentAlphaTextureLayerProgram,
235 : sLayerVS, sComponentPass1FS);
236 0 : SHADER_PROGRAM(ComponentAlphaPass2ProgramType, ComponentAlphaTextureLayerProgram,
237 : sLayerVS, sComponentPass2FS);
238 : /* Copy programs (used for final framebuffer blit) */
239 0 : SHADER_PROGRAM(Copy2DProgramType, CopyProgram,
240 : sCopyVS, sCopy2DFS);
241 0 : SHADER_PROGRAM(Copy2DRectProgramType, CopyProgram,
242 : sCopyVS, sCopy2DRectFS);
243 :
244 : #undef SHADER_PROGRAM
245 :
246 0 : NS_ASSERTION(programIndex == NumProgramTypes,
247 : "not all programs were initialized!");
248 :
249 : /**
250 : * We'll test the ability here to bind NPOT textures to a framebuffer, if
251 : * this fails we'll try ARB_texture_rectangle.
252 : */
253 0 : mGLContext->fGenFramebuffers(1, &mBackBufferFBO);
254 :
255 : GLenum textureTargets[] = {
256 : LOCAL_GL_TEXTURE_2D,
257 : #ifndef USE_GLES2
258 : LOCAL_GL_TEXTURE_RECTANGLE_ARB
259 : #endif
260 0 : };
261 :
262 0 : mFBOTextureTarget = LOCAL_GL_NONE;
263 :
264 0 : for (PRUint32 i = 0; i < ArrayLength(textureTargets); i++) {
265 0 : GLenum target = textureTargets[i];
266 0 : mGLContext->fGenTextures(1, &mBackBufferTexture);
267 0 : mGLContext->fBindTexture(target, mBackBufferTexture);
268 : mGLContext->fTexParameteri(target,
269 : LOCAL_GL_TEXTURE_MIN_FILTER,
270 0 : LOCAL_GL_NEAREST);
271 : mGLContext->fTexParameteri(target,
272 : LOCAL_GL_TEXTURE_MAG_FILTER,
273 0 : LOCAL_GL_NEAREST);
274 : mGLContext->fTexImage2D(target,
275 : 0,
276 : LOCAL_GL_RGBA,
277 : 5, 3, /* sufficiently NPOT */
278 : 0,
279 : LOCAL_GL_RGBA,
280 : LOCAL_GL_UNSIGNED_BYTE,
281 0 : NULL);
282 :
283 : // unbind this texture, in preparation for binding it to the FBO
284 0 : mGLContext->fBindTexture(target, 0);
285 :
286 0 : mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mBackBufferFBO);
287 : mGLContext->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
288 : LOCAL_GL_COLOR_ATTACHMENT0,
289 : target,
290 : mBackBufferTexture,
291 0 : 0);
292 :
293 0 : if (mGLContext->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER) ==
294 : LOCAL_GL_FRAMEBUFFER_COMPLETE)
295 : {
296 0 : mFBOTextureTarget = target;
297 0 : break;
298 : }
299 :
300 : // We weren't succesful with this texture, so we don't need it
301 : // any more.
302 0 : mGLContext->fDeleteTextures(1, &mBackBufferTexture);
303 : }
304 :
305 0 : if (mFBOTextureTarget == LOCAL_GL_NONE) {
306 : /* Unable to find a texture target that works with FBOs and NPOT textures */
307 0 : return false;
308 : }
309 :
310 0 : mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
311 :
312 0 : if (mFBOTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB) {
313 : /* If we're using TEXTURE_RECTANGLE, then we must have the ARB
314 : * extension -- the EXT variant does not provide support for
315 : * texture rectangle access inside GLSL (sampler2DRect,
316 : * texture2DRect).
317 : */
318 0 : if (!mGLContext->IsExtensionSupported(gl::GLContext::ARB_texture_rectangle))
319 0 : return false;
320 : }
321 :
322 : // If we're double-buffered, we don't need this fbo anymore.
323 0 : if (mGLContext->IsDoubleBuffered()) {
324 0 : mGLContext->fDeleteFramebuffers(1, &mBackBufferFBO);
325 0 : mBackBufferFBO = 0;
326 : }
327 :
328 : // back to default framebuffer, to avoid confusion
329 0 : mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
330 :
331 : /* Create a simple quad VBO */
332 :
333 0 : mGLContext->fGenBuffers(1, &mQuadVBO);
334 0 : mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO);
335 :
336 : GLfloat vertices[] = {
337 : /* First quad vertices */
338 : 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
339 : /* Then quad texcoords */
340 : 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
341 : /* Then flipped quad texcoords */
342 : 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
343 0 : };
344 0 : mGLContext->fBufferData(LOCAL_GL_ARRAY_BUFFER, sizeof(vertices), vertices, LOCAL_GL_STATIC_DRAW);
345 0 : mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
346 :
347 : nsCOMPtr<nsIConsoleService>
348 0 : console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
349 :
350 0 : if (console) {
351 0 : nsString msg;
352 : msg +=
353 0 : NS_LITERAL_STRING("OpenGL LayerManager Initialized Succesfully.\nVersion: ");
354 : msg += NS_ConvertUTF8toUTF16(
355 0 : nsDependentCString((const char*)mGLContext->fGetString(LOCAL_GL_VERSION)));
356 0 : msg += NS_LITERAL_STRING("\nVendor: ");
357 : msg += NS_ConvertUTF8toUTF16(
358 0 : nsDependentCString((const char*)mGLContext->fGetString(LOCAL_GL_VENDOR)));
359 0 : msg += NS_LITERAL_STRING("\nRenderer: ");
360 : msg += NS_ConvertUTF8toUTF16(
361 0 : nsDependentCString((const char*)mGLContext->fGetString(LOCAL_GL_RENDERER)));
362 0 : msg += NS_LITERAL_STRING("\nFBO Texture Target: ");
363 0 : if (mFBOTextureTarget == LOCAL_GL_TEXTURE_2D)
364 0 : msg += NS_LITERAL_STRING("TEXTURE_2D");
365 : else
366 0 : msg += NS_LITERAL_STRING("TEXTURE_RECTANGLE");
367 0 : console->LogStringMessage(msg.get());
368 : }
369 :
370 0 : if (NS_IsMainThread()) {
371 0 : Preferences::AddBoolVarCache(&sDrawFPS, "layers.acceleration.draw-fps");
372 : } else {
373 : // We have to dispatch an event to the main thread to read the pref.
374 0 : class ReadDrawFPSPref : public nsRunnable {
375 : public:
376 0 : NS_IMETHOD Run()
377 : {
378 0 : Preferences::AddBoolVarCache(&sDrawFPS, "layers.acceleration.draw-fps");
379 0 : return NS_OK;
380 : }
381 : };
382 0 : NS_DispatchToMainThread(new ReadDrawFPSPref());
383 : }
384 :
385 0 : reporter.SetSuccessful();
386 0 : return true;
387 : }
388 :
389 : void
390 0 : LayerManagerOGL::SetClippingRegion(const nsIntRegion& aClippingRegion)
391 : {
392 0 : mClippingRegion = aClippingRegion;
393 0 : }
394 :
395 : void
396 0 : LayerManagerOGL::BeginTransaction()
397 : {
398 0 : }
399 :
400 : void
401 0 : LayerManagerOGL::BeginTransactionWithTarget(gfxContext *aTarget)
402 : {
403 : #ifdef MOZ_LAYERS_HAVE_LOG
404 0 : MOZ_LAYERS_LOG(("[----- BeginTransaction"));
405 0 : Log();
406 : #endif
407 :
408 0 : if (mDestroyed) {
409 0 : NS_WARNING("Call on destroyed layer manager");
410 0 : return;
411 : }
412 :
413 0 : mTarget = aTarget;
414 : }
415 :
416 : bool
417 0 : LayerManagerOGL::EndEmptyTransaction()
418 : {
419 0 : if (!mRoot)
420 0 : return false;
421 :
422 0 : EndTransaction(nsnull, nsnull);
423 0 : return true;
424 : }
425 :
426 : void
427 0 : LayerManagerOGL::EndTransaction(DrawThebesLayerCallback aCallback,
428 : void* aCallbackData,
429 : EndTransactionFlags aFlags)
430 : {
431 : #ifdef MOZ_LAYERS_HAVE_LOG
432 0 : MOZ_LAYERS_LOG((" ----- (beginning paint)"));
433 0 : Log();
434 : #endif
435 :
436 0 : if (mDestroyed) {
437 0 : NS_WARNING("Call on destroyed layer manager");
438 0 : return;
439 : }
440 :
441 0 : if (mRoot && !(aFlags & END_NO_IMMEDIATE_REDRAW)) {
442 : // The results of our drawing always go directly into a pixel buffer,
443 : // so we don't need to pass any global transform here.
444 0 : mRoot->ComputeEffectiveTransforms(gfx3DMatrix());
445 :
446 0 : mThebesLayerCallback = aCallback;
447 0 : mThebesLayerCallbackData = aCallbackData;
448 :
449 0 : Render();
450 :
451 0 : mThebesLayerCallback = nsnull;
452 0 : mThebesLayerCallbackData = nsnull;
453 : }
454 :
455 0 : mTarget = NULL;
456 :
457 : #ifdef MOZ_LAYERS_HAVE_LOG
458 0 : Log();
459 0 : MOZ_LAYERS_LOG(("]----- EndTransaction"));
460 : #endif
461 : }
462 :
463 : already_AddRefed<ThebesLayer>
464 0 : LayerManagerOGL::CreateThebesLayer()
465 : {
466 0 : if (mDestroyed) {
467 0 : NS_WARNING("Call on destroyed layer manager");
468 0 : return nsnull;
469 : }
470 :
471 0 : nsRefPtr<ThebesLayer> layer = new ThebesLayerOGL(this);
472 0 : return layer.forget();
473 : }
474 :
475 : already_AddRefed<ContainerLayer>
476 0 : LayerManagerOGL::CreateContainerLayer()
477 : {
478 0 : if (mDestroyed) {
479 0 : NS_WARNING("Call on destroyed layer manager");
480 0 : return nsnull;
481 : }
482 :
483 0 : nsRefPtr<ContainerLayer> layer = new ContainerLayerOGL(this);
484 0 : return layer.forget();
485 : }
486 :
487 : already_AddRefed<ImageLayer>
488 0 : LayerManagerOGL::CreateImageLayer()
489 : {
490 0 : if (mDestroyed) {
491 0 : NS_WARNING("Call on destroyed layer manager");
492 0 : return nsnull;
493 : }
494 :
495 0 : nsRefPtr<ImageLayer> layer = new ImageLayerOGL(this);
496 0 : return layer.forget();
497 : }
498 :
499 : already_AddRefed<ColorLayer>
500 0 : LayerManagerOGL::CreateColorLayer()
501 : {
502 0 : if (mDestroyed) {
503 0 : NS_WARNING("Call on destroyed layer manager");
504 0 : return nsnull;
505 : }
506 :
507 0 : nsRefPtr<ColorLayer> layer = new ColorLayerOGL(this);
508 0 : return layer.forget();
509 : }
510 :
511 : already_AddRefed<CanvasLayer>
512 0 : LayerManagerOGL::CreateCanvasLayer()
513 : {
514 0 : if (mDestroyed) {
515 0 : NS_WARNING("Call on destroyed layer manager");
516 0 : return nsnull;
517 : }
518 :
519 0 : nsRefPtr<CanvasLayer> layer = new CanvasLayerOGL(this);
520 0 : return layer.forget();
521 : }
522 :
523 : LayerOGL*
524 0 : LayerManagerOGL::RootLayer() const
525 : {
526 0 : if (mDestroyed) {
527 0 : NS_WARNING("Call on destroyed layer manager");
528 0 : return nsnull;
529 : }
530 :
531 0 : return static_cast<LayerOGL*>(mRoot->ImplData());
532 : }
533 :
534 : bool LayerManagerOGL::sDrawFPS = false;
535 :
536 : /* This function tries to stick to portable C89 as much as possible
537 : * so that it can be easily copied into other applications */
538 : void
539 0 : LayerManagerOGL::FPSState::DrawFPS(GLContext* context, CopyProgram* copyprog)
540 : {
541 0 : fcount++;
542 :
543 0 : int rate = 30;
544 0 : if (fcount >= rate) {
545 0 : TimeStamp now = TimeStamp::Now();
546 0 : TimeDuration duration = now - last;
547 0 : last = now;
548 0 : fps = rate / duration.ToSeconds() + .5;
549 0 : fcount = 0;
550 : }
551 :
552 : GLint viewport[4];
553 0 : context->fGetIntegerv(LOCAL_GL_VIEWPORT, viewport);
554 :
555 : static GLuint texture;
556 0 : if (!initialized) {
557 : // Bind the number of textures we need, in this case one.
558 0 : context->fGenTextures(1, &texture);
559 0 : context->fBindTexture(LOCAL_GL_TEXTURE_2D, texture);
560 0 : context->fTexParameteri(LOCAL_GL_TEXTURE_2D,LOCAL_GL_TEXTURE_MIN_FILTER,LOCAL_GL_NEAREST);
561 0 : context->fTexParameteri(LOCAL_GL_TEXTURE_2D,LOCAL_GL_TEXTURE_MAG_FILTER,LOCAL_GL_NEAREST);
562 :
563 : unsigned char text[] = {
564 : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
565 : 0, 255, 255, 255, 0, 255, 255, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 0, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
566 : 0, 255, 0, 255, 0, 0, 255, 0, 0, 0, 0, 255, 0, 0, 0, 255, 0, 255, 0, 255, 0, 255, 0, 0, 0, 255, 0, 0, 0, 0, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0,
567 : 0, 255, 0, 255, 0, 0, 255, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
568 : 0, 255, 0, 255, 0, 0, 255, 0, 0, 255, 0, 0, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 255, 0, 255, 0, 0, 0, 255, 0, 255, 0, 255, 0, 0, 0, 255, 0,
569 : 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 255, 0, 255, 255, 255, 0, 0, 0, 255, 0,
570 : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
571 0 : };
572 :
573 : // convert from 8 bit to 32 bit so that don't have to write the text above out in 32 bit format
574 : // we rely on int being 32 bits
575 0 : unsigned int* buf = (unsigned int*)malloc(64 * 8 * 4);
576 0 : for (int i = 0; i < 7; i++) {
577 0 : for (int j = 0; j < 41; j++) {
578 0 : unsigned int purple = 0xfff000ff;
579 0 : unsigned int white = 0xffffffff;
580 0 : buf[i * 64 + j] = (text[i * 41 + j] == 0) ? purple : white;
581 : }
582 : }
583 0 : context->fTexImage2D(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_RGBA, 64, 8, 0, LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, buf);
584 0 : free(buf);
585 0 : initialized = true;
586 : }
587 :
588 : struct Vertex2D {
589 : float x,y;
590 : };
591 : const Vertex2D vertices[] = {
592 0 : { -1.0f, 1.0f - 42.f / viewport[3] },
593 : { -1.0f, 1.0f},
594 0 : { -1.0f + 22.f / viewport[2], 1.0f - 42.f / viewport[3] },
595 0 : { -1.0f + 22.f / viewport[2], 1.0f },
596 :
597 0 : { -1.0f + 22.f / viewport[2], 1.0f - 42.f / viewport[3] },
598 0 : { -1.0f + 22.f / viewport[2], 1.0f },
599 0 : { -1.0f + 44.f / viewport[2], 1.0f - 42.f / viewport[3] },
600 0 : { -1.0f + 44.f / viewport[2], 1.0f },
601 :
602 0 : { -1.0f + 44.f / viewport[2], 1.0f - 42.f / viewport[3] },
603 0 : { -1.0f + 44.f / viewport[2], 1.0f },
604 0 : { -1.0f + 66.f / viewport[2], 1.0f - 42.f / viewport[3] },
605 0 : { -1.0f + 66.f / viewport[2], 1.0f }
606 0 : };
607 :
608 0 : int v1 = fps % 10;
609 0 : int v10 = (fps % 100) / 10;
610 0 : int v100 = (fps % 1000) / 100;
611 :
612 : // Feel free to comment these texture coordinates out and use one
613 : // of the ones below instead, or play around with your own values.
614 : const GLfloat texCoords[] = {
615 : (v100 * 4.f) / 64, 7.f / 8,
616 : (v100 * 4.f) / 64, 0.0f,
617 : (v100 * 4.f + 4) / 64, 7.f / 8,
618 : (v100 * 4.f + 4) / 64, 0.0f,
619 :
620 : (v10 * 4.f) / 64, 7.f / 8,
621 : (v10 * 4.f) / 64, 0.0f,
622 : (v10 * 4.f + 4) / 64, 7.f / 8,
623 : (v10 * 4.f + 4) / 64, 0.0f,
624 :
625 : (v1 * 4.f) / 64, 7.f / 8,
626 : (v1 * 4.f) / 64, 0.0f,
627 : (v1 * 4.f + 4) / 64, 7.f / 8,
628 : (v1 * 4.f + 4) / 64, 0.0f,
629 0 : };
630 :
631 : // Turn necessary features on
632 0 : context->fEnable(LOCAL_GL_BLEND);
633 0 : context->fBlendFunc(LOCAL_GL_ONE, LOCAL_GL_SRC_COLOR);
634 :
635 0 : context->fActiveTexture(LOCAL_GL_TEXTURE0);
636 0 : context->fBindTexture(LOCAL_GL_TEXTURE_2D, texture);
637 :
638 0 : copyprog->Activate();
639 0 : copyprog->SetTextureUnit(0);
640 :
641 : // we're going to use client-side vertex arrays for this.
642 0 : context->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
643 :
644 : // "COPY"
645 : context->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ZERO,
646 0 : LOCAL_GL_ONE, LOCAL_GL_ZERO);
647 :
648 : // enable our vertex attribs; we'll call glVertexPointer below
649 : // to fill with the correct data.
650 0 : GLint vcattr = copyprog->AttribLocation(CopyProgram::VertexCoordAttrib);
651 0 : GLint tcattr = copyprog->AttribLocation(CopyProgram::TexCoordAttrib);
652 :
653 0 : context->fEnableVertexAttribArray(vcattr);
654 0 : context->fEnableVertexAttribArray(tcattr);
655 :
656 : context->fVertexAttribPointer(vcattr,
657 : 2, LOCAL_GL_FLOAT,
658 : LOCAL_GL_FALSE,
659 0 : 0, vertices);
660 :
661 : context->fVertexAttribPointer(tcattr,
662 : 2, LOCAL_GL_FLOAT,
663 : LOCAL_GL_FALSE,
664 0 : 0, texCoords);
665 :
666 0 : context->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 12);
667 0 : }
668 :
669 : // |aTexCoordRect| is the rectangle from the texture that we want to
670 : // draw using the given program. The program already has a necessary
671 : // offset and scale, so the geometry that needs to be drawn is a unit
672 : // square from 0,0 to 1,1.
673 : //
674 : // |aTexSize| is the actual size of the texture, as it can be larger
675 : // than the rectangle given by |aTexCoordRect|.
676 : void
677 0 : LayerManagerOGL::BindAndDrawQuadWithTextureRect(LayerProgram *aProg,
678 : const nsIntRect& aTexCoordRect,
679 : const nsIntSize& aTexSize,
680 : GLenum aWrapMode)
681 : {
682 : GLuint vertAttribIndex =
683 0 : aProg->AttribLocation(LayerProgram::VertexAttrib);
684 : GLuint texCoordAttribIndex =
685 0 : aProg->AttribLocation(LayerProgram::TexCoordAttrib);
686 0 : NS_ASSERTION(texCoordAttribIndex != GLuint(-1), "no texture coords?");
687 :
688 : // clear any bound VBO so that glVertexAttribPointer() goes back to
689 : // "pointer mode"
690 0 : mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
691 :
692 : // Given what we know about these textures and coordinates, we can
693 : // compute fmod(t, 1.0f) to get the same texture coordinate out. If
694 : // the texCoordRect dimension is < 0 or > width/height, then we have
695 : // wraparound that we need to deal with by drawing multiple quads,
696 : // because we can't rely on full non-power-of-two texture support
697 : // (which is required for the REPEAT wrap mode).
698 :
699 0 : GLContext::RectTriangles rects;
700 :
701 0 : if (aWrapMode == LOCAL_GL_REPEAT) {
702 : rects.addRect(/* dest rectangle */
703 : 0.0f, 0.0f, 1.0f, 1.0f,
704 : /* tex coords */
705 : aTexCoordRect.x / GLfloat(aTexSize.width),
706 : aTexCoordRect.y / GLfloat(aTexSize.height),
707 0 : aTexCoordRect.XMost() / GLfloat(aTexSize.width),
708 0 : aTexCoordRect.YMost() / GLfloat(aTexSize.height));
709 : } else {
710 0 : GLContext::DecomposeIntoNoRepeatTriangles(aTexCoordRect, aTexSize, rects);
711 : }
712 :
713 : mGLContext->fVertexAttribPointer(vertAttribIndex, 2,
714 : LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0,
715 0 : rects.vertexPointer());
716 :
717 : mGLContext->fVertexAttribPointer(texCoordAttribIndex, 2,
718 : LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0,
719 0 : rects.texCoordPointer());
720 :
721 : {
722 0 : mGLContext->fEnableVertexAttribArray(texCoordAttribIndex);
723 : {
724 0 : mGLContext->fEnableVertexAttribArray(vertAttribIndex);
725 :
726 0 : mGLContext->fDrawArrays(LOCAL_GL_TRIANGLES, 0, rects.elements());
727 :
728 0 : mGLContext->fDisableVertexAttribArray(vertAttribIndex);
729 : }
730 0 : mGLContext->fDisableVertexAttribArray(texCoordAttribIndex);
731 : }
732 0 : }
733 :
734 : void
735 0 : LayerManagerOGL::Render()
736 : {
737 0 : SAMPLE_LABEL("LayerManagerOGL", "Render");
738 0 : if (mDestroyed) {
739 0 : NS_WARNING("Call on destroyed layer manager");
740 : return;
741 : }
742 :
743 0 : nsIntRect rect;
744 0 : mWidget->GetClientBounds(rect);
745 0 : WorldTransformRect(rect);
746 :
747 0 : GLint width = rect.width;
748 0 : GLint height = rect.height;
749 :
750 : // We can't draw anything to something with no area
751 : // so just return
752 0 : if (width == 0 || height == 0)
753 : return;
754 :
755 : // If the widget size changed, we have to force a MakeCurrent
756 : // to make sure that GL sees the updated widget size.
757 0 : if (mWidgetSize.width != width ||
758 : mWidgetSize.height != height)
759 : {
760 0 : MakeCurrent(true);
761 :
762 0 : mWidgetSize.width = width;
763 0 : mWidgetSize.height = height;
764 : } else {
765 0 : MakeCurrent();
766 : }
767 :
768 0 : SetupBackBuffer(width, height);
769 0 : SetupPipeline(width, height, ApplyWorldTransform);
770 :
771 : // Default blend function implements "OVER"
772 : mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
773 0 : LOCAL_GL_ONE, LOCAL_GL_ONE);
774 0 : mGLContext->fEnable(LOCAL_GL_BLEND);
775 :
776 0 : const nsIntRect *clipRect = mRoot->GetClipRect();
777 :
778 0 : if (clipRect) {
779 0 : nsIntRect r = *clipRect;
780 0 : WorldTransformRect(r);
781 0 : mGLContext->fScissor(r.x, r.y, r.width, r.height);
782 : } else {
783 0 : mGLContext->fScissor(0, 0, width, height);
784 : }
785 :
786 0 : mGLContext->fEnable(LOCAL_GL_SCISSOR_TEST);
787 :
788 0 : mGLContext->fClearColor(0.0, 0.0, 0.0, 0.0);
789 0 : mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT);
790 :
791 : // Render our layers.
792 0 : RootLayer()->RenderLayer(mGLContext->IsDoubleBuffered() ? 0 : mBackBufferFBO,
793 0 : nsIntPoint(0, 0));
794 :
795 0 : mWidget->DrawWindowOverlay(this, rect);
796 :
797 : #ifdef MOZ_DUMP_PAINTING
798 0 : if (gfxUtils::sDumpPainting) {
799 0 : nsIntRect rect;
800 0 : mWidget->GetBounds(rect);
801 0 : nsRefPtr<gfxASurface> surf = gfxPlatform::GetPlatform()->CreateOffscreenSurface(rect.Size(), gfxASurface::CONTENT_COLOR_ALPHA);
802 0 : nsRefPtr<gfxContext> ctx = new gfxContext(surf);
803 0 : CopyToTarget(ctx);
804 :
805 0 : WriteSnapshotToDumpFile(this, surf);
806 : }
807 : #endif
808 :
809 0 : if (mTarget) {
810 0 : CopyToTarget(mTarget);
811 0 : mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
812 : return;
813 : }
814 :
815 0 : if (sDrawFPS) {
816 0 : mFPS.DrawFPS(mGLContext, GetCopy2DProgram());
817 : }
818 :
819 0 : if (mGLContext->IsDoubleBuffered()) {
820 0 : mGLContext->SwapBuffers();
821 0 : LayerManager::PostPresent();
822 0 : mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
823 : return;
824 : }
825 :
826 0 : mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
827 :
828 0 : mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
829 :
830 0 : CopyProgram *copyprog = GetCopy2DProgram();
831 :
832 0 : if (mFBOTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB) {
833 0 : copyprog = GetCopy2DRectProgram();
834 : }
835 :
836 0 : mGLContext->fBindTexture(mFBOTextureTarget, mBackBufferTexture);
837 :
838 0 : copyprog->Activate();
839 0 : copyprog->SetTextureUnit(0);
840 :
841 0 : if (copyprog->GetTexCoordMultiplierUniformLocation() != -1) {
842 0 : float f[] = { float(width), float(height) };
843 0 : copyprog->SetUniform(copyprog->GetTexCoordMultiplierUniformLocation(),
844 0 : 2, f);
845 : }
846 :
847 : // we're going to use client-side vertex arrays for this.
848 0 : mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
849 :
850 : // "COPY"
851 : mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ZERO,
852 0 : LOCAL_GL_ONE, LOCAL_GL_ZERO);
853 :
854 : // enable our vertex attribs; we'll call glVertexPointer below
855 : // to fill with the correct data.
856 0 : GLint vcattr = copyprog->AttribLocation(CopyProgram::VertexCoordAttrib);
857 0 : GLint tcattr = copyprog->AttribLocation(CopyProgram::TexCoordAttrib);
858 :
859 0 : mGLContext->fEnableVertexAttribArray(vcattr);
860 0 : mGLContext->fEnableVertexAttribArray(tcattr);
861 :
862 : const nsIntRect *r;
863 0 : nsIntRegionRectIterator iter(mClippingRegion);
864 :
865 0 : while ((r = iter.Next()) != nsnull) {
866 0 : nsIntRect cRect = *r; r = &cRect;
867 0 : WorldTransformRect(cRect);
868 0 : float left = (GLfloat)r->x / width;
869 0 : float right = (GLfloat)r->XMost() / width;
870 0 : float top = (GLfloat)r->y / height;
871 0 : float bottom = (GLfloat)r->YMost() / height;
872 :
873 : float vertices[] = { left * 2.0f - 1.0f,
874 : -(top * 2.0f - 1.0f),
875 : right * 2.0f - 1.0f,
876 : -(top * 2.0f - 1.0f),
877 : left * 2.0f - 1.0f,
878 : -(bottom * 2.0f - 1.0f),
879 : right * 2.0f - 1.0f,
880 0 : -(bottom * 2.0f - 1.0f) };
881 :
882 : // Use flipped texture coordinates since our
883 : // projection matrix also has a flip and we
884 : // need to cancel that out.
885 : float coords[] = { left, bottom,
886 : right, bottom,
887 : left, top,
888 0 : right, top };
889 :
890 : mGLContext->fVertexAttribPointer(vcattr,
891 : 2, LOCAL_GL_FLOAT,
892 : LOCAL_GL_FALSE,
893 0 : 0, vertices);
894 :
895 : mGLContext->fVertexAttribPointer(tcattr,
896 : 2, LOCAL_GL_FLOAT,
897 : LOCAL_GL_FALSE,
898 0 : 0, coords);
899 :
900 0 : mGLContext->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
901 : }
902 :
903 0 : mGLContext->fDisableVertexAttribArray(vcattr);
904 0 : mGLContext->fDisableVertexAttribArray(tcattr);
905 :
906 0 : mGLContext->fFlush();
907 0 : mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
908 : }
909 :
910 : void
911 0 : LayerManagerOGL::SetWorldTransform(const gfxMatrix& aMatrix)
912 : {
913 0 : NS_ASSERTION(aMatrix.PreservesAxisAlignedRectangles(),
914 : "SetWorldTransform only accepts matrices that satisfy PreservesAxisAlignedRectangles");
915 0 : NS_ASSERTION(!aMatrix.HasNonIntegerScale(),
916 : "SetWorldTransform only accepts matrices with integer scale");
917 :
918 0 : mWorldMatrix = aMatrix;
919 0 : }
920 :
921 : gfxMatrix&
922 0 : LayerManagerOGL::GetWorldTransform(void)
923 : {
924 0 : return mWorldMatrix;
925 : }
926 :
927 : void
928 0 : LayerManagerOGL::WorldTransformRect(nsIntRect& aRect)
929 : {
930 0 : gfxRect grect(aRect.x, aRect.y, aRect.width, aRect.height);
931 0 : grect = mWorldMatrix.TransformBounds(grect);
932 0 : aRect.SetRect(grect.X(), grect.Y(), grect.Width(), grect.Height());
933 0 : }
934 :
935 : void
936 0 : LayerManagerOGL::SetupPipeline(int aWidth, int aHeight, WorldTransforPolicy aTransformPolicy)
937 : {
938 : // Set the viewport correctly.
939 0 : mGLContext->fViewport(0, 0, aWidth, aHeight);
940 :
941 : // We flip the view matrix around so that everything is right-side up; we're
942 : // drawing directly into the window's back buffer, so this keeps things
943 : // looking correct.
944 : //
945 : // XXX: We keep track of whether the window size changed, so we could skip
946 : // this update if it hadn't changed since the last call. We will need to
947 : // track changes to aTransformPolicy and mWorldMatrix for this to work
948 : // though.
949 :
950 : // Matrix to transform (0, 0, aWidth, aHeight) to viewport space (-1.0, 1.0,
951 : // 2, 2) and flip the contents.
952 0 : gfxMatrix viewMatrix;
953 0 : viewMatrix.Translate(-gfxPoint(1.0, -1.0));
954 0 : viewMatrix.Scale(2.0f / float(aWidth), 2.0f / float(aHeight));
955 0 : viewMatrix.Scale(1.0f, -1.0f);
956 :
957 0 : if (aTransformPolicy == ApplyWorldTransform) {
958 0 : viewMatrix = mWorldMatrix * viewMatrix;
959 : }
960 :
961 0 : gfx3DMatrix matrix3d = gfx3DMatrix::From2D(viewMatrix);
962 0 : matrix3d._33 = 0.0f;
963 :
964 0 : SetLayerProgramProjectionMatrix(matrix3d);
965 0 : }
966 :
967 : void
968 0 : LayerManagerOGL::SetupBackBuffer(int aWidth, int aHeight)
969 : {
970 0 : if (mGLContext->IsDoubleBuffered()) {
971 0 : mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
972 0 : return;
973 : }
974 :
975 : // Do we have a FBO of the right size already?
976 0 : if (mBackBufferSize.width == aWidth &&
977 : mBackBufferSize.height == aHeight)
978 : {
979 0 : mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mBackBufferFBO);
980 0 : return;
981 : }
982 :
983 : // we already have a FBO, but we need to resize its texture.
984 0 : mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
985 0 : mGLContext->fBindTexture(mFBOTextureTarget, mBackBufferTexture);
986 : mGLContext->fTexImage2D(mFBOTextureTarget,
987 : 0,
988 : LOCAL_GL_RGBA,
989 : aWidth, aHeight,
990 : 0,
991 : LOCAL_GL_RGBA,
992 : LOCAL_GL_UNSIGNED_BYTE,
993 0 : NULL);
994 0 : mGLContext->fBindTexture(mFBOTextureTarget, 0);
995 :
996 0 : mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mBackBufferFBO);
997 : mGLContext->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
998 : LOCAL_GL_COLOR_ATTACHMENT0,
999 : mFBOTextureTarget,
1000 : mBackBufferTexture,
1001 0 : 0);
1002 :
1003 0 : GLenum result = mGLContext->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
1004 0 : if (result != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
1005 0 : nsCAutoString msg;
1006 0 : msg.Append("Framebuffer not complete -- error 0x");
1007 0 : msg.AppendInt(result, 16);
1008 0 : NS_RUNTIMEABORT(msg.get());
1009 : }
1010 :
1011 0 : mBackBufferSize.width = aWidth;
1012 0 : mBackBufferSize.height = aHeight;
1013 : }
1014 :
1015 : void
1016 0 : LayerManagerOGL::CopyToTarget(gfxContext *aTarget)
1017 : {
1018 0 : nsIntRect rect;
1019 0 : mWidget->GetBounds(rect);
1020 0 : GLint width = rect.width;
1021 0 : GLint height = rect.height;
1022 :
1023 0 : if ((PRInt64(width) * PRInt64(height) * PRInt64(4)) > PR_INT32_MAX) {
1024 0 : NS_ERROR("Widget size too big - integer overflow!");
1025 0 : return;
1026 : }
1027 :
1028 : nsRefPtr<gfxImageSurface> imageSurface =
1029 : new gfxImageSurface(gfxIntSize(width, height),
1030 0 : gfxASurface::ImageFormatARGB32);
1031 :
1032 : mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER,
1033 0 : mGLContext->IsDoubleBuffered() ? 0 : mBackBufferFBO);
1034 :
1035 : #ifndef USE_GLES2
1036 : // GLES2 promises that binding to any custom FBO will attach
1037 : // to GL_COLOR_ATTACHMENT0 attachment point.
1038 0 : if (mGLContext->IsDoubleBuffered()) {
1039 0 : mGLContext->fReadBuffer(LOCAL_GL_BACK);
1040 : }
1041 : else {
1042 0 : mGLContext->fReadBuffer(LOCAL_GL_COLOR_ATTACHMENT0);
1043 : }
1044 : #endif
1045 :
1046 0 : NS_ASSERTION(imageSurface->Stride() == width * 4,
1047 : "Image Surfaces being created with weird stride!");
1048 :
1049 0 : mGLContext->ReadPixelsIntoImageSurface(0, 0, width, height, imageSurface);
1050 :
1051 0 : aTarget->SetOperator(gfxContext::OPERATOR_SOURCE);
1052 0 : aTarget->Scale(1.0, -1.0);
1053 0 : aTarget->Translate(-gfxPoint(0.0, height));
1054 0 : aTarget->SetSource(imageSurface);
1055 0 : aTarget->Paint();
1056 : }
1057 :
1058 : LayerManagerOGL::ProgramType LayerManagerOGL::sLayerProgramTypes[] = {
1059 : gl::RGBALayerProgramType,
1060 : gl::BGRALayerProgramType,
1061 : gl::RGBXLayerProgramType,
1062 : gl::BGRXLayerProgramType,
1063 : gl::RGBARectLayerProgramType,
1064 : gl::ColorLayerProgramType,
1065 : gl::YCbCrLayerProgramType,
1066 : gl::ComponentAlphaPass1ProgramType,
1067 : gl::ComponentAlphaPass2ProgramType
1068 : };
1069 :
1070 : #define FOR_EACH_LAYER_PROGRAM(vname) \
1071 : for (size_t lpindex = 0; \
1072 : lpindex < ArrayLength(sLayerProgramTypes); \
1073 : ++lpindex) \
1074 : { \
1075 : LayerProgram *vname = static_cast<LayerProgram*> \
1076 : (mPrograms[sLayerProgramTypes[lpindex]]); \
1077 : do
1078 :
1079 : #define FOR_EACH_LAYER_PROGRAM_END \
1080 : while (0); \
1081 : } \
1082 :
1083 : void
1084 0 : LayerManagerOGL::SetLayerProgramProjectionMatrix(const gfx3DMatrix& aMatrix)
1085 : {
1086 0 : FOR_EACH_LAYER_PROGRAM(lp) {
1087 0 : lp->Activate();
1088 0 : lp->SetProjectionMatrix(aMatrix);
1089 : } FOR_EACH_LAYER_PROGRAM_END
1090 0 : }
1091 :
1092 : static GLenum
1093 0 : GetFrameBufferInternalFormat(GLContext* gl,
1094 : GLuint aCurrentFrameBuffer,
1095 : nsIWidget* aWidget)
1096 : {
1097 0 : if (aCurrentFrameBuffer == 0) { // default framebuffer
1098 0 : return aWidget->GetGLFrameBufferFormat();
1099 : }
1100 0 : return LOCAL_GL_RGBA;
1101 : }
1102 :
1103 : static bool
1104 0 : AreFormatsCompatibleForCopyTexImage2D(GLenum aF1, GLenum aF2)
1105 : {
1106 : // GL requires that the implementation has to handle copies between
1107 : // different formats, so all are "compatible". GLES does not
1108 : // require that.
1109 : #ifdef USE_GLES2
1110 : return (aF1 == aF2);
1111 : #else
1112 0 : return true;
1113 : #endif
1114 : }
1115 :
1116 : void
1117 0 : LayerManagerOGL::CreateFBOWithTexture(const nsIntRect& aRect, InitMode aInit,
1118 : GLuint aCurrentFrameBuffer,
1119 : GLuint *aFBO, GLuint *aTexture)
1120 : {
1121 : GLuint tex, fbo;
1122 :
1123 0 : mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
1124 0 : mGLContext->fGenTextures(1, &tex);
1125 0 : mGLContext->fBindTexture(mFBOTextureTarget, tex);
1126 0 : if (aInit == InitModeCopy) {
1127 : // We're going to create an RGBA temporary fbo. But to
1128 : // CopyTexImage() from the current framebuffer, the framebuffer's
1129 : // format has to be compatible with the new texture's. So we
1130 : // check the format of the framebuffer here and take a slow path
1131 : // if it's incompatible.
1132 : GLenum format =
1133 0 : GetFrameBufferInternalFormat(gl(), aCurrentFrameBuffer, mWidget);
1134 0 : if (AreFormatsCompatibleForCopyTexImage2D(format, LOCAL_GL_RGBA)) {
1135 : mGLContext->fCopyTexImage2D(mFBOTextureTarget,
1136 : 0,
1137 : LOCAL_GL_RGBA,
1138 : aRect.x, aRect.y,
1139 : aRect.width, aRect.height,
1140 0 : 0);
1141 : } else {
1142 : // Curses, incompatible formats. Take a slow path.
1143 : //
1144 : // XXX Technically CopyTexSubImage2D also has the requirement of
1145 : // matching formats, but it doesn't seem to affect us in the
1146 : // real world.
1147 : mGLContext->fTexImage2D(mFBOTextureTarget,
1148 : 0,
1149 : LOCAL_GL_RGBA,
1150 : aRect.width, aRect.height,
1151 : 0,
1152 : LOCAL_GL_RGBA,
1153 : LOCAL_GL_UNSIGNED_BYTE,
1154 0 : NULL);
1155 : mGLContext->fCopyTexSubImage2D(mFBOTextureTarget,
1156 : 0, // level
1157 : 0, 0, // offset
1158 : aRect.x, aRect.y,
1159 0 : aRect.width, aRect.height);
1160 : }
1161 : } else {
1162 : mGLContext->fTexImage2D(mFBOTextureTarget,
1163 : 0,
1164 : LOCAL_GL_RGBA,
1165 : aRect.width, aRect.height,
1166 : 0,
1167 : LOCAL_GL_RGBA,
1168 : LOCAL_GL_UNSIGNED_BYTE,
1169 0 : NULL);
1170 : }
1171 : mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_MIN_FILTER,
1172 0 : LOCAL_GL_LINEAR);
1173 : mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_MAG_FILTER,
1174 0 : LOCAL_GL_LINEAR);
1175 : mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_WRAP_S,
1176 0 : LOCAL_GL_CLAMP_TO_EDGE);
1177 : mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_WRAP_T,
1178 0 : LOCAL_GL_CLAMP_TO_EDGE);
1179 0 : mGLContext->fBindTexture(mFBOTextureTarget, 0);
1180 :
1181 0 : mGLContext->fGenFramebuffers(1, &fbo);
1182 0 : mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, fbo);
1183 : mGLContext->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
1184 : LOCAL_GL_COLOR_ATTACHMENT0,
1185 : mFBOTextureTarget,
1186 : tex,
1187 0 : 0);
1188 :
1189 : // Making this call to fCheckFramebufferStatus prevents a crash on
1190 : // PowerVR. See bug 695246.
1191 0 : GLenum result = mGLContext->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
1192 0 : if (result != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
1193 0 : nsCAutoString msg;
1194 0 : msg.Append("Framebuffer not complete -- error 0x");
1195 0 : msg.AppendInt(result, 16);
1196 0 : msg.Append(", mFBOTextureTarget 0x");
1197 0 : msg.AppendInt(mFBOTextureTarget, 16);
1198 0 : msg.Append(", aRect.width ");
1199 0 : msg.AppendInt(aRect.width);
1200 0 : msg.Append(", aRect.height ");
1201 0 : msg.AppendInt(aRect.height);
1202 0 : NS_RUNTIMEABORT(msg.get());
1203 : }
1204 :
1205 0 : SetupPipeline(aRect.width, aRect.height, DontApplyWorldTransform);
1206 0 : mGLContext->fScissor(0, 0, aRect.width, aRect.height);
1207 :
1208 0 : if (aInit == InitModeClear) {
1209 0 : mGLContext->fClearColor(0.0, 0.0, 0.0, 0.0);
1210 0 : mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT);
1211 : }
1212 :
1213 0 : *aFBO = fbo;
1214 0 : *aTexture = tex;
1215 0 : }
1216 :
1217 : already_AddRefed<ShadowThebesLayer>
1218 0 : LayerManagerOGL::CreateShadowThebesLayer()
1219 : {
1220 0 : if (LayerManagerOGL::mDestroyed) {
1221 0 : NS_WARNING("Call on destroyed layer manager");
1222 0 : return nsnull;
1223 : }
1224 0 : return nsRefPtr<ShadowThebesLayerOGL>(new ShadowThebesLayerOGL(this)).forget();
1225 : }
1226 :
1227 : already_AddRefed<ShadowContainerLayer>
1228 0 : LayerManagerOGL::CreateShadowContainerLayer()
1229 : {
1230 0 : if (LayerManagerOGL::mDestroyed) {
1231 0 : NS_WARNING("Call on destroyed layer manager");
1232 0 : return nsnull;
1233 : }
1234 0 : return nsRefPtr<ShadowContainerLayerOGL>(new ShadowContainerLayerOGL(this)).forget();
1235 : }
1236 :
1237 : already_AddRefed<ShadowImageLayer>
1238 0 : LayerManagerOGL::CreateShadowImageLayer()
1239 : {
1240 0 : if (LayerManagerOGL::mDestroyed) {
1241 0 : NS_WARNING("Call on destroyed layer manager");
1242 0 : return nsnull;
1243 : }
1244 0 : return nsRefPtr<ShadowImageLayerOGL>(new ShadowImageLayerOGL(this)).forget();
1245 : }
1246 :
1247 : already_AddRefed<ShadowColorLayer>
1248 0 : LayerManagerOGL::CreateShadowColorLayer()
1249 : {
1250 0 : if (LayerManagerOGL::mDestroyed) {
1251 0 : NS_WARNING("Call on destroyed layer manager");
1252 0 : return nsnull;
1253 : }
1254 0 : return nsRefPtr<ShadowColorLayerOGL>(new ShadowColorLayerOGL(this)).forget();
1255 : }
1256 :
1257 : already_AddRefed<ShadowCanvasLayer>
1258 0 : LayerManagerOGL::CreateShadowCanvasLayer()
1259 : {
1260 0 : if (LayerManagerOGL::mDestroyed) {
1261 0 : NS_WARNING("Call on destroyed layer manager");
1262 0 : return nsnull;
1263 : }
1264 0 : return nsRefPtr<ShadowCanvasLayerOGL>(new ShadowCanvasLayerOGL(this)).forget();
1265 : }
1266 :
1267 :
1268 : } /* layers */
1269 : } /* mozilla */
|