b=571831; use the new CreateOffscreen API in WebGL; r=bjacob

This commit is contained in:
Vladimir Vukicevic 2010-07-18 22:01:14 -07:00
Родитель 2f984cc829
Коммит 95c827946f
4 изменённых файлов: 219 добавлений и 60 удалений

Просмотреть файл

@ -99,6 +99,106 @@ WebGLContext::WebGLContext()
WebGLContext::~WebGLContext() WebGLContext::~WebGLContext()
{ {
DestroyResourcesAndContext();
}
static PLDHashOperator
DeleteTextureFunction(const PRUint32& aKey, WebGLTexture *aValue, void *aData)
{
gl::GLContext *gl = (gl::GLContext *) aData;
NS_ASSERTION(!aValue->Deleted(), "Texture is still in mMapTextures, but is deleted?");
GLuint name = aValue->GLName();
gl->fDeleteTextures(1, &name);
aValue->Delete();
return PL_DHASH_NEXT;
}
static PLDHashOperator
DeleteBufferFunction(const PRUint32& aKey, WebGLBuffer *aValue, void *aData)
{
gl::GLContext *gl = (gl::GLContext *) aData;
NS_ASSERTION(!aValue->Deleted(), "Buffer is still in mMapBuffers, but is deleted?");
GLuint name = aValue->GLName();
gl->fDeleteBuffers(1, &name);
aValue->Delete();
return PL_DHASH_NEXT;
}
static PLDHashOperator
DeleteFramebufferFunction(const PRUint32& aKey, WebGLFramebuffer *aValue, void *aData)
{
gl::GLContext *gl = (gl::GLContext *) aData;
NS_ASSERTION(!aValue->Deleted(), "Framebuffer is still in mMapFramebuffers, but is deleted?");
GLuint name = aValue->GLName();
gl->fDeleteFramebuffers(1, &name);
aValue->Delete();
return PL_DHASH_NEXT;
}
static PLDHashOperator
DeleteRenderbufferFunction(const PRUint32& aKey, WebGLRenderbuffer *aValue, void *aData)
{
gl::GLContext *gl = (gl::GLContext *) aData;
NS_ASSERTION(!aValue->Deleted(), "Renderbuffer is still in mMapRenderbuffers, but is deleted?");
GLuint name = aValue->GLName();
gl->fDeleteRenderbuffers(1, &name);
aValue->Delete();
return PL_DHASH_NEXT;
}
static PLDHashOperator
DeleteProgramFunction(const PRUint32& aKey, WebGLProgram *aValue, void *aData)
{
gl::GLContext *gl = (gl::GLContext *) aData;
NS_ASSERTION(!aValue->Deleted(), "Program is still in mMapPrograms, but is deleted?");
GLuint name = aValue->GLName();
gl->fDeleteProgram(name);
aValue->Delete();
return PL_DHASH_NEXT;
}
static PLDHashOperator
DeleteShaderFunction(const PRUint32& aKey, WebGLShader *aValue, void *aData)
{
gl::GLContext *gl = (gl::GLContext *) aData;
NS_ASSERTION(!aValue->Deleted(), "Shader is still in mMapShaders, but is deleted?");
GLuint name = aValue->GLName();
gl->fDeleteShader(name);
aValue->Delete();
return PL_DHASH_NEXT;
}
void
WebGLContext::DestroyResourcesAndContext()
{
if (!gl)
return;
gl->MakeCurrent();
mMapTextures.EnumerateRead(DeleteTextureFunction, gl);
mMapTextures.Clear();
mMapBuffers.EnumerateRead(DeleteBufferFunction, gl);
mMapBuffers.Clear();
mMapPrograms.EnumerateRead(DeleteProgramFunction, gl);
mMapPrograms.Clear();
mMapShaders.EnumerateRead(DeleteShaderFunction, gl);
mMapShaders.Clear();
mMapFramebuffers.EnumerateRead(DeleteFramebufferFunction, gl);
mMapFramebuffers.Clear();
mMapRenderbuffers.EnumerateRead(DeleteRenderbufferFunction, gl);
mMapRenderbuffers.Clear();
// We just got rid of everything, so the context had better
// have been going away.
printf_stderr("--- WebGL context destroyed: %p\n", gl.get());
gl = nsnull;
} }
void void
@ -141,38 +241,42 @@ WebGLContext::SetCanvasElement(nsHTMLCanvasElement* aParentCanvas)
NS_IMETHODIMP NS_IMETHODIMP
WebGLContext::SetDimensions(PRInt32 width, PRInt32 height) WebGLContext::SetDimensions(PRInt32 width, PRInt32 height)
{ {
if (mWidth == width && mHeight == height)
return NS_OK;
// If we already have a gl context, then we just need to resize
// FB0.
if (gl &&
gl->ResizeOffscreen(gfxIntSize(width, height)))
{
// everything's good, we're done here
mWidth = width;
mHeight = height;
return NS_OK;
}
// We're going to create an entirely new context. If our
// generation is not 0 right now (that is, if this isn't the first
// context we're creating), we may have to dispatch a context lost
// event.
// If incrementing the generation would cause overflow, // If incrementing the generation would cause overflow,
// don't allow it. Allowing this would allow us to use // don't allow it. Allowing this would allow us to use
// resource handles created from older context generations. // resource handles created from older context generations.
if (!(mGeneration+1).valid()) if (!(mGeneration+1).valid())
return NS_ERROR_FAILURE; // exit without changing the value of mGeneration return NS_ERROR_FAILURE; // exit without changing the value of mGeneration
if (mWidth == width && mHeight == height) // We're going to recreate our context, so make sure we clean up
return NS_OK; // after ourselves.
DestroyResourcesAndContext();
if (gl) {
// hey we already have something
if (gl->Resize(gfxIntSize(width, height))) {
mWidth = width;
mHeight = height;
gl->fViewport(0, 0, mWidth, mHeight);
gl->fClearColor(0, 0, 0, 0);
gl->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT | LOCAL_GL_STENCIL_BUFFER_BIT);
// great success!
return NS_OK;
}
}
gl::ContextFormat format(gl::ContextFormat::BasicRGBA32); gl::ContextFormat format(gl::ContextFormat::BasicRGBA32);
format.depth = 16; format.depth = 16;
format.minDepth = 1; format.minDepth = 1;
gl = gl::GLContextProvider::CreatePBuffer(gfxIntSize(width, height), gl = gl::GLContextProvider::CreateOffscreen(gfxIntSize(width, height), format);
gl::GLContextProvider::GetGlobalContext(),
format); printf_stderr ("--- WebGL context created: %p\n", gl.get());
#ifdef USE_GLES2 #ifdef USE_GLES2
// On native GLES2, no need to validate, the compiler will do it // On native GLES2, no need to validate, the compiler will do it
@ -186,17 +290,14 @@ WebGLContext::SetDimensions(PRInt32 width, PRInt32 height)
#endif #endif
if (!InitAndValidateGL()) { if (!InitAndValidateGL()) {
gl = gl::GLContextProviderOSMesa::CreatePBuffer(gfxIntSize(width, height), gl = gl::GLContextProviderOSMesa::CreateOffscreen(gfxIntSize(width, height), format);
nsnull,
format);
if (!InitAndValidateGL()) { if (!InitAndValidateGL()) {
LogMessage("WebGL: Can't get a usable OpenGL context."); LogMessage("WebGL: Can't get a usable OpenGL context.");
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
else {
LogMessage("WebGL: Using software rendering via OSMesa"); LogMessage("WebGL: Using software rendering via OSMesa");
} }
}
mWidth = width; mWidth = width;
mHeight = height; mHeight = height;
@ -205,12 +306,25 @@ WebGLContext::SetDimensions(PRInt32 width, PRInt32 height)
// increment the generation number // increment the generation number
++mGeneration; ++mGeneration;
#if 0
if (mGeneration > 0) {
// XXX dispatch context lost event
}
#endif
MakeContextCurrent(); MakeContextCurrent();
// Make sure that we clear this out, otherwise // Make sure that we clear this out, otherwise
// we'll end up displaying random memory // we'll end up displaying random memory
gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, gl->GetOffscreenFBO());
gl->fViewport(0, 0, mWidth, mHeight); gl->fViewport(0, 0, mWidth, mHeight);
gl->fClearColor(0, 0, 0, 0); gl->fClearColor(0.0f, 0.0f, 0.0f, 0.0f);
#ifdef USE_GLES2
gl->fClearDepthf(0.0f);
#else
gl->fClearDepth(0.0f);
#endif
gl->fClearStencil(0);
gl->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT | LOCAL_GL_STENCIL_BUFFER_BIT); gl->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT | LOCAL_GL_STENCIL_BUFFER_BIT);
return NS_OK; return NS_OK;
@ -348,26 +462,19 @@ WebGLContext::GetCanvasLayer(CanvasLayer *aOldLayer,
// data with the gl context directly, or may provide a surface to which it renders (this is the case // data with the gl context directly, or may provide a surface to which it renders (this is the case
// of OSMesa contexts), in which case we want to initialize data with that surface. // of OSMesa contexts), in which case we want to initialize data with that surface.
void* native_pbuffer = gl->GetNativeData(gl::GLContext::NativePBuffer);
void* native_surface = gl->GetNativeData(gl::GLContext::NativeImageSurface); void* native_surface = gl->GetNativeData(gl::GLContext::NativeImageSurface);
if (native_pbuffer) { if (native_surface) {
data.mGLContext = gl.get();
}
else if (native_surface) {
data.mSurface = static_cast<gfxASurface*>(native_surface); data.mSurface = static_cast<gfxASurface*>(native_surface);
} } else {
else { data.mGLContext = gl.get();
NS_WARNING("The GLContext has neither a native PBuffer nor a native surface!");
return nsnull;
} }
data.mSize = nsIntSize(mWidth, mHeight); data.mSize = nsIntSize(mWidth, mHeight);
data.mGLBufferIsPremultiplied = PR_FALSE; data.mGLBufferIsPremultiplied = PR_FALSE;
canvasLayer->Initialize(data); canvasLayer->Initialize(data);
// once we support GL context attributes, we'll set the right thing here canvasLayer->SetIsOpaqueContent(gl->CreationFormat().alpha == 0 ? PR_TRUE : PR_FALSE);
canvasLayer->SetIsOpaqueContent(PR_FALSE);
canvasLayer->Updated(nsIntRect(0, 0, mWidth, mHeight)); canvasLayer->Updated(nsIntRect(0, 0, mWidth, mHeight));
mInvalidated = PR_FALSE; mInvalidated = PR_FALSE;

Просмотреть файл

@ -57,7 +57,7 @@
#include "nsIDOMHTMLElement.h" #include "nsIDOMHTMLElement.h"
#include "nsIJSNativeInitializer.h" #include "nsIJSNativeInitializer.h"
#include "GLContext.h" #include "GLContextProvider.h"
#include "Layers.h" #include "Layers.h"
#include "CheckedInt.h" #include "CheckedInt.h"
@ -359,6 +359,7 @@ protected:
PRBool ValidateDrawModeEnum(WebGLenum mode, const char *info); PRBool ValidateDrawModeEnum(WebGLenum mode, const char *info);
void Invalidate(); void Invalidate();
void DestroyResourcesAndContext();
void MakeContextCurrent() { gl->MakeCurrent(); } void MakeContextCurrent() { gl->MakeCurrent(); }

Просмотреть файл

@ -227,7 +227,11 @@ WebGLContext::BindFramebuffer(WebGLenum target, nsIWebGLFramebuffer *fbobj)
MakeContextCurrent(); MakeContextCurrent();
if (isNull) {
gl->fBindFramebuffer(target, gl->GetOffscreenFBO());
} else {
gl->fBindFramebuffer(target, framebuffername); gl->fBindFramebuffer(target, framebuffername);
}
mBoundFramebuffer = wfb; mBoundFramebuffer = wfb;
@ -503,7 +507,9 @@ NS_IMETHODIMP
WebGLContext::CheckFramebufferStatus(WebGLenum target, WebGLenum *retval) WebGLContext::CheckFramebufferStatus(WebGLenum target, WebGLenum *retval)
{ {
MakeContextCurrent(); MakeContextCurrent();
// XXX check target if (target != LOCAL_GL_FRAMEBUFFER)
return ErrorInvalidEnum("CheckFramebufferStatus: target must be FRAMEBUFFER");
*retval = gl->fCheckFramebufferStatus(target); *retval = gl->fCheckFramebufferStatus(target);
return NS_OK; return NS_OK;
} }
@ -1013,8 +1019,11 @@ WebGLContext::FramebufferRenderbuffer(WebGLenum target, WebGLenum attachment, We
if (rbtarget != LOCAL_GL_RENDERBUFFER) if (rbtarget != LOCAL_GL_RENDERBUFFER)
return ErrorInvalidEnumInfo("framebufferRenderbuffer: renderbuffer target:", rbtarget); return ErrorInvalidEnumInfo("framebufferRenderbuffer: renderbuffer target:", rbtarget);
if (!mBoundFramebuffer)
return ErrorInvalidOperation("FramebufferRenderbuffer: cannot modify framebuffer 0");
// dimensions are kept for readPixels primarily, function only uses COLOR_ATTACHMENT0 // dimensions are kept for readPixels primarily, function only uses COLOR_ATTACHMENT0
if (mBoundFramebuffer && attachment == LOCAL_GL_COLOR_ATTACHMENT0) if (attachment == LOCAL_GL_COLOR_ATTACHMENT0)
mBoundFramebuffer->setDimensions(wrb); mBoundFramebuffer->setDimensions(wrb);
MakeContextCurrent(); MakeContextCurrent();
@ -1055,8 +1064,11 @@ WebGLContext::FramebufferTexture2D(WebGLenum target,
if (level != 0) if (level != 0)
return ErrorInvalidValue("FramebufferTexture2D: level must be 0"); return ErrorInvalidValue("FramebufferTexture2D: level must be 0");
if (!mBoundFramebuffer)
return ErrorInvalidOperation("FramebufferTexture2D: cannot modify framebuffer 0");
// dimensions are kept for readPixels primarily, function only uses COLOR_ATTACHMENT0 // dimensions are kept for readPixels primarily, function only uses COLOR_ATTACHMENT0
if (mBoundFramebuffer && attachment == LOCAL_GL_COLOR_ATTACHMENT0) if (attachment == LOCAL_GL_COLOR_ATTACHMENT0)
mBoundFramebuffer->setDimensions(wtex); mBoundFramebuffer->setDimensions(wtex);
// XXXXX we need to store/reference this attachment! // XXXXX we need to store/reference this attachment!
@ -1478,7 +1490,7 @@ WebGLContext::GetParameter(PRUint32 pname, nsIVariant **retval)
break; break;
case LOCAL_GL_TEXTURE_BINDING_2D: case LOCAL_GL_TEXTURE_BINDING_2D:
wrval->SetAsISupports( mBound2DTextures[mActiveTexture]); wrval->SetAsISupports(mBound2DTextures[mActiveTexture]);
break; break;
case LOCAL_GL_TEXTURE_BINDING_CUBE_MAP: case LOCAL_GL_TEXTURE_BINDING_CUBE_MAP:
@ -1544,14 +1556,49 @@ WebGLContext::GetFramebufferAttachmentParameter(WebGLenum target, WebGLenum atta
return ErrorInvalidEnumInfo("GetFramebufferAttachmentParameter: attachment", attachment); return ErrorInvalidEnumInfo("GetFramebufferAttachmentParameter: attachment", attachment);
} }
if (!mBoundFramebuffer)
return ErrorInvalidOperation("GetFramebufferAttachmentParameter: cannot query framebuffer 0");
MakeContextCurrent(); MakeContextCurrent();
GLint atype = 0;
gl->fGetFramebufferAttachmentParameteriv(target, attachment, LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &atype);
if (atype == LOCAL_GL_RENDERBUFFER) {
switch (pname) { switch (pname) {
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE: case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: wrval->SetAsInt32(atype);
break;
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: {
GLint i = 0;
gl->fGetFramebufferAttachmentParameteriv(target, attachment, pname, &i);
WebGLRenderbuffer *rb = mMapRenderbuffers.GetWeak(PRUint32(i));
NS_ASSERTION(rb, "Expected to find renderbuffer in table, but it's not there?");
wrval->SetAsISupports(rb);
}
break;
default:
return ErrorInvalidEnum("GetFramebufferAttachmentParameter: invalid parameter");
}
} else if (atype == LOCAL_GL_TEXTURE) {
switch (pname) {
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
wrval->SetAsInt32(atype);
break;
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: {
GLint i = 0;
gl->fGetFramebufferAttachmentParameteriv(target, attachment, pname, &i);
WebGLTexture *tex = mMapTextures.GetWeak(PRUint32(i));
NS_ASSERTION(tex, "Expected to find texture in table, but it's not there?");
wrval->SetAsISupports(tex);
}
break;
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL: case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE: case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE: {
{
GLint i = 0; GLint i = 0;
gl->fGetFramebufferAttachmentParameteriv(target, attachment, pname, &i); gl->fGetFramebufferAttachmentParameteriv(target, attachment, pname, &i);
wrval->SetAsInt32(i); wrval->SetAsInt32(i);
@ -1559,7 +1606,11 @@ WebGLContext::GetFramebufferAttachmentParameter(WebGLenum target, WebGLenum atta
break; break;
default: default:
return ErrorInvalidEnumInfo("GetFramebufferAttachmentParameter: parameter", pname); return ErrorInvalidEnum("GetFramebufferAttachmentParameter: invalid parameter");
}
} else {
NS_WARNING("Unknown framebuffer attachment type?");
return NS_ERROR_FAILURE;
} }
*retval = wrval.forget().get(); *retval = wrval.forget().get();

Просмотреть файл

@ -384,7 +384,7 @@ WebGLContext::InitAndValidateGL()
gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_ATTRIBS, (GLint*) &mGLMaxVertexAttribs); gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_ATTRIBS, (GLint*) &mGLMaxVertexAttribs);
if (mGLMaxVertexAttribs < 8) { if (mGLMaxVertexAttribs < 8) {
LogMessage("GL_MAX_VERTEX_ATTRIBS is < 8!"); LogMessage("GL_MAX_VERTEX_ATTRIBS: %d is < 8!", mGLMaxVertexAttribs);
return PR_FALSE; return PR_FALSE;
} }
@ -395,7 +395,7 @@ WebGLContext::InitAndValidateGL()
// GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS value is the accurate value. // GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS value is the accurate value.
gl->fGetIntegerv(LOCAL_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, (GLint*) &mGLMaxTextureUnits); gl->fGetIntegerv(LOCAL_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, (GLint*) &mGLMaxTextureUnits);
if (mGLMaxTextureUnits < 8) { if (mGLMaxTextureUnits < 8) {
LogMessage("GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS is < 8!"); LogMessage("GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: %d is < 8!", mGLMaxTextureUnits);
return PR_FALSE; return PR_FALSE;
} }