This commit is contained in:
Robert Sayre 2010-08-06 22:47:02 -07:00
commit b8be454ea7
45 changed files with 1401 additions and 549 deletions

View File

@ -212,7 +212,7 @@ nsICanvasRenderingContextWebGL_BufferSubData(JSContext *cx, uintN argc, jsval *v
/*
* ReadPixels takes:
* TexImage2D(int, int, int, int, uint, uint, ArrayBufferView)
* ReadPixels(int, int, int, int, uint, uint, ArrayBufferView)
*/
static JSBool
nsICanvasRenderingContextWebGL_ReadPixels(JSContext *cx, uintN argc, jsval *vp)
@ -230,8 +230,7 @@ nsICanvasRenderingContextWebGL_ReadPixels(JSContext *cx, uintN argc, jsval *vp)
if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.jsval_addr(), nsnull))
return JS_FALSE;
// XXX we currently allow passing only 6 args to support the API. Eventually drop that.
if (argc < 6)
if (argc < 7)
return xpc_qsThrow(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
jsval *argv = JS_ARGV(cx, vp);
@ -244,40 +243,8 @@ nsICanvasRenderingContextWebGL_ReadPixels(JSContext *cx, uintN argc, jsval *vp)
GET_UINT32_ARG(argv4, 4);
GET_UINT32_ARG(argv5, 5);
if (argc == 6) {
/*** BEGIN old API deprecated code. Eventually drop that. ***/
// the code here is ugly, but temporary. It comes from the old ReadPixels implementation.
// Remove it as soon as it's OK to drop the old API.
PRInt32 byteLength;
rv = self->ReadPixels_byteLength_old_API_deprecated(argv2, argv3, argv4, argv5, &byteLength);
if (NS_FAILED(rv)) {
xpc_qsThrow(cx, NS_ERROR_FAILURE);
return JS_FALSE;
}
JSObject *abufObject = js_CreateArrayBuffer(cx, byteLength);
if (!abufObject) {
xpc_qsThrow(cx, NS_ERROR_FAILURE);
return JS_FALSE;
}
js::ArrayBuffer *abuf = js::ArrayBuffer::fromJSObject(abufObject);
rv = self->ReadPixels_buf(
argv0, argv1, argv2, argv3, argv4, argv5, abuf);
if (NS_FAILED(rv)) {
xpc_qsThrow(cx, NS_ERROR_FAILURE);
return JS_FALSE;
}
JSObject *retval = js_CreateTypedArrayWithBuffer(cx, js::TypedArray::TYPE_UINT8,
abufObject, 0, byteLength);
*vp = OBJECT_TO_JSVAL(retval);
return JS_TRUE; // return here to be unaffected by the *vp = JSVAL_VOID; below
/*** END old API deprecated code ***/
} else if (argc == 7 &&
!JSVAL_IS_PRIMITIVE(argv[6]))
if (argc == 7 &&
!JSVAL_IS_PRIMITIVE(argv[6]))
{
JSObject *argv6 = JSVAL_TO_OBJECT(argv[6]);
if (js_IsArrayBuffer(argv6)) {
@ -306,7 +273,7 @@ nsICanvasRenderingContextWebGL_ReadPixels(JSContext *cx, uintN argc, jsval *vp)
/*
* TexImage2D takes:
* TexImage2D(uint, int, uint, int, int, int, uint, uint, ArrayBufferView)\
* TexImage2D(uint, int, uint, int, int, int, uint, uint, ArrayBufferView)
* TexImage2D(uint, int, uint, uint, uint, nsIDOMElement)
* TexImage2D(uint, int, uint, uint, uint, ImageData)
*/
@ -326,9 +293,7 @@ nsICanvasRenderingContextWebGL_TexImage2D(JSContext *cx, uintN argc, jsval *vp)
if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.jsval_addr(), nsnull))
return JS_FALSE;
// XXX we currently allow passing only 3 args to support the API. Eventually drop that.
// if (argc < 6 || argc == 7 || argc == 8)
if (argc < 3)
if (argc < 6 || argc == 7 || argc == 8)
return xpc_qsThrow(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
jsval *argv = JS_ARGV(cx, vp);
@ -337,22 +302,9 @@ nsICanvasRenderingContextWebGL_TexImage2D(JSContext *cx, uintN argc, jsval *vp)
GET_UINT32_ARG(argv0, 0);
GET_INT32_ARG(argv1, 1);
if (argc > 2 && JSVAL_IS_OBJECT(argv[2])) {
// the old API. Eventually drop that.
nsIDOMElement *elt;
xpc_qsSelfRef eltRef;
rv = xpc_qsUnwrapArg<nsIDOMElement>(cx, argv[2], &elt, &eltRef.ptr, &argv[2]);
if (NS_FAILED(rv)) return JS_FALSE;
GET_OPTIONAL_UINT32_ARG(argv3, 3);
GET_OPTIONAL_UINT32_ARG(argv4, 4);
rv = self->TexImage2D_dom_old_API_deprecated(argv0, argv1, elt, argv3, argv4);
} else if (argc > 5 &&
!JSVAL_IS_PRIMITIVE(argv[5]))
if (argc > 5 &&
!JSVAL_IS_PRIMITIVE(argv[5]))
{
// implement the variants taking a DOMElement as argv[5]
GET_UINT32_ARG(argv2, 2);
GET_UINT32_ARG(argv3, 3);

View File

@ -56,6 +56,8 @@
#include "GLContextProvider.h"
#include "prenv.h"
using namespace mozilla;
using namespace mozilla::gl;
@ -275,29 +277,77 @@ WebGLContext::SetDimensions(PRInt32 width, PRInt32 height)
format.depth = 16;
format.minDepth = 1;
gl = gl::GLContextProvider::CreateOffscreen(gfxIntSize(width, height), format);
#ifdef XP_WIN
// On Windows, we may have a choice of backends, including straight
// OpenGL, D3D through ANGLE via EGL, or straight EGL/GLES2.
// We don't differentiate the latter two yet, but we allow for
// a env var to try EGL first, instead of last.
bool preferEGL = PR_GetEnv("MOZ_WEBGL_PREFER_EGL") != nsnull;
// if we want EGL, try it first
if (!gl && preferEGL) {
gl = gl::GLContextProviderEGL::CreateOffscreen(gfxIntSize(width, height), format);
if (gl && !InitAndValidateGL()) {
gl = nsnull;
}
}
// if it failed, then try the default provider, whatever that is
if (!gl) {
gl = gl::GLContextProvider::CreateOffscreen(gfxIntSize(width, height), format);
if (gl && !InitAndValidateGL()) {
gl = nsnull;
}
}
// if that failed, and we weren't already preferring EGL, try it now.
if (!gl && !preferEGL) {
gl = gl::GLContextProviderEGL::CreateOffscreen(gfxIntSize(width, height), format);
if (gl && !InitAndValidateGL()) {
gl = nsnull;
}
}
#else
// other platforms just use whatever the default is
if (!gl) {
gl = gl::GLContextProvider::CreateOffscreen(gfxIntSize(width, height), format);
if (gl && !InitAndValidateGL()) {
gl = nsnull;
}
}
#endif
// last chance, try OSMesa
if (!gl) {
gl = gl::GLContextProviderOSMesa::CreateOffscreen(gfxIntSize(width, height), format);
if (gl) {
if (!InitAndValidateGL()) {
gl = nsnull;
} else {
// make sure we notify always in this case, because it's likely going to be
// painfully slow
LogMessage("WebGL: Using software rendering via OSMesa");
}
}
}
if (!gl) {
LogMessage("WebGL: Can't get a usable OpenGL context.");
return NS_ERROR_FAILURE;
}
printf_stderr ("--- WebGL context created: %p\n", gl.get());
#ifdef USE_GLES2
// On native GLES2, no need to validate, the compiler will do it
mShaderValidation = PR_FALSE;
#else
// Check the shader validator pref
nsCOMPtr<nsIPrefBranch> prefService = do_GetService(NS_PREFSERVICE_CONTRACTID);
NS_ENSURE_TRUE(prefService != nsnull, NS_ERROR_FAILURE);
if (gl->IsGLES2()) {
// On native GLES2, no need to validate, the compiler will do it
mShaderValidation = PR_FALSE;
} else {
// Otherwise, check the shader validator pref
nsCOMPtr<nsIPrefBranch> prefService = do_GetService(NS_PREFSERVICE_CONTRACTID);
NS_ENSURE_TRUE(prefService != nsnull, NS_ERROR_FAILURE);
prefService->GetBoolPref("webgl.shader_validator", &mShaderValidation);
#endif
if (!InitAndValidateGL()) {
gl = gl::GLContextProviderOSMesa::CreateOffscreen(gfxIntSize(width, height), format);
if (!InitAndValidateGL()) {
LogMessage("WebGL: Can't get a usable OpenGL context.");
return NS_ERROR_FAILURE;
}
LogMessage("WebGL: Using software rendering via OSMesa");
prefService->GetBoolPref("webgl.shader_validator", &mShaderValidation);
}
mWidth = width;

View File

@ -2409,58 +2409,6 @@ WebGLContext::ReadPixels_buf(WebGLint x, WebGLint y, WebGLsizei width, WebGLsize
pixels ? pixels->byteLength : 0);
}
NS_IMETHODIMP
WebGLContext::ReadPixels_byteLength_old_API_deprecated(WebGLsizei width, WebGLsizei height,
WebGLenum format, WebGLenum type, WebGLsizei *retval)
{
*retval = 0;
if (width < 0 || height < 0)
return ErrorInvalidValue("ReadPixels: negative size passed");
PRUint32 size = 0;
switch (format) {
case LOCAL_GL_ALPHA:
size = 1;
break;
case LOCAL_GL_RGB:
size = 3;
break;
case LOCAL_GL_RGBA:
size = 4;
break;
default:
return ErrorInvalidEnumInfo("ReadPixels: format", format);
}
switch (type) {
// case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
// case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
// case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
case LOCAL_GL_UNSIGNED_BYTE:
break;
default:
return ErrorInvalidEnumInfo("ReadPixels: type", type);
}
PRUint32 packAlignment;
gl->fGetIntegerv(LOCAL_GL_PACK_ALIGNMENT, (GLint*) &packAlignment);
CheckedUint32 checked_plainRowSize = CheckedUint32(width) * size;
// alignedRowSize = row size rounded up to next multiple of
// packAlignment which is a power of 2
CheckedUint32 checked_alignedRowSize
= ((checked_plainRowSize + packAlignment-1) / packAlignment) * packAlignment;
CheckedUint32 checked_neededByteLength = (height-1)*checked_alignedRowSize + checked_plainRowSize;
if (!checked_neededByteLength.valid())
return ErrorInvalidOperation("ReadPixels: integer overflow computing the needed buffer size");
*retval = checked_neededByteLength.value();
return NS_OK;
}
NS_IMETHODIMP
WebGLContext::RenderbufferStorage(WebGLenum target, WebGLenum internalformat, WebGLsizei width, WebGLsizei height)
{
@ -3229,27 +3177,6 @@ WebGLContext::TexImage2D_dom(WebGLenum target, WebGLint level, WebGLenum interna
isurf->Data(), byteLength);
}
NS_IMETHODIMP
WebGLContext::TexImage2D_dom_old_API_deprecated(WebGLenum target, WebGLint level, nsIDOMElement *elt,
PRBool flipY, PRBool premultiplyAlpha)
{
nsRefPtr<gfxImageSurface> isurf;
nsresult rv = DOMElementToImageSurface(elt, getter_AddRefs(isurf),
flipY, premultiplyAlpha);
if (NS_FAILED(rv))
return rv;
NS_ASSERTION(isurf->Stride() == isurf->Width() * 4, "Bad stride!");
PRUint32 byteLength = isurf->Stride() * isurf->Height();
return TexImage2D_base(target, level, LOCAL_GL_RGBA,
isurf->Width(), isurf->Height(), 0,
LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE,
isurf->Data(), byteLength);
}
NS_IMETHODIMP
WebGLContext::TexSubImage2D(PRInt32 dummy)
{

View File

@ -128,7 +128,7 @@ interface nsIWebGLUniformLocation : nsISupports
};
[scriptable, uuid(f02c85e0-8305-11de-abe2-000c29206271)]
[scriptable, uuid(2f21ca21-9720-4eee-ad94-27eefe4f72dc)]
interface nsICanvasRenderingContextWebGL : nsISupports
{
//
@ -725,8 +725,6 @@ interface nsICanvasRenderingContextWebGL : nsISupports
in WebGLenum format, in WebGLenum type, in WebGLArrayPtr pixels);
[noscript] void readPixels_buf(in WebGLint x, in WebGLint y, in WebGLsizei width, in WebGLsizei height,
in WebGLenum format, in WebGLenum type, in WebGLArrayBufferPtr pixels);
[noscript] WebGLsizei readPixels_byteLength_old_API_deprecated(
in WebGLsizei width, in WebGLsizei height, in WebGLenum format, in WebGLenum type);
//void glReleaseShaderCompiler();
@ -754,9 +752,6 @@ interface nsICanvasRenderingContextWebGL : nsISupports
// HTMLImageElement, HTMLCanvasElement, HTMLVideoElement
[noscript] void texImage2D_dom(in WebGLenum target, in WebGLint level, in WebGLenum internalformat,
in WebGLenum format, in WebGLenum type, in nsIDOMElement element);
// XXX the old API. Eventually drop that.
[noscript] void TexImage2D_dom_old_API_deprecated(in WebGLenum target, in WebGLint level,
in nsIDOMElement element, in PRBool flipY, in PRBool premultiplyAlpha);
void texSubImage2D([optional] in long dummy);
[noscript] void texSubImage2D_buf(in WebGLenum target, in WebGLint level,

View File

@ -172,6 +172,13 @@ public:
*/
virtual gfxIntSize GetCurrentSize() = 0;
/**
* Set a new layer manager for this image container. It must be
* either of the same type as the container's current layer manager,
* or null. TRUE is returned on success.
*/
virtual PRBool SetLayerManager(LayerManager *aManager) = 0;
protected:
LayerManager* mManager;

View File

@ -142,12 +142,21 @@ public:
LAYERS_D3D9
};
LayerManager() : mUserData(nsnull)
LayerManager() : mUserData(nsnull), mDestroyed(PR_FALSE)
{
InitLog();
}
virtual ~LayerManager() {}
/**
* Release layers and resources held by this layer manager, and mark
* it as destroyed. Should do any cleanup necessary in preparation
* for its widget going away. After this call, only user data calls
* are valid on the layer manager.
*/
virtual void Destroy() { mDestroyed = PR_TRUE; }
PRBool IsDestroyed() { return mDestroyed; }
/**
* Start a new transaction. Nested transactions are not allowed so
* there must be no transaction currently in progress.
@ -297,6 +306,7 @@ public:
protected:
nsRefPtr<Layer> mRoot;
void* mUserData;
PRPackedBool mDestroyed;
// Print interesting information about this into aTo. Internally
// used to implement Dump*() and Log*().
@ -328,7 +338,9 @@ public:
virtual ~Layer() {}
/**
* Returns the LayoutManager this Layer belongs to. Cannot be null.
* Returns the LayerManager this Layer belongs to. Note that the layer
* manager might be in a destroyed state, at which point it's only
* valid to set/get user data from it.
*/
LayerManager* Manager() { return mManager; }
@ -387,6 +399,7 @@ public:
}
Mutated();
}
/**
* CONSTRUCTION PHASE ONLY
* Set a clip rect which will be applied to this layer as it is

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
*
@ -226,6 +226,7 @@ public:
virtual already_AddRefed<Image> GetCurrentImage();
virtual already_AddRefed<gfxASurface> GetCurrentAsSurface(gfxIntSize* aSize);
virtual gfxIntSize GetCurrentSize();
virtual PRBool SetLayerManager(LayerManager *aManager);
protected:
Monitor mMonitor;
@ -302,6 +303,20 @@ BasicImageContainer::GetCurrentSize()
return !mImage ? gfxIntSize(0,0) : ToImageData(mImage)->GetSize();
}
PRBool
BasicImageContainer::SetLayerManager(LayerManager *aManager)
{
if (aManager &&
aManager->GetBackendType() != LayerManager::LAYERS_BASIC)
{
return PR_FALSE;
}
// for basic layers, we can just swap; no magic needed.
mManager = aManager;
return PR_TRUE;
}
already_AddRefed<ImageContainer>
BasicLayerManager::CreateImageContainer()
{

View File

@ -701,15 +701,9 @@ BasicCanvasLayer::Updated(const nsIntRect& aRect)
// For simplicity, we read the entire framebuffer for now -- in
// the future we should use mUpdatedRect, though with WebGL we don't
// have an easy way to generate one.
if (mGLContext->IsGLES2()) {
mGLContext->fReadPixels(0, 0, mBounds.width, mBounds.height,
LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE,
isurf->Data());
} else {
mGLContext->fReadPixels(0, 0, mBounds.width, mBounds.height,
LOCAL_GL_BGRA, LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV,
isurf->Data());
}
mGLContext->ReadPixelsIntoImageSurface(0, 0,
mBounds.width, mBounds.height,
isurf);
// Put back the previous framebuffer binding.
if (currentFramebuffer != mCanvasFramebuffer)

View File

@ -111,9 +111,15 @@ CanvasLayerD3D9::Updated(const nsIntRect& aRect)
// For simplicity, we read the entire framebuffer for now -- in
// the future we should use aRect, though with WebGL we don't
// have an easy way to generate one.
mGLContext->fReadPixels(0, 0, mBounds.width, mBounds.height,
LOCAL_GL_BGRA, LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV,
destination);
nsRefPtr<gfxImageSurface> tmpSurface =
new gfxImageSurface(destination,
gfxIntSize(mBounds.width, mBounds.height),
mBounds.width * 4,
gfxASurface::ImageFormatARGB32);
mGLContext->ReadPixelsIntoImageSurface(0, 0,
mBounds.width, mBounds.height,
tmpSurface);
tmpSurface = nsnull;
// Put back the previous framebuffer binding.
if (currentFramebuffer != mCanvasFramebuffer)

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
*
@ -130,6 +130,13 @@ ImageContainerD3D9::GetCurrentSize()
return gfxIntSize(0,0);
}
PRBool
ImageContainerD3D9::SetLayerManager(LayerManager *aManager)
{
// we can't do anything here for now
return PR_FALSE;
}
Layer*
ImageLayerD3D9::GetLayer()
{

View File

@ -62,6 +62,8 @@ public:
virtual gfxIntSize GetCurrentSize();
virtual PRBool SetLayerManager(LayerManager *aManager);
private:
typedef mozilla::Mutex Mutex;

View File

@ -54,12 +54,17 @@ using namespace mozilla;
using namespace mozilla::layers;
using namespace mozilla::gl;
CanvasLayerOGL::~CanvasLayerOGL()
void
CanvasLayerOGL::Destroy()
{
mOGLManager->MakeCurrent();
if (!mDestroyed) {
if (mTexture) {
GLContext *cx = mOGLManager->glForResources();
cx->MakeCurrent();
cx->fDeleteTextures(1, &mTexture);
}
if (mTexture) {
gl()->fDeleteTextures(1, &mTexture);
mDestroyed = PR_TRUE;
}
}
@ -116,6 +121,10 @@ CanvasLayerOGL::MakeTexture()
void
CanvasLayerOGL::Updated(const nsIntRect& aRect)
{
if (mDestroyed) {
return;
}
NS_ASSERTION(mUpdatedRect.IsEmpty(),
"CanvasLayer::Updated called more than once during a transaction!");
@ -123,13 +132,15 @@ CanvasLayerOGL::Updated(const nsIntRect& aRect)
mUpdatedRect.UnionRect(mUpdatedRect, aRect);
if (mCanvasGLContext) {
if (mCanvasGLContext &&
mCanvasGLContext->GetContextType() == gl()->GetContextType())
{
if (gl()->BindOffscreenNeedsTexture(mCanvasGLContext) &&
mTexture == 0)
{
MakeTexture();
}
} else if (mCanvasSurface) {
} else {
PRBool newTexture = mTexture == 0;
if (newTexture) {
MakeTexture();
@ -140,40 +151,50 @@ CanvasLayerOGL::Updated(const nsIntRect& aRect)
}
nsRefPtr<gfxImageSurface> updatedAreaImageSurface;
nsRefPtr<gfxASurface> sourceSurface = mCanvasSurface;
if (mCanvasSurface) {
nsRefPtr<gfxASurface> sourceSurface = mCanvasSurface;
#ifdef XP_WIN
if (sourceSurface->GetType() == gfxASurface::SurfaceTypeWin32) {
sourceSurface = static_cast<gfxWindowsSurface*>(sourceSurface.get())->GetImageSurface();
if (!sourceSurface)
sourceSurface = mCanvasSurface;
}
if (sourceSurface->GetType() == gfxASurface::SurfaceTypeWin32) {
sourceSurface = static_cast<gfxWindowsSurface*>(sourceSurface.get())->GetImageSurface();
if (!sourceSurface)
sourceSurface = mCanvasSurface;
}
#endif
#if 0
// XXX don't copy, blah.
// but need to deal with stride on the gl side; do this later.
if (mCanvasSurface->GetType() == gfxASurface::SurfaceTypeImage) {
gfxImageSurface *s = static_cast<gfxImageSurface*>(mCanvasSurface.get());
if (s->Format() == gfxASurface::ImageFormatARGB32 ||
s->Format() == gfxASurface::ImageFormatRGB24)
{
updatedAreaImageSurface = ...;
} else {
NS_WARNING("surface with format that we can't handle");
return;
}
} else
// XXX don't copy, blah.
// but need to deal with stride on the gl side; do this later.
if (mCanvasSurface->GetType() == gfxASurface::SurfaceTypeImage) {
gfxImageSurface *s = static_cast<gfxImageSurface*>(mCanvasSurface.get());
if (s->Format() == gfxASurface::ImageFormatARGB32 ||
s->Format() == gfxASurface::ImageFormatRGB24)
{
updatedAreaImageSurface = ...;
} else {
NS_WARNING("surface with format that we can't handle");
return;
}
} else
#endif
{
{
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);
ctx->SetSource(sourceSurface);
ctx->Paint();
}
} else if (mCanvasGLContext) {
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);
ctx->SetSource(sourceSurface);
ctx->Paint();
mCanvasGLContext->ReadPixelsIntoImageSurface(mUpdatedRect.x, mUpdatedRect.y,
mUpdatedRect.width,
mUpdatedRect.height,
updatedAreaImageSurface);
}
if (newTexture) {
@ -222,12 +243,12 @@ CanvasLayerOGL::RenderLayer(int aPreviousDestination,
gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
}
if (mCanvasGLContext) {
bool useGLContext = mCanvasGLContext &&
mCanvasGLContext->GetContextType() == gl()->GetContextType();
if (useGLContext) {
gl()->BindTex2DOffscreen(mCanvasGLContext);
DEBUG_GL_ERROR_CHECK(gl());
}
if (mCanvasGLContext) {
program = mOGLManager->GetRGBALayerProgram();
} else {
program = mOGLManager->GetBGRALayerProgram();
@ -244,7 +265,7 @@ CanvasLayerOGL::RenderLayer(int aPreviousDestination,
DEBUG_GL_ERROR_CHECK(gl());
if (mCanvasGLContext) {
if (useGLContext) {
gl()->UnbindTex2DOffscreen(mCanvasGLContext);
}

View File

@ -56,14 +56,14 @@ public:
{
mImplData = static_cast<LayerOGL*>(this);
}
~CanvasLayerOGL();
~CanvasLayerOGL() { Destroy(); }
// CanvasLayer implementation
virtual void Initialize(const Data& aData);
virtual void Updated(const nsIntRect& aRect);
// LayerOGL implementation
virtual void Destroy();
virtual Layer* GetLayer() { return this; }
virtual void RenderLayer(int aPreviousFrameBuffer,
const nsIntPoint& aOffset);

View File

@ -53,10 +53,13 @@ public:
{
mImplData = static_cast<LayerOGL*>(this);
}
~ColorLayerOGL() { Destroy(); }
// LayerOGL Implementation
virtual Layer* GetLayer();
virtual void Destroy() { mDestroyed = PR_TRUE; }
virtual void RenderLayer(int aPreviousFrameBuffer,
const nsIntPoint& aOffset);
};

View File

@ -49,8 +49,18 @@ ContainerLayerOGL::ContainerLayerOGL(LayerManagerOGL *aManager)
ContainerLayerOGL::~ContainerLayerOGL()
{
while (mFirstChild) {
RemoveChild(mFirstChild);
Destroy();
}
void
ContainerLayerOGL::Destroy()
{
if (!mDestroyed) {
while (mFirstChild) {
GetFirstChildOGL()->Destroy();
RemoveChild(mFirstChild);
}
mDestroyed = PR_TRUE;
}
}

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
*
@ -60,6 +60,8 @@ public:
/** LayerOGL implementation */
Layer* GetLayer();
void Destroy();
LayerOGL* GetFirstChildOGL();
PRBool IsEmpty();

View File

@ -57,11 +57,13 @@ public:
GLuint aTexture)
: mContext(aContext), mTexture(aTexture)
{
NS_ASSERTION(aTexture, "TextureDeleter instantiated with nothing to do");
}
NS_IMETHOD Run() {
if (mTexture) {
mContext->DestroyTexture(mTexture);
}
mContext->MakeCurrent();
mContext->fDeleteTextures(1, &mTexture);
// Ensure context is released on the main thread
mContext = nsnull;
return NS_OK;
@ -74,12 +76,15 @@ public:
void
GLTexture::Allocate(GLContext *aContext)
{
NS_ASSERTION(NS_IsMainThread(), "Can only allocate texture on main thread");
NS_ASSERTION(aContext->IsGlobalSharedContext() ||
NS_IsMainThread(), "Can only allocate texture on main thread or with cx sharing");
Release();
mContext = aContext;
mTexture = mContext->CreateTexture();
mContext->MakeCurrent();
mContext->fGenTextures(1, &mTexture);
}
void
@ -100,19 +105,20 @@ GLTexture::Release()
return;
}
if (NS_IsMainThread()) {
if (mTexture) {
mContext->DestroyTexture(mTexture);
mTexture = 0;
if (mTexture) {
if (NS_IsMainThread() || mContext->IsGlobalSharedContext()) {
mContext->MakeCurrent();
mContext->fDeleteTextures(1, &mTexture);
} else {
nsCOMPtr<nsIRunnable> runnable =
new TextureDeleter(mContext.forget(), mTexture);
NS_DispatchToMainThread(runnable);
}
mContext = nsnull;
return;
mTexture = 0;
}
nsCOMPtr<nsIRunnable> runnable =
new TextureDeleter(mContext.forget(), mTexture);
NS_DispatchToMainThread(runnable);
mTexture = 0;
mContext = nsnull;
}
RecycleBin::RecycleBin()
@ -133,7 +139,7 @@ RecycleBin::RecycleBuffer(PRUint8* aBuffer, PRUint32 aSize)
}
PRUint8*
RecycleBin::TakeBuffer(PRUint32 aSize)
RecycleBin::GetBuffer(PRUint32 aSize)
{
MutexAutoLock lock(mLock);
@ -163,8 +169,8 @@ RecycleBin::RecycleTexture(GLTexture *aTexture, TextureType aType,
}
void
RecycleBin::TakeTexture(TextureType aType, const gfxIntSize& aSize,
GLContext *aContext, GLTexture *aOutTexture)
RecycleBin::GetTexture(TextureType aType, const gfxIntSize& aSize,
GLContext *aContext, GLTexture *aOutTexture)
{
MutexAutoLock lock(mLock);
@ -184,6 +190,15 @@ ImageContainerOGL::ImageContainerOGL(LayerManagerOGL *aManager)
{
}
ImageContainerOGL::~ImageContainerOGL()
{
if (mManager) {
NS_ASSERTION(mManager->GetBackendType() == LayerManager::LAYERS_OPENGL, "Wrong layer manager got assigned to ImageContainerOGL!");
static_cast<LayerManagerOGL*>(mManager)->ForgetImageContainer(this);
}
}
already_AddRefed<Image>
ImageContainerOGL::CreateImage(const Image::Format *aFormats,
PRUint32 aNumFormats)
@ -193,7 +208,8 @@ ImageContainerOGL::CreateImage(const Image::Format *aFormats,
}
nsRefPtr<Image> img;
if (aFormats[0] == Image::PLANAR_YCBCR) {
img = new PlanarYCbCrImageOGL(mRecycleBin);
img = new PlanarYCbCrImageOGL(static_cast<LayerManagerOGL*>(mManager),
mRecycleBin);
} else if (aFormats[0] == Image::CAIRO_SURFACE) {
img = new CairoImageOGL(static_cast<LayerManagerOGL*>(mManager));
}
@ -228,7 +244,47 @@ ImageContainerOGL::GetCurrentImage()
already_AddRefed<gfxASurface>
ImageContainerOGL::GetCurrentAsSurface(gfxIntSize *aSize)
{
return nsnull;
MutexAutoLock lock(mActiveImageLock);
if (!mActiveImage) {
*aSize = gfxIntSize(0,0);
return nsnull;
}
GLContext *gl = nsnull;
// tex1 will be RGBA or Y, tex2 will Cb, tex3 will be Cr
GLuint tex1 = 0, tex2 = 0, tex3 = 0;
gfxIntSize size;
if (mActiveImage->GetFormat() == Image::PLANAR_YCBCR) {
PlanarYCbCrImageOGL *yuvImage =
static_cast<PlanarYCbCrImageOGL*>(mActiveImage.get());
if (!yuvImage->HasData() || !yuvImage->HasTextures()) {
*aSize = gfxIntSize(0, 0);
return nsnull;
}
size = yuvImage->mSize;
gl = yuvImage->mTextures[0].GetGLContext();
tex1 = yuvImage->mTextures[0].GetTextureID();
tex2 = yuvImage->mTextures[1].GetTextureID();
tex3 = yuvImage->mTextures[2].GetTextureID();
}
if (mActiveImage->GetFormat() == Image::CAIRO_SURFACE) {
CairoImageOGL *cairoImage =
static_cast<CairoImageOGL*>(mActiveImage.get());
size = cairoImage->mSize;
gl = cairoImage->mTexture.GetGLContext();
tex1 = cairoImage->mTexture.GetTextureID();
}
// XXX TODO: read all textures in YCbCr case and convert to RGB
// XXX Or maybe add a ReadYCbCrTextureImage that will take 3 textures
// and return RGB, since we can render YCbCr to the temporary framebuffer.
nsRefPtr<gfxImageSurface> s = gl->ReadTextureImage(tex1, size, LOCAL_GL_RGBA);
*aSize = size;
return s.forget();
}
gfxIntSize
@ -238,6 +294,7 @@ ImageContainerOGL::GetCurrentSize()
if (!mActiveImage) {
return gfxIntSize(0,0);
}
if (mActiveImage->GetFormat() == Image::PLANAR_YCBCR) {
PlanarYCbCrImageOGL *yuvImage =
static_cast<PlanarYCbCrImageOGL*>(mActiveImage.get());
@ -246,7 +303,9 @@ ImageContainerOGL::GetCurrentSize()
}
return yuvImage->mSize;
} else if (mActiveImage->GetFormat() == Image::CAIRO_SURFACE) {
}
if (mActiveImage->GetFormat() == Image::CAIRO_SURFACE) {
CairoImageOGL *cairoImage =
static_cast<CairoImageOGL*>(mActiveImage.get());
return cairoImage->mSize;
@ -255,6 +314,38 @@ ImageContainerOGL::GetCurrentSize()
return gfxIntSize(0,0);
}
PRBool
ImageContainerOGL::SetLayerManager(LayerManager *aManager)
{
if (!aManager) {
// the layer manager just entirely went away
// XXX if we don't have context sharing, we should tell our images
// that their textures are no longer valid.
mManager = nsnull;
return PR_TRUE;
}
if (aManager->GetBackendType() != LayerManager::LAYERS_OPENGL) {
return PR_FALSE;
}
LayerManagerOGL* lmOld = static_cast<LayerManagerOGL*>(mManager);
LayerManagerOGL* lmNew = static_cast<LayerManagerOGL*>(aManager);
if (lmOld) {
NS_ASSERTION(lmNew->glForResources() == lmOld->glForResources(),
"We require GL context sharing here!");
lmOld->ForgetImageContainer(this);
}
mManager = aManager;
lmNew->RememberImageContainer(this);
return PR_TRUE;
}
Layer*
ImageLayerOGL::GetLayer()
{
@ -276,11 +367,15 @@ ImageLayerOGL::RenderLayer(int,
PlanarYCbCrImageOGL *yuvImage =
static_cast<PlanarYCbCrImageOGL*>(image.get());
if (!yuvImage->HasData())
if (!yuvImage->HasData()) {
return;
}
if (!yuvImage->HasTextures()) {
yuvImage->AllocateTextures(gl());
}
if (!yuvImage->HasTextures())
yuvImage->AllocateTextures(mOGLManager);
yuvImage->UpdateTextures(gl());
gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, yuvImage->mTextures[0].GetTextureID());
@ -335,9 +430,39 @@ ImageLayerOGL::RenderLayer(int,
DEBUG_GL_ERROR_CHECK(gl());
}
PlanarYCbCrImageOGL::PlanarYCbCrImageOGL(RecycleBin *aRecycleBin)
static void
InitTexture(GLContext* aGL, GLuint aTexture, GLenum aFormat, const gfxIntSize& aSize)
{
aGL->fBindTexture(LOCAL_GL_TEXTURE_2D, aTexture);
aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR);
aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR);
aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
aGL->fTexImage2D(LOCAL_GL_TEXTURE_2D,
0,
aFormat,
aSize.width,
aSize.height,
0,
aFormat,
LOCAL_GL_UNSIGNED_BYTE,
NULL);
}
PlanarYCbCrImageOGL::PlanarYCbCrImageOGL(LayerManagerOGL *aManager,
RecycleBin *aRecycleBin)
: PlanarYCbCrImage(nsnull), mRecycleBin(aRecycleBin), mHasData(PR_FALSE)
{
#if 0
// We really want to allocate this on the decode thread -- but to do that,
// we need to create a per-thread shared GL context, and it will only work
// if we have context sharing. For now, create the textures on the main
// thread the first time we render.
if (aManager) {
AllocateTextures(aManager->glForResources());
}
#endif
}
PlanarYCbCrImageOGL::~PlanarYCbCrImageOGL()
@ -346,9 +471,11 @@ PlanarYCbCrImageOGL::~PlanarYCbCrImageOGL()
mRecycleBin->RecycleBuffer(mBuffer.forget(), mBufferSize);
}
mRecycleBin->RecycleTexture(&mTextures[0], RecycleBin::TEXTURE_Y, mData.mYSize);
mRecycleBin->RecycleTexture(&mTextures[1], RecycleBin::TEXTURE_C, mData.mCbCrSize);
mRecycleBin->RecycleTexture(&mTextures[2], RecycleBin::TEXTURE_C, mData.mCbCrSize);
if (HasTextures()) {
mRecycleBin->RecycleTexture(&mTextures[0], RecycleBin::TEXTURE_Y, mData.mYSize);
mRecycleBin->RecycleTexture(&mTextures[1], RecycleBin::TEXTURE_C, mData.mCbCrSize);
mRecycleBin->RecycleTexture(&mTextures[2], RecycleBin::TEXTURE_C, mData.mCbCrSize);
}
}
void
@ -384,7 +511,7 @@ PlanarYCbCrImageOGL::SetData(const PlanarYCbCrImage::Data &aData)
mBufferSize = mData.mCbCrStride * mData.mCbCrSize.height * 2 +
mData.mYStride * mData.mYSize.height;
mBuffer = mRecycleBin->TakeBuffer(mBufferSize);
mBuffer = mRecycleBin->GetBuffer(mBufferSize);
if (!mBuffer)
return;
@ -417,54 +544,24 @@ PlanarYCbCrImageOGL::SetData(const PlanarYCbCrImage::Data &aData)
mHasData = PR_TRUE;
}
static void
SetupPlaneTexture(GLContext* aGL, const gfxIntSize& aSize, PRUint8* aData, PRBool aIsNew)
void
PlanarYCbCrImageOGL::AllocateTextures(mozilla::gl::GLContext *gl)
{
aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR);
aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR);
aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
gl->MakeCurrent();
if (aIsNew) {
aGL->fTexImage2D(LOCAL_GL_TEXTURE_2D,
0,
LOCAL_GL_LUMINANCE,
aSize.width,
aSize.height,
0,
LOCAL_GL_LUMINANCE,
LOCAL_GL_UNSIGNED_BYTE,
aData);
} else {
aGL->fTexSubImage2D(LOCAL_GL_TEXTURE_2D,
0,
0, 0,
aSize.width,
aSize.height,
LOCAL_GL_LUMINANCE,
LOCAL_GL_UNSIGNED_BYTE,
aData);
}
mRecycleBin->GetTexture(RecycleBin::TEXTURE_Y, mData.mYSize, gl, &mTextures[0]);
InitTexture(gl, mTextures[0].GetTextureID(), LOCAL_GL_LUMINANCE, mData.mYSize);
mRecycleBin->GetTexture(RecycleBin::TEXTURE_C, mData.mCbCrSize, gl, &mTextures[1]);
InitTexture(gl, mTextures[1].GetTextureID(), LOCAL_GL_LUMINANCE, mData.mCbCrSize);
mRecycleBin->GetTexture(RecycleBin::TEXTURE_C, mData.mCbCrSize, gl, &mTextures[2]);
InitTexture(gl, mTextures[2].GetTextureID(), LOCAL_GL_LUMINANCE, mData.mCbCrSize);
}
void
PlanarYCbCrImageOGL::AllocateTextures(LayerManagerOGL *aManager)
PlanarYCbCrImageOGL::UpdateTextures(GLContext *gl)
{
aManager->MakeCurrent();
mozilla::gl::GLContext *gl = aManager->gl();
PRPackedBool isNewTexture[3];
for (PRUint32 i = 0; i < 3; ++i) {
isNewTexture[i] = !mTextures[i].IsAllocated();
}
mRecycleBin->TakeTexture(RecycleBin::TEXTURE_Y, mData.mYSize, gl, &mTextures[0]);
mRecycleBin->TakeTexture(RecycleBin::TEXTURE_C, mData.mCbCrSize, gl, &mTextures[1]);
mRecycleBin->TakeTexture(RecycleBin::TEXTURE_C, mData.mCbCrSize, gl, &mTextures[2]);
if (!HasTextures())
return;
GLint alignment;
if (!((ptrdiff_t)mData.mYStride & 0x7) && !((ptrdiff_t)mData.mYChannel & 0x7)) {
@ -481,12 +578,16 @@ PlanarYCbCrImageOGL::AllocateTextures(LayerManagerOGL *aManager)
gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, alignment);
gl->fBindTexture(LOCAL_GL_TEXTURE_2D, mTextures[0].GetTextureID());
SetupPlaneTexture(gl, mData.mYSize, mData.mYChannel, isNewTexture[0]);
gl->fTexSubImage2D(LOCAL_GL_TEXTURE_2D, 0,
0, 0, mData.mYSize.width, mData.mYSize.height,
LOCAL_GL_LUMINANCE,
LOCAL_GL_UNSIGNED_BYTE,
mData.mYChannel);
if (!((ptrdiff_t)mData.mCbCrStride & 0x7) &&
!((ptrdiff_t)mData.mCbChannel & 0x7) &&
!((ptrdiff_t)mData.mCrChannel & 0x7)) {
!((ptrdiff_t)mData.mCrChannel & 0x7))
{
alignment = 8;
} else if (!((ptrdiff_t)mData.mCbCrStride & 0x3)) {
alignment = 4;
@ -500,12 +601,18 @@ PlanarYCbCrImageOGL::AllocateTextures(LayerManagerOGL *aManager)
gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, alignment);
gl->fBindTexture(LOCAL_GL_TEXTURE_2D, mTextures[1].GetTextureID());
SetupPlaneTexture(gl, mData.mCbCrSize, mData.mCbChannel, isNewTexture[1]);
gl->fTexSubImage2D(LOCAL_GL_TEXTURE_2D, 0,
0, 0, mData.mCbCrSize.width, mData.mCbCrSize.height,
LOCAL_GL_LUMINANCE,
LOCAL_GL_UNSIGNED_BYTE,
mData.mCbChannel);
gl->fBindTexture(LOCAL_GL_TEXTURE_2D, mTextures[2].GetTextureID());
SetupPlaneTexture(gl, mData.mCbCrSize, mData.mCrChannel, isNewTexture[2]);
gl->fTexSubImage2D(LOCAL_GL_TEXTURE_2D, 0,
0, 0, mData.mCbCrSize.width, mData.mCbCrSize.height,
LOCAL_GL_LUMINANCE,
LOCAL_GL_UNSIGNED_BYTE,
mData.mCrChannel);
// Reset alignment to default
gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4);
@ -516,12 +623,15 @@ PlanarYCbCrImageOGL::AllocateTextures(LayerManagerOGL *aManager)
}
}
CairoImageOGL::CairoImageOGL(LayerManagerOGL *aManager) : CairoImage(nsnull)
CairoImageOGL::CairoImageOGL(LayerManagerOGL *aManager)
: CairoImage(nsnull)
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread to create a cairo image");
// Allocate texture now to grab a reference to the GLContext
mTexture.Allocate(aManager->gl());
if (aManager) {
// Allocate texture now to grab a reference to the GLContext
mTexture.Allocate(aManager->glForResources());
}
}
void
@ -533,20 +643,20 @@ CairoImageOGL::SetData(const CairoImage::Data &aData)
mozilla::gl::GLContext *gl = mTexture.GetGLContext();
gl->MakeCurrent();
mSize = aData.mSize;
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);
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);
if (mSize != aData.mSize) {
gl->fActiveTexture(LOCAL_GL_TEXTURE0);
InitTexture(gl, mTexture.GetTextureID(), LOCAL_GL_RGBA, aData.mSize);
mSize = aData.mSize;
} else {
gl->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture.GetTextureID());
}
if (!mASurfaceAsGLContext) {
mASurfaceAsGLContext = GLContextProvider::CreateForNativePixmapSurface(aData.mSurface);
if (mASurfaceAsGLContext)
mASurfaceAsGLContext->BindTexImage();
}
if (mASurfaceAsGLContext)
return;
@ -561,15 +671,11 @@ CairoImageOGL::SetData(const CairoImage::Data &aData)
context->SetSource(aData.mSurface);
context->Paint();
gl->fTexImage2D(LOCAL_GL_TEXTURE_2D,
0,
LOCAL_GL_RGBA,
mSize.width,
mSize.height,
0,
LOCAL_GL_RGBA,
LOCAL_GL_UNSIGNED_BYTE,
imageSurface->Data());
gl->fTexSubImage2D(LOCAL_GL_TEXTURE_2D, 0,
0, 0, mSize.width, mSize.height,
LOCAL_GL_RGBA,
LOCAL_GL_UNSIGNED_BYTE,
imageSurface->Data());
}
} /* layers */

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
*
@ -102,7 +102,7 @@ public:
void RecycleBuffer(PRUint8* aBuffer, PRUint32 aSize);
// Returns a recycled buffer of the right size, or allocates a new buffer.
PRUint8* TakeBuffer(PRUint32 aSize);
PRUint8* GetBuffer(PRUint32 aSize);
enum TextureType {
TEXTURE_Y,
@ -111,8 +111,8 @@ public:
void RecycleTexture(GLTexture *aTexture, TextureType aType,
const gfxIntSize& aSize);
void TakeTexture(TextureType aType, const gfxIntSize& aSize,
GLContext *aContext, GLTexture *aOutTexture);
void GetTexture(TextureType aType, const gfxIntSize& aSize,
GLContext *aContext, GLTexture *aOutTexture);
private:
typedef mozilla::Mutex Mutex;
@ -135,7 +135,7 @@ class THEBES_API ImageContainerOGL : public ImageContainer
{
public:
ImageContainerOGL(LayerManagerOGL *aManager);
virtual ~ImageContainerOGL() {}
virtual ~ImageContainerOGL();
virtual already_AddRefed<Image> CreateImage(const Image::Format* aFormats,
PRUint32 aNumFormats);
@ -148,6 +148,8 @@ public:
virtual gfxIntSize GetCurrentSize();
virtual PRBool SetLayerManager(LayerManager *aManager);
private:
typedef mozilla::Mutex Mutex;
@ -169,8 +171,10 @@ public:
{
mImplData = static_cast<LayerOGL*>(this);
}
~ImageLayerOGL() { Destroy(); }
// LayerOGL Implementation
virtual void Destroy() { mDestroyed = PR_TRUE; }
virtual Layer* GetLayer();
virtual void RenderLayer(int aPreviousFrameBuffer,
@ -182,7 +186,8 @@ class THEBES_API PlanarYCbCrImageOGL : public PlanarYCbCrImage
typedef mozilla::gl::GLContext GLContext;
public:
PlanarYCbCrImageOGL(RecycleBin *aRecycleBin);
PlanarYCbCrImageOGL(LayerManagerOGL *aManager,
RecycleBin *aRecycleBin);
~PlanarYCbCrImageOGL();
virtual void SetData(const Data &aData);
@ -191,7 +196,9 @@ public:
* Upload the data from out mData into our textures. For now we use this to
* make sure the textures are created and filled on the main thread.
*/
void AllocateTextures(LayerManagerOGL *aManager);
void AllocateTextures(GLContext *gl);
void UpdateTextures(GLContext *gl);
PRBool HasData() { return mHasData; }
PRBool HasTextures()
{

View File

@ -76,8 +76,30 @@ LayerManagerOGL::LayerManagerOGL(nsIWidget *aWidget)
LayerManagerOGL::~LayerManagerOGL()
{
mRoot = nsnull;
CleanupResources();
Destroy();
}
void
LayerManagerOGL::Destroy()
{
if (!mDestroyed) {
if (mRoot) {
RootLayer()->Destroy();
}
mRoot = nsnull;
// Make a copy, since SetLayerManager will cause mImageContainers
// to get mutated.
nsTArray<ImageContainer*> imageContainers(mImageContainers);
for (PRUint32 i = 0; i < imageContainers.Length(); ++i) {
ImageContainer *c = imageContainers[i];
c->SetLayerManager(nsnull);
}
CleanupResources();
mDestroyed = PR_TRUE;
}
}
void
@ -90,7 +112,7 @@ LayerManagerOGL::CleanupResources()
if (!ctx) {
ctx = mGLContext;
}
ctx->MakeCurrent();
for (unsigned int i = 0; i < mPrograms.Length(); ++i)
@ -125,6 +147,7 @@ LayerManagerOGL::Initialize(GLContext *aExistingContext)
} else {
if (mGLContext)
CleanupResources();
mGLContext = gl::GLContextProvider::CreateForWindow(mWidget);
if (!mGLContext) {
@ -137,10 +160,9 @@ LayerManagerOGL::Initialize(GLContext *aExistingContext)
DEBUG_GL_ERROR_CHECK(mGLContext);
const char *extensionStr =
(const char*) mGLContext->fGetString(LOCAL_GL_EXTENSIONS);
mHasBGRA = (strstr(extensionStr, "EXT_bgra") != nsnull);
mHasBGRA =
mGLContext->IsExtensionSupported(gl::GLContext::EXT_texture_format_BGRA8888) ||
mGLContext->IsExtensionSupported(gl::GLContext::EXT_bgra);
mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
LOCAL_GL_ONE, LOCAL_GL_ONE);
@ -259,7 +281,7 @@ LayerManagerOGL::Initialize(GLContext *aExistingContext)
* texture rectangle access inside GLSL (sampler2DRect,
* texture2DRect).
*/
if (strstr(extensionStr, "ARB_texture_rectangle") == NULL)
if (!mGLContext->IsExtensionSupported(gl::GLContext::ARB_texture_rectangle))
return false;
}
@ -327,6 +349,11 @@ LayerManagerOGL::BeginTransaction()
void
LayerManagerOGL::BeginTransactionWithTarget(gfxContext *aTarget)
{
if (mDestroyed) {
NS_WARNING("Call on destroyed layer manager");
return;
}
mTarget = aTarget;
}
@ -334,6 +361,11 @@ void
LayerManagerOGL::EndTransaction(DrawThebesLayerCallback aCallback,
void* aCallbackData)
{
if (mDestroyed) {
NS_WARNING("Call on destroyed layer manager");
return;
}
mThebesLayerCallback = aCallback;
mThebesLayerCallbackData = aCallbackData;
@ -348,6 +380,11 @@ LayerManagerOGL::EndTransaction(DrawThebesLayerCallback aCallback,
already_AddRefed<ThebesLayer>
LayerManagerOGL::CreateThebesLayer()
{
if (mDestroyed) {
NS_WARNING("Call on destroyed layer manager");
return nsnull;
}
nsRefPtr<ThebesLayer> layer = new ThebesLayerOGL(this);
return layer.forget();
}
@ -355,6 +392,11 @@ LayerManagerOGL::CreateThebesLayer()
already_AddRefed<ContainerLayer>
LayerManagerOGL::CreateContainerLayer()
{
if (mDestroyed) {
NS_WARNING("Call on destroyed layer manager");
return nsnull;
}
nsRefPtr<ContainerLayer> layer = new ContainerLayerOGL(this);
return layer.forget();
}
@ -362,13 +404,24 @@ LayerManagerOGL::CreateContainerLayer()
already_AddRefed<ImageContainer>
LayerManagerOGL::CreateImageContainer()
{
if (mDestroyed) {
NS_WARNING("Call on destroyed layer manager");
return nsnull;
}
nsRefPtr<ImageContainer> container = new ImageContainerOGL(this);
RememberImageContainer(container);
return container.forget();
}
already_AddRefed<ImageLayer>
LayerManagerOGL::CreateImageLayer()
{
if (mDestroyed) {
NS_WARNING("Call on destroyed layer manager");
return nsnull;
}
nsRefPtr<ImageLayer> layer = new ImageLayerOGL(this);
return layer.forget();
}
@ -376,6 +429,11 @@ LayerManagerOGL::CreateImageLayer()
already_AddRefed<ColorLayer>
LayerManagerOGL::CreateColorLayer()
{
if (mDestroyed) {
NS_WARNING("Call on destroyed layer manager");
return nsnull;
}
nsRefPtr<ColorLayer> layer = new ColorLayerOGL(this);
return layer.forget();
}
@ -383,25 +441,65 @@ LayerManagerOGL::CreateColorLayer()
already_AddRefed<CanvasLayer>
LayerManagerOGL::CreateCanvasLayer()
{
if (mDestroyed) {
NS_WARNING("Call on destroyed layer manager");
return nsnull;
}
nsRefPtr<CanvasLayer> layer = new CanvasLayerOGL(this);
return layer.forget();
}
void
LayerManagerOGL::ForgetImageContainer(ImageContainer *aContainer)
{
NS_ASSERTION(aContainer->Manager() == this,
"ForgetImageContainer called on non-owned container!");
if (!mImageContainers.RemoveElement(aContainer)) {
NS_WARNING("ForgetImageContainer couldn't find container it was supposed to forget!");
return;
}
}
void
LayerManagerOGL::RememberImageContainer(ImageContainer *aContainer)
{
NS_ASSERTION(aContainer->Manager() == this,
"RememberImageContainer called on non-owned container!");
mImageContainers.AppendElement(aContainer);
}
void
LayerManagerOGL::MakeCurrent()
{
if (mDestroyed) {
NS_WARNING("Call on destroyed layer manager");
return;
}
mGLContext->MakeCurrent();
}
LayerOGL*
LayerManagerOGL::RootLayer() const
{
if (mDestroyed) {
NS_WARNING("Call on destroyed layer manager");
return nsnull;
}
return static_cast<LayerOGL*>(mRoot->ImplData());
}
void
LayerManagerOGL::Render()
{
if (mDestroyed) {
NS_WARNING("Call on destroyed layer manager");
return;
}
nsIntRect rect;
mWidget->GetBounds(rect);
GLint width = rect.width;
@ -645,12 +743,22 @@ LayerManagerOGL::CopyToTarget()
NS_ASSERTION(imageSurface->Stride() == width * 4,
"Image Surfaces being created with weird stride!");
PRUint32 currentPackAlignment = 0;
mGLContext->fGetIntegerv(LOCAL_GL_PACK_ALIGNMENT, (GLint*)&currentPackAlignment);
if (currentPackAlignment != 4) {
mGLContext->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, 4);
}
mGLContext->fReadPixels(0, 0,
width, height,
format,
LOCAL_GL_UNSIGNED_BYTE,
imageSurface->Data());
if (currentPackAlignment != 4) {
mGLContext->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, currentPackAlignment);
}
if (!mHasBGRA) {
// need to swap B and R bytes
for (int j = 0; j < height; ++j) {
@ -739,6 +847,5 @@ LayerManagerOGL::CreateFBOWithTexture(int aWidth, int aHeight,
DEBUG_GL_ERROR_CHECK(gl());
}
} /* layers */
} /* mozilla */

View File

@ -83,6 +83,8 @@ public:
void CleanupResources();
void Destroy();
/**
* Initializes the layer manager, this is when the layer manager will
* actually access the device and attempt to create the swap chain used
@ -135,6 +137,16 @@ public:
virtual LayersBackend GetBackendType() { return LAYERS_OPENGL; }
/**
* Image Container management.
*/
/* Forget this image container. Should be called by ImageContainerOGL
* on its current layer manager before switching to a new one.
*/
void ForgetImageContainer(ImageContainer* aContainer);
void RememberImageContainer(ImageContainer* aContainer);
/**
* Helper methods.
*/
@ -182,6 +194,16 @@ public:
void* GetThebesLayerCallbackData() const
{ return mThebesLayerCallbackData; }
// This is a GLContext that can be used for resource
// management (creation, destruction). It is guaranteed
// to be either the same as the gl() context, or a context
// that is in the same share pool.
GLContext *glForResources() const {
if (mGLContext->GetSharedContext())
return mGLContext->GetSharedContext();
return mGLContext;
}
/*
* Helper functions for our layers
*/
@ -281,6 +303,11 @@ private:
nsRefPtr<GLContext> mGLContext;
// The image containers that this layer manager has created.
// The destructor will tell the layer manager to remove
// it from the list.
nsTArray<ImageContainer*> mImageContainers;
enum ProgramType {
RGBALayerProgramType,
BGRALayerProgramType,
@ -364,13 +391,20 @@ class LayerOGL
{
public:
LayerOGL(LayerManagerOGL *aManager)
: mOGLManager(aManager)
: mOGLManager(aManager), mDestroyed(PR_FALSE)
{ }
virtual ~LayerOGL() { }
virtual LayerOGL *GetFirstChildOGL() {
return nsnull;
}
/* Do NOT call this from the generic LayerOGL destructor. Only from the
* concrete class destructor
*/
virtual void Destroy() = 0;
virtual Layer* GetLayer() = 0;
virtual void RenderLayer(int aPreviousFrameBuffer,
@ -381,6 +415,7 @@ public:
GLContext *gl() const { return mOGLManager->gl(); }
protected:
LayerManagerOGL *mOGLManager;
PRPackedBool mDestroyed;
};
} /* layers */

View File

@ -300,19 +300,17 @@ protected:
}
fprintf (stderr, "=== Log:\n%s\n", nsPromiseFlatCString(log).get());
fprintf (stderr, "============\n");
}
// We can mark the shaders for deletion; they're attached to the program
// and will remain attached.
mGL->fDeleteShader(vertexShader);
mGL->fDeleteShader(fragmentShader);
// We can mark the shaders for deletion; they're attached to the program
// and will remain attached.
mGL->fDeleteShader(vertexShader);
mGL->fDeleteShader(fragmentShader);
if (!success) {
mGL->fDeleteProgram(mProgram);
mProgram = 0;
return false;
}
if (!success) {
mGL->fDeleteProgram(mProgram);
mProgram = 0;
return false;
}
// Now query uniforms, so that we can initialize mUniformValues

View File

@ -331,8 +331,18 @@ ThebesLayerOGL::ThebesLayerOGL(LayerManagerOGL *aManager)
ThebesLayerOGL::~ThebesLayerOGL()
{
mBuffer = nsnull;
DEBUG_GL_ERROR_CHECK(gl());
Destroy();
}
void
ThebesLayerOGL::Destroy()
{
if (!mDestroyed) {
mBuffer = nsnull;
DEBUG_GL_ERROR_CHECK(gl());
mDestroyed = PR_TRUE;
}
}
PRBool

View File

@ -50,7 +50,7 @@ namespace layers {
class ThebesLayerBufferOGL;
class ThebesLayerOGL : public ThebesLayer,
public LayerOGL
public LayerOGL
{
typedef ThebesLayerBufferOGL Buffer;
@ -65,6 +65,7 @@ public:
void InvalidateRegion(const nsIntRegion& aRegion);
/** LayerOGL implementation */
void Destroy();
Layer* GetLayer();
virtual PRBool IsEmpty();
virtual void RenderLayer(int aPreviousFrameBuffer,

View File

@ -309,9 +309,64 @@ GLContext::InitWithPrefix(const char *prefix, PRBool trygl)
};
mInitialized = LoadSymbols(&symbols[0], trygl, prefix);
if (mInitialized) {
InitExtensions();
}
return mInitialized;
}
// should match the order of GLExtensions
static const char *sExtensionNames[] = {
"GL_EXT_framebuffer_object",
"GL_ARB_framebuffer_object",
"GL_ARB_texture_rectangle",
"GL_EXT_bgra",
"GL_EXT_texture_format_BGRA8888",
"GL_OES_depth24",
"GL_OES_depth32",
"GL_OES_stencil8",
"GL_OES_texture_npot",
"GL_OES_depth_texture",
"GL_OES_packed_depth_stencil",
"GL_IMG_read_format",
"GL_EXT_read_format_bgra",
NULL
};
void
GLContext::InitExtensions()
{
MakeCurrent();
const GLubyte *extensions = fGetString(LOCAL_GL_EXTENSIONS);
char *exts = strdup((char *)extensions);
printf_stderr("GL extensions: %s\n", exts);
char *s = exts;
bool done = false;
while (!done) {
char *space = strchr(s, ' ');
if (space) {
*space = '\0';
} else {
done = true;
}
for (int i = 0; sExtensionNames[i]; ++i) {
if (strcmp(s, sExtensionNames[i]) == 0) {
printf_stderr("Found extension %s\n", s);
mAvailableExtensions[i] = 1;
}
}
s = space+1;
}
free(exts);
}
PRBool
GLContext::IsExtensionSupported(const char *extension)
{
@ -479,6 +534,9 @@ GLContext::ResizeOffscreenFBO(const gfxIntSize& aSize)
GLint viewport[4];
bool useDepthStencil =
!mIsGLES2 || IsExtensionSupported(OES_packed_depth_stencil);
// save a few things for later restoring
fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, (GLint*) &curBoundTexture);
fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, (GLint*) &curBoundFramebuffer);
@ -496,7 +554,7 @@ GLContext::ResizeOffscreenFBO(const gfxIntSize& aSize)
fGenFramebuffers(1, &mOffscreenFBO);
fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mOffscreenFBO);
if (depth && stencil && !mIsGLES2) {
if (depth && stencil && useDepthStencil) {
fGenRenderbuffers(1, &mOffscreenDepthRB);
} else {
if (depth) {
@ -529,18 +587,35 @@ GLContext::ResizeOffscreenFBO(const gfxIntSize& aSize)
aSize.width, aSize.height,
0,
LOCAL_GL_RGB,
#ifdef XP_WIN
LOCAL_GL_UNSIGNED_BYTE,
#else
mIsGLES2 ? LOCAL_GL_UNSIGNED_SHORT_5_6_5
: LOCAL_GL_UNSIGNED_BYTE,
#endif
NULL);
}
if (depth && stencil && !mIsGLES2) {
if (depth && stencil && useDepthStencil) {
fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mOffscreenDepthRB);
fRenderbufferStorage(LOCAL_GL_RENDERBUFFER,
LOCAL_GL_DEPTH24_STENCIL8,
aSize.width, aSize.height);
} else {
if (depth) {
GLenum depthType;
if (mIsGLES2) {
if (IsExtensionSupported(OES_depth32)) {
depthType = LOCAL_GL_DEPTH_COMPONENT32;
} else if (IsExtensionSupported(OES_depth24)) {
depthType = LOCAL_GL_DEPTH_COMPONENT24;
} else {
depthType = LOCAL_GL_DEPTH_COMPONENT16;
}
} else {
depthType = LOCAL_GL_DEPTH_COMPONENT24;
}
fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mOffscreenDepthRB);
fRenderbufferStorage(LOCAL_GL_RENDERBUFFER,
mIsGLES2 ? LOCAL_GL_DEPTH_COMPONENT16
@ -565,7 +640,7 @@ GLContext::ResizeOffscreenFBO(const gfxIntSize& aSize)
mOffscreenTexture,
0);
if (depth && stencil && !mIsGLES2) {
if (depth && stencil && useDepthStencil) {
fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
LOCAL_GL_DEPTH_ATTACHMENT,
LOCAL_GL_RENDERBUFFER,
@ -603,6 +678,10 @@ GLContext::ResizeOffscreenFBO(const gfxIntSize& aSize)
if (firstTime) {
UpdateActualFormat();
printf_stderr("Created offscreen FBO: r: %d g: %d b: %d a: %d depth: %d stencil: %d\n",
mActualFormat.red, mActualFormat.green, mActualFormat.blue, mActualFormat.alpha,
mActualFormat.depth, mActualFormat.stencil);
}
// We're good, and the framebuffer is already attached, so let's
@ -665,7 +744,216 @@ GLContext::ClearSafely()
void
GLContext::UpdateActualFormat()
{
// TODO
ContextFormat nf;
fGetIntegerv(LOCAL_GL_RED_BITS, (GLint*) &nf.alpha);
fGetIntegerv(LOCAL_GL_GREEN_BITS, (GLint*) &nf.alpha);
fGetIntegerv(LOCAL_GL_BLUE_BITS, (GLint*) &nf.alpha);
fGetIntegerv(LOCAL_GL_ALPHA_BITS, (GLint*) &nf.alpha);
fGetIntegerv(LOCAL_GL_DEPTH_BITS, (GLint*) &nf.depth);
fGetIntegerv(LOCAL_GL_STENCIL_BITS, (GLint*) &nf.depth);
mActualFormat = nf;
}
void
GLContext::MarkDestroyed()
{
MakeCurrent();
DeleteOffscreenFBO();
memset(&mFunctionListStartSentinel, 0, &mFunctionListEndSentinel - &mFunctionListStartSentinel);
}
already_AddRefed<gfxImageSurface>
GLContext::ReadTextureImage(GLuint aTexture,
const gfxIntSize& aSize,
GLenum aTextureFormat)
{
MakeCurrent();
nsRefPtr<gfxImageSurface> isurf;
GLint oldrb, oldfb, oldprog, oldvp[4], oldPackAlignment;
GLint success;
GLuint rb = 0, fb = 0;
GLuint vs = 0, fs = 0, prog = 0;
const char *vShader =
"attribute vec4 aVertex;\n"
"attribute vec2 aTexCoord;\n"
"varying vec2 vTexCoord;\n"
"void main() { gl_Position = aVertex; vTexCoord = aTexCoord; }";
const char *fShader =
"#ifdef GL_ES\n"
"precision mediump float;\n"
"#endif\n"
"varying vec2 vTexCoord;\n"
"uniform sampler2D uTexture;\n"
"void main() { gl_FragColor = texture2D(uTexture, vTexCoord); }";
float verts[4*4] = {
-1.0f, -1.0f, 0.0f, 1.0f,
1.0f, -1.0f, 0.0f, 1.0f,
-1.0f, 1.0f, 0.0f, 1.0f,
1.0f, 1.0f, 0.0f, 1.0f
};
float texcoords[2*4] = {
0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f
};
fGetIntegerv(LOCAL_GL_RENDERBUFFER_BINDING, &oldrb);
fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, &oldfb);
fGetIntegerv(LOCAL_GL_CURRENT_PROGRAM, &oldprog);
fGetIntegerv(LOCAL_GL_VIEWPORT, oldvp);
fGetIntegerv(LOCAL_GL_PACK_ALIGNMENT, &oldPackAlignment);
fGenRenderbuffers(1, &rb);
fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, rb);
fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, LOCAL_GL_RGBA,
aSize.width, aSize.height);
fGenFramebuffers(1, &fb);
fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, fb);
fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0,
LOCAL_GL_RENDERBUFFER, rb);
if (fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER) !=
LOCAL_GL_FRAMEBUFFER_COMPLETE)
{
goto cleanup;
}
vs = fCreateShader(LOCAL_GL_VERTEX_SHADER);
fs = fCreateShader(LOCAL_GL_FRAGMENT_SHADER);
fShaderSource(vs, 1, (const GLchar**) &vShader, NULL);
fShaderSource(fs, 1, (const GLchar**) &fShader, NULL);
prog = fCreateProgram();
fAttachShader(prog, vs);
fAttachShader(prog, fs);
fBindAttribLocation(prog, 0, "aVertex");
fBindAttribLocation(prog, 1, "aTexCoord");
fLinkProgram(prog);
fGetProgramiv(prog, LOCAL_GL_LINK_STATUS, &success);
if (!success) {
goto cleanup;
}
fUseProgram(prog);
fEnableVertexAttribArray(0);
fEnableVertexAttribArray(1);
fVertexAttribPointer(0, 4, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, verts);
fVertexAttribPointer(1, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, texcoords);
fActiveTexture(LOCAL_GL_TEXTURE0);
fBindTexture(LOCAL_GL_TEXTURE_2D, aTexture);
fUniform1i(fGetUniformLocation(prog, "uTexture"), 0);
fViewport(0, 0, aSize.width, aSize.height);
fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
fDisableVertexAttribArray(1);
fDisableVertexAttribArray(0);
isurf = new gfxImageSurface(aSize, gfxASurface::ImageFormatARGB32);
if (!isurf || isurf->CairoStatus()) {
isurf = nsnull;
goto cleanup;
}
if (oldPackAlignment != 4)
fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, 4);
fReadPixels(0, 0, aSize.width, aSize.height,
LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE,
isurf->Data());
if (oldPackAlignment != 4)
fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, oldPackAlignment);
cleanup:
// note that deleting 0 has no effect in any of these calls
fDeleteRenderbuffers(1, &rb);
fDeleteFramebuffers(1, &fb);
fDeleteShader(vs);
fDeleteShader(fs);
fDeleteProgram(prog);
fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, oldrb);
fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, oldfb);
fUseProgram(oldprog);
fViewport(oldvp[0], oldvp[1], oldvp[2], oldvp[3]);
return isurf.forget();
}
void
GLContext::ReadPixelsIntoImageSurface(GLint aX, GLint aY,
GLsizei aWidth, GLsizei aHeight,
gfxImageSurface *aDest)
{
MakeCurrent();
if (aDest->Format() != gfxASurface::ImageFormatARGB32 &&
aDest->Format() != gfxASurface::ImageFormatRGB24)
{
NS_WARNING("ReadPixelsIntoImageSurface called with invalid image format");
return;
}
if (aDest->Width() != aWidth ||
aDest->Height() != aHeight ||
aDest->Stride() != aWidth * 4)
{
NS_WARNING("ReadPixelsIntoImageSurface called with wrong size or stride surface");
return;
}
GLint currentPackAlignment = 0;
fGetIntegerv(LOCAL_GL_PACK_ALIGNMENT, &currentPackAlignment);
fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, 4);
// defaults for desktop
GLenum format = LOCAL_GL_BGRA;
GLenum datatype = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV;
bool swap = false;
if (IsGLES2()) {
datatype = LOCAL_GL_UNSIGNED_BYTE;
if (IsExtensionSupported(gl::GLContext::EXT_read_format_bgra) ||
IsExtensionSupported(gl::GLContext::IMG_read_format) ||
IsExtensionSupported(gl::GLContext::EXT_bgra))
{
format = LOCAL_GL_BGRA;
} else {
format = LOCAL_GL_RGBA;
swap = true;
}
}
fReadPixels(0, 0, aWidth, aHeight,
format, datatype,
aDest->Data());
if (swap) {
// swap B and R bytes
for (int j = 0; j < aHeight; ++j) {
PRUint32 *row = (PRUint32*) (aDest->Data() + aDest->Stride() * j);
for (int i = 0; i < aWidth; ++i) {
*row = (*row & 0xff00ff00) | ((*row & 0xff) << 16) | ((*row & 0xff0000) >> 16);
row++;
}
}
}
fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, currentPackAlignment);
}
#ifdef DEBUG

