From 4c3754729e0645c5e19a65a183219936ce03e717 Mon Sep 17 00:00:00 2001 From: Vladimir Vukicevic Date: Mon, 24 May 2010 23:35:35 -0700 Subject: [PATCH] b=567626; fix up opengl layers; r=bas --- gfx/layers/Makefile.in | 16 + gfx/layers/opengl/CanvasLayerOGL.cpp | 166 ++-- gfx/layers/opengl/CanvasLayerOGL.h | 11 +- gfx/layers/opengl/ColorLayerOGL.cpp | 51 +- gfx/layers/opengl/ColorLayerOGL.h | 9 +- gfx/layers/opengl/ContainerLayerOGL.cpp | 128 +-- gfx/layers/opengl/ContainerLayerOGL.h | 5 +- gfx/layers/opengl/ImageLayerOGL.cpp | 90 +- gfx/layers/opengl/ImageLayerOGL.h | 5 +- gfx/layers/opengl/LayerManagerOGL.cpp | 839 +++++++++---------- gfx/layers/opengl/LayerManagerOGL.h | 369 ++++---- gfx/layers/opengl/LayerManagerOGLProgram.h | 764 +++++++++++++++++ gfx/layers/opengl/LayerManagerOGLShaders.h | 48 -- gfx/layers/opengl/LayerManagerOGLShaders.txt | 279 ++++++ gfx/layers/opengl/ThebesLayerOGL.cpp | 97 +-- gfx/layers/opengl/ThebesLayerOGL.h | 8 +- gfx/layers/opengl/genshaders.py | 140 ++++ gfx/thebes/public/GLContext.h | 25 +- gfx/thebes/public/gfx3DMatrix.h | 17 + 19 files changed, 2098 insertions(+), 969 deletions(-) create mode 100644 gfx/layers/opengl/LayerManagerOGLProgram.h delete mode 100644 gfx/layers/opengl/LayerManagerOGLShaders.h create mode 100644 gfx/layers/opengl/LayerManagerOGLShaders.txt create mode 100644 gfx/layers/opengl/genshaders.py diff --git a/gfx/layers/Makefile.in b/gfx/layers/Makefile.in index cb4659cf30d2..7ae1d05184e1 100644 --- a/gfx/layers/Makefile.in +++ b/gfx/layers/Makefile.in @@ -62,6 +62,7 @@ EXPORTS = \ ImageLayers.h \ Layers.h \ LayerManagerOGL.h \ + LayerManagerOGLProgram.h \ $(NULL) CPPSRCS = \ @@ -90,6 +91,21 @@ CPPSRCS += \ endif endif +# Enable GLES2.0 under maemo +ifdef MOZ_X11 +ifdef MOZ_PLATFORM_MAEMO +DEFINES += -DUSE_GLES2 +endif +endif + include $(topsrcdir)/config/rules.mk CXXFLAGS += $(MOZ_CAIRO_CFLAGS) + +LayerManagerOGLShaders.h: LayerManagerOGLShaders.txt genshaders.py + $(PYTHON) $(srcdir)/opengl/genshaders.py $< $@ + +LayerManagerOGL.$(OBJ_SUFFIX): LayerManagerOGLShaders.h + +GARBAGE += LayerManagerOGLShaders.h + diff --git a/gfx/layers/opengl/CanvasLayerOGL.cpp b/gfx/layers/opengl/CanvasLayerOGL.cpp index 8c671c0bf7e4..4c0b9fb6f142 100644 --- a/gfx/layers/opengl/CanvasLayerOGL.cpp +++ b/gfx/layers/opengl/CanvasLayerOGL.cpp @@ -1,5 +1,5 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * ***** BEGIN LICENSE BLOCK ***** +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-/ +/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version @@ -55,25 +55,22 @@ using namespace mozilla::gl; CanvasLayerOGL::~CanvasLayerOGL() { - LayerManagerOGL *glManager = static_cast(mManager); - GLContext *gl = glManager->gl(); - glManager->MakeCurrent(); + mOGLManager->MakeCurrent(); - if (mTexture) { - gl->fDeleteTextures(1, &mTexture); - } + if (mTexture) + gl()->fDeleteTextures(1, &mTexture); } void CanvasLayerOGL::Initialize(const Data& aData) { - NS_ASSERTION(mSurface == nsnull, "BasicCanvasLayer::Initialize called twice!"); + NS_ASSERTION(mCanvasSurface == nsnull, "BasicCanvasLayer::Initialize called twice!"); if (aData.mSurface) { - mSurface = aData.mSurface; + mCanvasSurface = aData.mSurface; NS_ASSERTION(aData.mGLContext == nsnull, "CanvasLayerOGL can't have both surface and GLContext"); - mNeedsYFlip = PR_TRUE; + mNeedsYFlip = PR_FALSE; } else if (aData.mGLContext) { // this must be a pbuffer context void *pbuffer = aData.mGLContext->GetNativeData(GLContext::NativePBuffer); @@ -82,9 +79,9 @@ CanvasLayerOGL::Initialize(const Data& aData) return; } - mGLContext = aData.mGLContext; + mCanvasGLContext = aData.mGLContext; mGLBufferIsPremultiplied = aData.mGLBufferIsPremultiplied; - mNeedsYFlip = PR_FALSE; + mNeedsYFlip = PR_TRUE; } else { NS_WARNING("CanvasLayerOGL::Initialize called without surface or GL context!"); return; @@ -96,46 +93,46 @@ CanvasLayerOGL::Initialize(const Data& aData) void CanvasLayerOGL::Updated(const nsIntRect& aRect) { - LayerManagerOGL *glManager = static_cast(mManager); - GLContext *gl = glManager->gl(); - glManager->MakeCurrent(); + NS_ASSERTION(mUpdatedRect.IsEmpty(), + "CanvasLayer::Updated called more than once during a transaction!"); - NS_ASSERTION(mUpdatedRect.IsEmpty(), "CanvasLayer::Updated called more than once during a transaction!"); + mOGLManager->MakeCurrent(); mUpdatedRect.UnionRect(mUpdatedRect, aRect); - if (mSurface) { + if (mCanvasSurface) { if (mTexture == 0) { - gl->fGenTextures(1, (GLuint*)&mTexture); + gl()->fGenTextures(1, &mTexture); - gl->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture); + gl()->fActiveTexture(LOCAL_GL_TEXTURE0); + gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture); - gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR); - gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR); - gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE); - gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE); + gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR); + gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR); + gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE); + gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE); mUpdatedRect = mBounds; } else { - gl->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture); + gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture); } nsRefPtr updatedAreaImageSurface; - nsRefPtr sourceSurface = mSurface; + nsRefPtr sourceSurface = mCanvasSurface; #ifdef XP_WIN if (sourceSurface->GetType() == gfxASurface::SurfaceTypeWin32) { sourceSurface = static_cast(sourceSurface.get())->GetImageSurface(); if (!sourceSurface) - sourceSurface = mSurface; + sourceSurface = mCanvasSurface; } #endif #if 0 // XXX don't copy, blah. // but need to deal with stride on the gl side; do this later. - if (mSurface->GetType() == gfxASurface::SurfaceTypeImage) { - gfxImageSurface *s = static_cast(mSurface.get()); + if (mCanvasSurface->GetType() == gfxASurface::SurfaceTypeImage) { + gfxImageSurface *s = static_cast(mCanvasSurface.get()); if (s->Format() == gfxASurface::ImageFormatARGB32 || s->Format() == gfxASurface::ImageFormatRGB24) { @@ -147,8 +144,9 @@ CanvasLayerOGL::Updated(const nsIntRect& aRect) } else #endif { - updatedAreaImageSurface = new gfxImageSurface(gfxIntSize(mUpdatedRect.width, mUpdatedRect.height), - gfxASurface::ImageFormatARGB32); + updatedAreaImageSurface = + new gfxImageSurface(gfxIntSize(mUpdatedRect.width, mUpdatedRect.height), + gfxASurface::ImageFormatARGB32); nsRefPtr ctx = new gfxContext(updatedAreaImageSurface); ctx->Translate(gfxPoint(-mUpdatedRect.x, -mUpdatedRect.y)); ctx->SetOperator(gfxContext::OPERATOR_SOURCE); @@ -157,87 +155,70 @@ CanvasLayerOGL::Updated(const nsIntRect& aRect) } if (mUpdatedRect == mBounds) { - gl->fTexImage2D(LOCAL_GL_TEXTURE_2D, - 0, - LOCAL_GL_RGBA, - mUpdatedRect.width, - mUpdatedRect.height, - 0, - LOCAL_GL_BGRA, - LOCAL_GL_UNSIGNED_BYTE, - updatedAreaImageSurface->Data()); + gl()->fTexImage2D(LOCAL_GL_TEXTURE_2D, + 0, + LOCAL_GL_RGBA, + mUpdatedRect.width, + mUpdatedRect.height, + 0, + LOCAL_GL_RGBA, + LOCAL_GL_UNSIGNED_BYTE, + updatedAreaImageSurface->Data()); } else { - gl->fTexSubImage2D(LOCAL_GL_TEXTURE_2D, - 0, - mUpdatedRect.x, - mUpdatedRect.y, - mUpdatedRect.width, - mUpdatedRect.height, - LOCAL_GL_BGRA, - LOCAL_GL_UNSIGNED_BYTE, - updatedAreaImageSurface->Data()); + gl()->fTexSubImage2D(LOCAL_GL_TEXTURE_2D, + 0, + mUpdatedRect.x, + mUpdatedRect.y, + mUpdatedRect.width, + mUpdatedRect.height, + LOCAL_GL_RGBA, + LOCAL_GL_UNSIGNED_BYTE, + updatedAreaImageSurface->Data()); } - } else if (mGLContext) { + } else if (mCanvasGLContext) { // we just need to create a texture that we'll use, the first time through if (mTexture == 0) { - gl->fGenTextures(1, (GLuint*)&mTexture); + gl()->fGenTextures(1, (GLuint*)&mTexture); - gl->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture); + gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture); - gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR); - gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR); - gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE); - gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE); + gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR); + gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR); + gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE); + gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE); mUpdatedRect = mBounds; } } // sanity - NS_ASSERTION(mUpdatedRect.IsEmpty() || mBounds.Contains(mUpdatedRect), "CanvasLayer: Updated rect bigger than bounds!"); + NS_ASSERTION(mUpdatedRect.IsEmpty() || mBounds.Contains(mUpdatedRect), + "CanvasLayer: Updated rect bigger than bounds!"); } void CanvasLayerOGL::RenderLayer(int aPreviousDestination, - DrawThebesLayerCallback aCallback, - void* aCallbackData) + const nsIntPoint& aOffset) { - LayerManagerOGL *glManager = static_cast(mManager); - GLContext *gl = glManager->gl(); - glManager->MakeCurrent(); - - float quadTransform[4][4]; - // Transform the quad to the size of the canvas. - memset(&quadTransform, 0, sizeof(quadTransform)); - quadTransform[0][0] = (float)mBounds.width; - quadTransform[1][1] = (float)mBounds.height; - quadTransform[2][2] = 1.0f; - quadTransform[3][3] = 1.0f; + mOGLManager->MakeCurrent(); // XXX We're going to need a different program depending on if // mGLBufferIsPremultiplied is TRUE or not. The RGBLayerProgram // assumes that it's true. - // XXX this function needs to handle both mNeedsYFlip -- right now, - // as written, PBuffer canvas layers will be drawn upside-down. + ColorTextureLayerProgram *program = nsnull; - RGBLayerProgram *program = glManager->GetRGBLayerProgram(); + gl()->fActiveTexture(LOCAL_GL_TEXTURE0); + gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture); - program->Activate(); - - program->SetLayerQuadTransform(&quadTransform[0][0]); - - gl->fActiveTexture(LOCAL_GL_TEXTURE0); - gl->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture); - - if (mGLContext) { + if (mCanvasGLContext) { #if defined(XP_MACOSX) CGLError err; - err = CGLTexImagePBuffer((CGLContextObj) gl->GetNativeData(GLContext::NativeCGLContext), - (CGLPBufferObj) mGLContext->GetNativeData(GLContext::NativePBuffer), + err = CGLTexImagePBuffer((CGLContextObj) mCanvasGLContext->GetNativeData(GLContext::NativeCGLContext), + (CGLPBufferObj) mCanvasGLContext->GetNativeData(GLContext::NativePBuffer), LOCAL_GL_BACK); #elif defined(XP_WIN) - if (!sWGLLibrary.fBindTexImage((HANDLE) mGLContext->GetNativeData(GLContext::NativePBuffer), + if (!sWGLLibrary.fBindTexImage((HANDLE) mCanvasGLContext->GetNativeData(GLContext::NativePBuffer), LOCAL_WGL_FRONT_LEFT_ARB)) { NS_WARNING("CanvasLayerOGL::RenderLayer wglBindTexImageARB failed"); @@ -246,17 +227,24 @@ CanvasLayerOGL::RenderLayer(int aPreviousDestination, #else NS_WARNING("CanvasLayerOGL::RenderLayer with GL context, but I don't know how to render on this platform!"); #endif + + program = mOGLManager->GetRGBALayerProgram(); + } else { + program = mOGLManager->GetBGRALayerProgram(); } + program->Activate(); + program->SetLayerQuadRect(mBounds); + program->SetLayerTransform(mTransform); program->SetLayerOpacity(GetOpacity()); - program->SetLayerTransform(&mTransform._11); - program->Apply(); + program->SetRenderOffset(aOffset); + program->SetTextureUnit(0); - gl->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4); + mOGLManager->BindAndDrawQuad(program, mNeedsYFlip ? true : false); - if (mGLContext) { + if (mCanvasGLContext) { #if defined(XP_WIN) - sWGLLibrary.fReleaseTexImage((HANDLE) mGLContext->GetNativeData(GLContext::NativePBuffer), + sWGLLibrary.fReleaseTexImage((HANDLE) mCanvasGLContext->GetNativeData(GLContext::NativePBuffer), LOCAL_WGL_FRONT_LEFT_ARB); #endif } diff --git a/gfx/layers/opengl/CanvasLayerOGL.h b/gfx/layers/opengl/CanvasLayerOGL.h index 6f4587a85983..e651b410ee6a 100644 --- a/gfx/layers/opengl/CanvasLayerOGL.h +++ b/gfx/layers/opengl/CanvasLayerOGL.h @@ -66,15 +66,14 @@ public: // LayerOGL implementation virtual LayerType GetType() { return TYPE_CANVAS; } virtual Layer* GetLayer() { return this; } - virtual void RenderLayer(int aPreviousDestination, - DrawThebesLayerCallback aCallback, - void* aCallbackData); + virtual void RenderLayer(int aPreviousFrameBuffer, + const nsIntPoint& aOffset); protected: - nsRefPtr mSurface; - nsRefPtr mGLContext; + nsRefPtr mCanvasSurface; + nsRefPtr mCanvasGLContext; - unsigned int mTexture; + GLuint mTexture; nsIntRect mBounds; nsIntRect mUpdatedRect; diff --git a/gfx/layers/opengl/ColorLayerOGL.cpp b/gfx/layers/opengl/ColorLayerOGL.cpp index e87bae943bda..ffd36f917580 100644 --- a/gfx/layers/opengl/ColorLayerOGL.cpp +++ b/gfx/layers/opengl/ColorLayerOGL.cpp @@ -1,5 +1,5 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * ***** BEGIN LICENSE BLOCK ***** +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version @@ -20,6 +20,7 @@ * * Contributor(s): * Robert O'Callahan + * Vladimir Vukicevic * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -53,41 +54,37 @@ ColorLayerOGL::GetLayer() } void -ColorLayerOGL::RenderLayer(int, DrawThebesLayerCallback, void*) +ColorLayerOGL::RenderLayer(int, + const nsIntPoint& aOffset) { - static_cast(mManager)->MakeCurrent(); + mOGLManager->MakeCurrent(); // XXX we might be able to improve performance by using glClear - float quadTransform[4][4]; nsIntRect visibleRect = mVisibleRegion.GetBounds(); - // Transform the quad to the size of the visible area. - memset(&quadTransform, 0, sizeof(quadTransform)); - quadTransform[0][0] = (float)visibleRect.width; - quadTransform[1][1] = (float)visibleRect.height; - quadTransform[2][2] = 1.0f; - quadTransform[3][0] = (float)visibleRect.x; - quadTransform[3][1] = (float)visibleRect.y; - quadTransform[3][3] = 1.0f; - ColorLayerProgram *program = - static_cast(mManager)->GetColorLayerProgram(); + /* Multiply color by the layer opacity, as the shader + * ignores layer opacity and expects a final color to + * write to the color buffer. This saves a needless + * multiply in the fragment shader. + */ + float opacity = GetOpacity(); + gfxRGBA color(mColor); + color.r *= opacity; + color.g *= opacity; + color.b *= opacity; + color.a *= opacity; + SolidColorLayerProgram *program = mOGLManager->GetColorLayerProgram(); program->Activate(); + program->SetLayerQuadRect(visibleRect); + program->SetLayerTransform(mTransform); + program->SetRenderOffset(aOffset); + program->SetRenderColor(color); - program->SetLayerQuadTransform(&quadTransform[0][0]); + mOGLManager->BindAndDrawQuad(program); - gfxRGBA color = mColor; - // color is premultiplied, so we need to adjust all channels - color.r *= GetOpacity(); - color.g *= GetOpacity(); - color.b *= GetOpacity(); - color.a *= GetOpacity(); - program->SetLayerColor(color); - program->SetLayerTransform(&mTransform._11); - program->Apply(); - - gl()->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4); + DEBUG_GL_ERROR_CHECK(gl()); } } /* layers */ diff --git a/gfx/layers/opengl/ColorLayerOGL.h b/gfx/layers/opengl/ColorLayerOGL.h index 87c4b88eec11..821f29cb7a6d 100644 --- a/gfx/layers/opengl/ColorLayerOGL.h +++ b/gfx/layers/opengl/ColorLayerOGL.h @@ -1,5 +1,5 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * ***** BEGIN LICENSE BLOCK ***** +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-/ +/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version @@ -61,9 +61,8 @@ public: virtual Layer* GetLayer(); - virtual void RenderLayer(int aPreviousDestination, - DrawThebesLayerCallback aCallback, - void* aCallbackData); + virtual void RenderLayer(int aPreviousFrameBuffer, + const nsIntPoint& aOffset); protected: nsIntRegion mVisibleRegion; diff --git a/gfx/layers/opengl/ContainerLayerOGL.cpp b/gfx/layers/opengl/ContainerLayerOGL.cpp index 55fc3a952906..784c30860a95 100644 --- a/gfx/layers/opengl/ContainerLayerOGL.cpp +++ b/gfx/layers/opengl/ContainerLayerOGL.cpp @@ -1,4 +1,4 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * @@ -139,70 +139,29 @@ ContainerLayerOGL::GetFirstChildOGL() void ContainerLayerOGL::RenderLayer(int aPreviousFrameBuffer, - DrawThebesLayerCallback aCallback, - void* aCallbackData) + const nsIntPoint& aOffset) { /** * Setup our temporary texture for rendering the contents of this container. */ GLuint containerSurface; GLuint frameBuffer; - RGBLayerProgram *rgbProgram = - static_cast(mManager)->GetRGBLayerProgram(); - ColorLayerProgram *colorProgram = - static_cast(mManager)->GetColorLayerProgram(); - YCbCrLayerProgram *yCbCrProgram = - static_cast(mManager)->GetYCbCrLayerProgram(); + + nsIntPoint childOffset(aOffset); + bool needsFramebuffer = false; float opacity = GetOpacity(); if (opacity != 1.0) { - gl()->fGenTextures(1, &containerSurface); - gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, containerSurface); - gl()->fTexImage2D(LOCAL_GL_TEXTURE_2D, - 0, - LOCAL_GL_RGBA, - mVisibleRect.width, - mVisibleRect.height, - 0, - LOCAL_GL_BGRA, - LOCAL_GL_UNSIGNED_BYTE, - NULL); - gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR); - gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR); - - /** - * Create the framebuffer and bind it to make our content render into our - * framebuffer. - */ - gl()->fGenFramebuffers(1, &frameBuffer); - gl()->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, frameBuffer); - gl()->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, - LOCAL_GL_COLOR_ATTACHMENT0, - LOCAL_GL_TEXTURE_2D, - containerSurface, - 0); - - NS_ASSERTION( - gl()->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER) == - LOCAL_GL_FRAMEBUFFER_COMPLETE, "Error setting up framebuffer."); - - /** - * Store old shader program variables and set the ones used for rendering - * this container's content. - */ - - rgbProgram->Activate(); - rgbProgram->PushRenderTargetOffset((GLfloat)GetVisibleRect().x, (GLfloat)GetVisibleRect().y); - - colorProgram->Activate(); - colorProgram->PushRenderTargetOffset((GLfloat)GetVisibleRect().x, (GLfloat)GetVisibleRect().y); - - yCbCrProgram->Activate(); - yCbCrProgram->PushRenderTargetOffset((GLfloat)GetVisibleRect().x, (GLfloat)GetVisibleRect().y); + mOGLManager->CreateFBOWithTexture(mVisibleRect.width, + mVisibleRect.height, + &frameBuffer, + &containerSurface); + childOffset.x = mVisibleRect.x; + childOffset.y = mVisibleRect.y; } else { frameBuffer = aPreviousFrameBuffer; } - + /** * Render this container's contents. */ @@ -210,15 +169,16 @@ ContainerLayerOGL::RenderLayer(int aPreviousFrameBuffer, while (layerToRender) { const nsIntRect *clipRect = layerToRender->GetLayer()->GetClipRect(); if (clipRect) { - gl()->fScissor(clipRect->x - GetVisibleRect().x, - clipRect->y - GetVisibleRect().y, - clipRect->width, - clipRect->height); + gl()->fScissor(clipRect->x - mVisibleRect.x, + clipRect->y - mVisibleRect.y, + clipRect->width, + clipRect->height); } else { - gl()->fScissor(0, 0, GetVisibleRect().width, GetVisibleRect().height); + gl()->fScissor(0, 0, mVisibleRect.width, mVisibleRect.height); } - layerToRender->RenderLayer(frameBuffer, aCallback, aCallbackData); + layerToRender->RenderLayer(frameBuffer, childOffset); + layerToRender = layerToRender->GetNextSibling(); } @@ -227,44 +187,36 @@ ContainerLayerOGL::RenderLayer(int aPreviousFrameBuffer, gl()->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, aPreviousFrameBuffer); gl()->fDeleteFramebuffers(1, &frameBuffer); - // Restore old shader program variables. - yCbCrProgram->Activate(); - yCbCrProgram->PopRenderTargetOffset(); + gl()->fActiveTexture(LOCAL_GL_TEXTURE0); - colorProgram->Activate(); - colorProgram->PopRenderTargetOffset(); + gl()->fBindTexture(mOGLManager->FBOTextureTarget(), containerSurface); - rgbProgram->Activate(); - rgbProgram->PopRenderTargetOffset(); + ColorTextureLayerProgram *rgb = mOGLManager->GetFBOLayerProgram(); - /** - * Render the contents of this container to our destination. - */ - float quadTransform[4][4]; - /* - * Matrix to transform the <0.0,0.0>, <1.0,1.0> quad to the correct position - * and size. - */ - memset(&quadTransform, 0, sizeof(quadTransform)); - quadTransform[0][0] = (float)GetVisibleRect().width; - quadTransform[1][1] = (float)GetVisibleRect().height; - quadTransform[2][2] = 1.0f; - quadTransform[3][0] = (float)GetVisibleRect().x; - quadTransform[3][1] = (float)GetVisibleRect().y; - quadTransform[3][3] = 1.0f; + rgb->Activate(); + rgb->SetLayerQuadRect(mVisibleRect); + rgb->SetLayerTransform(mTransform); + rgb->SetLayerOpacity(opacity); + rgb->SetRenderOffset(aOffset); + rgb->SetTextureUnit(0); - rgbProgram->SetLayerQuadTransform(&quadTransform[0][0]); + if (rgb->GetTexCoordMultiplierUniformLocation() != -1) { + // 2DRect case, get the multiplier right for a sampler2DRect + float f[] = { float(mVisibleRect.width), float(mVisibleRect.height) }; + rgb->SetUniform(rgb->GetTexCoordMultiplierUniformLocation(), + 2, f); + } - gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, containerSurface); + DEBUG_GL_ERROR_CHECK(gl()); - rgbProgram->SetLayerOpacity(opacity); - rgbProgram->SetLayerTransform(&mTransform._11); - rgbProgram->Apply(); + mOGLManager->BindAndDrawQuad(rgb); - gl()->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4); + DEBUG_GL_ERROR_CHECK(gl()); - // Clean up resources. + // Clean up resources. This also unbinds the texture. gl()->fDeleteTextures(1, &containerSurface); + + DEBUG_GL_ERROR_CHECK(gl()); } } diff --git a/gfx/layers/opengl/ContainerLayerOGL.h b/gfx/layers/opengl/ContainerLayerOGL.h index 2d32bfa02957..a02040ee38a8 100644 --- a/gfx/layers/opengl/ContainerLayerOGL.h +++ b/gfx/layers/opengl/ContainerLayerOGL.h @@ -69,9 +69,8 @@ public: PRBool IsEmpty(); - void RenderLayer(int aPreviousFrameBuffer, - DrawThebesLayerCallback aCallback, - void* aCallbackData); + virtual void RenderLayer(int aPreviousFrameBuffer, + const nsIntPoint& aOffset); private: nsIntRect mVisibleRect; diff --git a/gfx/layers/opengl/ImageLayerOGL.cpp b/gfx/layers/opengl/ImageLayerOGL.cpp index a4b8e9d77722..223a74efc699 100644 --- a/gfx/layers/opengl/ImageLayerOGL.cpp +++ b/gfx/layers/opengl/ImageLayerOGL.cpp @@ -1,4 +1,4 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * @@ -20,6 +20,7 @@ * * Contributor(s): * Bas Schouten + * Vladimir Vukicevic * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -269,15 +270,13 @@ ImageLayerOGL::GetLayer() } void -ImageLayerOGL::RenderLayer(int, DrawThebesLayerCallback aCallback, - void* aCallbackData) +ImageLayerOGL::RenderLayer(int, + const nsIntPoint& aOffset) { - if (!GetContainer()) { + if (!GetContainer()) return; - } - LayerManagerOGL *manager = static_cast(mManager); - manager->MakeCurrent(); + mOGLManager->MakeCurrent(); nsRefPtr image = GetContainer()->GetCurrentImage(); @@ -285,28 +284,12 @@ ImageLayerOGL::RenderLayer(int, DrawThebesLayerCallback aCallback, PlanarYCbCrImageOGL *yuvImage = static_cast(image.get()); - if (!yuvImage->HasData()) { + if (!yuvImage->HasData()) return; - } - if (!yuvImage->HasTextures()) { - yuvImage->AllocateTextures(manager); - } + if (!yuvImage->HasTextures()) + yuvImage->AllocateTextures(mOGLManager); - float quadTransform[4][4]; - // Transform the quad to the size of the video. - memset(&quadTransform, 0, sizeof(quadTransform)); - quadTransform[0][0] = (float)yuvImage->mSize.width; - quadTransform[1][1] = (float)yuvImage->mSize.height; - quadTransform[2][2] = 1.0f; - quadTransform[3][3] = 1.0f; - - YCbCrLayerProgram *program = manager->GetYCbCrLayerProgram(); - - program->Activate(); - - program->SetLayerQuadTransform(&quadTransform[0][0]); - gl()->fActiveTexture(LOCAL_GL_TEXTURE0); gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, yuvImage->mTextures[0].GetTextureID()); gl()->fActiveTexture(LOCAL_GL_TEXTURE1); @@ -314,40 +297,46 @@ ImageLayerOGL::RenderLayer(int, DrawThebesLayerCallback aCallback, gl()->fActiveTexture(LOCAL_GL_TEXTURE2); gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, yuvImage->mTextures[2].GetTextureID()); + YCbCrTextureLayerProgram *program = mOGLManager->GetYCbCrLayerProgram(); + + program->Activate(); + program->SetLayerQuadRect(nsIntRect(0, 0, + yuvImage->mSize.width, + yuvImage->mSize.height)); + program->SetLayerTransform(mTransform); program->SetLayerOpacity(GetOpacity()); - program->SetLayerTransform(&mTransform._11); - program->Apply(); + program->SetRenderOffset(aOffset); + program->SetYCbCrTextureUnits(0, 1, 2); - gl()->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4); + DEBUG_GL_ERROR_CHECK(gl()); + mOGLManager->BindAndDrawQuad(program); + + // We shouldn't need to do this, but do it anyway just in case + // someone else forgets. gl()->fActiveTexture(LOCAL_GL_TEXTURE0); - } else if (image->GetFormat() == Image::CAIRO_SURFACE) { CairoImageOGL *cairoImage = static_cast(image.get()); - float quadTransform[4][4]; - // Transform the quad to the size of the video. - memset(&quadTransform, 0, sizeof(quadTransform)); - quadTransform[0][0] = (float)cairoImage->mSize.width; - quadTransform[1][1] = (float)cairoImage->mSize.height; - quadTransform[2][2] = 1.0f; - quadTransform[3][3] = 1.0f; - - RGBLayerProgram *program = manager->GetRGBLayerProgram(); - - program->Activate(); - - program->SetLayerQuadTransform(&quadTransform[0][0]); - gl()->fActiveTexture(LOCAL_GL_TEXTURE0); gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, cairoImage->mTexture.GetTextureID()); - program->SetLayerOpacity(GetOpacity()); - program->SetLayerTransform(&mTransform._11); - program->Apply(); + + ColorTextureLayerProgram *program = mOGLManager->GetBGRALayerProgram(); - gl()->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4); + program->Activate(); + program->SetLayerQuadRect(nsIntRect(0, 0, + cairoImage->mSize.width, + cairoImage->mSize.height)); + program->SetLayerTransform(mTransform); + program->SetLayerOpacity(GetOpacity()); + program->SetRenderOffset(aOffset); + program->SetTextureUnit(0); + + mOGLManager->BindAndDrawQuad(program); } + + DEBUG_GL_ERROR_CHECK(gl()); } PlanarYCbCrImageOGL::PlanarYCbCrImageOGL(RecycleBin *aRecycleBin) @@ -552,6 +541,8 @@ CairoImageOGL::SetData(const CairoImage::Data &aData) // XXX This could be a lot more efficient if we already have an image-compatible // surface + // XXX if we ever create an ImageFormatRGB24 surface, make sure that we use + // a BGRX program in that case (instead of BGRA) nsRefPtr imageSurface = new gfxImageSurface(aData.mSize, gfxASurface::ImageFormatARGB32); nsRefPtr context = new gfxContext(imageSurface); @@ -559,6 +550,7 @@ CairoImageOGL::SetData(const CairoImage::Data &aData) context->SetSource(aData.mSurface); context->Paint(); + gl->fActiveTexture(LOCAL_GL_TEXTURE0); gl->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture.GetTextureID()); gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR); @@ -572,7 +564,7 @@ CairoImageOGL::SetData(const CairoImage::Data &aData) mSize.width, mSize.height, 0, - LOCAL_GL_BGRA, + LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, imageSurface->Data()); } diff --git a/gfx/layers/opengl/ImageLayerOGL.h b/gfx/layers/opengl/ImageLayerOGL.h index 459b9202301d..cc0aab941f2c 100644 --- a/gfx/layers/opengl/ImageLayerOGL.h +++ b/gfx/layers/opengl/ImageLayerOGL.h @@ -175,9 +175,8 @@ public: virtual Layer* GetLayer(); - virtual void RenderLayer(int aPreviousDestination, - DrawThebesLayerCallback aCallback, - void* aCallbackData); + virtual void RenderLayer(int aPreviousFrameBuffer, + const nsIntPoint& aOffset); }; class THEBES_API PlanarYCbCrImageOGL : public PlanarYCbCrImage diff --git a/gfx/layers/opengl/LayerManagerOGL.cpp b/gfx/layers/opengl/LayerManagerOGL.cpp index 0d5c8b011da8..b86d99b529eb 100644 --- a/gfx/layers/opengl/LayerManagerOGL.cpp +++ b/gfx/layers/opengl/LayerManagerOGL.cpp @@ -1,5 +1,5 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * ***** BEGIN LICENSE BLOCK ***** +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version @@ -20,6 +20,8 @@ * * Contributor(s): * Bas Schouten + * Frederic Plourde + * Vladimir Vukicevic * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -53,34 +55,48 @@ #include "nsIServiceManager.h" #include "nsIConsoleService.h" -static const GLint VERTEX_ATTRIB_LOCATION = 0; - namespace mozilla { namespace layers { using namespace mozilla::gl; +int LayerManagerOGLProgram::sCurrentProgramKey = 0; + +static void +DumpLayerAndChildren(LayerOGL *l, int advance = 0) +{ + for (int i = 0; i < advance; i++) + fprintf(stderr, " "); + + fprintf(stderr, "%p: Layer type %d\n", l, l->GetType()); + + l = l->GetFirstChildOGL(); + while (l) { + DumpLayerAndChildren(l, advance+1); + l = l->GetNextSibling(); + } +} + /** * LayerManagerOGL */ LayerManagerOGL::LayerManagerOGL(nsIWidget *aWidget) : mWidget(aWidget) - , mBackBuffer(0) - , mFrameBuffer(0) - , mRGBLayerProgram(NULL) - , mYCbCrLayerProgram(NULL) - , mVertexShader(0) - , mRGBShader(0) - , mYUVShader(0) + , mBackBufferFBO(0) + , mBackBufferTexture(0) + , mHasBGRA(0) { } LayerManagerOGL::~LayerManagerOGL() { - mGLContext->MakeCurrent(); - delete mRGBLayerProgram; - delete mColorLayerProgram; - delete mYCbCrLayerProgram; + if (mGLContext) + mGLContext->MakeCurrent(); + + for (unsigned int i = 0; i < mPrograms.Length(); ++i) + delete mPrograms[i]; + + mPrograms.Clear(); } PRBool @@ -89,159 +105,157 @@ LayerManagerOGL::Initialize() mGLContext = sGLContextProvider.CreateForWindow(mWidget); if (!mGLContext) { + NS_WARNING("Failed to create LayerManagerOGL context"); return PR_FALSE; } MakeCurrent(); - mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA, LOCAL_GL_ONE, LOCAL_GL_ONE); + DEBUG_GL_ERROR_CHECK(mGLContext); + + const char *extensionStr = + (const char*) mGLContext->fGetString(LOCAL_GL_EXTENSIONS); + + mHasBGRA = (strstr(extensionStr, "EXT_bgra") != nsnull); + + mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA, + LOCAL_GL_ONE, LOCAL_GL_ONE); mGLContext->fEnable(LOCAL_GL_BLEND); - mGLContext->fEnable(LOCAL_GL_TEXTURE_2D); - mGLContext->fEnable(LOCAL_GL_SCISSOR_TEST); - mVertexShader = mGLContext->fCreateShader(LOCAL_GL_VERTEX_SHADER); - mRGBShader = mGLContext->fCreateShader(LOCAL_GL_FRAGMENT_SHADER); - mColorShader = mGLContext->fCreateShader(LOCAL_GL_FRAGMENT_SHADER); - mYUVShader = mGLContext->fCreateShader(LOCAL_GL_FRAGMENT_SHADER); + // We unfortunately can't do generic initialization here, since the + // concrete type actually matters. This macro generates the + // initialization using a concrete type and index. +#define SHADER_PROGRAM(penum, ptype, vsstr, fsstr) do { \ + NS_ASSERTION(programIndex++ == penum, "out of order shader initialization!"); \ + ptype *p = new ptype(mGLContext); \ + if (!p->Initialize(vsstr, fsstr)) \ + return PR_FALSE; \ + mPrograms.AppendElement(p); \ + } while (0) - mGLContext->fShaderSource(mVertexShader, 1, (const GLchar**)&sVertexShader, NULL); - mGLContext->fShaderSource(mRGBShader, 1, (const GLchar**)&sRGBLayerPS, NULL); - mGLContext->fShaderSource(mColorShader, 1, (const GLchar**)&sColorLayerPS, NULL); - mGLContext->fShaderSource(mYUVShader, 1, (const GLchar**)&sYUVLayerPS, NULL); - mGLContext->fCompileShader(mVertexShader); - mGLContext->fCompileShader(mRGBShader); - mGLContext->fCompileShader(mColorShader); - mGLContext->fCompileShader(mYUVShader); + // NOTE: Order matters here, and should be in the same order as the + // ProgramType enum! + GLint programIndex = 0; - GLint status; - mGLContext->fGetShaderiv(mVertexShader, LOCAL_GL_COMPILE_STATUS, &status); - if (!status) { - return false; - } + /* Layer programs */ + SHADER_PROGRAM(RGBALayerProgramType, ColorTextureLayerProgram, + sLayerVS, sRGBATextureLayerFS); + SHADER_PROGRAM(BGRALayerProgramType, ColorTextureLayerProgram, + sLayerVS, sBGRATextureLayerFS); + SHADER_PROGRAM(RGBXLayerProgramType, ColorTextureLayerProgram, + sLayerVS, sRGBXTextureLayerFS); + SHADER_PROGRAM(BGRXLayerProgramType, ColorTextureLayerProgram, + sLayerVS, sBGRXTextureLayerFS); + SHADER_PROGRAM(RGBARectLayerProgramType, ColorTextureLayerProgram, + sLayerVS, sRGBARectTextureLayerFS); + SHADER_PROGRAM(ColorLayerProgramType, SolidColorLayerProgram, + sLayerVS, sSolidColorLayerFS); + SHADER_PROGRAM(YCbCrLayerProgramType, YCbCrTextureLayerProgram, + sLayerVS, sYCbCrTextureLayerFS); + /* Copy programs (used for final framebuffer blit) */ + SHADER_PROGRAM(Copy2DProgramType, CopyProgram, + sCopyVS, sCopy2DFS); + SHADER_PROGRAM(Copy2DRectProgramType, CopyProgram, + sCopyVS, sCopy2DRectFS); - mGLContext->fGetShaderiv(mRGBShader, LOCAL_GL_COMPILE_STATUS, &status); - if (!status) { - return false; - } +#undef SHADER_PROGRAM - mGLContext->fGetShaderiv(mColorShader, LOCAL_GL_COMPILE_STATUS, &status); - if (!status) { - return false; - } - - mGLContext->fGetShaderiv(mYUVShader, LOCAL_GL_COMPILE_STATUS, &status); - if (!status) { - return false; - } + NS_ASSERTION(programIndex == NumProgramTypes, + "not all programs were initialized!"); /** * We'll test the ability here to bind NPOT textures to a framebuffer, if - * this fails we'll try EXT_texture_rectangle. + * this fails we'll try ARB_texture_rectangle. */ - mGLContext->fGenFramebuffers(1, &mFrameBuffer); + mGLContext->fGenFramebuffers(1, &mBackBufferFBO); - GLenum textureTargets[] = { LOCAL_GL_TEXTURE_2D, - LOCAL_GL_TEXTURE_RECTANGLE_EXT }; - mFBOTextureTarget = 0; + GLenum textureTargets[] = { + LOCAL_GL_TEXTURE_2D, +#ifndef USE_GLES2 + LOCAL_GL_TEXTURE_RECTANGLE_ARB +#endif + }; + + mFBOTextureTarget = LOCAL_GL_NONE; for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(textureTargets); i++) { - mGLContext->fGenTextures(1, &mBackBuffer); - mGLContext->fBindTexture(textureTargets[i], mBackBuffer); - mGLContext->fTexParameteri(textureTargets[i], + GLenum target = textureTargets[i]; + mGLContext->fGenTextures(1, &mBackBufferTexture); + mGLContext->fBindTexture(target, mBackBufferTexture); + mGLContext->fTexParameteri(target, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_NEAREST); - mGLContext->fTexParameteri(textureTargets[i], + mGLContext->fTexParameteri(target, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_NEAREST); - mGLContext->fTexImage2D(textureTargets[i], + mGLContext->fTexImage2D(target, 0, LOCAL_GL_RGBA, - 200, - 100, + 5, 3, /* sufficiently NPOT */ 0, LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, NULL); - mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mFrameBuffer); + // unbind this texture, in preparation for binding it to the FBO + mGLContext->fBindTexture(target, 0); + + mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mBackBufferFBO); mGLContext->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, - textureTargets[i], - mBackBuffer, + target, + mBackBufferTexture, 0); if (mGLContext->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER) == - LOCAL_GL_FRAMEBUFFER_COMPLETE) { - mFBOTextureTarget = textureTargets[i]; - break; + LOCAL_GL_FRAMEBUFFER_COMPLETE) + { + mFBOTextureTarget = target; + break; } - mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0); - mGLContext->fBindTexture(textureTargets[i], 0); - /** - * We need to delete this texture since we can't bind a texture multiple - * time to different textures. - */ - mGLContext->fDeleteTextures(1, &mBackBuffer); + // We weren't succesful with this texture, so we don't need it + // any more. + mGLContext->fDeleteTextures(1, &mBackBufferTexture); } - if (mFBOTextureTarget == 0) { + + if (mFBOTextureTarget == LOCAL_GL_NONE) { /* Unable to find a texture target that works with FBOs and NPOT textures */ return false; } - mRGBLayerProgram = new RGBLayerProgram(); - if (!mRGBLayerProgram->Initialize(mVertexShader, mRGBShader, mGLContext)) { - return false; - } - mColorLayerProgram = new ColorLayerProgram(); - if (!mColorLayerProgram->Initialize(mVertexShader, mColorShader, mGLContext)) { - return false; - } - mYCbCrLayerProgram = new YCbCrLayerProgram(); - if (!mYCbCrLayerProgram->Initialize(mVertexShader, mYUVShader, mGLContext)) { - return false; + if (mFBOTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB) { + /* If we're using TEXTURE_RECTANGLE, then we must have the ARB + * extension -- the EXT variant does not provide support for + * texture rectangle access inside GLSL (sampler2DRect, + * texture2DRect). + */ + if (strstr(extensionStr, "ARB_texture_rectangle") == NULL) + return false; } - mRGBLayerProgram->UpdateLocations(); - mColorLayerProgram->UpdateLocations(); - mYCbCrLayerProgram->UpdateLocations(); + // back to default framebuffer, to avoid confusion + mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0); - mGLContext->fGenBuffers(1, &mVBO); - mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mVBO); - mGLContext->fEnableClientState(LOCAL_GL_VERTEX_ARRAY); - mGLContext->fEnableVertexAttribArray(VERTEX_ATTRIB_LOCATION); + DEBUG_GL_ERROR_CHECK(mGLContext); - GLfloat vertices[] = { 0, 0, 1.0f, 0, 0, 1.0f, 1.0f, 1.0f }; + /* Create a simple quad VBO */ + + mGLContext->fGenBuffers(1, &mQuadVBO); + mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO); + + GLfloat vertices[] = { + /* First quad vertices */ + 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, + /* Then quad texcoords */ + 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, + /* Then flipped quad texcoords */ + 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, + }; mGLContext->fBufferData(LOCAL_GL_ARRAY_BUFFER, sizeof(vertices), vertices, LOCAL_GL_STATIC_DRAW); - mRGBLayerProgram->Activate(); - mGLContext->fVertexAttribPointer(VERTEX_ATTRIB_LOCATION, - 2, - LOCAL_GL_FLOAT, - LOCAL_GL_FALSE, - 0, - 0); - mColorLayerProgram->Activate(); - mGLContext->fVertexAttribPointer(VERTEX_ATTRIB_LOCATION, - 2, - LOCAL_GL_FLOAT, - LOCAL_GL_FALSE, - 0, - 0); - mYCbCrLayerProgram->Activate(); - mGLContext->fVertexAttribPointer(VERTEX_ATTRIB_LOCATION, - 2, - LOCAL_GL_FLOAT, - LOCAL_GL_FALSE, - 0, - 0); - - mRGBLayerProgram->SetLayerTexture(0); - - mYCbCrLayerProgram->SetYTexture(0); - mYCbCrLayerProgram->SetCbTexture(1); - mYCbCrLayerProgram->SetCrTexture(2); + DEBUG_GL_ERROR_CHECK(mGLContext); nsCOMPtr console(do_GetService(NS_CONSOLESERVICE_CONTRACTID)); @@ -258,9 +272,16 @@ LayerManagerOGL::Initialize() msg += NS_LITERAL_STRING("\nRenderer: "); msg += NS_ConvertUTF8toUTF16( nsDependentCString((const char*)mGLContext->fGetString(LOCAL_GL_RENDERER))); + msg += NS_LITERAL_STRING("\nFBO Texture Target: "); + if (mFBOTextureTarget == LOCAL_GL_TEXTURE_2D) + msg += NS_LITERAL_STRING("TEXTURE_2D"); + else + msg += NS_LITERAL_STRING("TEXTURE_RECTANGLE"); console->LogStringMessage(msg.get()); } + DEBUG_GL_ERROR_CHECK(mGLContext); + return true; } @@ -273,6 +294,7 @@ LayerManagerOGL::SetClippingRegion(const nsIntRegion& aClippingRegion) void LayerManagerOGL::BeginTransaction() { + NS_ASSERTION(mRootLayer, "Root not set"); } void @@ -285,14 +307,21 @@ void LayerManagerOGL::EndTransaction(DrawThebesLayerCallback aCallback, void* aCallbackData) { - Render(aCallback, aCallbackData); + mThebesLayerCallback = aCallback; + mThebesLayerCallbackData = aCallbackData; + + Render(); + + mThebesLayerCallback = nsnull; + mThebesLayerCallbackData = nsnull; + mTarget = NULL; } void LayerManagerOGL::SetRoot(Layer *aLayer) { - mRootLayer = static_cast(aLayer->ImplData());; + mRootLayer = static_cast(aLayer->ImplData());; } already_AddRefed @@ -337,190 +366,206 @@ LayerManagerOGL::CreateCanvasLayer() return layer.forget(); } -void -LayerManagerOGL::SetClippingEnabled(PRBool aEnabled) -{ - if (aEnabled) { - mGLContext->fEnable(LOCAL_GL_SCISSOR_TEST); - } else { - mGLContext->fDisable(LOCAL_GL_SCISSOR_TEST); - } -} - void LayerManagerOGL::MakeCurrent() { - mGLContext->MakeCurrent(); + mGLContext->MakeCurrent(); } void -LayerManagerOGL::Render(DrawThebesLayerCallback aCallback, - void* aCallbackData) +LayerManagerOGL::Render() { + static int rcount = 0; + + //DumpLayerAndChildren(mRootLayer); + nsIntRect rect; mWidget->GetBounds(rect); GLint width = rect.width; GLint height = rect.height; MakeCurrent(); - SetupBackBuffer(); - mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mFrameBuffer); - mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA, LOCAL_GL_ONE, LOCAL_GL_ONE); - mGLContext->fClearColor(0.0, 0.0, 0.0, 0.0); - mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT); + DEBUG_GL_ERROR_CHECK(mGLContext); - SetupPipeline(); - SetClippingEnabled(PR_FALSE); + SetupBackBuffer(width, height); + SetupPipeline(width, height); - if (mRootLayer) { - const nsIntRect *clipRect = mRootLayer->GetLayer()->GetClipRect(); - if (clipRect) { - mGLContext->fScissor(clipRect->x, clipRect->y, clipRect->width, clipRect->height); - } else { - mGLContext->fScissor(0, 0, width, height); - } + // Default blend function implements "OVER" + mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA, + LOCAL_GL_ONE, LOCAL_GL_ONE); - mRootLayer->RenderLayer(mFrameBuffer, aCallback, aCallbackData); + DEBUG_GL_ERROR_CHECK(mGLContext); + +#if 0 + // XXX for whatever reason, scissor is not working -- even with no + // cliprect set, so we go through the 0,0,w,h path, any updates + // after the initial render end up failing the scissor rectangle. I + // have no idea why. We disable it for now, because it's not actually + // helping us with anything -- we draw to a specific location in the + // front buffer as it is. + + const nsIntRect *clipRect = mRootLayer->GetLayer()->GetClipRect(); + + if (clipRect) { + mGLContext->fScissor(clipRect->x, clipRect->y, + clipRect->width, clipRect->height); + } else { + mGLContext->fScissor(0, 0, width, height); } + mGLContext->fEnable(LOCAL_GL_SCISSOR_TEST); +#else + mGLContext->fDisable(LOCAL_GL_SCISSOR_TEST); +#endif + + DEBUG_GL_ERROR_CHECK(mGLContext); + + // Render our layers. + mRootLayer->RenderLayer(mBackBufferFBO, nsIntPoint(0, 0)); + + DEBUG_GL_ERROR_CHECK(mGLContext); + if (mTarget) { CopyToTarget(); - } else { - /** - * Draw our backbuffer to the screen without using vertex or fragment - * shaders. We're fine with just calculating the viewport coordinates - * in software. And nothing special is required for the texture sampling. - */ - mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0); - mGLContext->fUseProgram(0); - if (mFBOTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE_EXT) { - mGLContext->fEnable(LOCAL_GL_TEXTURE_RECTANGLE_EXT); - } - mGLContext->fDisableVertexAttribArray(VERTEX_ATTRIB_LOCATION); - mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); - mGLContext->fEnableClientState(LOCAL_GL_VERTEX_ARRAY); - mGLContext->fEnableClientState(LOCAL_GL_TEXTURE_COORD_ARRAY); - mGLContext->fBindTexture(mFBOTextureTarget, mBackBuffer); - - const nsIntRect *r; - for (nsIntRegionRectIterator iter(mClippingRegion); - (r = iter.Next()) != nsnull;) { - mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ZERO, LOCAL_GL_ONE, LOCAL_GL_ZERO); - float left = (GLfloat)r->x / width; - float right = (GLfloat)r->XMost() / width; - float top = (GLfloat)r->y / height; - float bottom = (GLfloat)r->YMost() / height; - - float vertices[] = { left * 2.0f - 1.0f, - -(top * 2.0f - 1.0f), - right * 2.0f - 1.0f, - -(top * 2.0f - 1.0f), - left * 2.0f - 1.0f, - -(bottom * 2.0f - 1.0f), - right * 2.0f - 1.0f, - -(bottom * 2.0f - 1.0f) }; - - float coords[8]; - if (mFBOTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE_EXT) { - /* These are in non-normalized texture coords */ - coords[0] = (GLfloat)r->x; coords[1] = (GLfloat)r->y; - coords[2] = (GLfloat)r->XMost(); coords[3] = (GLfloat)r->y; - coords[4] = (GLfloat)r->x; coords[5] = (GLfloat)r->YMost(); - coords[6] = (GLfloat)r->XMost(); coords[7] = (GLfloat)r->YMost(); - } else { - coords[0] = left; coords[1] = top; - coords[2] = right; coords[3] = top; - coords[4] = left; coords[5] = bottom; - coords[6] = right; coords[7] = bottom; - } - - mGLContext->fVertexPointer(2, LOCAL_GL_FLOAT, 0, vertices); - mGLContext->fTexCoordPointer(2, LOCAL_GL_FLOAT, 0, coords); - mGLContext->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4); - } - mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mVBO); - mGLContext->fEnableVertexAttribArray(VERTEX_ATTRIB_LOCATION); - mGLContext->fDisableClientState(LOCAL_GL_TEXTURE_COORD_ARRAY); - if (mFBOTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE_EXT) { - mGLContext->fDisable(LOCAL_GL_TEXTURE_RECTANGLE_EXT); - } + return; } + mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0); + + mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0); + + CopyProgram *copyprog = GetCopy2DProgram(); + + if (mFBOTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB) { + copyprog = GetCopy2DRectProgram(); + } + + mGLContext->fBindTexture(mFBOTextureTarget, mBackBufferTexture); + + copyprog->Activate(); + copyprog->SetTextureUnit(0); + + if (copyprog->GetTexCoordMultiplierUniformLocation() != -1) { + float f[] = { float(width), float(height) }; + copyprog->SetUniform(copyprog->GetTexCoordMultiplierUniformLocation(), + 2, f); + } + + DEBUG_GL_ERROR_CHECK(mGLContext); + + // we're going to use client-side vertex arrays for this. + mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); + + // "COPY" + mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ZERO, + LOCAL_GL_ONE, LOCAL_GL_ZERO); + + // enable our vertex attribs; we'll call glVertexPointer below + // to fill with the correct data. + GLint vcattr = copyprog->AttribLocation(CopyProgram::VertexCoordAttrib); + GLint tcattr = copyprog->AttribLocation(CopyProgram::TexCoordAttrib); + + mGLContext->fEnableVertexAttribArray(vcattr); + mGLContext->fEnableVertexAttribArray(tcattr); + + const nsIntRect *r; + nsIntRegionRectIterator iter(mClippingRegion); + + while ((r = iter.Next()) != nsnull) { + float left = (GLfloat)r->x / width; + float right = (GLfloat)r->XMost() / width; + float top = (GLfloat)r->y / height; + float bottom = (GLfloat)r->YMost() / height; + + float vertices[] = { left * 2.0f - 1.0f, + -(top * 2.0f - 1.0f), + right * 2.0f - 1.0f, + -(top * 2.0f - 1.0f), + left * 2.0f - 1.0f, + -(bottom * 2.0f - 1.0f), + right * 2.0f - 1.0f, + -(bottom * 2.0f - 1.0f) }; + + float coords[] = { left, top, + right, top, + left, bottom, + right, bottom }; + + mGLContext->fVertexAttribPointer(vcattr, + 2, LOCAL_GL_FLOAT, + LOCAL_GL_FALSE, + 0, vertices); + + mGLContext->fVertexAttribPointer(tcattr, + 2, LOCAL_GL_FLOAT, + LOCAL_GL_FALSE, + 0, coords); + + mGLContext->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4); + DEBUG_GL_ERROR_CHECK(mGLContext); + } + + mGLContext->fDisableVertexAttribArray(vcattr); + mGLContext->fDisableVertexAttribArray(tcattr); + + DEBUG_GL_ERROR_CHECK(mGLContext); + mGLContext->fFinish(); + + DEBUG_GL_ERROR_CHECK(mGLContext); } void -LayerManagerOGL::SetupPipeline() +LayerManagerOGL::SetupPipeline(int aWidth, int aHeight) { - nsIntRect rect; - mWidget->GetBounds(rect); + // Set the viewport correctly + mGLContext->fViewport(0, 0, aWidth, aHeight); - mGLContext->fViewport(0, 0, rect.width, rect.height); + // Matrix to transform to viewport space ( <-1.0, 1.0> topleft, + // <1.0, -1.0> bottomright) + gfx3DMatrix viewMatrix; + viewMatrix._11 = 2.0f / float(aWidth); + viewMatrix._22 = 2.0f / float(aHeight); + viewMatrix._41 = -1.0f; + viewMatrix._42 = -1.0f; - float viewMatrix[4][4]; - /** - * Matrix to transform to viewport space ( <-1.0, 1.0> topleft, - * <1.0, -1.0> bottomright) - */ - memset(&viewMatrix, 0, sizeof(viewMatrix)); - viewMatrix[0][0] = 2.0f / rect.width; - viewMatrix[1][1] = 2.0f / rect.height; - viewMatrix[2][2] = 1.0f; - viewMatrix[3][0] = -1.0f; - viewMatrix[3][1] = -1.0f; - viewMatrix[3][3] = 1.0f; - - mRGBLayerProgram->Activate(); - mRGBLayerProgram->SetMatrixProj(&viewMatrix[0][0]); - - mColorLayerProgram->Activate(); - mColorLayerProgram->SetMatrixProj(&viewMatrix[0][0]); - - mYCbCrLayerProgram->Activate(); - mYCbCrLayerProgram->SetMatrixProj(&viewMatrix[0][0]); + SetLayerProgramProjectionMatrix(viewMatrix); } -PRBool -LayerManagerOGL::SetupBackBuffer() +void +LayerManagerOGL::SetupBackBuffer(int aWidth, int aHeight) { - nsIntRect rect; - mWidget->GetBounds(rect); - GLint width = rect.width; - GLint height = rect.height; - - if (width == mBackBufferSize.width && height == mBackBufferSize.height) { - return PR_TRUE; + // Do we have a FBO of the right size already? + if (mBackBufferSize.width == aWidth && + mBackBufferSize.height == aHeight) + { + mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mBackBufferFBO); + return; } - /** - * Setup the texture used as the backbuffer. We use a texture as our - * backbuffer since we can rely on both GLES and OGL 2.1 to support this - * method. - */ - mGLContext->fBindTexture(mFBOTextureTarget, mBackBuffer); - mGLContext->fTexEnvf(LOCAL_GL_TEXTURE_ENV, LOCAL_GL_TEXTURE_ENV_MODE, LOCAL_GL_MODULATE); - mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_NEAREST); - mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_NEAREST); + // we already have a FBO, but we need to resize its texture. + mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0); + mGLContext->fBindTexture(mFBOTextureTarget, mBackBufferTexture); mGLContext->fTexImage2D(mFBOTextureTarget, - 0, - LOCAL_GL_RGBA, - width, - height, - 0, - LOCAL_GL_RGBA, - LOCAL_GL_UNSIGNED_BYTE, - NULL); + 0, + LOCAL_GL_RGBA, + aWidth, aHeight, + 0, + LOCAL_GL_RGBA, + LOCAL_GL_UNSIGNED_BYTE, + NULL); + mGLContext->fBindTexture(mFBOTextureTarget, 0); - /* Bind our framebuffer to make our content render into our backbuffer. */ - mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mFrameBuffer); + mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mBackBufferFBO); mGLContext->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, - LOCAL_GL_COLOR_ATTACHMENT0, - mFBOTextureTarget, - mBackBuffer, - 0); + LOCAL_GL_COLOR_ATTACHMENT0, + mFBOTextureTarget, + mBackBufferTexture, + 0); - return PR_TRUE; + mBackBufferSize.width = aWidth; + mBackBufferSize.height = aHeight; } void @@ -531,7 +576,7 @@ LayerManagerOGL::CopyToTarget() GLint width = rect.width; GLint height = rect.height; - if ((PRInt64)width * (PRInt64)height > PR_INT32_MAX) { + if ((PRInt64(width) * PRInt64(height) * PRInt64(4)) > PR_INT32_MAX) { NS_ERROR("Widget size too big - integer overflow!"); return; } @@ -540,193 +585,115 @@ LayerManagerOGL::CopyToTarget() new gfxImageSurface(gfxIntSize(width, height), gfxASurface::ImageFormatARGB32); +#ifdef USE_GLES2 + // GLES2 promises that binding to any custom FBO will attach + // to GL_COLOR_ATTACHMENT0 attachment point. + mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mBackBufferFBO); +#else mGLContext->fReadBuffer(LOCAL_GL_COLOR_ATTACHMENT0); +#endif - if (imageSurface->Stride() != width * 4) { - char *tmpData = new char[width * height * 4]; + GLenum format = LOCAL_GL_RGBA; + if (mHasBGRA) + format = LOCAL_GL_BGRA; - mGLContext->fReadPixels(0, - 0, - width, - height, - LOCAL_GL_BGRA, - LOCAL_GL_UNSIGNED_BYTE, - tmpData); - mGLContext->fFinish(); + NS_ASSERTION(imageSurface->Stride() == width * 4, + "Image Surfaces being created with weird stride!"); - for (int y = 0; y < height; y++) { - memcpy(imageSurface->Data() + imageSurface->Stride() * y, - tmpData + width * 4 * y, - width * 4); - } - delete [] tmpData; - } else { - mGLContext->fReadPixels(0, - 0, - width, - height, - LOCAL_GL_BGRA, + mGLContext->fReadPixels(0, 0, + width, height, + format, LOCAL_GL_UNSIGNED_BYTE, imageSurface->Data()); - mGLContext->fFinish(); - } + + if (!mHasBGRA) { + // need to swap B and R bytes + for (int j = 0; j < height; ++j) { + PRUint32 *row = (PRUint32*) (imageSurface->Data() + imageSurface->Stride() * j); + for (int i = 0; i < width; ++i) { + *row = (*row & 0xff00ff00) | ((*row & 0xff) << 16) | ((*row & 0xff0000) >> 16); + row++; + } + } + } mTarget->SetOperator(gfxContext::OPERATOR_OVER); mTarget->SetSource(imageSurface); mTarget->Paint(); } -LayerOGL::LayerOGL(LayerManagerOGL *aManager) - : mOGLManager(aManager) - , mNextSibling(NULL) -{ -} +LayerManagerOGL::ProgramType LayerManagerOGL::sLayerProgramTypes[] = { + LayerManagerOGL::RGBALayerProgramType, + LayerManagerOGL::BGRALayerProgramType, + LayerManagerOGL::RGBXLayerProgramType, + LayerManagerOGL::BGRXLayerProgramType, + LayerManagerOGL::RGBARectLayerProgramType, + LayerManagerOGL::ColorLayerProgramType, + LayerManagerOGL::YCbCrLayerProgramType +}; -LayerOGL* -LayerOGL::GetNextSibling() +#define FOR_EACH_LAYER_PROGRAM(vname) \ + for (int lpindex = 0; \ + lpindex < sizeof(sLayerProgramTypes)/sizeof(int); \ + ++lpindex) \ + { \ + LayerProgram *vname = static_cast \ + (mPrograms[sLayerProgramTypes[lpindex]]); \ + do + +#define FOR_EACH_LAYER_PROGRAM_END \ + while (0); \ + } \ + +void +LayerManagerOGL::SetLayerProgramProjectionMatrix(const gfx3DMatrix& aMatrix) { - return mNextSibling; + FOR_EACH_LAYER_PROGRAM(lp) { + lp->Activate(); + lp->SetProjectionMatrix(aMatrix); + } FOR_EACH_LAYER_PROGRAM_END } void -LayerOGL::SetNextSibling(LayerOGL *aNextSibling) +LayerManagerOGL::CreateFBOWithTexture(int aWidth, int aHeight, + GLuint *aFBO, GLuint *aTexture) { - mNextSibling = aNextSibling; -} - -/** - * LayerProgram Helpers - */ -LayerProgram::LayerProgram() - : mGLContext(NULL) - , mProgram(0) -{ -} - -LayerProgram::~LayerProgram() -{ - mGLContext->fDeleteProgram(mProgram); -} - -PRBool -LayerProgram::Initialize(GLuint aVertexShader, - GLuint aFragmentShader, - mozilla::gl::GLContext *aContext) -{ - mGLContext = aContext; - - mProgram = mGLContext->fCreateProgram(); - mGLContext->fAttachShader(mProgram, aVertexShader); - mGLContext->fAttachShader(mProgram, aFragmentShader); - - mGLContext->fBindAttribLocation(mProgram, VERTEX_ATTRIB_LOCATION, "aVertex"); - - mGLContext->fLinkProgram(mProgram); - - GLint status; - mGLContext->fGetProgramiv(mProgram, LOCAL_GL_LINK_STATUS, &status); - - if (!status) { - return false; - } - return true; -} - -void -LayerProgram::Activate() -{ - mGLContext->fUseProgram(mProgram); -} - -void -LayerProgram::UpdateLocations() -{ - mMatrixProjLocation = mGLContext->fGetUniformLocation(mProgram, "uMatrixProj"); - mLayerQuadTransformLocation = - mGLContext->fGetUniformLocation(mProgram, "uLayerQuadTransform"); - mLayerTransformLocation = mGLContext->fGetUniformLocation(mProgram, "uLayerTransform"); - mRenderTargetOffsetLocation = - mGLContext->fGetUniformLocation(mProgram, "uRenderTargetOffset"); - mLayerOpacityLocation = mGLContext->fGetUniformLocation(mProgram, "uLayerOpacity"); -} - -void -LayerProgram::SetMatrixUniform(GLint aLocation, const GLfloat *aValue) -{ - mGLContext->fUniformMatrix4fv(aLocation, 1, false, aValue); -} - -void -LayerProgram::SetInt(GLint aLocation, GLint aValue) -{ - mGLContext->fUniform1i(aLocation, aValue); -} - -void -LayerProgram::SetColor(GLint aLocation, const gfxRGBA& aColor) -{ - mGLContext->fUniform4f(aLocation, aColor.r, aColor.g, aColor.b, aColor.a); -} - -void -LayerProgram::SetLayerOpacity(GLfloat aValue) -{ - mGLContext->fUniform1f(mLayerOpacityLocation, aValue); -} - -void -LayerProgram::PushRenderTargetOffset(GLfloat aValueX, GLfloat aValueY) -{ - GLvec2 vector; - vector.mX = aValueX; - vector.mY = aValueY; - mRenderTargetOffsetStack.AppendElement(vector); -} - -void -LayerProgram::PopRenderTargetOffset() -{ - NS_ASSERTION(mRenderTargetOffsetStack.Length(), "Unbalanced push/pops"); - mRenderTargetOffsetStack.RemoveElementAt(mRenderTargetOffsetStack.Length() - 1); -} - -void -LayerProgram::Apply() -{ - if (!mRenderTargetOffsetStack.Length()) { - mGLContext->fUniform4f(mRenderTargetOffsetLocation, 0, 0, 0, 0); - } else { - GLvec2 vector = - mRenderTargetOffsetStack[mRenderTargetOffsetStack.Length() - 1]; - mGLContext->fUniform4f(mRenderTargetOffsetLocation, vector.mX, vector.mY, 0, 0); - } -} - -void -RGBLayerProgram::UpdateLocations() -{ - LayerProgram::UpdateLocations(); - - mLayerTextureLocation = mGLContext->fGetUniformLocation(mProgram, "uLayerTexture"); -} - -void -ColorLayerProgram::UpdateLocations() -{ - LayerProgram::UpdateLocations(); - - mRenderColorLocation = mGLContext->fGetUniformLocation(mProgram, "uRenderColor"); -} - -void -YCbCrLayerProgram::UpdateLocations() -{ - LayerProgram::UpdateLocations(); - - mYTextureLocation = mGLContext->fGetUniformLocation(mProgram, "uYTexture"); - mCbTextureLocation = mGLContext->fGetUniformLocation(mProgram, "uCbTexture"); - mCrTextureLocation = mGLContext->fGetUniformLocation(mProgram, "uCrTexture"); + GLuint tex, fbo; + + mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0); + mGLContext->fGenTextures(1, &tex); + mGLContext->fBindTexture(mFBOTextureTarget, tex); + mGLContext->fTexImage2D(mFBOTextureTarget, + 0, + LOCAL_GL_RGBA, + aWidth, aHeight, + 0, + LOCAL_GL_RGBA, + LOCAL_GL_UNSIGNED_BYTE, + NULL); + mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_MIN_FILTER, + LOCAL_GL_LINEAR); + mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_MAG_FILTER, + LOCAL_GL_LINEAR); + mGLContext->fBindTexture(mFBOTextureTarget, 0); + + mGLContext->fGenFramebuffers(1, &fbo); + mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, fbo); + mGLContext->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, + LOCAL_GL_COLOR_ATTACHMENT0, + mFBOTextureTarget, + tex, + 0); + + NS_ASSERTION(mGLContext->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER) == + LOCAL_GL_FRAMEBUFFER_COMPLETE, "Error setting up framebuffer."); + + *aFBO = fbo; + *aTexture = tex; + + DEBUG_GL_ERROR_CHECK(gl()); } + } /* layers */ } /* mozilla */ diff --git a/gfx/layers/opengl/LayerManagerOGL.h b/gfx/layers/opengl/LayerManagerOGL.h index cb613c327565..ab6e9001c315 100644 --- a/gfx/layers/opengl/LayerManagerOGL.h +++ b/gfx/layers/opengl/LayerManagerOGL.h @@ -20,6 +20,8 @@ * * Contributor(s): * Bas Schouten + * Frederic Plourde + * Vladimir Vukicevic * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -57,126 +59,17 @@ typedef int GLsizei; #define BUFFER_OFFSET(i) ((char *)NULL + (i)) #include "gfxContext.h" +#include "gfx3DMatrix.h" #include "nsIWidget.h" #include "GLContext.h" +#include "LayerManagerOGLProgram.h" + namespace mozilla { namespace layers { class LayerOGL; -struct GLvec2 -{ - GLfloat mX; - GLfloat mY; -}; - -/** - * Helper class for Layer Programs. - */ -class LayerProgram -{ -public: - LayerProgram(); - virtual ~LayerProgram(); - - PRBool Initialize(GLuint aVertexShader, - GLuint aFragmentShader, - mozilla::gl::GLContext *aContext); - - virtual void UpdateLocations(); - - void Activate(); - - void SetMatrixUniform(GLint aLocation, const GLfloat *aValue); - void SetInt(GLint aLocation, GLint aValue); - void SetColor(GLint aLocation, const gfxRGBA& aColor); - - void SetMatrixProj(GLfloat *aValue) - { - SetMatrixUniform(mMatrixProjLocation, aValue); - } - - void SetLayerQuadTransform(GLfloat *aValue) - { - SetMatrixUniform(mLayerQuadTransformLocation, aValue); - } - - void SetLayerTransform(const GLfloat *aValue) - { - SetMatrixUniform(mLayerTransformLocation, aValue); - } - - void SetLayerOpacity(GLfloat aValue); - - void PushRenderTargetOffset(GLfloat aValueX, GLfloat aValueY); - void PopRenderTargetOffset(); - - void Apply(); - -protected: - mozilla::gl::GLContext *mGLContext; - - GLuint mProgram; - GLint mMatrixProjLocation; - GLint mLayerQuadTransformLocation; - GLint mLayerTransformLocation; - GLint mRenderTargetOffsetLocation; - GLint mLayerOpacityLocation; - - nsTArray mRenderTargetOffsetStack; -}; - -class RGBLayerProgram : public LayerProgram -{ -public: - void UpdateLocations(); - - void SetLayerTexture(GLint aValue) - { - SetInt(mLayerTextureLocation, aValue); - } -protected: - GLint mLayerTextureLocation; -}; - -class ColorLayerProgram : public LayerProgram -{ -public: - void UpdateLocations(); - - void SetLayerColor(const gfxRGBA& aColor) - { - SetColor(mRenderColorLocation, aColor); - } - -protected: - GLint mRenderColorLocation; -}; - -class YCbCrLayerProgram : public LayerProgram -{ -public: - void UpdateLocations(); - - void SetYTexture(GLint aValue) - { - SetInt(mYTextureLocation, aValue); - } - void SetCbTexture(GLint aValue) - { - SetInt(mCbTextureLocation, aValue); - } - void SetCrTexture(GLint aValue) - { - SetInt(mCrTextureLocation, aValue); - } -protected: - GLint mYTextureLocation; - GLint mCbTextureLocation; - GLint mCrTextureLocation; -}; - /** * This is the LayerManager used for OpenGL 2.1. For now this will render on * the main thread. @@ -185,7 +78,7 @@ class THEBES_API LayerManagerOGL : public LayerManager { public: LayerManagerOGL(nsIWidget *aWidget); virtual ~LayerManagerOGL(); - + /** * Initializes the layer manager, this is when the layer manager will * actually access the device and attempt to create the swap chain used @@ -238,18 +131,134 @@ public: /** * Helper methods. */ - void SetClippingEnabled(PRBool aEnabled); - void MakeCurrent(); - RGBLayerProgram *GetRGBLayerProgram() { return mRGBLayerProgram; } - ColorLayerProgram *GetColorLayerProgram() { return mColorLayerProgram; } - YCbCrLayerProgram *GetYCbCrLayerProgram() { return mYCbCrLayerProgram; } + ColorTextureLayerProgram *GetRGBALayerProgram() { + return static_cast(mPrograms[RGBALayerProgramType]); + } + ColorTextureLayerProgram *GetBGRALayerProgram() { + return static_cast(mPrograms[BGRALayerProgramType]); + } + ColorTextureLayerProgram *GetRGBXLayerProgram() { + return static_cast(mPrograms[RGBXLayerProgramType]); + } + ColorTextureLayerProgram *GetBGRXLayerProgram() { + return static_cast(mPrograms[BGRXLayerProgramType]); + } + ColorTextureLayerProgram *GetRGBARectLayerProgram() { + return static_cast(mPrograms[RGBARectLayerProgramType]); + } + SolidColorLayerProgram *GetColorLayerProgram() { + return static_cast(mPrograms[ColorLayerProgramType]); + } + YCbCrTextureLayerProgram *GetYCbCrLayerProgram() { + return static_cast(mPrograms[YCbCrLayerProgramType]); + } + CopyProgram *GetCopy2DProgram() { + return static_cast(mPrograms[Copy2DProgramType]); + } + CopyProgram *GetCopy2DRectProgram() { + return static_cast(mPrograms[Copy2DRectProgramType]); + } + + ColorTextureLayerProgram *GetFBOLayerProgram() { + if (mFBOTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB) + return static_cast(mPrograms[RGBARectLayerProgramType]); + return static_cast(mPrograms[RGBALayerProgramType]); + } typedef mozilla::gl::GLContext GLContext; GLContext *gl() const { return mGLContext; } + /* + * Helper functions for our layers + */ + void CallThebesLayerDrawCallback(ThebesLayer* aLayer, + gfxContext* aContext, + const nsIntRegion& aRegionToDraw) + { + NS_ASSERTION(mThebesLayerCallback, + "CallThebesLayerDrawCallback without callback!"); + mThebesLayerCallback(aLayer, aContext, + aRegionToDraw, mThebesLayerCallbackData); + } + + GLenum FBOTextureTarget() { return mFBOTextureTarget; } + + /* Create a FBO backed by a texture; will leave the FBO + * bound. Note that the texture target type will be + * of the type returned by FBOTextureTarget; different + * shaders are required to sample from the different + * texture types. + */ + void CreateFBOWithTexture(int aWidth, int aHeight, + GLuint *aFBO, GLuint *aTexture); + + GLuint QuadVBO() { return mQuadVBO; } + GLintptr QuadVBOVertexOffset() { return 0; } + GLintptr QuadVBOTexCoordOffset() { return sizeof(float)*4*2; } + GLintptr QuadVBOFlippedTexCoordOffset() { return sizeof(float)*8*2; } + + void BindQuadVBO() { + mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO); + } + + void QuadVBOVerticesAttrib(GLuint aAttribIndex) { + mGLContext->fVertexAttribPointer(aAttribIndex, 2, + LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, + (GLvoid*) QuadVBOVertexOffset()); + } + + void QuadVBOTexCoordsAttrib(GLuint aAttribIndex) { + mGLContext->fVertexAttribPointer(aAttribIndex, 2, + LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, + (GLvoid*) QuadVBOTexCoordOffset()); + } + + void QuadVBOFlippedTexCoordsAttrib(GLuint aAttribIndex) { + mGLContext->fVertexAttribPointer(aAttribIndex, 2, + LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, + (GLvoid*) QuadVBOFlippedTexCoordOffset()); + } + + // Super common + + void BindAndDrawQuad(GLuint aVertAttribIndex, + GLuint aTexCoordAttribIndex, + bool aFlipped = false) + { + BindQuadVBO(); + QuadVBOVerticesAttrib(aVertAttribIndex); + + if (aTexCoordAttribIndex != -1) { + if (aFlipped) + QuadVBOFlippedTexCoordsAttrib(aTexCoordAttribIndex); + else + QuadVBOTexCoordsAttrib(aTexCoordAttribIndex); + + mGLContext->fEnableVertexAttribArray(aTexCoordAttribIndex); + } + + mGLContext->fEnableVertexAttribArray(aVertAttribIndex); + + mGLContext->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4); + + mGLContext->fDisableVertexAttribArray(aVertAttribIndex); + + if (aTexCoordAttribIndex != -1) { + mGLContext->fDisableVertexAttribArray(aTexCoordAttribIndex); + } + } + + void BindAndDrawQuad(LayerProgram *aProg, + bool aFlipped = false) + { + BindAndDrawQuad(aProg->AttribLocation(LayerProgram::VertexAttrib), + aProg->AttribLocation(LayerProgram::TexCoordAttrib), + aFlipped); + } + private: /** Widget associated with this layer manager */ nsIWidget *mWidget; @@ -260,56 +269,80 @@ private: nsRefPtr mGLContext; - /** Backbuffer */ - GLuint mBackBuffer; - /** Backbuffer size */ - nsIntSize mBackBufferSize; - /** Framebuffer */ - GLuint mFrameBuffer; - /** RGB Layer Program */ - RGBLayerProgram *mRGBLayerProgram; - /** Color Layer Program */ - ColorLayerProgram *mColorLayerProgram; - /** YUV Layer Program */ - YCbCrLayerProgram *mYCbCrLayerProgram; - /** Vertex Shader */ - GLuint mVertexShader; - /** RGB fragment shader */ - GLuint mRGBShader; - /** Solid color shader */ - GLuint mColorShader; - /** YUV fragment shader */ - GLuint mYUVShader; + enum ProgramType { + RGBALayerProgramType, + BGRALayerProgramType, + RGBXLayerProgramType, + BGRXLayerProgramType, + RGBARectLayerProgramType, + ColorLayerProgramType, + YCbCrLayerProgramType, + Copy2DProgramType, + Copy2DRectProgramType, + NumProgramTypes + }; + + static ProgramType sLayerProgramTypes[]; + /** Current root layer. */ LayerOGL *mRootLayer; - /** Vertex buffer */ - GLuint mVBO; + + /** Backbuffer */ + GLuint mBackBufferFBO; + GLuint mBackBufferTexture; + nsIntSize mBackBufferSize; + + /** Shader Programs */ + nsTArray mPrograms; + /** Texture target to use for FBOs */ GLenum mFBOTextureTarget; - /** - * Region we're clipping our current drawing to. - */ + /** VBO that has some basics in it for a textured quad, + * including vertex coords and texcoords for both + * flipped and unflipped textures */ + GLuint mQuadVBO; + + /** Region we're clipping our current drawing to. */ nsIntRegion mClippingRegion; + + /** Misc */ + PRPackedBool mHasBGRA; + /** * Render the current layer tree to the active target. */ - void Render(DrawThebesLayerCallback aCallback, - void* aCallbackData); + void Render(); /** - * Setup the pipeline. + * Setup the viewport and projection matrix for rendering + * to a window of the given dimensions. */ - void SetupPipeline(); + void SetupPipeline(int aWidth, int aHeight); /** - * Setup the backbuffer. - * - * \return PR_TRUE if setup was succesful + * Setup a backbuffer of the given dimensions. */ - PRBool SetupBackBuffer(); + void SetupBackBuffer(int aWidth, int aHeight); /** * Copies the content of our backbuffer to the set transaction target. */ void CopyToTarget(); + + /** + * Updates all layer programs with a new projection matrix. + * + * XXX we need a way to be able to delay setting this until + * the program is actually used. Maybe a DelayedSetUniform + * on Program, that will delay the set until the next Activate? + * + * XXX this is only called once per frame, so it's not awful. + * If we have any more similar updates, then we should delay. + */ + void SetLayerProgramProjectionMatrix(const gfx3DMatrix& aMatrix); + + /* Thebes layer callbacks; valid at the end of a transaciton, + * while rendering */ + DrawThebesLayerCallback mThebesLayerCallback; + void *mThebesLayerCallbackData; }; /** @@ -318,9 +351,9 @@ private: class LayerOGL { public: - typedef LayerManager::DrawThebesLayerCallback DrawThebesLayerCallback; - - LayerOGL(LayerManagerOGL *aManager); + LayerOGL(LayerManagerOGL *aManager) + : mOGLManager(aManager), mNextSibling(nsnull) + { } enum LayerType { TYPE_THEBES, @@ -332,16 +365,22 @@ public: virtual LayerType GetType() = 0; - LayerOGL *GetNextSibling(); - virtual LayerOGL *GetFirstChildOGL() { return nsnull; } + LayerOGL *GetNextSibling() { + return mNextSibling; + } - void SetNextSibling(LayerOGL *aParent); - void SetFirstChild(LayerOGL *aParent); + void SetNextSibling(LayerOGL *aSibling) { + mNextSibling = aSibling; + } + + virtual LayerOGL *GetFirstChildOGL() { + return nsnull; + } virtual Layer* GetLayer() = 0; - virtual void RenderLayer(int aPreviousFrameBuffer, DrawThebesLayerCallback aCallback, - void* aCallbackData) = 0; + virtual void RenderLayer(int aPreviousFrameBuffer, + const nsIntPoint& aOffset) = 0; typedef mozilla::gl::GLContext GLContext; @@ -351,6 +390,16 @@ protected: LayerOGL *mNextSibling; }; +#ifdef DEBUG +#define DEBUG_GL_ERROR_CHECK(cx) do { \ + /*fprintf (stderr, "trace %s %d\n", __FILE__, __LINE__);*/ \ + GLenum err = (cx)->fGetError(); \ + if (err) { fprintf (stderr, "GL ERROR: 0x%04x at %s:%d\n", err, __FILE__, __LINE__); } \ + } while (0) +#else +#define DEBUG_GL_ERROR_CHECK(cx) do { } while (0) +#endif + } /* layers */ } /* mozilla */ diff --git a/gfx/layers/opengl/LayerManagerOGLProgram.h b/gfx/layers/opengl/LayerManagerOGLProgram.h new file mode 100644 index 000000000000..6eef51cc2376 --- /dev/null +++ b/gfx/layers/opengl/LayerManagerOGLProgram.h @@ -0,0 +1,764 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Vladimir Vukicevic + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef GFX_LAYERMANAGEROGLPROGRAM_H +#define GFX_LAYERMANAGEROGLPROGRAM_H + +#include + +#include "prenv.h" + +#include "nsString.h" +#include "GLContext.h" + +namespace mozilla { +namespace layers { + +#define ASSERT_THIS_PROGRAM \ + do { \ + NS_ASSERTION(mGL->GetUserData(&sCurrentProgramKey) == this, \ + "SetUniform with wrong program active!"); \ + } while (0) + +struct UniformValue { + UniformValue() { + memset(this, 0, sizeof(UniformValue)); + } + + void setInt(const int i) { + value.i[0] = i; + } + + void setFloat(const float f) { + value.f[0] = f; + } + + void setFloatN(const float *f, const int n) { + memcpy(value.f, f, sizeof(float)*n); + } + + void setColor(const gfxRGBA& c) { + value.f[0] = float(c.r); + value.f[1] = float(c.g); + value.f[2] = float(c.b); + value.f[3] = float(c.a); + } + + bool equalsInt(const int i) { + return i == value.i[0]; + } + + bool equalsFloat(const float f) { + return f == value.f[0]; + } + + bool equalsFloatN(const float *f, const int n) { + return memcmp(f, value.f, sizeof(float)*n) == 0; + } + + bool equalsColor(const gfxRGBA& c) { + return value.f[0] == float(c.r) && + value.f[1] == float(c.g) && + value.f[2] == float(c.b) && + value.f[3] == float(c.a); + } + + union { + int i[1]; + float f[16]; + } value; +}; + +class LayerManagerOGLProgram { +protected: + static int sCurrentProgramKey; + +public: + typedef mozilla::gl::GLContext GLContext; + + // common attrib locations + enum { + VertexAttrib = 0, + TexCoordAttrib = 1 + }; + + LayerManagerOGLProgram(GLContext *aGL) + : mGL(aGL), mProgram(0) + { } + + virtual ~LayerManagerOGLProgram() { } + + void Activate() { + NS_ASSERTION(mProgram != 0, "Attempting to activate a program that's not in use!"); + mGL->fUseProgram(mProgram); + mGL->SetUserData(&sCurrentProgramKey, this); + } + + void SetUniform(GLuint aUniform, float aFloatValue) { + ASSERT_THIS_PROGRAM; + + if (aUniform == -1) + return; + + if (!mUniformValues[aUniform].equalsFloat(aFloatValue)) { + mGL->fUniform1f(aUniform, aFloatValue); + mUniformValues[aUniform].setFloat(aFloatValue); + } + } + + void SetUniform(GLuint aUniform, const gfxRGBA& aColor) { + ASSERT_THIS_PROGRAM; + + if (aUniform == -1) + return; + + if (!mUniformValues[aUniform].equalsColor(aColor)) { + mGL->fUniform4f(aUniform, float(aColor.r), float(aColor.g), float(aColor.b), float(aColor.a)); + mUniformValues[aUniform].setColor(aColor); + } + } + + void SetUniform(GLuint aUniform, int aLength, float *aFloatValues) { + ASSERT_THIS_PROGRAM; + + if (aUniform == -1) + return; + + if (!mUniformValues[aUniform].equalsFloatN(aFloatValues, aLength)) { + if (aLength == 1) { + mGL->fUniform1fv(aUniform, 1, aFloatValues); + } else if (aLength == 2) { + mGL->fUniform2fv(aUniform, 1, aFloatValues); + } else if (aLength == 3) { + mGL->fUniform3fv(aUniform, 1, aFloatValues); + } else if (aLength == 4) { + mGL->fUniform4fv(aUniform, 1, aFloatValues); + } else { + NS_NOTREACHED("Bogus aLength param"); + } + mUniformValues[aUniform].setFloatN(aFloatValues, aLength); + } + } + + void SetUniform(GLuint aUniform, GLint aIntValue) { + ASSERT_THIS_PROGRAM; + + if (aUniform == -1) + return; + + if (!mUniformValues[aUniform].equalsInt(aIntValue)) { + mGL->fUniform1i(aUniform, aIntValue); + mUniformValues[aUniform].setInt(aIntValue); + } + } + + void SetMatrixUniform(GLuint aUniform, const float *aFloatValues) { + ASSERT_THIS_PROGRAM; + + if (aUniform == -1) + return; + + if (!mUniformValues[aUniform].equalsFloatN(aFloatValues, 16)) { + mGL->fUniformMatrix4fv(aUniform, 1, false, aFloatValues); + mUniformValues[aUniform].setFloatN(aFloatValues, 16); + } + } + +protected: + GLContext *mGL; + + GLuint mProgram; + GLuint mFragmentShader; + GLuint mVertexShader; + + nsTArray mUniformValues; + + GLint CreateShader(GLenum aShaderType, + const char *aShaderSource) + { + GLint success, len = 0; + + GLint sh = mGL->fCreateShader(aShaderType); + mGL->fShaderSource(sh, 1, (const GLchar**)&aShaderSource, NULL); + mGL->fCompileShader(sh); + mGL->fGetShaderiv(sh, LOCAL_GL_COMPILE_STATUS, &success); + mGL->fGetShaderiv(sh, LOCAL_GL_INFO_LOG_LENGTH, (GLint*) &len); + /* Even if compiling is successful, there may still be warnings. Print them + * in a debug build. The > 10 is to catch silly compilers that might put + * some whitespace in the log but otherwise leave it empty. + */ + if (!success +#ifdef DEBUG + || (len > 10 && PR_GetEnv("MOZ_DEBUG_SHADERS")) +#endif + ) + { + nsCAutoString log; + log.SetCapacity(len); + mGL->fGetShaderInfoLog(sh, len, (GLint*) &len, (char*) log.BeginWriting()); + log.SetLength(len); + + if (!success) { + fprintf (stderr, "=== SHADER COMPILATION FAILED ===\n"); + } else { + fprintf (stderr, "=== SHADER COMPILATION WARNINGS ===\n"); + } + + fprintf (stderr, "=== Source:\n%s\n", aShaderSource); + fprintf (stderr, "=== Log:\n%s\n", nsPromiseFlatCString(log).get()); + fprintf (stderr, "============\n"); + + if (!success) { + mGL->fDeleteShader(sh); + return 0; + } + } + + return sh; + } + + bool CreateProgram(const char *aVertexShaderString, + const char *aFragmentShaderString) + { + mVertexShader = CreateShader(LOCAL_GL_VERTEX_SHADER, aVertexShaderString); + mFragmentShader = CreateShader(LOCAL_GL_FRAGMENT_SHADER, aFragmentShaderString); + + if (!mVertexShader || !mFragmentShader) + return false; + + mProgram = mGL->fCreateProgram(); + mGL->fAttachShader(mProgram, mVertexShader); + mGL->fAttachShader(mProgram, mFragmentShader); + + // bind common attribs to consistent indices + mGL->fBindAttribLocation(mProgram, VertexAttrib, "aVertex"); + mGL->fBindAttribLocation(mProgram, TexCoordAttrib, "aTexCoord"); + + mGL->fLinkProgram(mProgram); + + GLint success, len; + mGL->fGetProgramiv(mProgram, LOCAL_GL_LINK_STATUS, &success); + mGL->fGetProgramiv(mProgram, LOCAL_GL_INFO_LOG_LENGTH, (GLint*) &len); + /* Even if linking is successful, there may still be warnings. Print them + * in a debug build. The > 10 is to catch silly compilers that might put + * some whitespace in the log but otherwise leave it empty. + */ + if (!success +#ifdef DEBUG + || (len > 10 && PR_GetEnv("MOZ_DEBUG_SHADERS")) +#endif + ) + { + nsCAutoString log; + log.SetCapacity(len); + mGL->fGetProgramInfoLog(mProgram, len, (GLint*) &len, (char*) log.BeginWriting()); + log.SetLength(len); + + if (!success) { + fprintf (stderr, "=== PROGRAM LINKING FAILED ===\n"); + } else { + fprintf (stderr, "=== PROGRAM LINKING WARNINGS ===\n"); + } + fprintf (stderr, "=== Log:\n%s\n", nsPromiseFlatCString(log).get()); + fprintf (stderr, "============\n"); + + if (!success) { + mGL->fDeleteProgram(mProgram); + mGL->fDeleteShader(mVertexShader); + mGL->fDeleteShader(mFragmentShader); + + mProgram = 0; + + return false; + } + } + + // Now query uniforms, so that we can initialize mUniformValues + // note that for simplicity, mUniformLocations is indexed by the + // uniform -location-, and not the uniform -index-. This means + // that it might have a bunch of unused space as locations dense + // like indices are; however, there are unlikely to be enough for + // our shaders for this to become a significant memory issue. + GLint count, maxnamelen; + nsCAutoString uname; + GLint maxloc = 0; + mGL->fGetProgramiv(mProgram, LOCAL_GL_ACTIVE_UNIFORMS, &count); + mGL->fGetProgramiv(mProgram, LOCAL_GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxnamelen); + uname.SetCapacity(maxnamelen); + for (int i = 0; i < count; ++i) { + GLsizei namelen; + GLint usize; + GLenum utype; + + mGL->fGetActiveUniform(mProgram, i, maxnamelen, &namelen, &usize, &utype, uname.BeginWriting()); + uname.SetLength(namelen); + GLint uloc = mGL->fGetUniformLocation(mProgram, uname.BeginReading()); + if (maxloc < uloc) + maxloc = uloc; + } + + // Note +1: the last valid index needs to be 'maxloc', so we need + // to set the array length to 1 more than that. + mUniformValues.SetLength(maxloc+1); + + return true; + } + + void GetAttribLocations(const char **aAttribNames, + GLint *aAttribLocations) + { + NS_ASSERTION(mProgram != 0, "GetAttribLocations called with no program!"); + + for (int i = 0; aAttribNames[i] != nsnull; ++i) { + aAttribLocations[i] = mGL->fGetAttribLocation(mProgram, aAttribNames[i]); + } + } + + void GetUniformLocations(const char **aUniformNames, + GLint *aUniformLocations) + { + NS_ASSERTION(mProgram != 0, "GetUniformLocations called with no program!"); + + for (int i = 0; aUniformNames[i] != nsnull; ++i) { + aUniformLocations[i] = mGL->fGetUniformLocation(mProgram, aUniformNames[i]); + } + } +}; + +/* + * A LayerProgram is the base of all further LayerPrograms. + * + * It has a number of attributes and uniforms common to all layer programs. + * + * Attribute inputs: + * aVertexCoord - vertex coordinate + * + * Uniforms: + * uTransformMatrix - a transform matrix + * uQuadTransform + * uProjMatrix - projection matrix + * uOffset - a vec4 offset to apply to the transformed coordinates + * uLayerOpacity - a float, the layer opacity (final colors will be multiplied by this) + */ + +class LayerProgram : + public LayerManagerOGLProgram +{ +public: + enum { + TransformMatrixUniform = 0, + QuadTransformUniform, + ProjectionMatrixUniform, + OffsetUniform, + LayerOpacityUniform, + NumLayerUniforms + }; + + enum { + VertexCoordAttrib = 0, + NumLayerAttribs + }; + + LayerProgram(GLContext *aGL) + : LayerManagerOGLProgram(aGL) + { } + + bool Initialize(const char *aVertexShaderString, + const char *aFragmentShaderString) + { + if (!CreateProgram(aVertexShaderString, aFragmentShaderString)) + return false; + + const char *uniformNames[] = { + "uLayerTransform", + "uLayerQuadTransform", + "uMatrixProj", + "uRenderTargetOffset", + "uLayerOpacity", + NULL + }; + + mUniformLocations.SetLength(NumLayerUniforms); + GetUniformLocations(uniformNames, &mUniformLocations[0]); + + const char *attribNames[] = { + "aVertexCoord", + NULL + }; + + mAttribLocations.SetLength(NumLayerAttribs); + GetAttribLocations(attribNames, &mAttribLocations[0]); + + return true; + } + + GLint AttribLocation(int aWhich) { + if (aWhich < 0 || aWhich >= int(mAttribLocations.Length())) + return -1; + return mAttribLocations[aWhich]; + } + + void SetLayerTransform(const gfx3DMatrix& aMatrix) { + SetLayerTransform(&aMatrix._11); + } + + void SetLayerTransform(const float *aMatrix) { + SetMatrixUniform(mUniformLocations[TransformMatrixUniform], aMatrix); + } + + void SetLayerQuadRect(const nsIntRect& aRect) { + gfx3DMatrix m; + m._11 = float(aRect.width); + m._22 = float(aRect.height); + m._41 = float(aRect.x); + m._42 = float(aRect.y); + SetMatrixUniform(mUniformLocations[QuadTransformUniform], &m._11); + } + + void SetProjectionMatrix(const gfx3DMatrix& aMatrix) { + SetProjectionMatrix(&aMatrix._11); + } + + void SetProjectionMatrix(const float *aMatrix) { + SetMatrixUniform(mUniformLocations[ProjectionMatrixUniform], aMatrix); + } + + void SetRenderOffset(const nsIntPoint& aOffset) { + float vals[4] = { float(aOffset.x), float(aOffset.y), 0.0f, 0.0f }; + SetUniform(mUniformLocations[OffsetUniform], 4, vals); + } + + void SetRenderOffset(float aX, float aY) { + float vals[4] = { aX, aY, 0.0f, 0.0f }; + SetUniform(mUniformLocations[OffsetUniform], 4, vals); + } + + void SetLayerOpacity(float aOpacity) { + SetUniform(mUniformLocations[LayerOpacityUniform], aOpacity); + } + +protected: + nsTArray mUniformLocations; + nsTArray mAttribLocations; +}; + +/* + * A ColorTextureLayerProgram is a LayerProgram that renders + * a single texture. It adds the following attributes and uniforms: + * + * Attribute inputs: + * aTexCoord - texture coordinate + * + * Uniforms: + * uTexture - 2D texture unit which to sample + */ + +class ColorTextureLayerProgram : + public LayerProgram +{ +public: + enum { + TextureUniform = NumLayerUniforms, + NumUniforms + }; + + enum { + TexCoordAttrib = NumLayerAttribs, + NumAttribs + }; + + ColorTextureLayerProgram(GLContext *aGL) + : LayerProgram(aGL) + { } + + bool Initialize(const char *aVertexShaderString, + const char *aFragmentShaderString) + { + if (!LayerProgram::Initialize(aVertexShaderString, aFragmentShaderString)) + return false; + + const char *uniformNames[] = { + "uTexture", + NULL + }; + + mUniformLocations.SetLength(NumUniforms); + GetUniformLocations(uniformNames, &mUniformLocations[NumLayerUniforms]); + + const char *attribNames[] = { + "aTexCoord", + NULL + }; + + mAttribLocations.SetLength(NumAttribs); + GetAttribLocations(attribNames, &mAttribLocations[NumLayerAttribs]); + + // this is a one-off that's present in the 2DRect versions of some shaders. + mTexCoordMultiplierUniformLocation = + mGL->fGetUniformLocation(mProgram, "uTexCoordMultiplier"); + + return true; + } + + void SetTextureUnit(GLint aUnit) { + SetUniform(mUniformLocations[TextureUniform], aUnit); + } + + GLint GetTexCoordMultiplierUniformLocation() { + return mTexCoordMultiplierUniformLocation; + } + +protected: + GLint mTexCoordMultiplierUniformLocation; +}; + +/* + * A YCbCrTextureLayerProgram is a LayerProgram that renders a YCbCr + * image, reading from three texture units. The textures are assumed + * to be single-channel textures. + * + * Attribute inputs: + * aTexCoord - texture coordinate + * + * Uniforms: + * uYTexture - 2D texture unit which to sample Y + * uCbTexture - 2D texture unit which to sample Cb + * uCrTexture - 2D texture unit which to sample Cr + */ + +class YCbCrTextureLayerProgram : + public LayerProgram +{ +public: + enum { + YTextureUniform = NumLayerUniforms, + CbTextureUniform, + CrTextureUniform, + NumUniforms + }; + + enum { + TexCoordAttrib = NumLayerAttribs, + NumAttribs + }; + + YCbCrTextureLayerProgram(GLContext *aGL) + : LayerProgram(aGL) + { } + + bool Initialize(const char *aVertexShaderString, + const char *aFragmentShaderString) + { + if (!LayerProgram::Initialize(aVertexShaderString, aFragmentShaderString)) + return false; + + const char *uniformNames[] = { + "uYTexture", + "uCbTexture", + "uCrTexture", + NULL + }; + + mUniformLocations.SetLength(NumUniforms); + GetUniformLocations(uniformNames, &mUniformLocations[NumLayerUniforms]); + + const char *attribNames[] = { + "aTexCoord", + NULL + }; + + mAttribLocations.SetLength(NumAttribs); + GetAttribLocations(attribNames, &mAttribLocations[NumLayerAttribs]); + + return true; + } + + void SetYTextureUnit(GLint aUnit) { + SetUniform(mUniformLocations[YTextureUniform], aUnit); + } + + void SetCbTextureUnit(GLint aUnit) { + SetUniform(mUniformLocations[CbTextureUniform], aUnit); + } + + void SetCrTextureUnit(GLint aUnit) { + SetUniform(mUniformLocations[CrTextureUniform], aUnit); + } + + void SetYCbCrTextureUnits(GLint aYUnit, GLint aCbUnit, GLint aCrUnit) { + SetUniform(mUniformLocations[YTextureUniform], aYUnit); + SetUniform(mUniformLocations[CbTextureUniform], aCbUnit); + SetUniform(mUniformLocations[CrTextureUniform], aCrUnit); + } +}; + +/* + * A SolidColorLayerProgram is a LayerProgram that renders + * a solid color. It adds the following attributes and uniforms: + * + * Uniforms: + * uRenderColor - solid color to render; + * This should be with premultiplied opacity, as it's written + * to the color buffer directly. Layer Opacity is ignored. + */ + +class SolidColorLayerProgram : + public LayerProgram +{ +public: + enum { + RenderColorUniform = NumLayerUniforms, + NumUniforms + }; + + enum { + NumAttribs = NumLayerAttribs + }; + + SolidColorLayerProgram(GLContext *aGL) + : LayerProgram(aGL) + { } + + bool Initialize(const char *aVertexShaderString, + const char *aFragmentShaderString) + { + if (!LayerProgram::Initialize(aVertexShaderString, aFragmentShaderString)) + return false; + + const char *uniformNames[] = { + "uRenderColor", + NULL + }; + + mUniformLocations.SetLength(NumUniforms); + GetUniformLocations(uniformNames, &mUniformLocations[NumLayerUniforms]); + + return true; + } + + void SetRenderColor(const gfxRGBA& aColor) { + SetUniform(mUniformLocations[RenderColorUniform], aColor); + } +}; + +/* + * A CopyProgram is an OpenGL program that copies a 4-channel texture + * to the destination, making no attempt to transform any incoming + * vertices. It has the following attributes and uniforms: + * + * Attribute inputs: + * aVertex - vertex coordinate + * aTexCoord - texture coordinate + * + * Uniforms: + * uTexture - 2D texture unit which to sample + */ + +class CopyProgram : + public LayerManagerOGLProgram +{ +public: + enum { + TextureUniform = 0, + NumUniforms + }; + + enum { + VertexCoordAttrib = 0, + TexCoordAttrib, + NumAttribs + }; + + CopyProgram(GLContext *aGL) + : LayerManagerOGLProgram(aGL) + { } + + bool Initialize(const char *aVertexShaderString, + const char *aFragmentShaderString) + { + if (!CreateProgram(aVertexShaderString, aFragmentShaderString)) + return false; + + const char *uniformNames[] = { + "uTexture", + NULL + }; + + mUniformLocations.SetLength(NumUniforms); + GetUniformLocations(uniformNames, &mUniformLocations[0]); + + const char *attribNames[] = { + "aVertexCoord", + "aTexCoord", + NULL + }; + + mAttribLocations.SetLength(NumAttribs); + GetAttribLocations(attribNames, &mAttribLocations[0]); + + // this is a one-off that's present in the 2DRect versions of some shaders. + mTexCoordMultiplierUniformLocation = + mGL->fGetUniformLocation(mProgram, "uTexCoordMultiplier"); + + return true; + } + + GLint AttribLocation(int aWhich) { + if (aWhich < 0 || aWhich >= int(mAttribLocations.Length())) + return -1; + return mAttribLocations[aWhich]; + } + + void SetTextureUnit(GLint aUnit) { + SetUniform(mUniformLocations[TextureUniform], aUnit); + } + + GLint GetTexCoordMultiplierUniformLocation() { + return mTexCoordMultiplierUniformLocation; + } + +protected: + nsTArray mUniformLocations; + nsTArray mAttribLocations; + + GLint mTexCoordMultiplierUniformLocation; +}; + +} /* layers */ +} /* mozilla */ + +#endif /* GFX_LAYERMANAGEROGLPROGRAM_H */ diff --git a/gfx/layers/opengl/LayerManagerOGLShaders.h b/gfx/layers/opengl/LayerManagerOGLShaders.h deleted file mode 100644 index eb047691a4be..000000000000 --- a/gfx/layers/opengl/LayerManagerOGLShaders.h +++ /dev/null @@ -1,48 +0,0 @@ -#define SHADER_GLOBAL_VARS "uniform mat4 uMatrixProj; \ -uniform mat4 uLayerQuadTransform; \ -uniform mat4 uLayerTransform; \ -uniform vec4 uRenderTargetOffset; \ -uniform vec4 uRenderColor; \ -uniform float uLayerOpacity; \ -\ -uniform sampler2D uLayerTexture; \ -uniform sampler2D uYTexture; \ -uniform sampler2D uCbTexture; \ -uniform sampler2D uCrTexture; \ -varying vec2 vTextureCoordinate;" - -static const GLchar *sVertexShader = SHADER_GLOBAL_VARS "attribute vec4 aVertex; \ -void main() \ -{ \ - vec4 finalPosition = aVertex; \ - finalPosition = uLayerQuadTransform * finalPosition; \ - finalPosition = uLayerTransform * finalPosition; \ - finalPosition = finalPosition - uRenderTargetOffset; \ - finalPosition = uMatrixProj * finalPosition; \ - gl_Position = finalPosition; \ - vTextureCoordinate = vec2(aVertex); \ - }"; - -static const GLchar *sRGBLayerPS = SHADER_GLOBAL_VARS "void main() \ -{ \ -gl_FragColor = texture2D(uLayerTexture, vTextureCoordinate) * uLayerOpacity; \ -}"; - -static const GLchar *sColorLayerPS = SHADER_GLOBAL_VARS "void main() \ -{ \ -gl_FragColor = uRenderColor; \ -}"; - -static const GLchar *sYUVLayerPS = SHADER_GLOBAL_VARS "void main() \ -{ \ - vec4 yuv; \ - vec4 color; \ - yuv.r = texture2D(uCrTexture, vTextureCoordinate).r - 0.5; \ - yuv.g = texture2D(uYTexture, vTextureCoordinate).r - 0.0625; \ - yuv.b = texture2D(uCbTexture, vTextureCoordinate).r - 0.5; \ - color.r = yuv.g * 1.164 + yuv.r * 1.596; \ - color.g = yuv.g * 1.164 - 0.813 * yuv.r - 0.391 * yuv.b; \ - color.b = yuv.g * 1.164 + yuv.b * 2.018; \ - color.a = 1.0; \ - gl_FragColor = color * uLayerOpacity; \ -}"; diff --git a/gfx/layers/opengl/LayerManagerOGLShaders.txt b/gfx/layers/opengl/LayerManagerOGLShaders.txt new file mode 100644 index 000000000000..afb4f8e621a4 --- /dev/null +++ b/gfx/layers/opengl/LayerManagerOGLShaders.txt @@ -0,0 +1,279 @@ +// -*- Mode: glsl; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40; -*- +// ***** BEGIN LICENSE BLOCK ***** +// Version: MPL 1.1/GPL 2.0/LGPL 2.1 +// +// The contents of this file are subject to the Mozilla Public License Version +// 1.1 (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// http://www.mozilla.org/MPL/ +// +// Software distributed under the License is distributed on an "AS IS" basis, +// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +// for the specific language governing rights and limitations under the +// License. +// +// The Original Code is Mozilla Foundation code. +// +// The Initial Developer of the Original Code is +// Mozilla Foundation. +// Portions created by the Initial Developer are Copyright (C) 2010 +// the Initial Developer. All Rights Reserved. +// +// Contributor(s): +// Bas Schouten +// Vladimir Vukicevic +// +// Alternatively, the contents of this file may be used under the terms of +// either the GNU General Public License Version 2 or later (the "GPL"), or +// the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +// in which case the provisions of the GPL or the LGPL are applicable instead +// of those above. If you wish to allow use of your version of this file only +// under the terms of either the GPL or the LGPL, and not to allow others to +// use your version of this file under the terms of the MPL, indicate your +// decision by deleting the provisions above and replace them with the notice +// and other provisions required by the GPL or the LGPL. If you do not delete +// the provisions above, a recipient may use your version of this file under +// the terms of any one of the MPL, the GPL or the LGPL. +// +// ***** END LICENSE BLOCK ***** + +// +// Syntax: +// +// // comments (only at the start of a line) +// +// (@ is used because # is valid inside GLSL) +// +// multi-line: +// @define FOO +// ... +// @end +// +// single: +// @define FOO 123 +// +// $FOO$ to paste +// +// To generate a constant string named ShaderName: +// @shader ShaderName +// ... +// @end +// +// + +@define VERTEX_SHADER_HEADER +/* Vertex Shader */ +@end + +@define FRAGMENT_SHADER_HEADER +/* Fragment Shader */ +#ifdef GL_ES +precision mediump float; +#endif +@end + +// fragment shader header for all layers +@define LAYER_FRAGMENT +$FRAGMENT_SHADER_HEADER$ + +#ifndef NO_LAYER_OPACITY +uniform float uLayerOpacity; +#endif + +varying vec2 vTexCoord; +@end + +// This is a basic Layer vertex shader. It's used for all +// the Layer programs. + +@shader sLayerVS +$VERTEX_SHADER_HEADER$ + +uniform mat4 uMatrixProj; +uniform mat4 uLayerQuadTransform; +uniform mat4 uLayerTransform; +uniform vec4 uRenderTargetOffset; + +attribute vec4 aVertexCoord; +attribute vec2 aTexCoord; + +varying vec2 vTexCoord; + +void main() +{ + vec4 finalPosition = aVertexCoord; + finalPosition = uLayerQuadTransform * finalPosition; + finalPosition = uLayerTransform * finalPosition; + finalPosition = finalPosition - uRenderTargetOffset; + finalPosition = uMatrixProj * finalPosition; + + vTexCoord = aTexCoord; + gl_Position = finalPosition; +} +@end + +// Solid color rendering. +// texcoords are ignored (no texture to sample). +// The layer opacity is baked in to the color. +@shader sSolidColorLayerFS +#define NO_LAYER_OPACITY 1 +$LAYER_FRAGMENT$ +uniform vec4 uRenderColor; + +void main() +{ + gl_FragColor = uRenderColor; +} +@end + +// Single texture in RGBA format +@shader sRGBATextureLayerFS +$LAYER_FRAGMENT$ +uniform sampler2D uTexture; + +void main() +{ + gl_FragColor = texture2D(uTexture, vTexCoord) * uLayerOpacity; +} +@end + +// Single texture in RGBA format, but with a Rect texture. +// Container layer needs this to render a FBO group. +@shader sRGBARectTextureLayerFS +#extension GL_ARB_texture_rectangle : enable + +$LAYER_FRAGMENT$ + +/* This should not be used on GL ES */ +#ifndef GL_ES +uniform sampler2DRect uTexture; +uniform vec2 uTexCoordMultiplier; +void main() +{ + gl_FragColor = texture2DRect(uTexture, vec2(vTexCoord * uTexCoordMultiplier)) * uLayerOpacity; +} +#else +void main() +{ + gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); +} +#endif +@end + +// Single texture in BGRA format (via swizzle) +@shader sBGRATextureLayerFS +$LAYER_FRAGMENT$ +uniform sampler2D uTexture; + +void main() +{ + gl_FragColor = texture2D(uTexture, vTexCoord).bgra * uLayerOpacity; +} +@end + +// Single texture in RGBX format +@shader sRGBXTextureLayerFS +$LAYER_FRAGMENT$ +uniform sampler2D uTexture; + +void main() +{ + gl_FragColor = vec4(texture2D(uTexture, vTexCoord).rgb, 1.0) * uLayerOpacity; +} +@end + +// Single texture in BGRX format (via swizzle) +@shader sBGRXTextureLayerFS +$LAYER_FRAGMENT$ +uniform sampler2D uTexture; + +void main() +{ + gl_FragColor = vec4(texture2D(uTexture, vTexCoord).bgr, 1.0) * uLayerOpacity; +} +@end + +// Three textures, representing YCbCr planes of a video image +@shader sYCbCrTextureLayerFS +$LAYER_FRAGMENT$ +uniform sampler2D uYTexture; +uniform sampler2D uCbTexture; +uniform sampler2D uCrTexture; + +void main() +{ + vec4 yuv; + vec4 color; + yuv.r = texture2D(uCrTexture, vTexCoord).r - 0.5; + yuv.g = texture2D(uYTexture, vTexCoord).r - 0.0625; + yuv.b = texture2D(uCbTexture, vTexCoord).r - 0.5; + color.r = yuv.g * 1.164 + yuv.r * 1.596; + color.g = yuv.g * 1.164 - 0.813 * yuv.r - 0.391 * yuv.b; + color.b = yuv.g * 1.164 + yuv.b * 2.018; + color.a = 1.0; + gl_FragColor = color * uLayerOpacity; +} +@end + +// +// The "Copy" program is used for blitting a texture to a destination +// with no transforms or any other manipulation. They're used for +// blitting the contents of a FBO-rendered texture to a destination. +// +// There are two variants of the fragment shader: one that uses 2D +// textures and one that uses 2DRect textures (for when +// EXT_TEXTURE_RECTANGLE is used for FBOs). +// +// On GL ES, EXT_TEXTURE_RECTANGLE isn't available, so we still +// compile the shader but have it render pure red. It should never +// be used. +// + +@shader sCopyVS +$VERTEX_SHADER_HEADER$ + +attribute vec4 aVertexCoord; +attribute vec2 aTexCoord; + +varying vec2 vTexCoord; + +void main() +{ + gl_Position = aVertexCoord; + vTexCoord = aTexCoord; +} +@end + +@shader sCopy2DFS +$FRAGMENT_SHADER_HEADER$ + +varying vec2 vTexCoord; + +uniform sampler2D uTexture; +void main() +{ + gl_FragColor = texture2D(uTexture, vTexCoord); +} +@end + +@shader sCopy2DRectFS +#extension GL_ARB_texture_rectangle : enable + +$FRAGMENT_SHADER_HEADER$ + +varying vec2 vTexCoord; +uniform vec2 uTexCoordMultiplier; + +#ifndef GL_ES +uniform sampler2DRect uTexture; +void main() +{ + gl_FragColor = texture2DRect(uTexture, vTexCoord * uTexCoordMultiplier); +} +#else +void main() +{ + gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); +} +#endif +@end diff --git a/gfx/layers/opengl/ThebesLayerOGL.cpp b/gfx/layers/opengl/ThebesLayerOGL.cpp index fe45eb90807c..f3d8f2b4f1b5 100644 --- a/gfx/layers/opengl/ThebesLayerOGL.cpp +++ b/gfx/layers/opengl/ThebesLayerOGL.cpp @@ -1,5 +1,5 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * ***** BEGIN LICENSE BLOCK ***** +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version @@ -20,6 +20,7 @@ * * Contributor(s): * Bas Schouten + * Vladimir Vukicevic * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -79,7 +80,7 @@ ThebesLayerOGL::ThebesLayerOGL(LayerManagerOGL *aManager) ThebesLayerOGL::~ThebesLayerOGL() { - static_cast(mManager)->MakeCurrent(); + mOGLManager->MakeCurrent(); if (mTexture) { gl()->fDeleteTextures(1, &mTexture); } @@ -88,35 +89,35 @@ ThebesLayerOGL::~ThebesLayerOGL() void ThebesLayerOGL::SetVisibleRegion(const nsIntRegion &aRegion) { - if (aRegion.GetBounds() == mVisibleRect) { + if (aRegion.GetBounds() == mVisibleRect) return; - } + mVisibleRect = aRegion.GetBounds(); - - static_cast(mManager)->MakeCurrent(); - - if (!mTexture) { - gl()->fGenTextures(1, &mTexture); - } - mInvalidatedRect = mVisibleRect; - gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture); + mOGLManager->MakeCurrent(); + if (!mTexture) + gl()->fGenTextures(1, &mTexture); + + gl()->fActiveTexture(LOCAL_GL_TEXTURE0); + gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture); gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR); gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR); gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE); gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE); gl()->fTexImage2D(LOCAL_GL_TEXTURE_2D, - 0, - LOCAL_GL_RGBA, - mVisibleRect.width, - mVisibleRect.height, - 0, - LOCAL_GL_BGRA, - LOCAL_GL_UNSIGNED_BYTE, - NULL); + 0, + LOCAL_GL_RGBA, + mVisibleRect.width, + mVisibleRect.height, + 0, + LOCAL_GL_RGBA, + LOCAL_GL_UNSIGNED_BYTE, + NULL); + + DEBUG_GL_ERROR_CHECK(gl()); } void @@ -142,12 +143,15 @@ ThebesLayerOGL::GetVisibleRect() void ThebesLayerOGL::RenderLayer(int aPreviousFrameBuffer, - DrawThebesLayerCallback aCallback, - void* aCallbackData) + const nsIntPoint& aOffset) { - if (!mTexture) { + if (!mTexture) return; - } + + mOGLManager->MakeCurrent(); + gl()->fActiveTexture(LOCAL_GL_TEXTURE0); + + bool needsTextureBind = true; if (!mInvalidatedRect.IsEmpty()) { gfxASurface::gfxImageFormat imageFormat; @@ -166,10 +170,12 @@ ThebesLayerOGL::RenderLayer(int aPreviousFrameBuffer, nsRefPtr ctx = new gfxContext(surface); ctx->Translate(gfxPoint(-mInvalidatedRect.x, -mInvalidatedRect.y)); - aCallback(this, ctx, mInvalidatedRect, aCallbackData); - static_cast(mManager)->MakeCurrent(); + /* Call the thebes layer callback */ + mOGLManager->CallThebesLayerDrawCallback(this, ctx, mInvalidatedRect); + /* Then take its results and put it in an image surface, + * in preparation for a texture upload */ nsRefPtr imageSurface; switch (surface->GetType()) { @@ -207,36 +213,33 @@ ThebesLayerOGL::RenderLayer(int aPreviousFrameBuffer, mInvalidatedRect.y - mVisibleRect.y, mInvalidatedRect.width, mInvalidatedRect.height, - LOCAL_GL_BGRA, + LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, imageSurface->Data()); + + needsTextureBind = false; } - float quadTransform[4][4]; - /* - * Matrix to transform the <0.0,0.0>, <1.0,1.0> quad to the correct position - * and size. - */ - memset(&quadTransform, 0, sizeof(quadTransform)); - quadTransform[0][0] = (float)GetVisibleRect().width; - quadTransform[1][1] = (float)GetVisibleRect().height; - quadTransform[2][2] = 1.0f; - quadTransform[3][0] = (float)GetVisibleRect().x; - quadTransform[3][1] = (float)GetVisibleRect().y; - quadTransform[3][3] = 1.0f; + if (needsTextureBind) + gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture); - RGBLayerProgram *program = - static_cast(mManager)->GetRGBLayerProgram(); + // Note BGR: Cairo's image surfaces are always in what + // OpenGL and our shaders consider BGR format. + ColorTextureLayerProgram *program = + UseOpaqueSurface(this) + ? mOGLManager->GetBGRXLayerProgram() + : mOGLManager->GetBGRALayerProgram(); program->Activate(); - program->SetLayerQuadTransform(&quadTransform[0][0]); + program->SetLayerQuadRect(mVisibleRect); program->SetLayerOpacity(GetOpacity()); - program->SetLayerTransform(&mTransform._11); - program->Apply(); + program->SetLayerTransform(mTransform); + program->SetRenderOffset(aOffset); + program->SetTextureUnit(0); - gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture); + mOGLManager->BindAndDrawQuad(program); - gl()->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4); + DEBUG_GL_ERROR_CHECK(gl()); } const nsIntRect& diff --git a/gfx/layers/opengl/ThebesLayerOGL.h b/gfx/layers/opengl/ThebesLayerOGL.h index fbe9c16443b8..e2c3e996d478 100644 --- a/gfx/layers/opengl/ThebesLayerOGL.h +++ b/gfx/layers/opengl/ThebesLayerOGL.h @@ -1,5 +1,5 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * ***** BEGIN LICENSE BLOCK ***** +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-/ +/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version @@ -64,8 +64,7 @@ public: Layer* GetLayer(); virtual PRBool IsEmpty(); virtual void RenderLayer(int aPreviousFrameBuffer, - DrawThebesLayerCallback aCallback, - void* aCallbackData); + const nsIntPoint& aOffset); /** ThebesLayerOGL */ const nsIntRect &GetVisibleRect(); @@ -86,7 +85,6 @@ private: * OpenGL Texture */ GLuint mTexture; - }; } /* layers */ diff --git a/gfx/layers/opengl/genshaders.py b/gfx/layers/opengl/genshaders.py new file mode 100644 index 000000000000..b7e8b04d04d3 --- /dev/null +++ b/gfx/layers/opengl/genshaders.py @@ -0,0 +1,140 @@ +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Foundation code. +# +# The Initial Developer of the Original Code is +# Mozilla Foundation. +# Portions created by the Initial Developer are Copyright (C) 2010 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Vladimir Vukicevic +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + + +import sys +import re +import string + +defines = dict() + +def emitShader(fp, shadername, shaderlines): + eolContinue = "\\n\\\n"; + fp.write("const char %s[] = \"/* %s */%s" % (shadername,shadername,eolContinue)) + for line in shaderlines: + line.replace("\\", "\\\\") + while line.find('$') != -1: + expansions = re.findall('\$\S+\$', line) + for m in expansions: + mkey = m[1:-1] + if not defines.has_key(mkey): + print "Error: Undefined expansion used: '%s'" % (m,) + sys.exit(1) + mval = defines[mkey] + if type(mval) == str: + line = line.replace(m, mval) + elif type(mval) == list: + line = line.replace(m, eolContinue.join(mval) + eolContinue); + else: + print "Internal Error: Unknown type in defines array: '%s'" % (str(type(mval)),) + + fp.write("%s%s" % (line,eolContinue)) + fp.write("\";\n\n"); + +def genShaders(infile, outfile): + source = open(infile, "r").readlines() + desthdr = open(outfile, "w+") + + desthdr.write("/* AUTOMATICALLY GENERATED */\n"); + desthdr.write("/* DO NOT EDIT! */\n\n"); + + global defines + + indefine = None + inshader = None + + inblock = False + linebuffer = [] + + for line in source: + # strip comments, if not inblock + if not inblock and line.startswith("//"): + continue + line = string.strip(line) + + if len(line) == 0: + continue + + if line[0] == '@': + cmd = line + rest = '' + + if line.find(' ') != -1: + cmd = line[0:line.find(' ')] + rest = string.strip(line[len(cmd) + 1:]) + + if cmd == "@define": + if inblock: + raise Exception("@define inside a block!") + space = rest.find(' ') + if space != -1: + defines[rest[0:space]] = rest[space+1:] + else: + indefine = rest + inblock = True + elif cmd == "@shader": + if inblock: + raise Exception("@shader inside a block!") + if len(rest) == 0: + raise Exception("@shader without a name!") + inshader = rest + inblock = True + elif cmd == "@end": + if indefine is not None: + if type(linebuffer) == list: + for i in range(len(linebuffer)): + linebuffer[i] = linebuffer[i].replace("\\", "\\\\") + defines[indefine] = linebuffer + elif inshader is not None: + emitShader(desthdr, inshader, linebuffer) + else: + raise Exception("@end outside of a block!") + indefine = None + inshader = None + inblock = None + linebuffer = [] + else: + raise Exception("Unknown command: %s" % (cmd,)) + else: + if inblock: + linebuffer.append(line) + +if (len(sys.argv) != 3): + print "Usage: %s infile.txt outfile.h" % (sys.argv[0],) + sys.exit(1) + +genShaders(sys.argv[1], sys.argv[2]) diff --git a/gfx/thebes/public/GLContext.h b/gfx/thebes/public/GLContext.h index a9fa4f5b922e..f63f9a16c8c7 100644 --- a/gfx/thebes/public/GLContext.h +++ b/gfx/thebes/public/GLContext.h @@ -49,6 +49,9 @@ #include "nsISupportsImpl.h" #include "prlink.h" +#include "nsDataHashtable.h" +#include "nsHashKeys.h" + #ifndef GLAPIENTRY #ifdef XP_WIN #define GLAPIENTRY __stdcall @@ -110,13 +113,27 @@ class GLContext { THEBES_INLINE_DECL_THREADSAFE_REFCOUNTING(GLContext) public: - GLContext() : mInitialized(PR_FALSE) { } + GLContext() + : mInitialized(PR_FALSE) + { + mUserData.Init(); + } virtual ~GLContext() { } virtual PRBool MakeCurrent() = 0; virtual PRBool SetupLookupFunction() = 0; + void *GetUserData(void *aKey) { + void *result = nsnull; + mUserData.Get(aKey, &result); + return result; + } + + void SetUserData(void *aKey, void *aValue) { + mUserData.Put(aKey, aValue); + } + enum NativeDataType { NativeGLContext, NativeCGLContext, @@ -129,6 +146,7 @@ public: protected: PRBool mInitialized; + nsDataHashtable mUserData; PRBool InitWithPrefix(const char *prefix, PRBool trygl); @@ -136,8 +154,9 @@ protected: // the wrapped functions // public: - /* One would think that this would live in some nice perl-or-python-or-js script somewhere and would be autogenerated; - * one would be wrong. + /* One would think that this would live in some nice + * perl-or-python-or-js script somewhere and would be + * autogenerated; one would be wrong. */ typedef void (GLAPIENTRY * PFNGLACTIVETEXTUREPROC) (GLenum texture); PFNGLACTIVETEXTUREPROC fActiveTexture; diff --git a/gfx/thebes/public/gfx3DMatrix.h b/gfx/thebes/public/gfx3DMatrix.h index eeb8f1194c14..e2259fbf18ec 100644 --- a/gfx/thebes/public/gfx3DMatrix.h +++ b/gfx/thebes/public/gfx3DMatrix.h @@ -106,6 +106,11 @@ public: */ static inline gfx3DMatrix Scale(float aFactor); + /** + * Create a scale matrix. + */ + static inline gfx3DMatrix Scale(float aX, float aY, float aZ); + /** Matrix elements */ float _11, _12, _13, _14; float _21, _22, _23, _24; @@ -190,4 +195,16 @@ gfx3DMatrix::Scale(float aFactor) return matrix; } +inline gfx3DMatrix +gfx3DMatrix::Scale(float aX, float aY, float aZ) +{ + gfx3DMatrix matrix; + + matrix._11 = aX; + matrix._22 = aY; + matrix._33 = aZ; + + return matrix; +} + #endif /* GFX_3DMATRIX_H */