b=575469; implement CreateOffscreen and context sharing in GLContexts; r=bas

This commit is contained in:
Vladimir Vukicevic 2010-07-18 22:01:14 -07:00
parent dbd5cb620b
commit e5aa4fb514
16 changed files with 2646 additions and 613 deletions

View File

@ -170,7 +170,9 @@ WebGLContext::SetDimensions(PRInt32 width, PRInt32 height)
format.depth = 16;
format.minDepth = 1;
gl = gl::GLContextProvider::CreatePBuffer(gfxIntSize(width, height), format);
gl = gl::GLContextProvider::CreatePBuffer(gfxIntSize(width, height),
gl::GLContextProvider::GetGlobalContext(),
format);
#ifdef USE_GLES2
// On native GLES2, no need to validate, the compiler will do it
@ -184,7 +186,9 @@ WebGLContext::SetDimensions(PRInt32 width, PRInt32 height)
#endif
if (!InitAndValidateGL()) {
gl = gl::GLContextProviderOSMesa::CreatePBuffer(gfxIntSize(width, height), format);
gl = gl::GLContextProviderOSMesa::CreatePBuffer(gfxIntSize(width, height),
nsnull,
format);
if (!InitAndValidateGL()) {
LogMessage("WebGL: Can't get a usable OpenGL context.");
return NS_ERROR_FAILURE;

View File

@ -76,15 +76,40 @@ LayerManagerOGL::LayerManagerOGL(nsIWidget *aWidget)
LayerManagerOGL::~LayerManagerOGL()
{
if (mGLContext)
mGLContext->MakeCurrent();
mRoot = nsnull;
CleanupResources();
}
mRoot = NULL;
void
LayerManagerOGL::CleanupResources()
{
if (!mGLContext)
return;
mGLContext->MakeCurrent();
for (unsigned int i = 0; i < mPrograms.Length(); ++i)
delete mPrograms[i];
mPrograms.Clear();
mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
if (mBackBufferFBO) {
mGLContext->fDeleteFramebuffers(1, &mBackBufferFBO);
mBackBufferFBO = 0;
}
if (mBackBufferTexture) {
mGLContext->fDeleteTextures(1, &mBackBufferTexture);
mBackBufferTexture = 0;
}
if (mQuadVBO) {
mGLContext->fDeleteBuffers(1, &mQuadVBO);
mQuadVBO = 0;
}
mGLContext = nsnull;
}
PRBool
@ -93,6 +118,8 @@ LayerManagerOGL::Initialize(GLContext *aExistingContext)
if (aExistingContext) {
mGLContext = aExistingContext;
} else {
if (mGLContext)
CleanupResources();
mGLContext = gl::GLContextProvider::CreateForWindow(mWidget);
if (!mGLContext) {

View File

@ -80,7 +80,9 @@ class THEBES_API LayerManagerOGL : public LayerManager {
public:
LayerManagerOGL(nsIWidget *aWidget);
virtual ~LayerManagerOGL();
void CleanupResources();
/**
* Initializes the layer manager, this is when the layer manager will
* actually access the device and attempt to create the swap chain used

View File

@ -120,7 +120,10 @@ public:
: mGL(aGL), mProgram(0)
{ }
virtual ~LayerManagerOGLProgram() { }
virtual ~LayerManagerOGLProgram() {
mGL->MakeCurrent();
mGL->fDeleteProgram(mProgram);
}
void Activate() {
NS_ASSERTION(mProgram != 0, "Attempting to activate a program that's not in use!");
@ -199,11 +202,9 @@ public:
}
protected:
GLContext *mGL;
nsRefPtr<GLContext> mGL;
GLuint mProgram;
GLuint mFragmentShader;
GLuint mVertexShader;
nsTArray<UniformValue> mUniformValues;
@ -254,15 +255,15 @@ protected:
bool CreateProgram(const char *aVertexShaderString,
const char *aFragmentShaderString)
{
mVertexShader = CreateShader(LOCAL_GL_VERTEX_SHADER, aVertexShaderString);
mFragmentShader = CreateShader(LOCAL_GL_FRAGMENT_SHADER, aFragmentShaderString);
GLuint vertexShader = CreateShader(LOCAL_GL_VERTEX_SHADER, aVertexShaderString);
GLuint fragmentShader = CreateShader(LOCAL_GL_FRAGMENT_SHADER, aFragmentShaderString);
if (!mVertexShader || !mFragmentShader)
if (!vertexShader || !fragmentShader)
return false;
mProgram = mGL->fCreateProgram();
mGL->fAttachShader(mProgram, mVertexShader);
mGL->fAttachShader(mProgram, mFragmentShader);
mGL->fAttachShader(mProgram, vertexShader);
mGL->fAttachShader(mProgram, fragmentShader);
// bind common attribs to consistent indices
mGL->fBindAttribLocation(mProgram, VertexAttrib, "aVertexCoord");
@ -296,10 +297,13 @@ 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);
if (!success) {
mGL->fDeleteProgram(mProgram);
mGL->fDeleteShader(mVertexShader);
mGL->fDeleteShader(mFragmentShader);
mProgram = 0;

View File

@ -111,6 +111,7 @@ LibrarySymbolLoader::LoadSymbols(PRLibrary *lib,
const char *prefix)
{
char sbuf[MAX_SYMBOL_LENGTH * 2];
int failCount = 0;
SymLoadStruct *ss = firstStruct;
while (ss->symPointer) {
@ -136,13 +137,13 @@ LibrarySymbolLoader::LoadSymbols(PRLibrary *lib,
if (*ss->symPointer == 0) {
fprintf (stderr, "Can't find symbol '%s'\n", ss->symNames[0]);
return PR_FALSE;
failCount++;
}
ss++;
}
return PR_TRUE;
return failCount == 0 ? PR_TRUE : PR_FALSE;
}
/*
@ -179,13 +180,7 @@ GLContext::InitWithPrefix(const char *prefix, PRBool trygl)
#endif
{ (PRFuncPtr*) &fClearStencil, { "ClearStencil", NULL } },
{ (PRFuncPtr*) &fColorMask, { "ColorMask", NULL } },
{ (PRFuncPtr*) &fCreateProgram, { "CreateProgram", "CreateProgramARB", NULL } },
{ (PRFuncPtr*) &fCreateShader, { "CreateShader", "CreateShaderARB", NULL } },
{ (PRFuncPtr*) &fCullFace, { "CullFace", NULL } },
{ (PRFuncPtr*) &fDeleteBuffers, { "DeleteBuffers", "DeleteBuffersARB", NULL } },
{ (PRFuncPtr*) &fDeleteTextures, { "DeleteTextures", "DeleteTexturesARB", NULL } },
{ (PRFuncPtr*) &fDeleteProgram, { "DeleteProgram", "DeleteProgramARB", NULL } },
{ (PRFuncPtr*) &fDeleteShader, { "DeleteShader", "DeleteShaderARB", NULL } },
{ (PRFuncPtr*) &fDetachShader, { "DetachShader", "DetachShaderARB", NULL } },
{ (PRFuncPtr*) &fDepthFunc, { "DepthFunc", NULL } },
{ (PRFuncPtr*) &fDepthMask, { "DepthMask", NULL } },
@ -217,8 +212,6 @@ GLContext::InitWithPrefix(const char *prefix, PRBool trygl)
{ (PRFuncPtr*) &fGetFloatv, { "GetFloatv", NULL } },
{ (PRFuncPtr*) &fGetBooleanv, { "GetBooleanv", NULL } },
{ (PRFuncPtr*) &fGetBufferParameteriv, { "GetBufferParameteriv", "GetBufferParameterivARB", NULL } },
{ (PRFuncPtr*) &fGenBuffers, { "GenBuffers", "GenBuffersARB", NULL } },
{ (PRFuncPtr*) &fGenTextures, { "GenTextures", NULL } },
{ (PRFuncPtr*) &fGetError, { "GetError", NULL } },
{ (PRFuncPtr*) &fGetProgramiv, { "GetProgramiv", "GetProgramivARB", NULL } },
{ (PRFuncPtr*) &fGetProgramInfoLog, { "GetProgramInfoLog", "GetProgramInfoLogARB", NULL } },
@ -307,22 +300,28 @@ GLContext::InitWithPrefix(const char *prefix, PRBool trygl)
{ (PRFuncPtr*) &fBindFramebuffer, { "BindFramebuffer", "BindFramebufferEXT", NULL } },
{ (PRFuncPtr*) &fBindRenderbuffer, { "BindRenderbuffer", "BindRenderbufferEXT", NULL } },
{ (PRFuncPtr*) &fCheckFramebufferStatus, { "CheckFramebufferStatus", "CheckFramebufferStatusEXT", NULL } },
{ (PRFuncPtr*) &fDeleteFramebuffers, { "DeleteFramebuffers", "DeleteFramebuffersEXT", NULL } },
{ (PRFuncPtr*) &fDeleteRenderbuffers, { "DeleteRenderbuffers", "DeleteRenderbuffersEXT", NULL } },
{ (PRFuncPtr*) &fFramebufferRenderbuffer, { "FramebufferRenderbuffer", "FramebufferRenderbufferEXT", NULL } },
{ (PRFuncPtr*) &fFramebufferTexture2D, { "FramebufferTexture2D", "FramebufferTexture2DEXT", NULL } },
{ (PRFuncPtr*) &fGenerateMipmap, { "GenerateMipmap", "GenerateMipmapEXT", NULL } },
{ (PRFuncPtr*) &fGenFramebuffers, { "GenFramebuffers", "GenFramebuffersEXT", NULL } },
{ (PRFuncPtr*) &fGenRenderbuffers, { "GenRenderbuffers", "GenRenderbuffersEXT", NULL } },
{ (PRFuncPtr*) &fGetFramebufferAttachmentParameteriv, { "GetFramebufferAttachmentParameteriv", "GetFramebufferAttachmentParameterivEXT", NULL } },
{ (PRFuncPtr*) &fGetRenderbufferParameteriv, { "GetRenderbufferParameteriv", "GetRenderbufferParameterivEXT", NULL } },
{ (PRFuncPtr*) &fIsFramebuffer, { "IsFramebuffer", "IsFramebufferEXT", NULL } },
{ (PRFuncPtr*) &fIsRenderbuffer, { "IsRenderbuffer", "IsRenderbufferEXT", NULL } },
{ (PRFuncPtr*) &fRenderbufferStorage, { "RenderbufferStorage", "RenderbufferStorageEXT", NULL } },
#if 0
{ (PRFuncPtr*) &fMapBuffer, { "MapBuffer", NULL } },
{ (PRFuncPtr*) &fUnmapBuffer, { "UnmapBuffer", NULL } },
#endif
{ (PRFuncPtr*) &priv_fGenBuffers, { "GenBuffers", "GenBuffersARB", NULL } },
{ (PRFuncPtr*) &priv_fGenTextures, { "GenTextures", NULL } },
{ (PRFuncPtr*) &priv_fCreateProgram, { "CreateProgram", "CreateProgramARB", NULL } },
{ (PRFuncPtr*) &priv_fCreateShader, { "CreateShader", "CreateShaderARB", NULL } },
{ (PRFuncPtr*) &priv_fGenFramebuffers, { "GenFramebuffers", "GenFramebuffersEXT", NULL } },
{ (PRFuncPtr*) &priv_fGenRenderbuffers, { "GenRenderbuffers", "GenRenderbuffersEXT", NULL } },
{ (PRFuncPtr*) &priv_fDeleteBuffers, { "DeleteBuffers", "DeleteBuffersARB", NULL } },
{ (PRFuncPtr*) &priv_fDeleteTextures, { "DeleteTextures", "DeleteTexturesARB", NULL } },
{ (PRFuncPtr*) &priv_fDeleteProgram, { "DeleteProgram", "DeleteProgramARB", NULL } },
{ (PRFuncPtr*) &priv_fDeleteShader, { "DeleteShader", "DeleteShaderARB", NULL } },
{ (PRFuncPtr*) &priv_fDeleteFramebuffers, { "DeleteFramebuffers", "DeleteFramebuffersEXT", NULL } },
{ (PRFuncPtr*) &priv_fDeleteRenderbuffers, { "DeleteRenderbuffers", "DeleteRenderbuffersEXT", NULL } },
{ NULL, { NULL } },
@ -472,5 +471,361 @@ BasicTextureImage::EndUpdate()
return PR_TRUE; // mTexture is bound
}
PRBool
GLContext::ResizeOffscreenFBO(const gfxIntSize& aSize)
{
MakeCurrent();
bool alpha = mCreationFormat.alpha > 0;
int depth = mCreationFormat.depth;
int stencil = mCreationFormat.stencil;
#ifdef USE_GLES2
const bool isMobile = true;
#else
const bool isMobile = false;
#endif
bool firstTime = (mOffscreenFBO == 0);
GLuint curBoundTexture = 0;
GLuint curBoundRenderbuffer = 0;
GLuint curBoundFramebuffer = 0;
GLint viewport[4];
// save a few things for later restoring
fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, (GLint*) &curBoundTexture);
fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, (GLint*) &curBoundFramebuffer);
fGetIntegerv(LOCAL_GL_RENDERBUFFER_BINDING, (GLint*) &curBoundRenderbuffer);
fGetIntegerv(LOCAL_GL_VIEWPORT, viewport);
// If this is the first time we're going through this, we need
// to create the objects we'll use. Otherwise, just bind them.
if (firstTime) {
fGenTextures(1, &mOffscreenTexture);
fBindTexture(LOCAL_GL_TEXTURE_2D, mOffscreenTexture);
fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR);
fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR);
fGenFramebuffers(1, &mOffscreenFBO);
fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mOffscreenFBO);
if (depth) {
fGenRenderbuffers(1, &mOffscreenDepthRB);
}
if (stencil) {
fGenRenderbuffers(1, &mOffscreenStencilRB);
}
} else {
fBindTexture(LOCAL_GL_TEXTURE_2D, mOffscreenTexture);
fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mOffscreenFBO);
}
// resize the FBO components
if (alpha) {
fTexImage2D(LOCAL_GL_TEXTURE_2D,
0,
LOCAL_GL_RGBA,
aSize.width, aSize.height,
0,
LOCAL_GL_RGBA,
LOCAL_GL_UNSIGNED_BYTE,
NULL);
} else {
fTexImage2D(LOCAL_GL_TEXTURE_2D,
0,
LOCAL_GL_RGB,
aSize.width, aSize.height,
0,
LOCAL_GL_RGB,
isMobile ? LOCAL_GL_UNSIGNED_SHORT_5_6_5
: LOCAL_GL_UNSIGNED_BYTE,
NULL);
}
if (depth) {
fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mOffscreenDepthRB);
fRenderbufferStorage(LOCAL_GL_RENDERBUFFER,
LOCAL_GL_DEPTH_COMPONENT16,
aSize.width, aSize.height);
}
if (stencil) {
fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mOffscreenStencilRB);
fRenderbufferStorage(LOCAL_GL_RENDERBUFFER,
LOCAL_GL_STENCIL_INDEX8,
aSize.width, aSize.height);
}
// Now assemble the FBO, if we're creating one
// for the first time.
if (firstTime) {
fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
LOCAL_GL_COLOR_ATTACHMENT0,
LOCAL_GL_TEXTURE_2D,
mOffscreenTexture,
0);
if (depth) {
fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
LOCAL_GL_DEPTH_ATTACHMENT,
LOCAL_GL_RENDERBUFFER,
mOffscreenDepthRB);
}
if (stencil) {
fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
LOCAL_GL_STENCIL_ATTACHMENT,
LOCAL_GL_RENDERBUFFER,
mOffscreenStencilRB);
}
}
// We should be all resized. Check for framebuffer completeness.
GLenum status = fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
NS_WARNING("Error resizing offscreen framebuffer -- framebuffer not complete");
return PR_FALSE;
}
mOffscreenSize = aSize;
mOffscreenActualSize = aSize;
if (firstTime) {
UpdateActualFormat();
}
// We're good, and the framebuffer is already attached, so let's
// clear out our new framebuffer; otherwise we'll end up displaying
// random memory. We saved all of these things earlier so that we
// can restore them.
fViewport(0, 0, aSize.width, aSize.height);
// Ok, now restore the GL state back to what it was before the resize took place.
fBindTexture(LOCAL_GL_TEXTURE_2D, curBoundTexture);
fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, curBoundRenderbuffer);
fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, curBoundFramebuffer);
// -don't- restore the viewport the first time through this, since
// the previous one isn't valid.
if (!firstTime)
fViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
ClearSafely();
return PR_TRUE;
}
void
GLContext::DeleteOffscreenFBO()
{
fDeleteFramebuffers(1, &mOffscreenFBO);
fDeleteTextures(1, &mOffscreenTexture);
fDeleteRenderbuffers(1, &mOffscreenDepthRB);
fDeleteRenderbuffers(1, &mOffscreenStencilRB);
mOffscreenFBO = 0;
mOffscreenTexture = 0;
mOffscreenDepthRB = 0;
mOffscreenStencilRB = 0;
}
void
GLContext::ClearSafely()
{
GLfloat clearColor[4];
GLfloat clearDepth;
GLint clearStencil;
fGetFloatv(LOCAL_GL_COLOR_CLEAR_VALUE, clearColor);
fGetFloatv(LOCAL_GL_DEPTH_CLEAR_VALUE, &clearDepth);
fGetIntegerv(LOCAL_GL_STENCIL_CLEAR_VALUE, &clearStencil);
fClearColor(0.0f, 0.0f, 0.0f, 0.0f);
fClearStencil(0);
#ifdef USE_GLES2
fClearDepthf(1.0f);
#else
fClearDepth(1.0);
#endif
fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT | LOCAL_GL_STENCIL_BUFFER_BIT);
fClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
fClearStencil(clearStencil);
#ifdef USE_GLES2
fClearDepthf(clearDepth);
#else
fClearDepth(clearDepth);
#endif
}
void
GLContext::UpdateActualFormat()
{
// TODO
}
#ifdef DEBUG
void
GLContext::CreatedProgram(GLContext *aOrigin, GLuint aName)
{
mTrackedPrograms.AppendElement(NamedResource(aOrigin, aName));
}
void
GLContext::CreatedShader(GLContext *aOrigin, GLuint aName)
{
mTrackedShaders.AppendElement(NamedResource(aOrigin, aName));
}
void
GLContext::CreatedBuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames)
{
for (GLsizei i = 0; i < aCount; ++i) {
mTrackedBuffers.AppendElement(NamedResource(aOrigin, aNames[i]));
}
}
void
GLContext::CreatedTextures(GLContext *aOrigin, GLsizei aCount, GLuint *aNames)
{
for (GLsizei i = 0; i < aCount; ++i) {
mTrackedTextures.AppendElement(NamedResource(aOrigin, aNames[i]));
}
}
void
GLContext::CreatedFramebuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames)
{
for (GLsizei i = 0; i < aCount; ++i) {
mTrackedFramebuffers.AppendElement(NamedResource(aOrigin, aNames[i]));
}
}
void
GLContext::CreatedRenderbuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames)
{
for (GLsizei i = 0; i < aCount; ++i) {
mTrackedRenderbuffers.AppendElement(NamedResource(aOrigin, aNames[i]));
}
}
static void
RemoveNamesFromArray(GLContext *aOrigin, GLsizei aCount, GLuint *aNames, nsTArray<GLContext::NamedResource>& aArray)
{
for (GLsizei j = 0; j < aCount; ++j) {
GLuint name = aNames[j];
PRBool found = PR_FALSE;
for (PRUint32 i = 0; i < aArray.Length(); ++i) {
if (aArray[i].name == name) {
aArray.RemoveElementAt(i);
found = PR_TRUE;
break;
}
}
if (!found)
printf_stderr("GL Context %p deleting resource %d, which doesn't exist!", aOrigin, name);
}
}
void
GLContext::DeletedProgram(GLContext *aOrigin, GLuint aName)
{
RemoveNamesFromArray(aOrigin, 1, &aName, mTrackedPrograms);
}
void
GLContext::DeletedShader(GLContext *aOrigin, GLuint aName)
{
RemoveNamesFromArray(aOrigin, 1, &aName, mTrackedShaders);
}
void
GLContext::DeletedBuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames)
{
RemoveNamesFromArray(aOrigin, aCount, aNames, mTrackedBuffers);
}
void
GLContext::DeletedTextures(GLContext *aOrigin, GLsizei aCount, GLuint *aNames)
{
RemoveNamesFromArray(aOrigin, aCount, aNames, mTrackedTextures);
}
void
GLContext::DeletedFramebuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames)
{
RemoveNamesFromArray(aOrigin, aCount, aNames, mTrackedFramebuffers);
}
void
GLContext::DeletedRenderbuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames)
{
RemoveNamesFromArray(aOrigin, aCount, aNames, mTrackedRenderbuffers);
}
static void
MarkContextDestroyedInArray(GLContext *aContext, nsTArray<GLContext::NamedResource>& aArray)
{
for (PRUint32 i = 0; i < aArray.Length(); ++i) {
if (aArray[i].origin == aContext)
aArray[i].originDeleted = PR_TRUE;
}
}
void
GLContext::SharedContextDestroyed(GLContext *aChild)
{
MarkContextDestroyedInArray(aChild, mTrackedPrograms);
MarkContextDestroyedInArray(aChild, mTrackedShaders);
MarkContextDestroyedInArray(aChild, mTrackedTextures);
MarkContextDestroyedInArray(aChild, mTrackedFramebuffers);
MarkContextDestroyedInArray(aChild, mTrackedRenderbuffers);
MarkContextDestroyedInArray(aChild, mTrackedBuffers);
}
static void
ReportArrayContents(const nsTArray<GLContext::NamedResource>& aArray)
{
nsTArray<GLContext::NamedResource> copy(aArray);
copy.Sort();
GLContext *lastContext = NULL;
for (PRUint32 i = 0; i < copy.Length(); ++i) {
if (lastContext != copy[i].origin) {
if (lastContext)
printf_stderr("\n");
printf_stderr(" [%p - %s] ", copy[i].origin, copy[i].originDeleted ? "deleted" : "live");
lastContext = copy[i].origin;
}
printf_stderr("%d ", copy[i].name);
}
printf_stderr("\n");
}
void
GLContext::ReportOutstandingNames()
{
printf_stderr("== GLContext %p ==\n", this);
printf_stderr("Outstanding Textures:\n");
ReportArrayContents(mTrackedTextures);
printf_stderr("Outstanding Buffers:\n");
ReportArrayContents(mTrackedBuffers);
printf_stderr("Outstanding Programs:\n");
ReportArrayContents(mTrackedPrograms);
printf_stderr("Outstanding Shaders:\n");
ReportArrayContents(mTrackedShaders);
printf_stderr("Outstanding Framebuffers:\n");
ReportArrayContents(mTrackedFramebuffers);
printf_stderr("Outstanding Renderbuffers:\n");
ReportArrayContents(mTrackedRenderbuffers);
}
#endif /* DEBUG */
} /* namespace gl */
} /* namespace mozilla */

View File

@ -57,6 +57,7 @@
#include "nsDataHashtable.h"
#include "nsHashKeys.h"
#include "nsRegion.h"
#include "nsAutoPtr.h"
#ifndef GLAPIENTRY
#ifdef XP_WIN
@ -249,19 +250,110 @@ protected:
nsIntRect mUpdateRect;
};
struct THEBES_API ContextFormat {
static const ContextFormat BasicRGBA32Format;
enum StandardContextFormat {
Empty,
BasicRGBA32,
StrictBasicRGBA32,
BasicRGB24,
StrictBasicRGB24,
BasicRGB16_565,
StrictBasicRGB16_565
};
ContextFormat() {
memset(this, 0, sizeof(ContextFormat));
}
ContextFormat(const StandardContextFormat cf) {
memset(this, 0, sizeof(ContextFormat));
switch (cf) {
case BasicRGBA32:
red = green = blue = alpha = 8;
minRed = minGreen = minBlue = minAlpha = 1;
break;
case StrictBasicRGBA32:
red = green = blue = alpha = 8;
minRed = minGreen = minBlue = minAlpha = 8;
break;
case BasicRGB24:
red = green = blue = 8;
minRed = minGreen = minBlue = 1;
break;
case StrictBasicRGB24:
red = green = blue = 8;
minRed = minGreen = minBlue = 8;
break;
case StrictBasicRGB16_565:
red = minRed = 5;
green = minGreen = 6;
blue = minBlue = 5;
break;
default:
break;
}
}
int depth, minDepth;
int stencil, minStencil;
int red, minRed;
int green, minGreen;
int blue, minBlue;
int alpha, minAlpha;
int colorBits() const { return red + green + blue; }
};
class GLContext
: public LibrarySymbolLoader
{
THEBES_INLINE_DECL_THREADSAFE_REFCOUNTING(GLContext)
public:
GLContext()
: mInitialized(PR_FALSE)
GLContext(const ContextFormat& aFormat,
PRBool aIsOffscreen = PR_FALSE,
GLContext *aSharedContext = nsnull)
: mInitialized(PR_FALSE),
mCreationFormat(aFormat),
mIsOffscreen(aIsOffscreen),
mSharedContext(aSharedContext),
mOffscreenTexture(0),
mOffscreenFBO(0),
mOffscreenDepthRB(0),
mOffscreenStencilRB(0)
{
mUserData.Init();
}
virtual ~GLContext() { }
virtual ~GLContext() {
#ifdef DEBUG
if (mSharedContext) {
GLContext *tip = mSharedContext;
while (tip->mSharedContext)
tip = tip->mSharedContext;
tip->SharedContextDestroyed(this);
tip->ReportOutstandingNames();
}
#endif
}
enum GLContextType {
ContextTypeUnknown,
ContextTypeWGL,
ContextTypeCGL,
ContextTypeGLX,
ContextTypeEGL,
ContextTypeOSMesa
};
virtual GLContextType GetContextType() { return ContextTypeUnknown; }
virtual PRBool MakeCurrent() = 0;
virtual PRBool SetupLookupFunction() = 0;
@ -279,23 +371,22 @@ public:
enum NativeDataType {
NativeGLContext,
NativeCGLContext,
NativePBuffer,
NativeImageSurface,
NativeThebesSurface,
NativeDataTypeMax
};
virtual void *GetNativeData(NativeDataType aType) { return NULL; }
GLContext *GetSharedContext() { return mSharedContext; }
/* If this is a PBuffer context, resize the pbufer to the given dimensions,
* keping the same format and attributes. If the resize succeeds, return
* PR_TRUE. Otherwise, or if this is not a pbuffer, return PR_FALSE.
*
* On a successful resize, the previous contents of the pbuffer are cleared,
* and the new contents are undefined.
const ContextFormat& CreationFormat() { return mCreationFormat; }
const ContextFormat& ActualFormat() { return mActualFormat; }
/**
* If this context is double-buffered, returns TRUE.
*/
virtual PRBool Resize(const gfxIntSize& aNewSize) { return PR_FALSE; }
virtual PRBool IsDoubleBuffered() { return PR_FALSE; }
/**
* If this context wraps a double-buffered target, swap the back
* and front buffers. It should be assumed that after a swap, the
@ -326,6 +417,99 @@ public:
fDeleteTextures(1, &tex);
}
/*
* Offscreen support API
*/
/*
* Bind aOffscreen's color buffer as a texture to the TEXTURE_2D
* target. Returns TRUE on success, otherwise FALSE. If
* aOffscreen is not an offscreen context, returns FALSE. If
* BindOffscreenNeedsTexture() returns TRUE, then you should have
* a 2D texture name bound whose image will be replaced by the
* contents of the offscreen context. If it returns FALSE,
* the current 2D texture binding will be replaced.
*
* After a successul call to BindTex2DOffscreen, UnbindTex2DOffscreen
* *must* be called once rendering is complete.
*
* The same texture unit must be active for Bind/Unbind of a given
* context.
*/
virtual PRBool BindOffscreenNeedsTexture(GLContext *aOffscreen) {
return aOffscreen->mOffscreenTexture == 0;
}
virtual PRBool BindTex2DOffscreen(GLContext *aOffscreen) {
if (aOffscreen->GetContextType() != GetContextType()) {
return PR_FALSE;
}
if (!aOffscreen->mOffscreenFBO) {
return PR_FALSE;
}
if (!aOffscreen->mSharedContext ||
aOffscreen->mSharedContext != mSharedContext)
{
return PR_FALSE;
}
fBindTexture(LOCAL_GL_TEXTURE_2D, aOffscreen->mOffscreenTexture);
return PR_TRUE;
}
virtual void UnbindTex2DOffscreen(GLContext *aOffscreen) { }
PRBool IsOffscreen() {
return mIsOffscreen;
}
/*
* All the methods below are only valid if IsOffscreen() returns
* true.
*/
/*
* Resize the current offscreen buffer. Returns true on success.
* If it returns false, the context should be treated as unusable
* and should be recreated. After the resize, the viewport is not
* changed; glViewport should be called as appropriate.
*/
virtual PRBool ResizeOffscreen(const gfxIntSize& aNewSize) {
if (mOffscreenFBO)
return ResizeOffscreenFBO(aNewSize);
return PR_FALSE;
}
/*
* Return size of this offscreen context.
*/
gfxIntSize OffscreenSize() {
return mOffscreenSize;
}
/*
* In some cases, we have to allocate a bigger offscreen buffer
* than what's requested. This is the bigger size.
*/
gfxIntSize OffscreenActualSize() {
return mOffscreenActualSize;
}
/*
* If this context is FBO-backed, return the FBO or the color
* buffer texture. If the context is not FBO-backed, 0 is
* returned (which is also a valid FBO binding).
*/
GLuint GetOffscreenFBO() {
return mOffscreenFBO;
}
GLuint GetOffscreenTexture() {
return mOffscreenTexture;
}
/**
* Return a valid, allocated TextureImage of |aSize| with
* |aContentType|. The TextureImage's texture is configured to
@ -346,8 +530,31 @@ public:
PRBool aUseNearestFilter=PR_FALSE);
protected:
PRPackedBool mInitialized;
ContextFormat mCreationFormat;
PRPackedBool mIsOffscreen;
nsRefPtr<GLContext> mSharedContext;
void UpdateActualFormat();
ContextFormat mActualFormat;
gfxIntSize mOffscreenSize;
gfxIntSize mOffscreenActualSize;
GLuint mOffscreenTexture;
// helper to create/resize an offscreen FBO,
// for offscreen implementations that use FBOs.
PRBool ResizeOffscreenFBO(const gfxIntSize& aSize);
void DeleteOffscreenFBO();
GLuint mOffscreenFBO;
GLuint mOffscreenDepthRB;
GLuint mOffscreenStencilRB;
// Clear to transparent black, with 0 depth and stencil,
// while preserving current ClearColor etc. values.
// Useful for resizing offscreen buffers.
void ClearSafely();
PRBool mInitialized;
nsDataHashtable<nsVoidPtrHashKey, void*> mUserData;
PRBool InitWithPrefix(const char *prefix, PRBool trygl);
@ -408,20 +615,8 @@ public:
PFNGLCLEARSTENCILPROC fClearStencil;
typedef void (GLAPIENTRY * PFNGLCOLORMASKPROC) (realGLboolean red, realGLboolean green, realGLboolean blue, realGLboolean alpha);
PFNGLCOLORMASKPROC fColorMask;
typedef GLuint (GLAPIENTRY * PFNGLCREATEPROGRAMPROC) (void);
PFNGLCREATEPROGRAMPROC fCreateProgram;
typedef GLuint (GLAPIENTRY * PFNGLCREATESHADERPROC) (GLenum type);
PFNGLCREATESHADERPROC fCreateShader;
typedef void (GLAPIENTRY * PFNGLCULLFACEPROC) (GLenum mode);
PFNGLCULLFACEPROC fCullFace;
typedef void (GLAPIENTRY * PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint* buffers);
PFNGLDELETEBUFFERSPROC fDeleteBuffers;
typedef void (GLAPIENTRY * PFNGLDELETETEXTURESPROC) (GLsizei n, const GLuint* textures);
PFNGLDELETETEXTURESPROC fDeleteTextures;
typedef void (GLAPIENTRY * PFNGLDELETEPROGRAMPROC) (GLuint program);
PFNGLDELETEPROGRAMPROC fDeleteProgram;
typedef void (GLAPIENTRY * PFNGLDELETESHADERPROC) (GLuint shader);
PFNGLDELETESHADERPROC fDeleteShader;
typedef void (GLAPIENTRY * PFNGLDETACHSHADERPROC) (GLuint program, GLuint shader);
PFNGLDETACHSHADERPROC fDetachShader;
typedef void (GLAPIENTRY * PFNGLDEPTHFUNCPROC) (GLenum);
@ -473,10 +668,6 @@ public:
PFNGLGETBOOLEANBPROC fGetBooleanv;
typedef void (GLAPIENTRY * PFNGLGETBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint* params);
PFNGLGETBUFFERPARAMETERIVPROC fGetBufferParameteriv;
typedef void (GLAPIENTRY * PFNGLGENBUFFERSPROC) (GLsizei n, GLuint* buffers);
PFNGLGENBUFFERSPROC fGenBuffers;
typedef void (GLAPIENTRY * PFNGLGENTEXTURESPROC) (GLsizei n, GLuint *textures);
PFNGLGENTEXTURESPROC fGenTextures;
typedef void (GLAPIENTRY * PFNGLGENERATEMIPMAPPROC) (GLenum target);
PFNGLGENERATEMIPMAPPROC fGenerateMipmap;
typedef GLenum (GLAPIENTRY * PFNGLGETERRORPROC) (void);
@ -523,12 +714,6 @@ public:
PFNGLLINEWIDTHPROC fLineWidth;
typedef void (GLAPIENTRY * PFNGLLINKPROGRAMPROC) (GLuint program);
PFNGLLINKPROGRAMPROC fLinkProgram;
#if 0
typedef void * (GLAPIENTRY * PFNGLMAPBUFFERPROC) (GLenum target, GLenum access);
PFNGLMAPBUFFERPROC fMapBuffer;
typedef realGLboolean (GLAPIENTRY * PFNGLUNAMPBUFFERPROC) (GLenum target);
PFNGLUNAMPBUFFERPROC fUnmapBuffer;
#endif
typedef void (GLAPIENTRY * PFNGLPIXELSTOREIPROC) (GLenum pname, GLint param);
PFNGLPIXELSTOREIPROC fPixelStorei;
typedef void (GLAPIENTRY * PFNGLPOLYGONOFFSETPROC) (GLfloat factor, GLfloat bias);
@ -650,10 +835,6 @@ public:
PFNGLBINDRENDERBUFFER fBindRenderbuffer;
typedef GLenum (GLAPIENTRY * PFNGLCHECKFRAMEBUFFERSTATUS) (GLenum target);
PFNGLCHECKFRAMEBUFFERSTATUS fCheckFramebufferStatus;
typedef void (GLAPIENTRY * PFNGLDELETEFRAMEBUFFERS) (GLsizei n, const GLuint* ids);
PFNGLDELETEFRAMEBUFFERS fDeleteFramebuffers;
typedef void (GLAPIENTRY * PFNGLDELETERENDERBUFFERS) (GLsizei n, const GLuint* ids);
PFNGLDELETERENDERBUFFERS fDeleteRenderbuffers;
typedef void (GLAPIENTRY * PFNGLFRAMEBUFFERRENDERBUFFER) (GLenum target, GLenum attachmentPoint, GLenum renderbufferTarget, GLuint renderbuffer);
PFNGLFRAMEBUFFERRENDERBUFFER fFramebufferRenderbuffer;
typedef void (GLAPIENTRY * PFNGLFRAMEBUFFERTEXTURE2D) (GLenum target, GLenum attachmentPoint, GLenum textureTarget, GLuint texture, GLint level);
@ -662,10 +843,6 @@ public:
PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIV fGetFramebufferAttachmentParameteriv;
typedef void (GLAPIENTRY * PFNGLGETRENDERBUFFERPARAMETERIV) (GLenum target, GLenum pname, GLint* value);
PFNGLGETRENDERBUFFERPARAMETERIV fGetRenderbufferParameteriv;
typedef void (GLAPIENTRY * PFNGLGENFRAMEBUFFERS) (GLsizei n, GLuint* ids);
PFNGLGENFRAMEBUFFERS fGenFramebuffers;
typedef void (GLAPIENTRY * PFNGLGENRENDERBUFFERS) (GLsizei n, GLuint* ids);
PFNGLGENRENDERBUFFERS fGenRenderbuffers;
typedef realGLboolean (GLAPIENTRY * PFNGLISFRAMEBUFFER) (GLuint framebuffer);
PFNGLISFRAMEBUFFER fIsFramebuffer;
typedef realGLboolean (GLAPIENTRY * PFNGLISRENDERBUFFER) (GLuint renderbuffer);
@ -673,6 +850,264 @@ public:
typedef void (GLAPIENTRY * PFNGLRENDERBUFFERSTORAGE) (GLenum target, GLenum internalFormat, GLsizei width, GLsizei height);
PFNGLRENDERBUFFERSTORAGE fRenderbufferStorage;
protected:
/* These are special -- they create or delete GL resources that can live
* in a shared namespace. In DEBUG, we wrap these calls so that we can
* check when we have something that failed to do cleanup at the time the
* final context is destroyed.
*/
typedef GLuint (GLAPIENTRY * PFNGLCREATEPROGRAMPROC) (void);
PFNGLCREATEPROGRAMPROC priv_fCreateProgram;
typedef GLuint (GLAPIENTRY * PFNGLCREATESHADERPROC) (GLenum type);
PFNGLCREATESHADERPROC priv_fCreateShader;
typedef void (GLAPIENTRY * PFNGLGENBUFFERSPROC) (GLsizei n, GLuint* buffers);
PFNGLGENBUFFERSPROC priv_fGenBuffers;
typedef void (GLAPIENTRY * PFNGLGENTEXTURESPROC) (GLsizei n, GLuint *textures);
PFNGLGENTEXTURESPROC priv_fGenTextures;
typedef void (GLAPIENTRY * PFNGLGENFRAMEBUFFERS) (GLsizei n, GLuint* ids);
PFNGLGENFRAMEBUFFERS priv_fGenFramebuffers;
typedef void (GLAPIENTRY * PFNGLGENRENDERBUFFERS) (GLsizei n, GLuint* ids);
PFNGLGENRENDERBUFFERS priv_fGenRenderbuffers;
typedef void (GLAPIENTRY * PFNGLDELETEPROGRAMPROC) (GLuint program);
PFNGLDELETEPROGRAMPROC priv_fDeleteProgram;
typedef void (GLAPIENTRY * PFNGLDELETESHADERPROC) (GLuint shader);
PFNGLDELETESHADERPROC priv_fDeleteShader;
typedef void (GLAPIENTRY * PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint* buffers);
PFNGLDELETEBUFFERSPROC priv_fDeleteBuffers;
typedef void (GLAPIENTRY * PFNGLDELETETEXTURESPROC) (GLsizei n, const GLuint* textures);
PFNGLDELETETEXTURESPROC priv_fDeleteTextures;
typedef void (GLAPIENTRY * PFNGLDELETEFRAMEBUFFERS) (GLsizei n, const GLuint* ids);
PFNGLDELETEFRAMEBUFFERS priv_fDeleteFramebuffers;
typedef void (GLAPIENTRY * PFNGLDELETERENDERBUFFERS) (GLsizei n, const GLuint* ids);
PFNGLDELETERENDERBUFFERS priv_fDeleteRenderbuffers;
public:
#ifndef DEBUG
GLuint GLAPIENTRY fCreateProgram() {
return priv_fCreateProgram();
}
GLuint GLAPIENTRY fCreateShader(GLenum t) {
return priv_fCreateShader(t);
}
void GLAPIENTRY fGenBuffers(GLsizei n, GLuint* names) {
priv_fGenBuffers(n, names);
}
void GLAPIENTRY fGenTextures(GLsizei n, GLuint* names) {
priv_fGenTextures(n, names);
}
void GLAPIENTRY fGenFramebuffers(GLsizei n, GLuint* names) {
priv_fGenFramebuffers(n, names);
}
void GLAPIENTRY fGenRenderbuffers(GLsizei n, GLuint* names) {
priv_fGenRenderbuffers(n, names);
}
void GLAPIENTRY fDeleteProgram(GLuint program) {
priv_fDeleteProgram(program);
}
void GLAPIENTRY fDeleteShader(GLuint shader) {
priv_fDeleteShader(shader);
}
void GLAPIENTRY fDeleteBuffers(GLsizei n, GLuint *names) {
priv_fDeleteBuffers(n, names);
}
void GLAPIENTRY fDeleteTextures(GLsizei n, GLuint *names) {
priv_fDeleteTextures(n, names);
}
void GLAPIENTRY fDeleteFramebuffers(GLsizei n, GLuint *names) {
priv_fDeleteFramebuffers(n, names);
}
void GLAPIENTRY fDeleteRenderbuffers(GLsizei n, GLuint *names) {
priv_fDeleteRenderbuffers(n, names);
}
#else
GLuint GLAPIENTRY fCreateProgram() {
GLuint ret = priv_fCreateProgram();
if (mSharedContext) {
GLContext *tip = mSharedContext;
while (tip->mSharedContext)
tip = tip->mSharedContext;
tip->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);
}
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);
}
}
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);
}
}
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);
}
}
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);
}
}
void GLAPIENTRY fDeleteProgram(GLuint program) {
priv_fDeleteProgram(program);
if (mSharedContext) {
GLContext *tip = mSharedContext;
while (tip->mSharedContext)
tip = tip->mSharedContext;
tip->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);
}
}
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);
}
}
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);
}
}
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);
}
}
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);
}
}
void CreatedProgram(GLContext *aOrigin, GLuint aName);
void CreatedShader(GLContext *aOrigin, GLuint aName);
void CreatedBuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames);
void CreatedTextures(GLContext *aOrigin, GLsizei aCount, GLuint *aNames);
void CreatedFramebuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames);
void CreatedRenderbuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames);
void DeletedProgram(GLContext *aOrigin, GLuint aName);
void DeletedShader(GLContext *aOrigin, GLuint aName);
void DeletedBuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames);
void DeletedTextures(GLContext *aOrigin, GLsizei aCount, GLuint *aNames);
void DeletedFramebuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames);
void DeletedRenderbuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames);
void SharedContextDestroyed(GLContext *aChild);
void ReportOutstandingNames();
struct NamedResource {
NamedResource()
: origin(nsnull), name(0), originDeleted(PR_FALSE)
{ }
NamedResource(GLContext *aOrigin, GLuint aName)
: origin(aOrigin), name(aName), originDeleted(PR_FALSE)
{ }
GLContext *origin;
GLuint name;
PRBool originDeleted;
// for sorting
bool operator<(const NamedResource& aOther) const {
if (intptr_t(origin) < intptr_t(aOther.origin))
return true;
if (name < aOther.name)
return true;
return false;
}
bool operator==(const NamedResource& aOther) const {
return origin == aOther.origin &&
name == aOther.name &&
originDeleted == aOther.originDeleted;
}
};
nsTArray<NamedResource> mTrackedPrograms;
nsTArray<NamedResource> mTrackedShaders;
nsTArray<NamedResource> mTrackedTextures;
nsTArray<NamedResource> mTrackedFramebuffers;
nsTArray<NamedResource> mTrackedRenderbuffers;
nsTArray<NamedResource> mTrackedBuffers;
#endif
};
inline void