View File

@ -385,6 +385,10 @@ public:
mUserData.Put(aKey, aValue);
}
// Mark this context as destroyed. This will NULL out all
// the GL function pointers!
void MarkDestroyed();
enum NativeDataType {
NativeGLContext,
NativeImageSurface,
@ -395,6 +399,9 @@ public:
virtual void *GetNativeData(NativeDataType aType) { return NULL; }
GLContext *GetSharedContext() { return mSharedContext; }
PRBool IsGlobalSharedContext() { return mIsGlobalSharedContext; }
void SetIsGlobalSharedContext(PRBool aIsOne) { mIsGlobalSharedContext = aIsOne; }
const ContextFormat& CreationFormat() { return mCreationFormat; }
const ContextFormat& ActualFormat() { return mActualFormat; }
@ -428,20 +435,6 @@ public:
*/
virtual PRBool ReleaseTexImage() { return PR_FALSE; }
virtual GLuint CreateTexture()
{
GLuint tex;
MakeCurrent();
fGenTextures(1, &tex);
return tex;
}
virtual void DestroyTexture(GLuint tex)
{
MakeCurrent();
fDeleteTextures(1, &tex);
}
/*
* Offscreen support API
*/
@ -554,10 +547,61 @@ public:
GLint aWrapMode,
PRBool aUseNearestFilter=PR_FALSE);
/**
* Read the image data contained in aTexture, and return it as an ImageSurface.
* If GL_RGBA is given as the format, a ImageFormatARGB32 surface is returned.
* Not implemented yet:
* If GL_RGB is given as the format, a ImageFormatRGB24 surface is returned.
* If GL_LUMINANCE is given as the format, a ImageFormatA8 surface is returned.
*
* THIS IS EXPENSIVE. It is ridiculously expensive. Only do this
* if you absolutely positively must, and never in any performance
* critical path.
*/
already_AddRefed<gfxImageSurface> ReadTextureImage(GLuint aTexture,
const gfxIntSize& aSize,
GLenum aTextureFormat);
/**
* Call ReadPixels into an existing gfxImageSurface for the given bounds.
* The image surface must be using image format RGBA32 or RGB24.
*/
void ReadPixelsIntoImageSurface(GLint aX, GLint aY, GLsizei aWidth, GLsizei aHeight,
gfxImageSurface *aDest);
/**
* Known GL extensions that can be queried by
* IsExtensionSupported. The results of this are cached, and as
* such it's safe to use this even in performance critical code.
* If you add to this array, remember to add to the string names
* in GLContext.cpp.
*/
enum GLExtensions {
EXT_framebuffer_object,
ARB_framebuffer_object,
ARB_texture_rectangle,
EXT_bgra,
EXT_texture_format_BGRA8888,
OES_depth24,
OES_depth32,
OES_stencil8,
OES_texture_npot,
OES_depth_texture,
OES_packed_depth_stencil,
IMG_read_format,
EXT_read_format_bgra,
Extensions_Max
};
PRBool IsExtensionSupported(GLExtensions aKnownExtension) {
return mAvailableExtensions[aKnownExtension];
}
protected:
PRPackedBool mInitialized;
PRPackedBool mIsOffscreen;
PRPackedBool mIsGLES2;
PRPackedBool mIsGlobalSharedContext;
ContextFormat mCreationFormat;
nsRefPtr<GLContext> mSharedContext;
@ -576,6 +620,25 @@ protected:
GLuint mOffscreenDepthRB;
GLuint mOffscreenStencilRB;
// this should just be a std::bitset, but that ended up breaking
// MacOS X builds; see bug 584919. We can replace this with one
// later on.
template<size_t setlen>
struct ExtensionBitset {
ExtensionBitset() {
for (int i = 0; i < setlen; ++i)
values[i] = false;
}
bool& operator[](const int index) {
NS_ASSERTION(index >= 0 && index < setlen, "out of range");
return values[index];
}
bool values[setlen];
};
ExtensionBitset<Extensions_Max> mAvailableExtensions;
// Clear to transparent black, with 0 depth and stencil,
// while preserving current ClearColor etc. values.
// Useful for resizing offscreen buffers.
@ -590,6 +653,7 @@ protected:
PRBool InitWithPrefix(const char *prefix, PRBool trygl);
void InitExtensions();
PRBool IsExtensionSupported(const char *extension);
virtual already_AddRefed<TextureImage>
@ -607,6 +671,9 @@ public:
* perl-or-python-or-js script somewhere and would be
* autogenerated; one would be wrong.
*/
// Keep this at the start of the function pointers
void *mFunctionListStartSentinel;
typedef void (GLAPIENTRY * PFNGLACTIVETEXTUREPROC) (GLenum texture);
PFNGLACTIVETEXTUREPROC fActiveTexture;
typedef void (GLAPIENTRY * PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader);
@ -851,6 +918,9 @@ public:
typedef void (GLAPIENTRY * PFNGLRENDERBUFFERSTORAGE) (GLenum target, GLenum internalFormat, GLsizei width, GLsizei height);
PFNGLRENDERBUFFERSTORAGE fRenderbufferStorage;
// keep this at the end of the function pointers
void *mFunctionListEndSentinel;
void fDepthRange(GLclampf a, GLclampf b) {
if (mIsGLES2) {
priv_fDepthRangef(a, b);
@ -963,127 +1033,73 @@ public:
priv_fDeleteRenderbuffers(n, names);
}
#else
GLContext *TrackingContext() {
GLContext *tip = this;
while (tip->mSharedContext)
tip = tip->mSharedContext;
return tip;
}
GLuint GLAPIENTRY fCreateProgram() {
GLuint ret = priv_fCreateProgram();
if (mSharedContext) {
GLContext *tip = mSharedContext;
while (tip->mSharedContext)
tip = tip->mSharedContext;
tip->CreatedProgram(this, ret);
}
TrackingContext()->CreatedProgram(this, ret);
return ret;
}
GLuint GLAPIENTRY fCreateShader(GLenum t) {
GLuint ret = priv_fCreateShader(t);
if (mSharedContext) {
GLContext *tip = mSharedContext;
while (tip->mSharedContext)
tip = tip->mSharedContext;
tip->CreatedShader(this, ret);
}
TrackingContext()->CreatedShader(this, ret);
return ret;
}
void GLAPIENTRY fGenBuffers(GLsizei n, GLuint* names) {
priv_fGenBuffers(n, names);
if (mSharedContext) {
GLContext *tip = mSharedContext;
while (tip->mSharedContext)
tip = tip->mSharedContext;
tip->CreatedBuffers(this, n, names);
}
TrackingContext()->CreatedBuffers(this, n, names);
}
void GLAPIENTRY fGenTextures(GLsizei n, GLuint* names) {
priv_fGenTextures(n, names);
if (mSharedContext) {
GLContext *tip = mSharedContext;
while (tip->mSharedContext)
tip = tip->mSharedContext;
tip->CreatedTextures(this, n, names);
}
TrackingContext()->CreatedTextures(this, n, names);
}
void GLAPIENTRY fGenFramebuffers(GLsizei n, GLuint* names) {
priv_fGenFramebuffers(n, names);
if (mSharedContext) {
GLContext *tip = mSharedContext;
while (tip->mSharedContext)
tip = tip->mSharedContext;
tip->CreatedFramebuffers(this, n, names);
}
TrackingContext()->CreatedFramebuffers(this, n, names);
}
void GLAPIENTRY fGenRenderbuffers(GLsizei n, GLuint* names) {
priv_fGenRenderbuffers(n, names);
if (mSharedContext) {
GLContext *tip = mSharedContext;
while (tip->mSharedContext)
tip = tip->mSharedContext;
tip->CreatedRenderbuffers(this, n, names);
}
TrackingContext()->CreatedRenderbuffers(this, n, names);
}
void GLAPIENTRY fDeleteProgram(GLuint program) {
priv_fDeleteProgram(program);
if (mSharedContext) {
GLContext *tip = mSharedContext;
while (tip->mSharedContext)
tip = tip->mSharedContext;
tip->DeletedProgram(this, program);
}
TrackingContext()->DeletedProgram(this, program);
}
void GLAPIENTRY fDeleteShader(GLuint shader) {
priv_fDeleteShader(shader);
if (mSharedContext) {
GLContext *tip = mSharedContext;
while (tip->mSharedContext)
tip = tip->mSharedContext;
tip->DeletedShader(this, shader);
}
TrackingContext()->DeletedShader(this, shader);
}
void GLAPIENTRY fDeleteBuffers(GLsizei n, GLuint *names) {
priv_fDeleteBuffers(n, names);
if (mSharedContext) {
GLContext *tip = mSharedContext;
while (tip->mSharedContext)
tip = tip->mSharedContext;
tip->DeletedBuffers(this, n, names);
}
TrackingContext()->DeletedBuffers(this, n, names);
}
void GLAPIENTRY fDeleteTextures(GLsizei n, GLuint *names) {
priv_fDeleteTextures(n, names);
if (mSharedContext) {
GLContext *tip = mSharedContext;
while (tip->mSharedContext)
tip = tip->mSharedContext;
tip->DeletedTextures(this, n, names);
}
TrackingContext()->DeletedTextures(this, n, names);
}
void GLAPIENTRY fDeleteFramebuffers(GLsizei n, GLuint *names) {
priv_fDeleteFramebuffers(n, names);
if (mSharedContext) {
GLContext *tip = mSharedContext;
while (tip->mSharedContext)
tip = tip->mSharedContext;
tip->DeletedFramebuffers(this, n, names);
}
TrackingContext()->DeletedFramebuffers(this, n, names);
}
void GLAPIENTRY fDeleteRenderbuffers(GLsizei n, GLuint *names) {
priv_fDeleteRenderbuffers(n, names);
if (mSharedContext) {
GLContext *tip = mSharedContext;
while (tip->mSharedContext)
tip = tip->mSharedContext;
tip->DeletedRenderbuffers(this, n, names);
}
TrackingContext()->DeletedRenderbuffers(this, n, names);
}
void THEBES_API CreatedProgram(GLContext *aOrigin, GLuint aName);

View File

@ -74,12 +74,15 @@ namespace gl {
#define GL_CONTEXT_PROVIDER_DEFAULT GLContextProviderCGL
#endif
#if defined(ANDROID) || defined(MOZ_PLATFORM_MAEMO)
#if defined(ANDROID) || defined(MOZ_PLATFORM_MAEMO) || defined(XP_WIN)
#define GL_CONTEXT_PROVIDER_NAME GLContextProviderEGL
#include "GLContextProviderImpl.h"
#undef GL_CONTEXT_PROVIDER_NAME
#ifndef GL_CONTEXT_PROVIDER_DEFAULT
#define GL_CONTEXT_PROVIDER_DEFAULT GLContextProviderEGL
#endif
#endif
// X11, but only if we didn't use EGL above
#if defined(MOZ_X11) && !defined(GL_CONTEXT_PROVIDER_DEFAULT)

View File

@ -520,6 +520,8 @@ GLContextProviderCGL::GetGlobalContext()
gGlobalContext = nsnull;
return nsnull;
}
gGlobalContext->SetIsGlobalSharedContext(PR_TRUE);
}
return gGlobalContext;

