b=567626; fix up opengl layers; r=bas

This commit is contained in:
Vladimir Vukicevic 2010-05-24 23:35:35 -07:00
parent 64b69309d0
commit 4c3754729e
19 changed files with 2098 additions and 969 deletions

View File

@ -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

View File

@ -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<LayerManagerOGL*>(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<LayerManagerOGL*>(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<gfxImageSurface> updatedAreaImageSurface;
nsRefPtr<gfxASurface> sourceSurface = mSurface;
nsRefPtr<gfxASurface> sourceSurface = mCanvasSurface;
#ifdef XP_WIN
if (sourceSurface->GetType() == gfxASurface::SurfaceTypeWin32) {
sourceSurface = static_cast<gfxWindowsSurface*>(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<gfxImageSurface*>(mSurface.get());
if (mCanvasSurface->GetType() == gfxASurface::SurfaceTypeImage) {
gfxImageSurface *s = static_cast<gfxImageSurface*>(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<gfxContext> 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<LayerManagerOGL*>(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
}

View File

@ -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<gfxASurface> mSurface;
nsRefPtr<GLContext> mGLContext;
nsRefPtr<gfxASurface> mCanvasSurface;
nsRefPtr<GLContext> mCanvasGLContext;
unsigned int mTexture;
GLuint mTexture;
nsIntRect mBounds;
nsIntRect mUpdatedRect;

View File

@ -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 <robert@ocallahan.org>
* 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
@ -53,41 +54,37 @@ ColorLayerOGL::GetLayer()
}
void
ColorLayerOGL::RenderLayer(int, DrawThebesLayerCallback, void*)
ColorLayerOGL::RenderLayer(int,
const nsIntPoint& aOffset)
{
static_cast<LayerManagerOGL*>(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<LayerManagerOGL*>(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 */

View File

@ -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;

View File

@ -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<LayerManagerOGL*>(mManager)->GetRGBLayerProgram();
ColorLayerProgram *colorProgram =
static_cast<LayerManagerOGL*>(mManager)->GetColorLayerProgram();
YCbCrLayerProgram *yCbCrProgram =
static_cast<LayerManagerOGL*>(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());
}
}

View File

@ -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;

View File

@ -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 <bschouten@mozilla.org>
* 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
@ -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<LayerManagerOGL*>(mManager);
manager->MakeCurrent();
mOGLManager->MakeCurrent();
nsRefPtr<Image> image = GetContainer()->GetCurrentImage();
@ -285,28 +284,12 @@ ImageLayerOGL::RenderLayer(int, DrawThebesLayerCallback aCallback,
PlanarYCbCrImageOGL *yuvImage =
static_cast<PlanarYCbCrImageOGL*>(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<CairoImageOGL*>(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<gfxImageSurface> imageSurface =
new gfxImageSurface(aData.mSize, gfxASurface::ImageFormatARGB32);
nsRefPtr<gfxContext> 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());
}

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -20,6 +20,8 @@
*
* Contributor(s):
* Bas Schouten <bschouten@mozilla.org>
* 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
@ -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<GLvec2> 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<ColorTextureLayerProgram*>(mPrograms[RGBALayerProgramType]);
}
ColorTextureLayerProgram *GetBGRALayerProgram() {
return static_cast<ColorTextureLayerProgram*>(mPrograms[BGRALayerProgramType]);
}
ColorTextureLayerProgram *GetRGBXLayerProgram() {
return static_cast<ColorTextureLayerProgram*>(mPrograms[RGBXLayerProgramType]);
}
ColorTextureLayerProgram *GetBGRXLayerProgram() {
return static_cast<ColorTextureLayerProgram*>(mPrograms[BGRXLayerProgramType]);
}
ColorTextureLayerProgram *GetRGBARectLayerProgram() {
return static_cast<ColorTextureLayerProgram*>(mPrograms[RGBARectLayerProgramType]);
}
SolidColorLayerProgram *GetColorLayerProgram() {
return static_cast<SolidColorLayerProgram*>(mPrograms[ColorLayerProgramType]);
}
YCbCrTextureLayerProgram *GetYCbCrLayerProgram() {
return static_cast<YCbCrTextureLayerProgram*>(mPrograms[YCbCrLayerProgramType]);
}
CopyProgram *GetCopy2DProgram() {
return static_cast<CopyProgram*>(mPrograms[Copy2DProgramType]);
}
CopyProgram *GetCopy2DRectProgram() {
return static_cast<CopyProgram*>(mPrograms[Copy2DRectProgramType]);
}
ColorTextureLayerProgram *GetFBOLayerProgram() {
if (mFBOTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB)
return static_cast<ColorTextureLayerProgram*>(mPrograms[RGBARectLayerProgramType]);
return static_cast<ColorTextureLayerProgram*>(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<GLContext> 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<LayerManagerOGLProgram*> 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 */

View File

@ -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 <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 ***** */
#ifndef GFX_LAYERMANAGEROGLPROGRAM_H
#define GFX_LAYERMANAGEROGLPROGRAM_H
#include <string.h>
#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<UniformValue> 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<GLint> mUniformLocations;
nsTArray<GLint> 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<GLint> mUniformLocations;
nsTArray<GLint> mAttribLocations;
GLint mTexCoordMultiplierUniformLocation;
};
} /* layers */
} /* mozilla */
#endif /* GFX_LAYERMANAGEROGLPROGRAM_H */

View File

@ -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; \
}";

View File

@ -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 <bschouten@mozilla.org>
// 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 *****
//
// 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

View File

@ -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 <bschouten@mozilla.org>
* 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
@ -79,7 +80,7 @@ ThebesLayerOGL::ThebesLayerOGL(LayerManagerOGL *aManager)
ThebesLayerOGL::~ThebesLayerOGL()
{
static_cast<LayerManagerOGL*>(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<LayerManagerOGL*>(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<gfxContext> ctx = new gfxContext(surface);
ctx->Translate(gfxPoint(-mInvalidatedRect.x, -mInvalidatedRect.y));
aCallback(this, ctx, mInvalidatedRect, aCallbackData);
static_cast<LayerManagerOGL*>(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<gfxImageSurface> 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<LayerManagerOGL*>(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&

View File

@ -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 */

View File

@ -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 <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 *****
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])

View File

@ -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<nsVoidPtrHashKey, void*> 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;

View File

@ -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 */