View File

@ -48,56 +48,6 @@ class gfxASurface;
namespace mozilla {
namespace gl {
struct THEBES_API ContextFormat {
static const ContextFormat BasicRGBA32Format;
enum StandardContextFormat {
Empty,
BasicRGBA32,
StrictBasicRGBA32,
BasicRGBX32,
StrictBasicRGBX32
};
ContextFormat(const StandardContextFormat cf) {
memset(this, 0, sizeof(ContextFormat));
switch (cf) {
case BasicRGBA32:
red = green = blue = alpha = 8;
minRed = minGreen = minBlue = minAlpha = 1;
break;
case StrictBasicRGBA32:
red = green = blue = alpha = 8;
minRed = minGreen = minBlue = minAlpha = 8;
break;
case BasicRGBX32:
red = green = blue = 8;
minRed = minGreen = minBlue = 1;
break;
case StrictBasicRGBX32:
red = green = blue = alpha = 8;
minRed = minGreen = minBlue = 8;
break;
default:
break;
}
}
int depth, minDepth;
int stencil, minStencil;
int red, minRed;
int green, minGreen;
int blue, minBlue;
int alpha, minAlpha;
int colorBits() const { return red + green + blue; }
};
#define IN_GL_CONTEXT_PROVIDER_H
// Null and OSMesa are always there

View File

@ -50,7 +50,11 @@ namespace gl {
class CGLLibrary
{
public:
CGLLibrary() : mInitialized(PR_FALSE), mOGLLibrary(nsnull) {}
CGLLibrary()
: mInitialized(PR_FALSE),
mOGLLibrary(nsnull),
mPixelFormat(nsnull)
{ }
PRBool EnsureInitialized()
{
@ -69,34 +73,68 @@ public:
return PR_TRUE;
}
NSOpenGLPixelFormat *PixelFormat()
{
if (mPixelFormat == nsnull) {
NSOpenGLPixelFormatAttribute attribs[] = {
NSOpenGLPFAAccelerated,
(NSOpenGLPixelFormatAttribute)nil
};
mPixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
}
return mPixelFormat;
}
private:
PRBool mInitialized;
PRLibrary *mOGLLibrary;
NSOpenGLPixelFormat *mPixelFormat;
};
CGLLibrary sCGLLibrary;
class GLContextCGL : public GLContext
{
friend class GLContextProviderCGL;
public:
GLContextCGL(NSOpenGLContext *aContext)
: mContext(aContext), mCGLContext(nsnull), mPBuffer(nsnull)
GLContextCGL(const ContextFormat& aFormat,
GLContext *aShareContext,
NSOpenGLContext *aContext,
PRBool aIsOffscreen = PR_FALSE)
: GLContext(aFormat, aIsOffscreen, aShareContext),
mContext(aContext),
mPBuffer(nsnull),
mTempTextureName(0)
{ }
GLContextCGL(CGLContextObj aContext, CGLPBufferObj aPBuffer)
: mContext(nsnull), mCGLContext(aContext), mPBuffer(aPBuffer)
GLContextCGL(const ContextFormat& aFormat,
GLContext *aShareContext,
NSOpenGLContext *aContext,
NSOpenGLPixelBuffer *aPixelBuffer)
: GLContext(aFormat, PR_TRUE, aShareContext),
mContext(aContext),
mPBuffer(aPixelBuffer),
mTempTextureName(0)
{ }
~GLContextCGL()
{
if (mOffscreenFBO) {
MakeCurrent();
DeleteOffscreenFBO();
}
if (mContext)
[mContext release];
if (mCGLContext)
CGLDestroyContext(mCGLContext);
if (mPBuffer)
CGLDestroyPBuffer(mPBuffer);
[mPBuffer release];
}
GLContextType GetContextType() {
return ContextTypeCGL;
}
PRBool Init()
@ -111,12 +149,6 @@ public:
case NativeGLContext:
return mContext;
case NativeCGLContext:
return mCGLContext ? mCGLContext : [mContext CGLContextObj];
case NativePBuffer:
return mPBuffer;
default:
return nsnull;
}
@ -126,8 +158,6 @@ public:
{
if (mContext) {
[mContext makeCurrentContext];
} else if (mCGLContext) {
CGLSetCurrentContext(mCGLContext);
}
return PR_TRUE;
}
@ -137,18 +167,104 @@ public:
return PR_FALSE;
}
PRBool BindTex2DOffscreen(GLContext *aOffscreen);
void UnbindTex2DOffscreen(GLContext *aOffscreen);
PRBool ResizeOffscreen(const gfxIntSize& aNewSize);
virtual already_AddRefed<TextureImage>
CreateBasicTextureImage(GLuint aTexture,
const nsIntSize& aSize,
TextureImage::ContentType aContentType,
GLContext* aContext);
private:
NSOpenGLContext *mContext;
CGLContextObj mCGLContext;
CGLPBufferObj mPBuffer;
NSOpenGLPixelBuffer *mPBuffer;
GLuint mTempTextureName;
};
PRBool
GLContextCGL::BindTex2DOffscreen(GLContext *aOffscreen)
{
if (aOffscreen->GetContextType() != ContextTypeCGL) {
NS_WARNING("non-CGL context");
return PR_FALSE;
}
if (!aOffscreen->IsOffscreen()) {
NS_WARNING("non-offscreen context");
return PR_FALSE;
}
GLContextCGL *offs = static_cast<GLContextCGL*>(aOffscreen);
if (offs->mPBuffer) {
fGenTextures(1, &mTempTextureName);
fBindTexture(LOCAL_GL_TEXTURE_2D, mTempTextureName);
[mContext
setTextureImageToPixelBuffer:offs->mPBuffer
colorBuffer:LOCAL_GL_FRONT];
} else if (offs->mOffscreenTexture) {
if (offs->GetSharedContext() != GLContextProviderCGL::GetGlobalContext())
{
NS_WARNING("offscreen FBO context can only be bound with context sharing!");
return PR_FALSE;
}
fBindTexture(LOCAL_GL_TEXTURE_2D, offs->mOffscreenTexture);
} else {
NS_WARNING("don't know how to bind this!");
return PR_FALSE;
}
return PR_TRUE;
}
void
GLContextCGL::UnbindTex2DOffscreen(GLContext *aOffscreen)
{
NS_ASSERTION(aOffscreen->GetContextType() == ContextTypeCGL, "wrong type");
GLContextCGL *offs = static_cast<GLContextCGL*>(aOffscreen);
if (offs->mPBuffer) {
NS_ASSERTION(mTempTextureName, "We didn't have an offscreen texture name?");
fDeleteTextures(1, &mTempTextureName);
mTempTextureName = 0;
}
}
PRBool
GLContextCGL::ResizeOffscreen(const gfxIntSize& aNewSize)
{
if (mPBuffer) {
NSOpenGLPixelBuffer *pb = [[NSOpenGLPixelBuffer alloc]
initWithTextureTarget:LOCAL_GL_TEXTURE_2D
textureInternalFormat:(mCreationFormat.alpha ? LOCAL_GL_RGBA : LOCAL_GL_RGB)
textureMaxMipMapLevel:0
pixelsWide:aNewSize.width
pixelsHigh:aNewSize.height];
if (!pb) {
return PR_FALSE;
}
[mPBuffer release];
mPBuffer = pb;
mOffscreenSize = aNewSize;
mOffscreenActualSize = aNewSize;
[mContext setPixelBuffer:pb cubeMapFace:0 mipMapLevel:0
currentVirtualScreen:[mContext currentVirtualScreen]];
MakeCurrent();
ClearSafely();
return PR_TRUE;
}
return ResizeOffscreenFBO(aNewSize);
}
class TextureImageCGL : public BasicTextureImage
{
friend already_AddRefed<TextureImage>
@ -204,112 +320,176 @@ GLContextCGL::CreateBasicTextureImage(GLuint aTexture,
return teximage.forget();
}
static GLContextCGL *
GetGlobalContextCGL()
{
return static_cast<GLContextCGL*>(GLContextProviderCGL::GetGlobalContext());
}
already_AddRefed<GLContext>
GLContextProviderCGL::CreateForWindow(nsIWidget *aWidget)
{
if (!sCGLLibrary.EnsureInitialized()) {
return nsnull;
}
NSOpenGLPixelFormatAttribute attributes [] = {
NSOpenGLPFAAccelerated,
(NSOpenGLPixelFormatAttribute)nil
};
NSOpenGLPixelFormat *pixelFormat = [[(NSOpenGLPixelFormat *)[NSOpenGLPixelFormat alloc]
initWithAttributes:attributes]
autorelease];
NSOpenGLContext *context = [[NSOpenGLContext alloc]
initWithFormat:pixelFormat
shareContext:NULL];
if (context == nil) {
GLContextCGL *shareContext = GetGlobalContextCGL();
NSOpenGLContext *context = [[NSOpenGLContext alloc]
initWithFormat:sCGLLibrary.PixelFormat()
shareContext:(shareContext ? shareContext->mContext : NULL)];
if (!context) {
return nsnull;
}
nsRefPtr<GLContextCGL> glContext = new GLContextCGL(context);
NSView *childView = (NSView *)aWidget->GetNativeData(NS_NATIVE_WIDGET);
[context setView:childView];
nsRefPtr<GLContextCGL> glContext = new GLContextCGL(ContextFormat(ContextFormat::BasicRGB24),
shareContext,
context);
if (!glContext->Init()) {
return nsnull;
}
NSView *childView = (NSView *)aWidget->GetNativeData(NS_NATIVE_WIDGET);
if ([context view] != childView) {
[context setView:childView];
}
}
return glContext.forget().get();
return glContext.forget();
}
already_AddRefed<GLContext>
GLContextProviderCGL::CreatePBuffer(const gfxIntSize &aSize,
const ContextFormat &aFormat)
static already_AddRefed<GLContextCGL>
CreateOffscreenPBufferContext(const gfxIntSize& aSize,
const ContextFormat& aFormat,
PRBool aShare = PR_FALSE)
{
if (!sCGLLibrary.EnsureInitialized()) {
return nsnull;
}
nsTArray<CGLPixelFormatAttribute> attribs;
#define A1_(_x) do { \
attribs.AppendElement((CGLPixelFormatAttribute) _x); \
} while(0)
#define A2_(_x,_y) do { \
attribs.AppendElement((CGLPixelFormatAttribute) _x); \
attribs.AppendElement((CGLPixelFormatAttribute) _y); \
} while(0)
A1_(kCGLPFAAccelerated);
A1_(kCGLPFAMinimumPolicy);
A1_(kCGLPFAPBuffer);
A2_(kCGLPFAColorSize, aFormat.colorBits());
A2_(kCGLPFAAlphaSize, aFormat.alpha);
A2_(kCGLPFADepthSize, aFormat.depth);
A1_(0);
CGLError err;
GLint nFormats;
CGLPixelFormatObj pixelFormat;
CGLContextObj context;
CGLPBufferObj pbuffer;
GLint screen;
err = CGLChoosePixelFormat(attribs.Elements(), &pixelFormat, &nFormats);
if (err) {
GLContextCGL *shareContext = aShare ? GetGlobalContextCGL() : nsnull;
if (aShare && !shareContext) {
return nsnull;
}
err = CGLCreateContext(pixelFormat, NULL, &context);
if (err) {
nsTArray<NSOpenGLPixelFormatAttribute> attribs;
#define A_(_x) attribs.AppendElement(NSOpenGLPixelFormatAttribute(_x))
A_(NSOpenGLPFAAccelerated);
A_(NSOpenGLPFAPixelBuffer);
A_(NSOpenGLPFAMinimumPolicy);
A_(NSOpenGLPFAColorSize);
A_(aFormat.colorBits());
A_(NSOpenGLPFAAlphaSize);
A_(aFormat.alpha);
A_(NSOpenGLPFADepthSize);
A_(aFormat.depth);
A_(NSOpenGLPFAStencilSize);
A_(aFormat.stencil);
A_(0);
#undef A_
printf_stderr("colorbits: %d alpha: %d depth: %d stencil: %d\n", aFormat.colorBits(), aFormat.alpha, aFormat.depth, aFormat.stencil);
NSOpenGLPixelFormat *pbFormat = [[NSOpenGLPixelFormat alloc]
initWithAttributes:attribs.Elements()];
if (!pbFormat) {
return nsnull;
}
err = CGLCreatePBuffer(aSize.width, aSize.height, LOCAL_GL_TEXTURE_2D,
LOCAL_GL_RGBA,
0, &pbuffer);
if (err) {
NSOpenGLPixelBuffer *pb = [[NSOpenGLPixelBuffer alloc]
initWithTextureTarget:LOCAL_GL_TEXTURE_2D
textureInternalFormat:(aFormat.alpha ? LOCAL_GL_RGBA : LOCAL_GL_RGB)
textureMaxMipMapLevel:0
pixelsWide:aSize.width
pixelsHigh:aSize.height];
if (!pb) {
[pbFormat release];
return nsnull;
}
err = CGLGetVirtualScreen(context, &screen);
if (err) {
NSOpenGLContext *context = [[NSOpenGLContext alloc]
initWithFormat:pbFormat
shareContext:shareContext ? shareContext->mContext : NULL];
if (!context) {
[pbFormat release];
[pb release];
return nsnull;
}
err = CGLSetPBuffer(context, pbuffer, 0, 0, screen);
if (err) {
[context
setPixelBuffer:pb
cubeMapFace:0
mipMapLevel:0
currentVirtualScreen:[context currentVirtualScreen]];
{
GLint l;
[pbFormat getValues:&l forAttribute:NSOpenGLPFADepthSize forVirtualScreen:[context currentVirtualScreen]];
printf_stderr("*** depth: %d (req: %d)\n", l, aFormat.depth);
}
[pbFormat release];
nsRefPtr<GLContextCGL> glContext = new GLContextCGL(aFormat, shareContext, context, pb);
return glContext.forget();
}
static already_AddRefed<GLContextCGL>
CreateOffscreenFBOContext(const gfxIntSize& aSize,
const ContextFormat& aFormat,
PRBool aShare = PR_TRUE)
{
if (!sCGLLibrary.EnsureInitialized()) {
return nsnull;
}
CGLDestroyPixelFormat(pixelFormat);
nsRefPtr<GLContextCGL> glContext = new GLContextCGL(context, pbuffer);
if (!glContext->Init()) {
GLContextCGL *shareContext = aShare ? GetGlobalContextCGL() : nsnull;
if (aShare && !shareContext) {
// if there is no share context, then we can't use FBOs.
return nsnull;
}
return glContext.forget().get();
NSOpenGLContext *context = [[NSOpenGLContext alloc]
initWithFormat:sCGLLibrary.PixelFormat()
shareContext:shareContext ? shareContext->mContext : NULL];
if (!context) {
return nsnull;
}
nsRefPtr<GLContextCGL> glContext = new GLContextCGL(aFormat, shareContext, context, PR_TRUE);
return glContext.forget();
}
already_AddRefed<GLContext>
GLContextProviderCGL::CreateOffscreen(const gfxIntSize& aSize,
const ContextFormat& aFormat)
{
nsRefPtr<GLContextCGL> glContext;
glContext = CreateOffscreenPBufferContext(aSize, aFormat);
if (glContext &&
glContext->Init())
{
glContext->mOffscreenSize = aSize;
glContext->mOffscreenActualSize = aSize;
return glContext.forget();
}
// try a FBO as second choice
glContext = CreateOffscreenFBOContext(aSize, aFormat);
if (glContext &&
glContext->Init() &&
glContext->ResizeOffscreenFBO(aSize))
{
return glContext.forget();
}
// everything failed
return nsnull;
}
already_AddRefed<GLContext>
@ -318,5 +498,27 @@ GLContextProviderCGL::CreateForNativePixmapSurface(gfxASurface *aSurface)
return nsnull;
}
static nsRefPtr<GLContext> gGlobalContext;
GLContext *
GLContextProviderCGL::GetGlobalContext()
{
if (!sCGLLibrary.EnsureInitialized()) {
return nsnull;
}
if (!gGlobalContext) {
// There are bugs in some older drivers with pbuffers less
// than 16x16 in size; also 16x16 is POT so that we can do
// a FBO with it on older video cards. A FBO context for
// sharing is preferred since it has no associated target.
gGlobalContext = CreateOffscreenFBOContext(gfxIntSize(16, 16),
ContextFormat(ContextFormat::BasicRGB24),
PR_FALSE);
}
return gGlobalContext;
}
} /* namespace gl */
} /* namespace mozilla */

File diff suppressed because it is too large Load Diff

View File

@ -53,7 +53,7 @@
#include "nsDebug.h"
#include "nsIWidget.h"
#include "GLXLibrary.h"
#include "gfxASurface.h"
#include "gfxXlibSurface.h"
#include "gfxContext.h"
#include "gfxImageSurface.h"
#include "gfxPlatform.h"
@ -61,6 +61,10 @@
namespace mozilla {
namespace gl {
static PRBool gIsATI = PR_FALSE;
static PRBool gIsChromium = PR_FALSE;
static int gGLXVersion = 0;
PRBool
GLXLibrary::EnsureInitialized()
{
@ -90,6 +94,10 @@ GLXLibrary::EnsureInitialized()
{ (PRFuncPtr*) &xGetFBConfigAttrib, { "glXGetFBConfigAttrib", NULL } },
{ (PRFuncPtr*) &xSwapBuffers, { "glXSwapBuffers", NULL } },
{ (PRFuncPtr*) &xQueryServerString, { "glXQueryServerString", NULL } },
{ (PRFuncPtr*) &xCreatePixmap, { "glXCreatePixmap", NULL } },
{ (PRFuncPtr*) &xDestroyPixmap, { "glXDestroyPixmap", NULL } },
{ (PRFuncPtr*) &xGetClientString, { "glXGetClientString", NULL } },
{ (PRFuncPtr*) &xCreateContext, { "glXCreateContext", NULL } },
{ NULL, { NULL } }
};
@ -98,6 +106,40 @@ GLXLibrary::EnsureInitialized()
return PR_FALSE;
}
const char *vendor = xQueryServerString(DefaultXDisplay(),
DefaultScreen(DefaultXDisplay()),
GLX_VENDOR);
const char *serverVersionStr = xQueryServerString(DefaultXDisplay(),
DefaultScreen(DefaultXDisplay()),
GLX_VERSION);
const char *clientVersionStr = xGetClientString(DefaultXDisplay(),
GLX_VERSION);
int serverVersion = 0, clientVersion = 0;
if (serverVersionStr &&
strlen(serverVersionStr) > 3 &&
serverVersionStr[1] == '.')
{
serverVersion = (serverVersionStr[0] - '0') << 8 | (serverVersionStr[2] - '0');
}
if (clientVersion &&
strlen(clientVersionStr) > 3 &&
clientVersionStr[1] == '.')
{
clientVersion = (clientVersionStr[0] - '0') << 8 | (clientVersionStr[2] - '0');
}
gGLXVersion = PR_MIN(clientVersion, serverVersion);
if (gGLXVersion < 0x0103)
return PR_FALSE;
gIsATI = vendor && strstr(vendor, "ATI");
gIsChromium = (vendor && strstr(vendor, "Chromium")) ||
(serverVersion && strstr(serverVersionStr, "Chromium"));
mInitialized = PR_TRUE;
return PR_TRUE;
}
@ -116,7 +158,14 @@ class GLContextGLX : public GLContext
{
public:
static already_AddRefed<GLContextGLX>
CreateGLContext(Display *display, GLXDrawable drawable, GLXFBConfig cfg, PRBool pbuffer)
CreateGLContext(const ContextFormat& format,
Display *display,
GLXDrawable drawable,
GLXFBConfig cfg,
XVisualInfo *vinfo,
GLContextGLX *shareContext,
PRBool deleteDrawable,
gfxXlibSurface *pixmap = nsnull)
{
int db = 0, err;
err = sGLXLibrary.xGetFBConfigAttrib(display, cfg,
@ -128,27 +177,45 @@ public:
}
ctxErrorOccurred = false;
int (*oldHandler)(Display *, XErrorEvent *) = XSetErrorHandler(&ctxErrorHandler);
int (*oldHandler)(Display *, XErrorEvent *);
GLXContext context;
GLXContext context = sGLXLibrary.xCreateNewContext(display,
cfg,
GLX_RGBA_TYPE,
NULL,
True);
TRY_AGAIN_NO_SHARING:
oldHandler = XSetErrorHandler(&ctxErrorHandler);
if (gGLXVersion >= 0x0103) {
context = sGLXLibrary.xCreateNewContext(display,
cfg,
GLX_RGBA_TYPE,
shareContext ? shareContext->mContext : NULL,
True);
} else {
context = sGLXLibrary.xCreateContext(display,
vinfo,
shareContext ? shareContext->mContext : NULL,
True);
}
XSync(display, False);
XSetErrorHandler(oldHandler);
if (!context || ctxErrorOccurred) {
if (shareContext) {
shareContext = nsnull;
goto TRY_AGAIN_NO_SHARING;
}
NS_WARNING("Failed to create GLXContext!");
return nsnull;
}
nsRefPtr<GLContextGLX> glContext(new GLContextGLX(display,
nsRefPtr<GLContextGLX> glContext(new GLContextGLX(format,
shareContext,
display,
drawable,
context,
pbuffer,
db));
deleteDrawable,
db,
pixmap));
if (!glContext->Init()) {
return nsnull;
}
@ -158,11 +225,15 @@ public:
~GLContextGLX()
{
if (mPBuffer) {
sGLXLibrary.xDestroyPbuffer(mDisplay, mWindow);
}
sGLXLibrary.xDeleteContext(mDisplay, mContext);
if (mDeleteDrawable) {
sGLXLibrary.xDestroyPixmap(mDisplay, mDrawable);
}
}
GLContextType GetContextType() {
return ContextTypeGLX;
}
PRBool Init()
@ -178,7 +249,7 @@ public:
PRBool MakeCurrent()
{
Bool succeeded = sGLXLibrary.xMakeCurrent(mDisplay, mWindow, mContext);
Bool succeeded = sGLXLibrary.xMakeCurrent(mDisplay, mDrawable, mContext);
NS_ASSERTION(succeeded, "Failed to make GL context current!");
return succeeded;
}
@ -195,22 +266,24 @@ public:
case NativeGLContext:
return mContext;
case NativePBuffer:
if (mPBuffer) {
return (void *)mWindow;
}
// fall through
case NativeThebesSurface:
return mPixmap;
default:
return nsnull;
}
}
virtual PRBool SwapBuffers()
PRBool IsDoubleBuffered()
{
if (mPBuffer || !mDoubleBuffered)
return mDoubleBuffered;
}
PRBool SwapBuffers()
{
if (!mDoubleBuffered)
return PR_FALSE;
sGLXLibrary.xSwapBuffers(mDisplay, mWindow);
sGLXLibrary.xSwapBuffers(mDisplay, mDrawable);
return PR_TRUE;
}
@ -249,19 +322,33 @@ public:
GLContext* aContext);
private:
GLContextGLX(Display *aDisplay, GLXDrawable aWindow, GLXContext aContext, PRBool aPBuffer = PR_FALSE, PRBool aDoubleBuffered=PR_FALSE)
: mContext(aContext),
mDisplay(aDisplay),
mWindow(aWindow),
mPBuffer(aPBuffer),
mDoubleBuffered(aDoubleBuffered) {}
friend class GLContextProviderGLX;
GLContextGLX(const ContextFormat& aFormat,
GLContext *aShareContext,
Display *aDisplay,
GLXDrawable aDrawable,
GLXContext aContext,
PRBool aDeleteDrawable,
PRBool aDoubleBuffered,
gfxXlibSurface *aPixmap)
: GLContext(aFormat, aDeleteDrawable ? PR_TRUE : PR_FALSE, aShareContext),
mContext(aContext),
mDisplay(aDisplay),
mDrawable(aDrawable),
mDeleteDrawable(aDeleteDrawable),
mDoubleBuffered(aDoubleBuffered),
mPixmap(aPixmap)
{ }
GLXContext mContext;
Display *mDisplay;
GLXDrawable mWindow;
PRBool mPBuffer;
PRBool mDoubleBuffered;
GLXDrawable mDrawable;
PRPackedBool mDeleteDrawable;
PRPackedBool mDoubleBuffered;
nsTArray<GLuint> textures;
nsRefPtr<gfxXlibSurface> mPixmap;
};
// FIXME/bug 575505: this is a (very slow!) placeholder
@ -321,7 +408,14 @@ GLContextGLX::CreateBasicTextureImage(GLuint aTexture,
return teximage.forget();
}
static PRBool AreCompatibleVisuals(XVisualInfo *one, XVisualInfo *two)
static GLContextGLX *
GetGlobalContextGLX()
{
return static_cast<GLContextGLX*>(GLContextProviderGLX::GetGlobalContext());
}
static PRBool
AreCompatibleVisuals(XVisualInfo *one, XVisualInfo *two)
{
if (one->c_class != two->c_class) {
return PR_FALSE;
@ -362,11 +456,9 @@ GLContextProviderGLX::CreateForWindow(nsIWidget *aWidget)
int xscreen = DefaultScreen(display);
Window window = GET_NATIVE_WINDOW(aWidget);
const char *vendor = sGLXLibrary.xQueryServerString(display, xscreen, GLX_VENDOR);
PRBool isATI = vendor && strstr(vendor, "ATI");
int numConfigs;
ScopedXFree<GLXFBConfig> cfgs;
if (isATI) {
if (gIsATI) {
const int attribs[] = {
GLX_DOUBLEBUFFER, False,
0
@ -402,7 +494,7 @@ GLContextProviderGLX::CreateForWindow(nsIWidget *aWidget)
#endif
ScopedXFree<XVisualInfo> vi;
if (isATI) {
if (gIsATI) {
XVisualInfo vinfo_template;
int nvisuals;
vinfo_template.visual = widgetAttrs.visual;
@ -415,18 +507,20 @@ GLContextProviderGLX::CreateForWindow(nsIWidget *aWidget)
}
int matchIndex = -1;
ScopedXFree<XVisualInfo> vinfo;
for (int i = 0; i < numConfigs; i++) {
ScopedXFree<XVisualInfo> info(sGLXLibrary.xGetVisualFromFBConfig(display, cfgs[i]));
if (!info) {
vinfo = sGLXLibrary.xGetVisualFromFBConfig(display, cfgs[i]);
if (!vinfo) {
continue;
}
if (isATI) {
if (AreCompatibleVisuals(vi, info)) {
if (gIsATI) {
if (AreCompatibleVisuals(vi, vinfo)) {
matchIndex = i;
break;
}
} else {
if (widgetVisualID == info->visualid) {
if (widgetVisualID == vinfo->visualid) {
matchIndex = i;
break;
}
@ -438,21 +532,155 @@ GLContextProviderGLX::CreateForWindow(nsIWidget *aWidget)
return nsnull;
}
nsRefPtr<GLContextGLX> glContext = GLContextGLX::CreateGLContext(display,
GLContextGLX *shareContext = GetGlobalContextGLX();
nsRefPtr<GLContextGLX> glContext = GLContextGLX::CreateGLContext(ContextFormat(ContextFormat::BasicRGB24),
display,
window,
cfgs[matchIndex],
vinfo,
shareContext,
PR_FALSE);
return glContext.forget();
}
already_AddRefed<GLContext>
GLContextProviderGLX::CreatePBuffer(const gfxIntSize &aSize, const ContextFormat& aFormat)
static already_AddRefed<GLContextGLX>
CreateOffscreenPixmapContext(const gfxIntSize& aSize,
const ContextFormat& aFormat,
PRBool aShare)
{
if (!sGLXLibrary.EnsureInitialized()) {
return nsnull;
}
nsTArray<int> attribs;
Display *display = DefaultXDisplay();
int xscreen = DefaultScreen(display);
int attribs[] = {
GLX_DOUBLEBUFFER, False,
GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
GLX_X_RENDERABLE, True,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1,
GLX_ALPHA_SIZE, 0,
GLX_DEPTH_SIZE, 0,
0
};
int numConfigs = 0;
ScopedXFree<GLXFBConfig> cfgs;
cfgs = sGLXLibrary.xChooseFBConfig(display,
xscreen,
attribs,
&numConfigs);
if (!cfgs) {
return nsnull;
}
NS_ASSERTION(numConfigs > 0,
"glXChooseFBConfig() failed to match our requested format and violated its spec (!)");
ScopedXFree<XVisualInfo> vinfo;
int chosenIndex;
for (int i = 0; i < numConfigs; ++i) {
int dtype, visid;
if (sGLXLibrary.xGetFBConfigAttrib(display, cfgs[i], GLX_DRAWABLE_TYPE, &dtype) != Success
|| !(dtype & GLX_PIXMAP_BIT))
{
continue;
}
if (sGLXLibrary.xGetFBConfigAttrib(display, cfgs[i], GLX_VISUAL_ID, &visid) != Success
|| visid == 0)
{
continue;
}
vinfo = sGLXLibrary.xGetVisualFromFBConfig(display, cfgs[i]);
if (vinfo) {
chosenIndex = i;
break;
}
}
if (!vinfo) {
NS_WARNING("glXChooseFBConfig() didn't give us any configs with visuals!");
return nsnull;
}
nsRefPtr<gfxXlibSurface> xsurface = gfxXlibSurface::Create(DefaultScreenOfDisplay(display),
vinfo->visual,
gfxIntSize(16, 16));
if (xsurface->CairoStatus() != 0) {
return nsnull;
}
GLXPixmap glxpixmap = sGLXLibrary.xCreatePixmap(display,
cfgs[chosenIndex],
xsurface->XDrawable(),
NULL);
if (glxpixmap == 0) {
return nsnull;
}
GLContextGLX *shareContext = aShare ? GetGlobalContextGLX() : nsnull;
nsRefPtr<GLContextGLX> glContext = GLContextGLX::CreateGLContext(aFormat,
display,
glxpixmap,
cfgs[chosenIndex],
vinfo,
shareContext,
PR_TRUE,
xsurface);
return glContext.forget();
}
already_AddRefed<GLContext>
GLContextProviderGLX::CreateOffscreen(const gfxIntSize& aSize,
const ContextFormat& aFormat)
{
nsRefPtr<GLContextGLX> glContext =
CreateOffscreenPixmapContext(aSize, aFormat, PR_TRUE);
if (!glContext) {
return nsnull;
}
if (!glContext->GetSharedContext()) {
// no point in returning anything if sharing failed, we can't
// render from this
return nsnull;
}
if (!glContext->ResizeOffscreenFBO(aSize)) {
// we weren't able to create the initial
// offscreen FBO, so this is dead
return nsnull;
}
return glContext.forget();
}
already_AddRefed<GLContext>
GLContextProviderGLX::CreateForNativePixmapSurface(gfxASurface *aSurface)
{
if (!sGLXLibrary.EnsureInitialized()) {
return nsnull;
}
if (aSurface->GetType() != gfxASurface::SurfaceTypeXlib) {
NS_WARNING("GLContextProviderGLX::CreateForNativePixmapSurface called with non-Xlib surface");
return nsnull;
}
nsAutoTArray<int, 20> attribs;
#define A1_(_x) do { attribs.AppendElement(_x); } while(0)
#define A2_(_x,_y) do { \
@ -460,20 +688,14 @@ GLContextProviderGLX::CreatePBuffer(const gfxIntSize &aSize, const ContextFormat
attribs.AppendElement(_y); \
} while(0)
A2_(GLX_DOUBLEBUFFER, False);
A2_(GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT);
A1_(0);
int numFormats;
Display *display = DefaultXDisplay();
int xscreen = DefaultScreen(display);
A2_(GLX_DOUBLEBUFFER, False);
A2_(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT);
A2_(GLX_RED_SIZE, aFormat.red);
A2_(GLX_GREEN_SIZE, aFormat.green);
A2_(GLX_BLUE_SIZE, aFormat.blue);
A2_(GLX_ALPHA_SIZE, aFormat.alpha);
A2_(GLX_DEPTH_SIZE, aFormat.depth);
A1_(0);
ScopedXFree<GLXFBConfig> cfg(sGLXLibrary.xChooseFBConfig(display,
xscreen,
attribs.Elements(),
@ -483,35 +705,44 @@ GLContextProviderGLX::CreatePBuffer(const gfxIntSize &aSize, const ContextFormat
}
NS_ASSERTION(numFormats > 0,
"glXChooseFBConfig() failed to match our requested format and violated its spec (!)");
nsTArray<int> pbattribs;
pbattribs.AppendElement(GLX_PBUFFER_WIDTH);
pbattribs.AppendElement(aSize.width);
pbattribs.AppendElement(GLX_PBUFFER_HEIGHT);
pbattribs.AppendElement(aSize.height);
pbattribs.AppendElement(GLX_PRESERVED_CONTENTS);
pbattribs.AppendElement(True);
pbattribs.AppendElement(0);
GLXPbuffer pbuffer = sGLXLibrary.xCreatePbuffer(display,
gfxXlibSurface *xs = static_cast<gfxXlibSurface*>(aSurface);
GLXPixmap glxpixmap = sGLXLibrary.xCreatePixmap(display,
cfg[0],
pbattribs.Elements());
xs->XDrawable(),
NULL);
if (pbuffer == 0) {
nsRefPtr<GLContextGLX> glContext = GLContextGLX::CreateGLContext(ContextFormat(ContextFormat::BasicRGB24),
display,
glxpixmap,
cfg[0],
NULL,
NULL,
PR_FALSE,
xs);
if (!glContext->Init()) {
return nsnull;
}
nsRefPtr<GLContextGLX> glContext = GLContextGLX::CreateGLContext(display,
pbuffer,
cfg[0],
PR_TRUE);
return glContext.forget();
}
already_AddRefed<GLContext>
GLContextProviderGLX::CreateForNativePixmapSurface(gfxASurface *aSurface)
static nsRefPtr<GLContext> gGlobalContext;
GLContext *
GLContextProviderGLX::GetGlobalContext()
{
return nsnull;
static bool triedToCreateContext = false;
if (!triedToCreateContext && !gGlobalContext) {
triedToCreateContext = true;
gGlobalContext = CreateOffscreenPixmapContext(gfxIntSize(1, 1),
ContextFormat(ContextFormat::BasicRGB24),
PR_FALSE);
}
return gGlobalContext;
}
} /* namespace gl */

View File

@ -47,33 +47,65 @@ class THEBES_API GL_CONTEXT_PROVIDER_NAME
public:
/**
* Create a context that renders to the surface of the widget that is
* passed in.
* passed in. The context is always created with an RGB pixel format,
* with no alpha, depth or stencil. If any of those features are needed,
* either use a framebuffer, or use CreateOffscreen.
*
* @param Widget whose surface to create a context for
* @return Context to use for this window
* This context will attempt to share resources with all other window
* contexts. As such, it's critical that resources allocated that are not
* needed by other contexts be deleted before the context is destroyed.
*
* The GetSharedContext() method will return non-null if sharing
* was successful.
*
* Note: a context created for a widget /must not/ hold a strong
* reference to the widget; otherwise a cycle can be created through
* a GL layer manager.
*
* @param aWidget Widget whose surface to create a context for
*
* @return Context to use for the window
*/
static already_AddRefed<GLContext>
CreateForWindow(nsIWidget *aWidget);
/**
* Creates a PBuffer.
* Create a context for offscreen rendering. The target of this
* context should be treated as opaque -- it might be a FBO, or a
* pbuffer, or some other construct. Users of this GLContext
* should not bind framebuffer 0 directly, and instead should bind
* the framebuffer returned by GetOffscreenFBO().
*
* @param aSize Size of the pbuffer to create
* @param aFormat A ContextFormat describing the desired context attributes. Defaults to a basic RGBA32 context.
* The offscreen context returned by this method will always have
* the ability to be rendered into a context created by a window.
* It might or might not share resources with the global context;
* query GetSharedContext() for a non-null result to check. If
* resource sharing can be avoided on the target platform, it will
* be, in order to isolate the offscreen context.
*
* @return Context to use for this Pbuffer
* @param aSize The initial size of this offscreen context.
* @param aFormat The ContextFormat for this offscreen context.
*
* @return Context to use for offscreen rendering
*/
static already_AddRefed<GLContext>
CreatePBuffer(const gfxIntSize &aSize,
const ContextFormat& aFormat = ContextFormat::BasicRGBA32Format);
CreateOffscreen(const gfxIntSize& aSize,
const ContextFormat& aFormat = ContextFormat::BasicRGBA32Format);
/**
* Try to create a GL context from native surface for arbitrary gfxASurface
* If surface not compatible this will return NULL
*
* @param aSurface surface to create a context for
*
* @return Context to use for this surface
*/
static already_AddRefed<GLContext>
CreateForNativePixmapSurface(gfxASurface *aSurface);
/**
* Get a pointer to the global context, creating it if it doesn't exist.
*/
static GLContext *
GetGlobalContext();
};

View File

@ -45,13 +45,20 @@ GLContextProviderNull::CreateForWindow(nsIWidget*)
}
already_AddRefed<GLContext>
GLContextProviderNull::CreateForNativePixmapSurface(gfxASurface *aSurface)
GLContextProviderNull::CreateOffscreen(const gfxIntSize&,
const ContextFormat&)
{
return 0;
return nsnull;
}
already_AddRefed<GLContext>
GLContextProviderNull::CreatePBuffer(const gfxIntSize &, const ContextFormat &)
GLContextProviderNull::CreateForNativePixmapSurface(gfxASurface *)
{
return nsnull;
}
GLContext *
GLContextProviderNull::GetGlobalContext()
{
return nsnull;
}

View File

@ -153,8 +153,9 @@ OSMesaLibrary::EnsureInitialized()
class GLContextOSMesa : public GLContext
{
public:
GLContextOSMesa()
: mThebesSurface(nsnull),
GLContextOSMesa(const ContextFormat& aFormat)
: GLContext(aFormat, PR_TRUE, nsnull),
mThebesSurface(nsnull),
mContext(nsnull)
{
}
@ -165,25 +166,34 @@ public:
sOSMesaLibrary.fDestroyContext(mContext);
}
PRBool Init(const gfxIntSize &aSize, const ContextFormat& aFormat)
GLContextType GetContextType() {
return ContextTypeOSMesa;
}
PRBool Init(const gfxIntSize &aSize)
{
int osmesa_format = -1;
int gfxasurface_imageformat = -1;
PRBool format_accepted = PR_FALSE;
if (aFormat.red == 8 && aFormat.green == 8 && aFormat.blue == 8) {
if (aFormat.alpha == 8) {
osmesa_format = OSMESA_BGRA;
gfxasurface_imageformat = gfxASurface::ImageFormatARGB32;
format_accepted = PR_TRUE;
}
else if (aFormat.alpha == 0) {
if (mCreationFormat.red > 0 &&
mCreationFormat.green > 0 &&
mCreationFormat.blue > 0 &&
mCreationFormat.red <= 8 &&
mCreationFormat.green <= 8 &&
mCreationFormat.blue <= 8)
{
if (mCreationFormat.alpha == 0) {
// we can't use OSMESA_BGR because it is packed 24 bits per pixel.
// So we use OSMESA_BGRA and have to use ImageFormatRGB24
// to make sure that the dummy alpha channel is ignored.
osmesa_format = OSMESA_BGRA;
gfxasurface_imageformat = gfxASurface::ImageFormatRGB24;
format_accepted = PR_TRUE;
} else if (mCreationFormat.alpha <= 8) {
osmesa_format = OSMESA_BGRA;
gfxasurface_imageformat = gfxASurface::ImageFormatARGB32;
format_accepted = PR_TRUE;
}
}
if (!format_accepted) {
@ -197,7 +207,7 @@ public:
return PR_FALSE;
}
mContext = sOSMesaLibrary.fCreateContextExt(osmesa_format, aFormat.depth, aFormat.stencil, 0, NULL);
mContext = sOSMesaLibrary.fCreateContextExt(osmesa_format, mCreationFormat.depth, mCreationFormat.stencil, 0, NULL);
if (!mContext) {
NS_WARNING("OSMesaCreateContextExt failed!");
return PR_FALSE;
@ -215,10 +225,10 @@ public:
PRBool MakeCurrent()
{
PRBool succeeded
= sOSMesaLibrary.fMakeCurrent (mContext, mThebesSurface->Data(),
LOCAL_GL_UNSIGNED_BYTE,
mThebesSurface->Width(),
mThebesSurface->Height());
= sOSMesaLibrary.fMakeCurrent(mContext, mThebesSurface->Data(),
LOCAL_GL_UNSIGNED_BYTE,
mThebesSurface->Width(),
mThebesSurface->Height());
NS_ASSERTION(succeeded, "Failed to make OSMesa context current!");
return succeeded;
@ -252,25 +262,27 @@ GLContextProviderOSMesa::CreateForWindow(nsIWidget *aWidget)
}
already_AddRefed<GLContext>
GLContextProviderOSMesa::CreateForNativePixmapSurface(gfxASurface *aSurface)
{
return 0;
}
already_AddRefed<GLContext>
GLContextProviderOSMesa::CreatePBuffer(const gfxIntSize &aSize, const ContextFormat& aFormat)
GLContextProviderOSMesa::CreateOffscreen(const gfxIntSize& aSize,
const ContextFormat& aFormat)
{
if (!sOSMesaLibrary.EnsureInitialized()) {
return nsnull;
}
nsRefPtr<GLContextOSMesa> glContext = new GLContextOSMesa;
nsRefPtr<GLContextOSMesa> glContext = new GLContextOSMesa(aFormat);
if (!glContext->Init(aSize, aFormat)) {
if (!glContext->Init(aSize))
{
return nsnull;
}
return glContext.forget().get();
return glContext.forget();
}
GLContext *
GLContextProviderOSMesa::GetGlobalContext()
{
return nsnull;
}
} /* namespace gl */

View File

@ -49,9 +49,62 @@ namespace gl {
WGLLibrary sWGLLibrary;
static HWND gDummyWindow = 0;
static HDC gDummyWindowDC = 0;
static HANDLE gDummyWindowGLContext = 0;
static HWND gSharedWindow = 0;
static HDC gSharedWindowDC = 0;
static HGLRC gSharedWindowGLContext = 0;
static int gSharedWindowPixelFormat = 0;
static HWND
CreateDummyWindow(HDC *aWindowDC = nsnull)
{
WNDCLASSW wc;
if (!GetClassInfoW(GetModuleHandle(NULL), L"GLContextWGLClass", &wc)) {
ZeroMemory(&wc, sizeof(WNDCLASSW));
wc.style = CS_OWNDC;
wc.hInstance = GetModuleHandle(NULL);
wc.lpfnWndProc = DefWindowProc;
wc.lpszClassName = L"GLContextWGLClass";
if (!RegisterClassW(&wc)) {
NS_WARNING("Failed to register GLContextWGLClass?!");
// er. failed to register our class?
return NULL;
}
}
HWND win = CreateWindowW(L"GLContextWGLClass", L"GLContextWGL", 0,
0, 0, 16, 16,
NULL, NULL, GetModuleHandle(NULL), NULL);
NS_ENSURE_TRUE(win, NULL);
HDC dc = GetDC(win);
NS_ENSURE_TRUE(dc, NULL);
if (gSharedWindowPixelFormat == 0) {
PIXELFORMATDESCRIPTOR pfd;
ZeroMemory(&pfd, sizeof(PIXELFORMATDESCRIPTOR));
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 24;
pfd.cDepthBits = 0;
pfd.iLayerType = PFD_MAIN_PLANE;
gSharedWindowPixelFormat = ChoosePixelFormat(dc, &pfd);
}
if (!SetPixelFormat(dc, gSharedWindowPixelFormat, NULL)) {
NS_WARNING("SetPixelFormat failed!");
DestroyWindow(win);
return NULL;
}
if (aWindowDC) {
*aWindowDC = dc;
}
return win;
}
PRBool
WGLLibrary::EnsureInitialized()
@ -74,6 +127,7 @@ WGLLibrary::EnsureInitialized()
{ (PRFuncPtr*) &fDeleteContext, { "wglDeleteContext", NULL } },
{ (PRFuncPtr*) &fGetCurrentContext, { "wglGetCurrentContext", NULL } },
{ (PRFuncPtr*) &fGetCurrentDC, { "wglGetCurrentDC", NULL } },
{ (PRFuncPtr*) &fShareLists, { "wglShareLists", NULL } },
{ NULL, { NULL } }
};
@ -82,61 +136,19 @@ WGLLibrary::EnsureInitialized()
return PR_FALSE;
}
// This is ridiculous -- we have to actually create a context to get the OpenGL
// ICD to load.
WNDCLASSW wc;
if (!GetClassInfoW(GetModuleHandle(NULL), L"DummyGLWindowClass", &wc)) {
ZeroMemory(&wc, sizeof(WNDCLASSW));
wc.hInstance = GetModuleHandle(NULL);
wc.lpfnWndProc = DefWindowProc;
wc.lpszClassName = L"DummyGLWindowClass";
if (!RegisterClassW(&wc)) {
NS_WARNING("Failed to register DummyGLWindowClass?!");
// er. failed to register our class?
return PR_FALSE;
}
}
gDummyWindow = CreateWindowW(L"DummyGLWindowClass", L"DummyGLWindow", 0,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, NULL, NULL, GetModuleHandle(NULL), NULL);
if (!gDummyWindow) {
NS_WARNING("CreateWindow DummyGLWindow failed");
return PR_FALSE;
}
gDummyWindowDC = GetDC(gDummyWindow);
if (!gDummyWindowDC) {
NS_WARNING("GetDC gDummyWindow failed");
return PR_FALSE;
}
// find default pixel format
PIXELFORMATDESCRIPTOR pfd;
ZeroMemory(&pfd, sizeof(PIXELFORMATDESCRIPTOR));
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
int pixelformat = ChoosePixelFormat(gDummyWindowDC, &pfd);
// set the pixel format for the dc
if (!SetPixelFormat(gDummyWindowDC, pixelformat, &pfd)) {
NS_WARNING("SetPixelFormat failed");
return PR_FALSE;
}
// This is ridiculous -- we have to actually create a context to
// get the OpenGL ICD to load.
gSharedWindow = CreateDummyWindow(&gSharedWindowDC);
NS_ENSURE_TRUE(gSharedWindow, PR_FALSE);
// create rendering context
gDummyWindowGLContext = fCreateContext(gDummyWindowDC);
if (!gDummyWindowGLContext) {
NS_WARNING("wglCreateContext failed");
return PR_FALSE;
}
gSharedWindowGLContext = fCreateContext(gSharedWindowDC);
NS_ENSURE_TRUE(gSharedWindowGLContext, PR_FALSE);
HGLRC curCtx = fGetCurrentContext();
HDC curDC = fGetCurrentDC();
if (!fMakeCurrent((HDC)gDummyWindowDC, (HGLRC)gDummyWindowGLContext)) {
if (!fMakeCurrent((HDC)gSharedWindowDC, (HGLRC)gSharedWindowGLContext)) {
NS_WARNING("wglMakeCurrent failed");
return PR_FALSE;
}
@ -177,33 +189,75 @@ WGLLibrary::EnsureInitialized()
fMakeCurrent(curDC, curCtx);
mInitialized = PR_TRUE;
// Call this to create the global GLContext instance,
// and to check for errors. Note that this must happen /after/
// setting mInitialized to TRUE, or an infinite loop results.
if (GLContextProviderWGL::GetGlobalContext() == nsnull) {
mInitialized = PR_FALSE;
return PR_FALSE;
}
return PR_TRUE;
}
class GLContextWGL : public GLContext
{
public:
GLContextWGL(HDC aDC, HGLRC aContext)
: mContext(aContext), mDC(aDC), mPBuffer(nsnull), mPixelFormat(-1)
{ }
GLContextWGL(const ContextFormat& aFormat,
GLContext *aSharedContext,
HDC aDC,
HGLRC aContext,
HWND aWindow = nsnull,
PRBool aIsOffscreen = PR_FALSE)
: GLContext(aFormat, aIsOffscreen, aSharedContext),
mDC(aDC),
mContext(aContext),
mWnd(aWindow),
mPBuffer(NULL),
mPixelFormat(0)
{
}
GLContextWGL(HANDLE aPBuffer, int aPixelFormat) {
mPBuffer = aPBuffer;
mPixelFormat = aPixelFormat;
mDC = sWGLLibrary.fGetPbufferDC(mPBuffer);
mContext = sWGLLibrary.fCreateContext(mDC);
GLContextWGL(const ContextFormat& aFormat,
GLContext *aSharedContext,
HANDLE aPbuffer,
HDC aDC,
HGLRC aContext,
int aPixelFormat)
: GLContext(aFormat, PR_TRUE, aSharedContext),
mDC(aDC),
mContext(aContext),
mWnd(NULL),
mPBuffer(aPbuffer),
mPixelFormat(aPixelFormat)
{
}
~GLContextWGL()
{
if (mOffscreenFBO) {
MakeCurrent();
DeleteOffscreenFBO();
}
sWGLLibrary.fDeleteContext(mContext);
if (mPBuffer)
sWGLLibrary.fDestroyPbuffer(mPBuffer);
if (mWnd)
DestroyWindow(mWnd);
}
GLContextType GetContextType() {
return ContextTypeWGL;
}
PRBool Init()
{
if (!mDC || !mContext)
return PR_FALSE;
MakeCurrent();
SetupLookupFunction();
return InitWithPrefix("gl", PR_TRUE);
@ -237,34 +291,100 @@ public:
case NativeGLContext:
return mContext;
case NativePBuffer:
return mPBuffer;
default:
return nsnull;
}
}
PRBool Resize(const gfxIntSize& aNewSize) {
if (!mPBuffer)
PRBool BindTex2DOffscreen(GLContext *aOffscreen);
void UnbindTex2DOffscreen(GLContext *aOffscreen);
PRBool ResizeOffscreen(const gfxIntSize& aNewSize);
HGLRC Context() { return mContext; }
virtual already_AddRefed<TextureImage>
CreateBasicTextureImage(GLuint aTexture,
const nsIntSize& aSize,
TextureImage::ContentType aContentType,
GLContext* aContext);
protected:
friend class GLContextProviderWGL;
HDC mDC;
HGLRC mContext;
HWND mWnd;
HANDLE mPBuffer;
int mPixelFormat;
};
PRBool
GLContextWGL::BindTex2DOffscreen(GLContext *aOffscreen)
{
if (aOffscreen->GetContextType() != ContextTypeWGL) {
NS_WARNING("non-WGL context");
return PR_FALSE;
}
if (!aOffscreen->IsOffscreen()) {
NS_WARNING("non-offscreen context");
return PR_FALSE;
}
GLContextWGL *offs = static_cast<GLContextWGL*>(aOffscreen);
if (offs->mPBuffer) {
BOOL ok = sWGLLibrary.fBindTexImage(offs->mPBuffer,
LOCAL_WGL_FRONT_LEFT_ARB);
if (!ok) {
NS_WARNING("CanvasLayerOGL::Updated wglBindTexImageARB failed");
return PR_FALSE;
}
} else if (offs->mOffscreenTexture) {
if (offs->GetSharedContext() != GLContextProviderWGL::GetGlobalContext())
{
NS_WARNING("offscreen FBO context can only be bound with context sharing!");
return PR_FALSE;
nsTArray<int> pbattribs;
pbattribs.AppendElement(LOCAL_WGL_TEXTURE_FORMAT_ARB);
// XXX fixme after bug 571092 lands and we have the format available
if (true /*aFormat.alpha > 0*/) {
pbattribs.AppendElement(LOCAL_WGL_TEXTURE_RGBA_ARB);
} else {
pbattribs.AppendElement(LOCAL_WGL_TEXTURE_RGB_ARB);
}
pbattribs.AppendElement(LOCAL_WGL_TEXTURE_TARGET_ARB);
pbattribs.AppendElement(LOCAL_WGL_TEXTURE_2D_ARB);
pbattribs.AppendElement(0);
fBindTexture(LOCAL_GL_TEXTURE_2D, offs->mOffscreenTexture);
} else {
NS_WARNING("don't know how to bind this!");
return PR_FALSE;
}
HANDLE newbuf = sWGLLibrary.fCreatePbuffer(gDummyWindowDC, mPixelFormat,
return PR_TRUE;
}
void
GLContextWGL::UnbindTex2DOffscreen(GLContext *aOffscreen)
{
NS_ASSERTION(aOffscreen->GetContextType() == ContextTypeWGL, "wrong type");
GLContextWGL *offs = static_cast<GLContextWGL*>(aOffscreen);
if (offs->mPBuffer) {
// XXX so, according to the extension, ReleaseTexImage is not required to
// preserve color buffer contents. This sucks, but everywhere that I've
// tried it the color buffer is preserved. So let's cross our fingers..
sWGLLibrary.fReleaseTexImage(offs->mPBuffer, LOCAL_WGL_FRONT_LEFT_ARB);
}
}
PRBool
GLContextWGL::ResizeOffscreen(const gfxIntSize& aNewSize)
{
if (mPBuffer) {
int pbattrs[] = {
LOCAL_WGL_TEXTURE_FORMAT_ARB,
mCreationFormat.alpha > 0 ? LOCAL_WGL_TEXTURE_RGBA_ARB
: LOCAL_WGL_TEXTURE_RGB_ARB,
LOCAL_WGL_TEXTURE_TARGET_ARB, LOCAL_WGL_TEXTURE_2D_ARB,
0
};
HANDLE newbuf = sWGLLibrary.fCreatePbuffer(gSharedWindowDC, mPixelFormat,
aNewSize.width, aNewSize.height,
pbattribs.Elements());
pbattrs);
if (!newbuf)
return PR_FALSE;
@ -274,30 +394,28 @@ public:
isCurrent = true;
}
// hey, it worked!
sWGLLibrary.fDestroyPbuffer(mPBuffer);
mPBuffer = newbuf;
mDC = sWGLLibrary.fGetPbufferDC(mPBuffer);
if (isCurrent)
MakeCurrent();
mOffscreenSize = aNewSize;
mOffscreenActualSize = aNewSize;
MakeCurrent();
ClearSafely();
return PR_TRUE;
}
virtual already_AddRefed<TextureImage>
CreateBasicTextureImage(GLuint aTexture,
const nsIntSize& aSize,
TextureImage::ContentType aContentType,
GLContext* aContext);
return ResizeOffscreenFBO(aNewSize);
}
private:
HGLRC mContext;
HDC mDC;
HANDLE mPBuffer;
int mPixelFormat;
};
static GLContextWGL *
GetGlobalContextWGL()
{
return static_cast<GLContextWGL*>(GLContextProviderWGL::GetGlobalContext());
}
class TextureImageWGL : public BasicTextureImage
{
@ -351,6 +469,7 @@ GLContextProviderWGL::CreateForWindow(nsIWidget *aWidget)
if (!sWGLLibrary.EnsureInitialized()) {
return nsnull;
}
/**
* We need to make sure we call SetPixelFormat -after- calling
* EnsureInitialized, otherwise it can load/unload the dll and
@ -359,75 +478,77 @@ GLContextProviderWGL::CreateForWindow(nsIWidget *aWidget)
HDC dc = (HDC)aWidget->GetNativeData(NS_NATIVE_GRAPHIC);
PIXELFORMATDESCRIPTOR pfd;
ZeroMemory(&pfd, sizeof(pfd));
pfd.nSize = sizeof(pfd);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 32;
pfd.cDepthBits = 0;
pfd.iLayerType = PFD_MAIN_PLANE;
int iFormat = ChoosePixelFormat(dc, &pfd);
SetPixelFormat(dc, iFormat, &pfd);
SetPixelFormat(dc, gSharedWindowPixelFormat, NULL);
HGLRC context = sWGLLibrary.fCreateContext(dc);
if (!context) {
return nsnull;
}
nsRefPtr<GLContextWGL> glContext = new GLContextWGL(dc, context);
glContext->Init();
GLContextWGL *shareContext = GetGlobalContextWGL();
if (shareContext &&
!sWGLLibrary.fShareLists(shareContext->Context(), context))
{
shareContext = nsnull;
}
return glContext.forget().get();
}
already_AddRefed<GLContext>
GLContextProviderWGL::CreatePBuffer(const gfxIntSize& aSize, const ContextFormat& aFormat)
{
if (!sWGLLibrary.EnsureInitialized()) {
nsRefPtr<GLContextWGL> glContext = new GLContextWGL(ContextFormat(ContextFormat::BasicRGB24),
shareContext, dc, context);
if (!glContext->Init()) {
return nsnull;
}
nsTArray<int> attribs;
return glContext.forget();
}
#define A1_(_x) do { attribs.AppendElement(_x); } while(0)
#define A2_(_x,_y) do { \
attribs.AppendElement(_x); \
attribs.AppendElement(_y); \
} while(0)
static already_AddRefed<GLContextWGL>
CreatePBufferOffscreenContext(const gfxIntSize& aSize,
const ContextFormat& aFormat)
{
#define A1(_a,_x) do { _a.AppendElement(_x); } while(0)
#define A2(_a,_x,_y) do { _a.AppendElement(_x); _a.AppendElement(_y); } while(0)
A2_(LOCAL_WGL_SUPPORT_OPENGL_ARB, LOCAL_GL_TRUE);
A2_(LOCAL_WGL_DRAW_TO_PBUFFER_ARB, LOCAL_GL_TRUE);
A2_(LOCAL_WGL_DOUBLE_BUFFER_ARB, LOCAL_GL_FALSE);
nsTArray<int> attrs;
A2_(LOCAL_WGL_ACCELERATION_ARB, LOCAL_WGL_FULL_ACCELERATION_ARB);
A2(attrs, LOCAL_WGL_SUPPORT_OPENGL_ARB, LOCAL_GL_TRUE);
A2(attrs, LOCAL_WGL_DRAW_TO_PBUFFER_ARB, LOCAL_GL_TRUE);
A2(attrs, LOCAL_WGL_DOUBLE_BUFFER_ARB, LOCAL_GL_FALSE);
A2_(LOCAL_WGL_COLOR_BITS_ARB, aFormat.colorBits());
A2_(LOCAL_WGL_RED_BITS_ARB, aFormat.red);
A2_(LOCAL_WGL_GREEN_BITS_ARB, aFormat.green);
A2_(LOCAL_WGL_BLUE_BITS_ARB, aFormat.blue);
A2_(LOCAL_WGL_ALPHA_BITS_ARB, aFormat.alpha);
A2(attrs, LOCAL_WGL_ACCELERATION_ARB, LOCAL_WGL_FULL_ACCELERATION_ARB);
A2_(LOCAL_WGL_DEPTH_BITS_ARB, aFormat.depth);
A2(attrs, LOCAL_WGL_COLOR_BITS_ARB, aFormat.colorBits());
A2(attrs, LOCAL_WGL_RED_BITS_ARB, aFormat.red);
A2(attrs, LOCAL_WGL_GREEN_BITS_ARB, aFormat.green);
A2(attrs, LOCAL_WGL_BLUE_BITS_ARB, aFormat.blue);
A2(attrs, LOCAL_WGL_ALPHA_BITS_ARB, aFormat.alpha);
if (aFormat.alpha > 0)
A2_(LOCAL_WGL_BIND_TO_TEXTURE_RGBA_ARB, LOCAL_GL_TRUE);
else
A2_(LOCAL_WGL_BIND_TO_TEXTURE_RGB_ARB, LOCAL_GL_TRUE);
A2(attrs, LOCAL_WGL_DEPTH_BITS_ARB, aFormat.depth);
A2_(LOCAL_WGL_DOUBLE_BUFFER_ARB, LOCAL_GL_FALSE);
A2_(LOCAL_WGL_STEREO_ARB, LOCAL_GL_FALSE);
if (aFormat.alpha > 0) {
A2(attrs, LOCAL_WGL_BIND_TO_TEXTURE_RGBA_ARB, LOCAL_GL_TRUE);
} else {
A2(attrs, LOCAL_WGL_BIND_TO_TEXTURE_RGB_ARB, LOCAL_GL_TRUE);
}
A1_(0);
A2(attrs, LOCAL_WGL_DOUBLE_BUFFER_ARB, LOCAL_GL_FALSE);
A2(attrs, LOCAL_WGL_STEREO_ARB, LOCAL_GL_FALSE);
#define MAX_NUM_FORMATS 256
UINT numFormats = MAX_NUM_FORMATS;
int formats[MAX_NUM_FORMATS];
A1(attrs, 0);
if (!sWGLLibrary.fChoosePixelFormat(gDummyWindowDC,
attribs.Elements(), NULL,
nsTArray<int> pbattrs;
A2(pbattrs, LOCAL_WGL_TEXTURE_TARGET_ARB, LOCAL_WGL_TEXTURE_2D_ARB);
if (aFormat.alpha > 0) {
A2(pbattrs, LOCAL_WGL_TEXTURE_FORMAT_ARB, LOCAL_WGL_TEXTURE_RGBA_ARB);
} else {
A2(pbattrs, LOCAL_WGL_TEXTURE_FORMAT_ARB, LOCAL_WGL_TEXTURE_RGB_ARB);
}
A1(pbattrs, 0);
UINT numFormats = 256;
int formats[256];
if (!sWGLLibrary.fChoosePixelFormat(gSharedWindowDC,
attrs.Elements(), NULL,
numFormats, formats, &numFormats)
|| numFormats == 0)
{
@ -437,33 +558,106 @@ GLContextProviderWGL::CreatePBuffer(const gfxIntSize& aSize, const ContextFormat
// XXX add back the priority choosing code here
int chosenFormat = formats[0];
nsTArray<int> pbattribs;
pbattribs.AppendElement(LOCAL_WGL_TEXTURE_FORMAT_ARB);
if (aFormat.alpha > 0) {
pbattribs.AppendElement(LOCAL_WGL_TEXTURE_RGBA_ARB);
} else {
pbattribs.AppendElement(LOCAL_WGL_TEXTURE_RGB_ARB);
}
pbattribs.AppendElement(LOCAL_WGL_TEXTURE_TARGET_ARB);
pbattribs.AppendElement(LOCAL_WGL_TEXTURE_2D_ARB);
// hmm, do we need mipmaps?
//pbattribs.AppendElement(LOCAL_WGL_MIPMAP_TEXTURE_ARB);
//pbattribs.AppendElement(LOCAL_GL_TRUE);
pbattribs.AppendElement(0);
HANDLE pbuffer = sWGLLibrary.fCreatePbuffer(gDummyWindowDC, chosenFormat,
HANDLE pbuffer = sWGLLibrary.fCreatePbuffer(gSharedWindowDC, chosenFormat,
aSize.width, aSize.height,
pbattribs.Elements());
pbattrs.Elements());
if (!pbuffer) {
return nsnull;
}
nsRefPtr<GLContextWGL> glContext = new GLContextWGL(pbuffer, chosenFormat);
glContext->Init();
HDC pbdc = sWGLLibrary.fGetPbufferDC(pbuffer);
NS_ASSERTION(pbdc, "expected a dc");
return glContext.forget().get();
HGLRC context = sWGLLibrary.fCreateContext(pbdc);
if (!context) {
sWGLLibrary.fDestroyPbuffer(pbuffer);
return PR_FALSE;
}
nsRefPtr<GLContextWGL> glContext = new GLContextWGL(aFormat,
nsnull,
pbuffer,
pbdc,
context,
chosenFormat);
return glContext.forget();
}
static already_AddRefed<GLContextWGL>
CreateWindowOffscreenContext(const gfxIntSize& aSize,
const ContextFormat& aFormat)
{
// CreateWindowOffscreenContext must return a global-shared context
GLContextWGL *shareContext = GetGlobalContextWGL();
if (!shareContext) {
return nsnull;
}
HDC dc;
HWND win = CreateDummyWindow(&dc);
if (!win) {
return nsnull;
}
HGLRC context = sWGLLibrary.fCreateContext(dc);
if (!context) {
return nsnull;
}
if (!sWGLLibrary.fShareLists(shareContext->Context(), context)) {
NS_WARNING("wglShareLists failed!");
sWGLLibrary.fDeleteContext(context);
DestroyWindow(win);
return nsnull;
}
nsRefPtr<GLContextWGL> glContext = new GLContextWGL(aFormat, shareContext,
dc, context, win, PR_TRUE);
return glContext.forget();
}
already_AddRefed<GLContext>
GLContextProviderWGL::CreateOffscreen(const gfxIntSize& aSize,
const ContextFormat& aFormat)
{
if (!sWGLLibrary.EnsureInitialized()) {
return nsnull;
}
nsRefPtr<GLContextWGL> glContext;
// Always try to create a pbuffer context first, because we
// want the context isolation.
if (sWGLLibrary.fCreatePbuffer &&
sWGLLibrary.fChoosePixelFormat)
{
glContext = CreatePBufferOffscreenContext(aSize, aFormat);
}
// If it failed, then create a window context and use a FBO.
if (!glContext) {
glContext = CreateWindowOffscreenContext(aSize, aFormat);
}
if (!glContext ||
!glContext->Init())
{
return nsnull;
}
glContext->mOffscreenSize = aSize;
glContext->mOffscreenActualSize = aSize;
if (!glContext->mPBuffer &&
!glContext->ResizeOffscreenFBO(aSize))
{
return nsnull;
}
return glContext.forget();
}
already_AddRefed<GLContext>
@ -472,5 +666,32 @@ GLContextProviderWGL::CreateForNativePixmapSurface(gfxASurface *aSurface)
return nsnull;
}
static nsRefPtr<GLContextWGL> gGlobalContext;
GLContext *
GLContextProviderWGL::GetGlobalContext()
{
if (!sWGLLibrary.EnsureInitialized()) {
return nsnull;
}
static bool triedToCreateContext = false;
if (!triedToCreateContext && !gGlobalContext) {
triedToCreateContext = true;
// conveniently, we already have what we need...
gGlobalContext = new GLContextWGL(ContextFormat(ContextFormat::BasicRGB24), nsnull,
gSharedWindowDC, gSharedWindowGLContext);
if (!gGlobalContext->Init()) {
NS_WARNING("Global context GLContext initialization failed?");
gGlobalContext = nsnull;
return PR_FALSE;
}
}
return static_cast<GLContext*>(gGlobalContext);
}
} /* namespace gl */
} /* namespace mozilla */

View File

@ -100,6 +100,23 @@ public:
int);
PFNGLXQUERYSERVERSTRING xQueryServerString;
typedef GLXPixmap (GLAPIENTRY * PFNGLXCREATEPIXMAP) (Display *,
GLXFBConfig,
Pixmap,
const int *);
PFNGLXCREATEPIXMAP xCreatePixmap;
typedef void (GLAPIENTRY * PFNGLXDESTROYPIXMAP) (Display *,
GLXPixmap);
PFNGLXDESTROYPIXMAP xDestroyPixmap;
typedef const char * (GLAPIENTRY * PFNGLXGETCLIENTSTRING) (Display *,
int);
PFNGLXGETCLIENTSTRING xGetClientString;
typedef GLXContext (GLAPIENTRY * PFNGLXCREATECONTEXT) (Display *,
XVisualInfo *,
GLXContext,
Bool);
PFNGLXCREATECONTEXT xCreateContext;
PRBool EnsureInitialized();
private:

View File

@ -56,6 +56,8 @@ public:
PFNWGLGETCURRENTCONTEXT fGetCurrentContext;
typedef HDC (GLAPIENTRY * PFNWGLGETCURRENTDC) (void);
PFNWGLGETCURRENTDC fGetCurrentDC;
typedef BOOL (GLAPIENTRY * PFNWGLSHARELISTS) (HGLRC oldContext, HGLRC newContext);
PFNWGLSHARELISTS fShareLists;
typedef HANDLE (WINAPI * PFNWGLCREATEPBUFFERPROC) (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int* piAttribList);
PFNWGLCREATEPBUFFERPROC fCreatePbuffer;