gecko-dev/gfx/layers/opengl/LayerManagerOGL.cpp

705 lines
22 KiB
C++
Raw Normal View History

2010-05-25 06:35:35 +00:00
/* -*- 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) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Bas Schouten <bschouten@mozilla.org>
2010-05-25 06:35:35 +00:00
* Frederic Plourde <frederic.plourde@collabora.co.uk>
* Vladimir Vukicevic <vladimir@pobox.com>
*
* 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 ***** */
#include "LayerManagerOGL.h"
#include "ThebesLayerOGL.h"
#include "ContainerLayerOGL.h"
#include "ImageLayerOGL.h"
#include "ColorLayerOGL.h"
#include "CanvasLayerOGL.h"
#include "LayerManagerOGLShaders.h"
#include "gfxContext.h"
#include "nsIWidget.h"
#include "GLContext.h"
#include "GLContextProvider.h"
#include "nsIServiceManager.h"
#include "nsIConsoleService.h"
namespace mozilla {
namespace layers {
using namespace mozilla::gl;
2010-05-25 06:35:35 +00:00
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);
Layer *genl = l->GetLayer()->GetNextSibling();
l = genl ? static_cast<LayerOGL*>(genl->ImplData()) : nsnull;
2010-05-25 06:35:35 +00:00
}
}
/**
* LayerManagerOGL
*/
LayerManagerOGL::LayerManagerOGL(nsIWidget *aWidget)
: mWidget(aWidget)
2010-05-25 06:35:35 +00:00
, mBackBufferFBO(0)
, mBackBufferTexture(0)
, mBackBufferSize(-1, -1)
2010-05-25 06:35:35 +00:00
, mHasBGRA(0)
{
}
LayerManagerOGL::~LayerManagerOGL()
{
2010-05-25 06:35:35 +00:00
if (mGLContext)
mGLContext->MakeCurrent();
for (unsigned int i = 0; i < mPrograms.Length(); ++i)
delete mPrograms[i];
mPrograms.Clear();
}
PRBool
LayerManagerOGL::Initialize()
{
mGLContext = sGLContextProvider.CreateForWindow(mWidget);
if (!mGLContext) {
2010-05-25 06:35:35 +00:00
NS_WARNING("Failed to create LayerManagerOGL context");
return PR_FALSE;
}
MakeCurrent();
2010-05-25 06:35:35 +00:00
DEBUG_GL_ERROR_CHECK(mGLContext);
2010-05-25 06:35:35 +00:00
const char *extensionStr =
(const char*) mGLContext->fGetString(LOCAL_GL_EXTENSIONS);
2010-05-25 06:35:35 +00:00
mHasBGRA = (strstr(extensionStr, "EXT_bgra") != nsnull);
2010-05-25 06:35:35 +00:00
mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
LOCAL_GL_ONE, LOCAL_GL_ONE);
mGLContext->fEnable(LOCAL_GL_BLEND);
2010-05-25 06:35:35 +00:00
// 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)
// NOTE: Order matters here, and should be in the same order as the
// ProgramType enum!
GLint programIndex = 0;
/* 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);
#undef SHADER_PROGRAM
NS_ASSERTION(programIndex == NumProgramTypes,
"not all programs were initialized!");
/**
* We'll test the ability here to bind NPOT textures to a framebuffer, if
2010-05-25 06:35:35 +00:00
* this fails we'll try ARB_texture_rectangle.
*/
2010-05-25 06:35:35 +00:00
mGLContext->fGenFramebuffers(1, &mBackBufferFBO);
GLenum textureTargets[] = {
LOCAL_GL_TEXTURE_2D,
#ifndef USE_GLES2
LOCAL_GL_TEXTURE_RECTANGLE_ARB
#endif
};
2010-05-25 06:35:35 +00:00
mFBOTextureTarget = LOCAL_GL_NONE;
for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(textureTargets); i++) {
2010-05-25 06:35:35 +00:00
GLenum target = textureTargets[i];
mGLContext->fGenTextures(1, &mBackBufferTexture);
mGLContext->fBindTexture(target, mBackBufferTexture);
mGLContext->fTexParameteri(target,
LOCAL_GL_TEXTURE_MIN_FILTER,
LOCAL_GL_NEAREST);
2010-05-25 06:35:35 +00:00
mGLContext->fTexParameteri(target,
LOCAL_GL_TEXTURE_MAG_FILTER,
LOCAL_GL_NEAREST);
2010-05-25 06:35:35 +00:00
mGLContext->fTexImage2D(target,
0,
LOCAL_GL_RGBA,
2010-05-25 06:35:35 +00:00
5, 3, /* sufficiently NPOT */
0,
LOCAL_GL_RGBA,
LOCAL_GL_UNSIGNED_BYTE,
NULL);
2010-05-25 06:35:35 +00:00
// 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,
2010-05-25 06:35:35 +00:00
target,
mBackBufferTexture,
0);
if (mGLContext->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER) ==
2010-05-25 06:35:35 +00:00
LOCAL_GL_FRAMEBUFFER_COMPLETE)
{
mFBOTextureTarget = target;
break;
}
2010-05-25 06:35:35 +00:00
// We weren't succesful with this texture, so we don't need it
// any more.
mGLContext->fDeleteTextures(1, &mBackBufferTexture);
}
2010-05-25 06:35:35 +00:00
if (mFBOTextureTarget == LOCAL_GL_NONE) {
/* Unable to find a texture target that works with FBOs and NPOT textures */
return false;
}
mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
2010-05-25 06:35:35 +00:00
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;
}
2010-05-25 06:35:35 +00:00
// back to default framebuffer, to avoid confusion
mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
2010-05-25 06:35:35 +00:00
DEBUG_GL_ERROR_CHECK(mGLContext);
2010-05-25 06:35:35 +00:00
/* 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);
2010-05-25 06:35:35 +00:00
DEBUG_GL_ERROR_CHECK(mGLContext);
nsCOMPtr<nsIConsoleService>
console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
if (console) {
nsString msg;
msg +=
NS_LITERAL_STRING("OpenGL LayerManager Initialized Succesfully.\nVersion: ");
msg += NS_ConvertUTF8toUTF16(
nsDependentCString((const char*)mGLContext->fGetString(LOCAL_GL_VERSION)));
msg += NS_LITERAL_STRING("\nVendor: ");
msg += NS_ConvertUTF8toUTF16(
nsDependentCString((const char*)mGLContext->fGetString(LOCAL_GL_VENDOR)));
msg += NS_LITERAL_STRING("\nRenderer: ");
msg += NS_ConvertUTF8toUTF16(
nsDependentCString((const char*)mGLContext->fGetString(LOCAL_GL_RENDERER)));
2010-05-25 06:35:35 +00:00
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());
}
2010-05-25 06:35:35 +00:00
DEBUG_GL_ERROR_CHECK(mGLContext);
return true;
}
void
LayerManagerOGL::SetClippingRegion(const nsIntRegion& aClippingRegion)
{
mClippingRegion = aClippingRegion;
}
void
LayerManagerOGL::BeginTransaction()
{
}
void
LayerManagerOGL::BeginTransactionWithTarget(gfxContext *aTarget)
{
mTarget = aTarget;
}
void
LayerManagerOGL::EndTransaction(DrawThebesLayerCallback aCallback,
void* aCallbackData)
{
2010-05-25 06:35:35 +00:00
mThebesLayerCallback = aCallback;
mThebesLayerCallbackData = aCallbackData;
Render();
mThebesLayerCallback = nsnull;
mThebesLayerCallbackData = nsnull;
mTarget = NULL;
}
already_AddRefed<ThebesLayer>
LayerManagerOGL::CreateThebesLayer()
{
nsRefPtr<ThebesLayer> layer = new ThebesLayerOGL(this);
return layer.forget();
}
already_AddRefed<ContainerLayer>
LayerManagerOGL::CreateContainerLayer()
{
nsRefPtr<ContainerLayer> layer = new ContainerLayerOGL(this);
return layer.forget();
}
already_AddRefed<ImageContainer>
LayerManagerOGL::CreateImageContainer()
{
nsRefPtr<ImageContainer> container = new ImageContainerOGL(this);
return container.forget();
}
already_AddRefed<ImageLayer>
LayerManagerOGL::CreateImageLayer()
{
nsRefPtr<ImageLayer> layer = new ImageLayerOGL(this);
return layer.forget();
}
already_AddRefed<ColorLayer>
LayerManagerOGL::CreateColorLayer()
{
nsRefPtr<ColorLayer> layer = new ColorLayerOGL(this);
return layer.forget();
}
already_AddRefed<CanvasLayer>
LayerManagerOGL::CreateCanvasLayer()
{
nsRefPtr<CanvasLayer> layer = new CanvasLayerOGL(this);
return layer.forget();
}
void
LayerManagerOGL::MakeCurrent()
{
2010-05-25 06:35:35 +00:00
mGLContext->MakeCurrent();
}
LayerOGL*
LayerManagerOGL::RootLayer() const
{
return static_cast<LayerOGL*>(mRoot->ImplData());
}
void
2010-05-25 06:35:35 +00:00
LayerManagerOGL::Render()
{
nsIntRect rect;
mWidget->GetBounds(rect);
GLint width = rect.width;
GLint height = rect.height;
MakeCurrent();
2010-05-25 06:35:35 +00:00
DEBUG_GL_ERROR_CHECK(mGLContext);
SetupBackBuffer(width, height);
SetupPipeline(width, height);
// Default blend function implements "OVER"
mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
LOCAL_GL_ONE, LOCAL_GL_ONE);
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 = mRoot->GetClipRect();
2010-05-25 06:35:35 +00:00
if (clipRect) {
mGLContext->fScissor(clipRect->x, clipRect->y,
clipRect->width, clipRect->height);
} else {
mGLContext->fScissor(0, 0, width, height);
}
2010-05-25 06:35:35 +00:00
mGLContext->fEnable(LOCAL_GL_SCISSOR_TEST);
#else
mGLContext->fDisable(LOCAL_GL_SCISSOR_TEST);
#endif
DEBUG_GL_ERROR_CHECK(mGLContext);
// Render our layers.
RootLayer()->RenderLayer(mBackBufferFBO, nsIntPoint(0, 0));
2010-05-25 06:35:35 +00:00
DEBUG_GL_ERROR_CHECK(mGLContext);
if (mTarget) {
CopyToTarget();
2010-05-25 06:35:35 +00:00
return;
}
2010-05-25 06:35:35 +00:00
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);
}
2010-05-25 06:35:35 +00:00
mGLContext->fDisableVertexAttribArray(vcattr);
mGLContext->fDisableVertexAttribArray(tcattr);
DEBUG_GL_ERROR_CHECK(mGLContext);
// XXX this is an intermediate workaround for windows that are
// double-buffered by default on GLX systems. The swap is a no-op
// everywhere else (and for non-double-buffered GLX windows). If
// the swap is actually performed, it implicitly glFlush()s.
if (!mGLContext->SwapBuffers()) {
mGLContext->fFlush();
}
2010-05-25 06:35:35 +00:00
DEBUG_GL_ERROR_CHECK(mGLContext);
}
void
2010-05-25 06:35:35 +00:00
LayerManagerOGL::SetupPipeline(int aWidth, int aHeight)
{
2010-05-25 06:35:35 +00:00
// Set the viewport correctly
mGLContext->fViewport(0, 0, aWidth, aHeight);
2010-05-25 06:35:35 +00:00
// 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;
2010-05-25 06:35:35 +00:00
SetLayerProgramProjectionMatrix(viewMatrix);
}
2010-05-25 06:35:35 +00:00
void
LayerManagerOGL::SetupBackBuffer(int aWidth, int aHeight)
{
2010-05-25 06:35:35 +00:00
// Do we have a FBO of the right size already?
if (mBackBufferSize.width == aWidth &&
mBackBufferSize.height == aHeight)
{
mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mBackBufferFBO);
return;
}
2010-05-25 06:35:35 +00:00
// we already have a FBO, but we need to resize its texture.
mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
mGLContext->fBindTexture(mFBOTextureTarget, mBackBufferTexture);
mGLContext->fTexImage2D(mFBOTextureTarget,
2010-05-25 06:35:35 +00:00
0,
LOCAL_GL_RGBA,
aWidth, aHeight,
0,
LOCAL_GL_RGBA,
LOCAL_GL_UNSIGNED_BYTE,
NULL);
mGLContext->fBindTexture(mFBOTextureTarget, 0);
mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mBackBufferFBO);
mGLContext->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
2010-05-25 06:35:35 +00:00
LOCAL_GL_COLOR_ATTACHMENT0,
mFBOTextureTarget,
mBackBufferTexture,
0);
2010-05-25 06:35:35 +00:00
mBackBufferSize.width = aWidth;
mBackBufferSize.height = aHeight;
}
void
LayerManagerOGL::CopyToTarget()
{
nsIntRect rect;
mWidget->GetBounds(rect);
GLint width = rect.width;
GLint height = rect.height;
2010-05-25 06:35:35 +00:00
if ((PRInt64(width) * PRInt64(height) * PRInt64(4)) > PR_INT32_MAX) {
NS_ERROR("Widget size too big - integer overflow!");
return;
}
nsRefPtr<gfxImageSurface> imageSurface =
new gfxImageSurface(gfxIntSize(width, height),
gfxASurface::ImageFormatARGB32);
2010-05-25 06:35:35 +00:00
#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);
2010-05-25 06:35:35 +00:00
#endif
2010-05-25 06:35:35 +00:00
GLenum format = LOCAL_GL_RGBA;
if (mHasBGRA)
format = LOCAL_GL_BGRA;
2010-05-25 06:35:35 +00:00
NS_ASSERTION(imageSurface->Stride() == width * 4,
"Image Surfaces being created with weird stride!");
2010-05-25 06:35:35 +00:00
mGLContext->fReadPixels(0, 0,
width, height,
format,
LOCAL_GL_UNSIGNED_BYTE,
imageSurface->Data());
2010-05-25 06:35:35 +00:00
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();
}
2010-05-25 06:35:35 +00:00
LayerManagerOGL::ProgramType LayerManagerOGL::sLayerProgramTypes[] = {
LayerManagerOGL::RGBALayerProgramType,
LayerManagerOGL::BGRALayerProgramType,
LayerManagerOGL::RGBXLayerProgramType,
LayerManagerOGL::BGRXLayerProgramType,
LayerManagerOGL::RGBARectLayerProgramType,
LayerManagerOGL::ColorLayerProgramType,
LayerManagerOGL::YCbCrLayerProgramType
};
#define FOR_EACH_LAYER_PROGRAM(vname) \
for (size_t lpindex = 0; \
lpindex < NS_ARRAY_LENGTH(sLayerProgramTypes); \
2010-05-25 06:35:35 +00:00
++lpindex) \
{ \
LayerProgram *vname = static_cast<LayerProgram*> \
(mPrograms[sLayerProgramTypes[lpindex]]); \
do
#define FOR_EACH_LAYER_PROGRAM_END \
while (0); \
} \
void
2010-05-25 06:35:35 +00:00
LayerManagerOGL::SetLayerProgramProjectionMatrix(const gfx3DMatrix& aMatrix)
{
2010-05-25 06:35:35 +00:00
FOR_EACH_LAYER_PROGRAM(lp) {
lp->Activate();
lp->SetProjectionMatrix(aMatrix);
} FOR_EACH_LAYER_PROGRAM_END
}
void
2010-05-25 06:35:35 +00:00
LayerManagerOGL::CreateFBOWithTexture(int aWidth, int aHeight,
GLuint *aFBO, GLuint *aTexture)
{
2010-05-25 06:35:35 +00:00
GLuint tex, fbo;
2010-05-25 06:35:35 +00:00
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);
2010-05-25 06:35:35 +00:00
NS_ASSERTION(mGLContext->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER) ==
LOCAL_GL_FRAMEBUFFER_COMPLETE, "Error setting up framebuffer.");
2010-05-25 06:35:35 +00:00
*aFBO = fbo;
*aTexture = tex;
2010-05-25 06:35:35 +00:00
DEBUG_GL_ERROR_CHECK(gl());
}
2010-05-25 06:35:35 +00:00
} /* layers */
} /* mozilla */