View File

@ -76,6 +76,62 @@ typedef void *EGLNativeWindowType;
#define EGL_LIB "/system/lib/libEGL.so"
#define GLES2_LIB "/system/lib/libGLESv2.so"
#elif defined(XP_WIN)
#include <nsServiceManagerUtils.h>
#include <nsIPrefBranch.h>
#include <nsILocalFile.h>
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN 1
#endif
#include <windows.h>
typedef HDC EGLNativeDisplayType;
typedef HBITMAP EGLNativePixmapType;
typedef HWND EGLNativeWindowType;
#define GET_NATIVE_WINDOW(aWidget) ((EGLNativeWindowType)aWidget->GetNativeData(NS_NATIVE_WINDOW))
#define EGL_LIB "libEGL.dll"
#define GLES2_LIB "libGLESv2.dll"
// a little helper
class AutoDestroyHWND {
public:
AutoDestroyHWND(HWND aWnd = NULL)
: mWnd(aWnd)
{
}
~AutoDestroyHWND() {
if (mWnd) {
::DestroyWindow(mWnd);
}
}
operator HWND() {
return mWnd;
}
HWND forget() {
HWND w = mWnd;
mWnd = NULL;
return w;
}
HWND operator=(HWND aWnd) {
if (mWnd && mWnd != aWnd) {
::DestroyWindow(mWnd);
}
mWnd = aWnd;
return mWnd;
}
HWND mWnd;
};
#else
#error "Platform not recognized"
@ -147,58 +203,58 @@ public:
mHave_EGL_KHR_gl_texture_2D_image = PR_FALSE;
}
typedef EGLDisplay (*pfnGetDisplay)(void *display_id);
typedef EGLDisplay (GLAPIENTRY * pfnGetDisplay)(void *display_id);
pfnGetDisplay fGetDisplay;
typedef EGLContext (*pfnGetCurrentContext)(void);
typedef EGLContext (GLAPIENTRY * pfnGetCurrentContext)(void);
pfnGetCurrentContext fGetCurrentContext;
typedef EGLBoolean (*pfnMakeCurrent)(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);
typedef EGLBoolean (GLAPIENTRY * pfnMakeCurrent)(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);
pfnMakeCurrent fMakeCurrent;
typedef EGLBoolean (*pfnDestroyContext)(EGLDisplay dpy, EGLContext ctx);
typedef EGLBoolean (GLAPIENTRY * pfnDestroyContext)(EGLDisplay dpy, EGLContext ctx);
pfnDestroyContext fDestroyContext;
typedef EGLContext (*pfnCreateContext)(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list);
typedef EGLContext (GLAPIENTRY * pfnCreateContext)(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list);
pfnCreateContext fCreateContext;
typedef EGLBoolean (*pfnDestroySurface)(EGLDisplay dpy, EGLSurface surface);
typedef EGLBoolean (GLAPIENTRY * pfnDestroySurface)(EGLDisplay dpy, EGLSurface surface);
pfnDestroySurface fDestroySurface;
typedef EGLSurface (*pfnCreateWindowSurface)(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list);
typedef EGLSurface (GLAPIENTRY * pfnCreateWindowSurface)(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list);
pfnCreateWindowSurface fCreateWindowSurface;
typedef EGLSurface (*pfnCreatePbufferSurface)(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list);
typedef EGLSurface (GLAPIENTRY * pfnCreatePbufferSurface)(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list);
pfnCreatePbufferSurface fCreatePbufferSurface;
typedef EGLSurface (*pfnCreatePixmapSurface)(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list);
typedef EGLSurface (GLAPIENTRY * pfnCreatePixmapSurface)(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list);
pfnCreatePixmapSurface fCreatePixmapSurface;
typedef EGLBoolean (*pfnBindAPI)(EGLenum api);
typedef EGLBoolean (GLAPIENTRY * pfnBindAPI)(EGLenum api);
pfnBindAPI fBindAPI;
typedef EGLBoolean (*pfnInitialize)(EGLDisplay dpy, EGLint *major, EGLint *minor);
typedef EGLBoolean (GLAPIENTRY * pfnInitialize)(EGLDisplay dpy, EGLint *major, EGLint *minor);
pfnInitialize fInitialize;
typedef EGLBoolean (*pfnChooseConfig)(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config);
typedef EGLBoolean (GLAPIENTRY * pfnChooseConfig)(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config);
pfnChooseConfig fChooseConfig;
typedef EGLint (*pfnGetError)(void);
typedef EGLint (GLAPIENTRY * pfnGetError)(void);
pfnGetError fGetError;
typedef EGLBoolean (*pfnGetConfigAttrib)(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value);
typedef EGLBoolean (GLAPIENTRY * pfnGetConfigAttrib)(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value);
pfnGetConfigAttrib fGetConfigAttrib;
typedef EGLBoolean (*pfnGetConfigs)(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config);
typedef EGLBoolean (GLAPIENTRY * pfnGetConfigs)(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config);
pfnGetConfigs fGetConfigs;
typedef EGLBoolean (*pfnWaitNative)(EGLint engine);
typedef EGLBoolean (GLAPIENTRY * pfnWaitNative)(EGLint engine);
pfnWaitNative fWaitNative;
typedef EGLCastToRelevantPtr (*pfnGetProcAddress)(const char *procname);
typedef EGLCastToRelevantPtr (GLAPIENTRY * pfnGetProcAddress)(const char *procname);
pfnGetProcAddress fGetProcAddress;
typedef EGLBoolean (*pfnSwapBuffers)(EGLDisplay dpy, EGLSurface surface);
typedef EGLBoolean (GLAPIENTRY * pfnSwapBuffers)(EGLDisplay dpy, EGLSurface surface);
pfnSwapBuffers fSwapBuffers;
typedef EGLBoolean (*pfnCopyBuffers)(EGLDisplay dpy, EGLSurface surface,
EGLNativePixmapType target);
typedef EGLBoolean (GLAPIENTRY * pfnCopyBuffers)(EGLDisplay dpy, EGLSurface surface,
EGLNativePixmapType target);
pfnCopyBuffers fCopyBuffers;
typedef const GLubyte* (*pfnQueryString)(EGLDisplay, EGLint name);
typedef const GLubyte* (GLAPIENTRY * pfnQueryString)(EGLDisplay, EGLint name);
pfnQueryString fQueryString;
typedef EGLBoolean (*pfnBindTexImage)(EGLDisplay, EGLSurface surface, EGLint buffer);
typedef EGLBoolean (GLAPIENTRY * pfnBindTexImage)(EGLDisplay, EGLSurface surface, EGLint buffer);
pfnBindTexImage fBindTexImage;
typedef EGLBoolean (*pfnReleaseTexImage)(EGLDisplay, EGLSurface surface, EGLint buffer);
typedef EGLBoolean (GLAPIENTRY * pfnReleaseTexImage)(EGLDisplay, EGLSurface surface, EGLint buffer);
pfnReleaseTexImage fReleaseTexImage;
typedef EGLImageKHR (*pfnCreateImageKHR)(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
typedef EGLImageKHR (GLAPIENTRY * pfnCreateImageKHR)(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
pfnCreateImageKHR fCreateImageKHR;
typedef EGLBoolean (*pfnDestroyImageKHR)(EGLDisplay dpy, EGLImageKHR image);
typedef EGLBoolean (GLAPIENTRY * pfnDestroyImageKHR)(EGLDisplay dpy, EGLImageKHR image);
pfnDestroyImageKHR fDestroyImageKHR;
// This is EGL specific GL ext symbol "glEGLImageTargetTexture2DOES"
// Lets keep it here for now.
typedef void (*pfnImageTargetTexture2DOES)(GLenum target, GLeglImageOES image);
typedef void (GLAPIENTRY * pfnImageTargetTexture2DOES)(GLenum target, GLeglImageOES image);
pfnImageTargetTexture2DOES fImageTargetTexture2DOES;
PRBool EnsureInitialized()
@ -207,6 +263,43 @@ public:
return PR_TRUE;
}
#ifdef XP_WIN
// ANGLE is an addon currently, so we have to do a bit of work
// to find the directory; the addon sets this on startup/shutdown.
do {
nsCOMPtr<nsIPrefBranch> prefs = do_GetService("@mozilla.org/preferences-service;1");
nsCOMPtr<nsILocalFile> angleFile, glesv2File;
if (!prefs)
break;
nsresult rv = prefs->GetComplexValue("gfx.angle.egl.path",
NS_GET_IID(nsILocalFile),
getter_AddRefs(angleFile));
if (NS_FAILED(rv) || !angleFile)
break;
nsCAutoString s;
// note that we have to load the libs in this order, because libEGL.dll
// depends on libGLESv2.dll, but is not in our search path.
nsCOMPtr<nsIFile> f;
angleFile->Clone(getter_AddRefs(f));
glesv2File = do_QueryInterface(f);
if (!glesv2File)
break;
glesv2File->Append(NS_LITERAL_STRING("libGLESv2.dll"));
PRLibrary *glesv2lib = nsnull; // this will be leaked on purpose
glesv2File->Load(&glesv2lib);
if (!glesv2lib)
break;
angleFile->Append(NS_LITERAL_STRING("libEGL.dll"));
angleFile->Load(&mEGLLibrary);
} while (false);
#endif
if (!mEGLLibrary) {
mEGLLibrary = PR_LoadLibrary(EGL_LIB);
if (!mEGLLibrary) {
@ -253,6 +346,11 @@ public:
return PR_FALSE;
const char *extensions = (const char*) fQueryString(mEGLDisplay, LOCAL_EGL_EXTENSIONS);
if (!extensions)
extensions = "";
printf_stderr("Extensions: %s 0x%02x\n", extensions, extensions[0]);
printf_stderr("Extensions length: %d\n", strlen(extensions));
// note the extra space -- this ugliness tries to match
// EGL_KHR_image in the middle of the string, or right at the
@ -406,10 +504,21 @@ public:
, mThebesSurface(nsnull)
, mBound(PR_FALSE)
, mIsPBuffer(PR_FALSE)
{}
#ifdef XP_WIN
, mWnd(0)
#endif
{
// any EGL contexts will always be GLESv2
SetIsGLES2(PR_TRUE);
}
~GLContextEGL()
{
if (mOffscreenFBO) {
MakeCurrent();
DeleteOffscreenFBO();
}
// If mGLWidget is non-null, then we've been given it by the GL context provider,
// and it's managed by the widget implementation. In this case, We can't destroy
// our contexts.
@ -559,6 +668,15 @@ public:
CreateEGLPBufferOffscreenContext(const gfxIntSize& aSize,
const ContextFormat& aFormat);
#ifdef XP_WIN
static already_AddRefed<GLContextEGL>
CreateEGLWin32OffscreenContext(const gfxIntSize& aSize,
const ContextFormat& aFormat);
void HoldWin32Window(HWND aWnd) { mWnd = aWnd; }
HWND GetWin32Window() { return mWnd; }
#endif
void SetOffscreenSize(const gfxIntSize &aRequestedSize,
const gfxIntSize &aActualSize)
{
@ -577,6 +695,10 @@ protected:
PRBool mBound;
PRPackedBool mIsPBuffer;
#ifdef XP_WIN
AutoDestroyHWND mWnd;
#endif
};
PRBool
@ -1167,6 +1289,95 @@ GLContextEGL::CreateEGLPixmapOffscreenContext(const gfxIntSize& aSize,
return glContext.forget();
}
#ifdef XP_WIN
already_AddRefed<GLContextEGL>
GLContextEGL::CreateEGLWin32OffscreenContext(const gfxIntSize& aSize,
const ContextFormat& aFormat)
{
if (!sEGLLibrary.EnsureInitialized()) {
return nsnull;
}
WNDCLASSW wc;
if (!GetClassInfoW(GetModuleHandle(NULL), L"ANGLEContextClass", &wc)) {
ZeroMemory(&wc, sizeof(WNDCLASSW));
wc.style = CS_OWNDC;
wc.hInstance = GetModuleHandle(NULL);
wc.lpfnWndProc = DefWindowProc;
wc.lpszClassName = L"ANGLEContextClass";
if (!RegisterClassW(&wc)) {
NS_WARNING("Failed to register ANGLEContextClass?!");
return NULL;
}
}
AutoDestroyHWND wnd = CreateWindowW(L"ANGLEContextClass", L"ANGLEContext", 0,
0, 0, 16, 16,
NULL, NULL, GetModuleHandle(NULL), NULL);
NS_ENSURE_TRUE(HWND(wnd), NULL);
EGLConfig config;
EGLSurface surface;
EGLContext context;
// We don't really care, we're going to use a FBO anyway
EGLint attribs[] = {
LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_WINDOW_BIT,
LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT,
LOCAL_EGL_NONE
};
EGLint ncfg = 1;
if (!sEGLLibrary.fChooseConfig(sEGLLibrary.Display(), attribs, &config, ncfg, &ncfg) ||
ncfg < 1)
{
return nsnull;
}
surface = sEGLLibrary.fCreateWindowSurface(sEGLLibrary.Display(),
config,
HWND(wnd),
0);
if (!surface) {
return nsnull;
}
if (!sEGLLibrary.fBindAPI(LOCAL_EGL_OPENGL_ES_API)) {
sEGLLibrary.fDestroySurface(sEGLLibrary.Display(), surface);
return nsnull;
}
EGLint cxattribs[] = {
LOCAL_EGL_CONTEXT_CLIENT_VERSION, 2,
LOCAL_EGL_NONE
};
context = sEGLLibrary.fCreateContext(sEGLLibrary.Display(),
config,
EGL_NO_CONTEXT,
cxattribs);
if (!context) {
sEGLLibrary.fDestroySurface(sEGLLibrary.Display(), surface);
return nsnull;
}
nsRefPtr<GLContextEGL> glContext = new GLContextEGL(aFormat, nsnull,
config, surface, context,
PR_TRUE);
// hold this even before we initialize, because we need to make
// sure it gets destroyed after the surface etc. in case of error.
glContext->HoldWin32Window(wnd.forget());
if (!glContext->Init() ||
!glContext->ResizeOffscreenFBO(aSize))
{
return nsnull;
}
return glContext.forget();
}
#endif
// Under EGL, if we're under X11, then we have to create a Pixmap
// because Maemo's EGL implementation doesn't support pbuffers at all
// for some reason. On Android, pbuffers are supported fine, though
@ -1183,6 +1394,8 @@ GLContextProviderEGL::CreateOffscreen(const gfxIntSize& aSize,
return GLContextEGL::CreateEGLPBufferOffscreenContext(aSize, aFormat);
#elif defined(MOZ_X11)
return GLContextEGL::CreateEGLPixmapOffscreenContext(aSize, aFormat);
#elif defined(XP_WIN)
return GLContextEGL::CreateEGLWin32OffscreenContext(aSize, aFormat);
#else
return nsnull;
#endif
@ -1291,6 +1504,8 @@ GLContextProviderEGL::GetGlobalContext()
if (!triedToCreateContext && !gGlobalContext) {
triedToCreateContext = true;
gGlobalContext = CreateOffscreen(gfxIntSize(16, 16));
if (gGlobalContext)
gGlobalContext->SetIsGlobalSharedContext(PR_TRUE);
}
return gGlobalContext;

View File

@ -225,6 +225,11 @@ TRY_AGAIN_NO_SHARING:
~GLContextGLX()
{
if (mOffscreenFBO) {
MakeCurrent();
DeleteOffscreenFBO();
}
sGLXLibrary.xDeleteContext(mDisplay, mContext);
if (mDeleteDrawable) {
@ -287,34 +292,6 @@ TRY_AGAIN_NO_SHARING:
return PR_TRUE;
}
void WindowDestroyed()
{
for (unsigned int i=0; i<textures.Length(); i++) {
GLContext::DestroyTexture(textures.ElementAt(i));
}
textures.Clear();
}
// NB: we could set a flag upon WindowDestroyed() to dictate an
// early-return from CreateTexture(), but then we would need the
// same check before all GL calls, and that heads down a rabbit
// hole.
virtual GLuint CreateTexture()
{
GLuint tex = GLContext::CreateTexture();
NS_ASSERTION(!textures.Contains(tex), "");
textures.AppendElement(tex);
return tex;
}
virtual void DestroyTexture(GLuint texture)
{
if (textures.Contains(texture)) {
textures.RemoveElement(texture);
GLContext::DestroyTexture(texture);
}
}
virtual already_AddRefed<TextureImage>
CreateBasicTextureImage(GLuint aTexture,
const nsIntSize& aSize,
@ -347,7 +324,6 @@ private:
PRPackedBool mDeleteDrawable;
PRPackedBool mDoubleBuffered;
nsTArray<GLuint> textures;
nsRefPtr<gfxXlibSurface> mPixmap;
};
@ -740,6 +716,8 @@ GLContextProviderGLX::GetGlobalContext()
gGlobalContext = CreateOffscreenPixmapContext(gfxIntSize(1, 1),
ContextFormat(ContextFormat::BasicRGB24),
PR_FALSE);
if (gGlobalContext)
gGlobalContext->SetIsGlobalSharedContext(PR_TRUE);
}
return gGlobalContext;

View File

@ -87,6 +87,10 @@ CreateDummyWindow(HDC *aWindowDC = nsnull)
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 24;
pfd.cRedBits = 8;
pfd.cGreenBits = 8;
pfd.cBlueBits = 8;
pfd.cAlphaBits = 8;
pfd.cDepthBits = 0;
pfd.iLayerType = PFD_MAIN_PLANE;
@ -688,6 +692,8 @@ GLContextProviderWGL::GetGlobalContext()
gGlobalContext = nsnull;
return PR_FALSE;
}
gGlobalContext->SetIsGlobalSharedContext(PR_TRUE);
}
return static_cast<GLContext*>(gGlobalContext);

View File

@ -116,6 +116,15 @@ public:
GLXContext,
Bool);
PFNGLXCREATECONTEXT xCreateContext;
typedef int (GLAPIENTRY * PFNGLXGETCONFIG) (Display *,
XVisualInfo *,
int,
int *);
PFNGLXGETCONFIG xGetConfig;
typedef GLXPixmap (GLAPIENTRY * PFNGLXCREATEGLXPIXMAP) (Display *,
XVisualInfo *,
Pixmap);
PFNGLXCREATEGLXPIXMAP xCreateGLXPixmap;
PRBool EnsureInitialized();

View File

@ -414,6 +414,11 @@ else
CPPSRCS += GLContextProvider$(GL_PROVIDER).cpp
endif
# Win32 is a special snowflake, for ANGLE
ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
CPPSRCS += GLContextProviderEGL.cpp
endif
DEFINES += -DIMPL_THEBES -DWOFF_MOZILLA_CLIENT
include $(topsrcdir)/config/rules.mk

View File

@ -187,6 +187,14 @@ nsVideoFrame::BuildLayer(nsDisplayListBuilder* aBuilder,
return nsnull;
nsRefPtr<ImageContainer> container = element->GetImageContainer();
// If we have a container with a different layer manager, try to hand
// off the container to the new one.
if (container && container->Manager() != aManager) {
// we don't care about the return type here -- if the set didn't take, it'll
// be handled when we next check the manager
container->SetLayerManager(aManager);
}
// If we have a container with the right layer manager already, we don't
// need to do anything here. Otherwise we need to set up a temporary
// ImageContainer, capture the video data and store it in the temp
@ -203,6 +211,10 @@ nsVideoFrame::BuildLayer(nsDisplayListBuilder* aBuilder,
// Get video from the existing container. It was created for a
// different layer manager, so we do fallback through cairo.
imageSurface = container->GetCurrentAsSurface(&cairoData.mSize);
if (!imageSurface) {
// we couldn't do fallback, so we've got nothing to do here
return nsnull;
}
cairoData.mSurface = imageSurface;
} else {
// We're probably printing.

View File

@ -3128,7 +3128,7 @@ pref("image.mem.min_discard_timeout_ms", 10000);
// WebGL prefs
pref("webgl.enabled_for_all_sites", false);
pref("webgl.shader_validator", false);
pref("webgl.shader_validator", true);
pref("webgl.software_render", false);
pref("webgl.osmesalib", "");

View File

@ -40,10 +40,6 @@
#include <windows.h>
#include "nsToolkit.h"
#ifdef MOZ_ENABLE_LIBXUL
#include "../xre/nsWindowsDllBlocklist.cpp"
#endif
#if defined(__GNUC__)
// If DllMain gets name mangled, it won't be seen.
extern "C" {
@ -60,9 +56,6 @@ BOOL APIENTRY DllMain(
{
switch( reason ) {
case DLL_PROCESS_ATTACH:
#ifdef MOZ_ENABLE_LIBXUL
SetupDllBlocklist();
#endif
nsToolkit::Startup((HINSTANCE)hModule);
break;

View File

@ -1218,8 +1218,8 @@ var gSearchView = {
return score;
aStr = aStr.trim().toLocaleLowerCase();
var haystack = aStr.split(/\W+/);
var needles = aQuery.split(/\W+/);
var haystack = aStr.split(/\s+/);
var needles = aQuery.split(/\s+/);
for (let n = 0; n < needles.length; n++) {
for (let h = 0; h < haystack.length; h++) {

View File

@ -47,6 +47,7 @@ include $(DEPTH)/config/autoconf.mk
_TEST_FILES = \
head.js \
browser_bug557943.js \
browser_bug562890.js \
browser_bug562899.js \
browser_bug562992.js \

View File

@ -0,0 +1,77 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
// Bug 557943 - Searching for addons can result in wrong results
var gManagerWindow;
function test() {
waitForExplicitFinish();
gProvider = new MockProvider();
gProvider.createAddons([{
id: "addon1@tests.mozilla.org",
name: "Microsoft .NET Framework Assistant",
description: "",
version: "6.66"
}, {
id: "addon2@tests.mozilla.org",
name: "AwesomeNet Addon",
description: ""
}, {
id: "addon3@tests.mozilla.org",
name: "Dictionnaire MySpell en Francais (réforme 1990)",
description: ""
}]);
open_manager(null, function(aWindow) {
gManagerWindow = aWindow;
run_next_test();
});
}
function end_test() {
close_manager(gManagerWindow, function() {
finish();
});
}
function perform_search(aQuery, aCallback) {
var searchBox = gManagerWindow.document.getElementById("header-search");
searchBox.value = aQuery;
EventUtils.synthesizeMouse(searchBox, 2, 2, { }, gManagerWindow);
EventUtils.synthesizeKey("VK_RETURN", { }, gManagerWindow);
wait_for_view_load(gManagerWindow, function() {
var list = gManagerWindow.document.getElementById("search-list");
var rows = list.getElementsByTagName("richlistitem");
aCallback(rows);
});
}
add_test(function() {
perform_search(".net", function(aRows) {
is(aRows.length, 1, "Should only get one result");
is(aRows[0].mAddon.id, "addon1@tests.mozilla.org", "Should get expected addon as only result");
run_next_test();
});
});
add_test(function() {
perform_search("réf", function(aRows) {
is(aRows.length, 1, "Should only get one result");
is(aRows[0].mAddon.id, "addon3@tests.mozilla.org", "Should get expected addon as only result");
run_next_test();
});
});
add_test(function() {
perform_search("javascript:void()", function(aRows) {
is(aRows.length, 0, "Should not get any results");
run_next_test();
});
});

View File

@ -20,6 +20,9 @@ var gServer;
var gAddonInstalled = false;
function test() {
// Turn on searching for this test
Services.prefs.setIntPref(PREF_SEARCH_MAXRESULTS, 15);
waitForExplicitFinish();
gProvider = new MockProvider();

View File

@ -41,9 +41,6 @@ function test() {
operationsRequiringRestart: AddonManager.OP_NEEDS_RESTART_NONE
}]);
// Turn off searching
Services.prefs.setIntPref("extensions.getAddons.maxResults", 0);
open_manager(null, function(aWindow) {
gManagerWindow = aWindow;
gDocument = gManagerWindow.document;

View File

@ -15,14 +15,22 @@ const CHROMEROOT = "chrome://mochikit/content/" + RELATIVE_DIR;
const MANAGER_URI = "about:addons";
const INSTALL_URI = "chrome://mozapps/content/xpinstall/xpinstallConfirm.xul";
const PREF_LOGGING_ENABLED = "extensions.logging.enabled";
const PREF_SEARCH_MAXRESULTS = "extensions.getAddons.maxResults";
var gPendingTests = [];
var gTestsRun = 0;
// Turn logging on for all tests
Services.prefs.setBoolPref(PREF_LOGGING_ENABLED, true);
// Turn off remote results in searches
Services.prefs.setIntPref(PREF_SEARCH_MAXRESULTS, 0);
registerCleanupFunction(function() {
Services.prefs.clearUserPref(PREF_LOGGING_ENABLED);
try {
Services.prefs.clearUserPref(PREF_SEARCH_MAXRESULTS);
}
catch (e) {
}
});
function add_test(test) {

View File

@ -40,7 +40,6 @@
#include <winternl.h>
#include <stdio.h>
#include <string.h>
#include "nsAutoPtr.h"
@ -58,31 +57,6 @@
// define this for very verbose dll load debug spew
#undef DEBUG_very_verbose
// This class takes care of setting and restoring the current directory
// to make sure that the process current directory is not searched when
// loading DLLs.
class CurrentDirectoryGuard {
public:
CurrentDirectoryGuard() {
::GetCurrentDirectoryW(MAX_PATH, mCwd);
WCHAR appPath[MAX_PATH] = {L'\0'};
::GetModuleFileNameW(NULL, appPath, MAX_PATH);
LPWSTR lastBackslash = wcsrchr(appPath, L'\\');
if (lastBackslash) {
*lastBackslash = L'\0';
}
::SetCurrentDirectoryW(appPath);
}
~CurrentDirectoryGuard() {
::SetCurrentDirectoryW(mCwd);
}
private:
WCHAR mCwd[MAX_PATH];
};
// The signature for LdrLoadDll changed at some point, with the second arg
// becoming a PULONG instead of a ULONG. This should only matter on 64-bit
// systems, for which there was no support earlier -- on 32-bit systems,
@ -235,14 +209,6 @@ continue_loading:
NS_SetHasLoadedNewDLLs();
// We need to make sure that the OS implementation of LdrLoadDll does not attempt
// to load any DLLs from the current working directory. That's almost never what
// we want, and it can cause us load unexpected DLLs. This guard protects against
// that by setting the current directory to the application's directory before
// LdrLoadDll is called, and restoring it to the original value when that call
// returns.
CurrentDirectoryGuard cwdGuard;
return stub_LdrLoadDll(filePath, flags, moduleFileName, handle);
}

View File

@ -8,8 +8,7 @@
#include "nsUTF8Utils.h"
#if defined(_MSC_VER) && defined(_M_IX86) && defined(XRE_WANT_DLL_BLOCKLIST) \
!defined(MOZ_ENABLE_LIBXUL)
#if defined(_MSC_VER) && defined(_M_IX86) && defined(XRE_WANT_DLL_BLOCKLIST)
#include "nsWindowsDllBlocklist.cpp"
#else
#undef XRE_WANT_DLL_BLOCKLIST

View File

@ -704,15 +704,21 @@ nsWindow::Destroy(void)
mIsDestroyed = PR_TRUE;
mCreated = PR_FALSE;
nsRefPtr<GLContext> gl;
if (GetLayerManager()->GetBackendType() == LayerManager::LAYERS_OPENGL)
{
LayerManagerOGL *manager = static_cast<LayerManagerOGL*>(GetLayerManager());
gl = manager->gl();
}
/** Need to clean our LayerManager up while still alive */
mLayerManager = NULL;
if (mLayerManager) {
nsRefPtr<GLContext> gl = nsnull;
if (mLayerManager->GetBackendType() == LayerManager::LAYERS_OPENGL) {
LayerManagerOGL *ogllm = static_cast<LayerManagerOGL*>(mLayerManager.get());
gl = ogllm->gl();
}
mLayerManager->Destroy();
if (gl) {
gl->MarkDestroyed();
}
}
mLayerManager = nsnull;
g_signal_handlers_disconnect_by_func(gtk_settings_get_default(),
FuncToGpointer(theme_changed_cb),
@ -789,9 +795,6 @@ nsWindow::Destroy(void)
gdk_window_set_user_data(mGdkWindow, NULL);
g_object_set_data(G_OBJECT(mGdkWindow), "nsWindow", NULL);
if (gl) {
gl->WindowDestroyed();
}
gdk_window_destroy(mGdkWindow);
mGdkWindow = nsnull;
}

View File

@ -665,7 +665,10 @@ NS_METHOD nsWindow::Destroy()
* On windows the LayerManagerOGL destructor wants the widget to be around for
* cleanup. It also would like to have the HWND intact, so we NULL it here.
*/
mLayerManager = NULL;
if (mLayerManager) {
mLayerManager->Destroy();
}
mLayerManager = nsnull;
// The DestroyWindow function destroys the specified window. The function sends WM_DESTROY
// and WM_NCDESTROY messages to the window to deactivate it and remove the keyboard focus