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
Родитель 27b296ce6e
Коммит 68ca026ffa
4 изменённых файлов: 219 добавлений и 60 удалений

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

@ -99,6 +99,106 @@ 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
@ -141,38 +241,42 @@ WebGLContext::SetCanvasElement(nsHTMLCanvasElement* aParentCanvas)
NS_IMETHODIMP
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,
// don't allow it. Allowing this would allow us to use
// resource handles created from older context generations.
if (!(mGeneration+1).valid())
return NS_ERROR_FAILURE; // exit without changing the value of mGeneration
if (mWidth == width && mHeight == height)
return NS_OK;
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;
}
}
// We're going to recreate our context, so make sure we clean up
// after ourselves.
DestroyResourcesAndContext();
gl::ContextFormat format(gl::ContextFormat::BasicRGBA32);
format.depth = 16;
format.minDepth = 1;
gl = gl::GLContextProvider::CreatePBuffer(gfxIntSize(width, height),
gl::GLContextProvider::GetGlobalContext(),
format);
gl = gl::GLContextProvider::CreateOffscreen(gfxIntSize(width, height), format);
printf_stderr ("--- WebGL context created: %p\n", gl.get());
#ifdef USE_GLES2
// On native GLES2, no need to validate, the compiler will do it
@ -186,16 +290,13 @@ WebGLContext::SetDimensions(PRInt32 width, PRInt32 height)
#endif
if (!InitAndValidateGL()) {
gl = gl::GLContextProviderOSMesa::CreatePBuffer(gfxIntSize(width, height),
nsnull,
format);
gl = gl::GLContextProviderOSMesa::CreateOffscreen(gfxIntSize(width, height), format);
if (!InitAndValidateGL()) {
LogMessage("WebGL: Can't get a usable OpenGL context.");
return NS_ERROR_FAILURE;
}
else {
LogMessage("WebGL: Using software rendering via OSMesa");
}
LogMessage("WebGL: Using software rendering via OSMesa");
}
mWidth = width;
@ -205,12 +306,25 @@ WebGLContext::SetDimensions(PRInt32 width, PRInt32 height)
// increment the generation number
++mGeneration;
#if 0
if (mGeneration > 0) {
// XXX dispatch context lost event
}
#endif
MakeContextCurrent();
// Make sure that we clear this out, otherwise
// we'll end up displaying random memory
gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, gl->GetOffscreenFBO());
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);
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
// 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);
if (native_pbuffer) {
data.mGLContext = gl.get();
}
else if (native_surface) {
if (native_surface) {
data.mSurface = static_cast<gfxASurface*>(native_surface);
}
else {
NS_WARNING("The GLContext has neither a native PBuffer nor a native surface!");
return nsnull;
} else {
data.mGLContext = gl.get();
}
data.mSize = nsIntSize(mWidth, mHeight);
data.mGLBufferIsPremultiplied = PR_FALSE;
canvasLayer->Initialize(data);
// once we support GL context attributes, we'll set the right thing here
canvasLayer->SetIsOpaqueContent(PR_FALSE);
canvasLayer->SetIsOpaqueContent(gl->CreationFormat().alpha == 0 ? PR_TRUE : PR_FALSE);
canvasLayer->Updated(nsIntRect(0, 0, mWidth, mHeight));
mInvalidated = PR_FALSE;

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

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

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

@ -227,7 +227,11 @@ WebGLContext::BindFramebuffer(WebGLenum target, nsIWebGLFramebuffer *fbobj)
MakeContextCurrent();
gl->fBindFramebuffer(target, framebuffername);
if (isNull) {
gl->fBindFramebuffer(target, gl->GetOffscreenFBO());
} else {
gl->fBindFramebuffer(target, framebuffername);
}
mBoundFramebuffer = wfb;
@ -503,7 +507,9 @@ NS_IMETHODIMP
WebGLContext::CheckFramebufferStatus(WebGLenum target, WebGLenum *retval)
{
MakeContextCurrent();
// XXX check target
if (target != LOCAL_GL_FRAMEBUFFER)
return ErrorInvalidEnum("CheckFramebufferStatus: target must be FRAMEBUFFER");
*retval = gl->fCheckFramebufferStatus(target);
return NS_OK;
}
@ -1013,8 +1019,11 @@ WebGLContext::FramebufferRenderbuffer(WebGLenum target, WebGLenum attachment, We
if (rbtarget != LOCAL_GL_RENDERBUFFER)
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
if (mBoundFramebuffer && attachment == LOCAL_GL_COLOR_ATTACHMENT0)
if (attachment == LOCAL_GL_COLOR_ATTACHMENT0)
mBoundFramebuffer->setDimensions(wrb);
MakeContextCurrent();
@ -1055,8 +1064,11 @@ WebGLContext::FramebufferTexture2D(WebGLenum target,
if (level != 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
if (mBoundFramebuffer && attachment == LOCAL_GL_COLOR_ATTACHMENT0)
if (attachment == LOCAL_GL_COLOR_ATTACHMENT0)
mBoundFramebuffer->setDimensions(wtex);
// XXXXX we need to store/reference this attachment!
@ -1478,7 +1490,7 @@ WebGLContext::GetParameter(PRUint32 pname, nsIVariant **retval)
break;
case LOCAL_GL_TEXTURE_BINDING_2D:
wrval->SetAsISupports( mBound2DTextures[mActiveTexture]);
wrval->SetAsISupports(mBound2DTextures[mActiveTexture]);
break;
case LOCAL_GL_TEXTURE_BINDING_CUBE_MAP:
@ -1544,22 +1556,61 @@ WebGLContext::GetFramebufferAttachmentParameter(WebGLenum target, WebGLenum atta
return ErrorInvalidEnumInfo("GetFramebufferAttachmentParameter: attachment", attachment);
}
if (!mBoundFramebuffer)
return ErrorInvalidOperation("GetFramebufferAttachmentParameter: cannot query framebuffer 0");
MakeContextCurrent();
switch (pname) {
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
{
GLint i = 0;
gl->fGetFramebufferAttachmentParameteriv(target, attachment, pname, &i);
wrval->SetAsInt32(i);
}
break;
GLint atype = 0;
gl->fGetFramebufferAttachmentParameteriv(target, attachment, LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &atype);
default:
return ErrorInvalidEnumInfo("GetFramebufferAttachmentParameter: parameter", pname);
if (atype == LOCAL_GL_RENDERBUFFER) {
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);
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_CUBE_MAP_FACE: {
GLint i = 0;
gl->fGetFramebufferAttachmentParameteriv(target, attachment, pname, &i);
wrval->SetAsInt32(i);
}
break;
default:
return ErrorInvalidEnum("GetFramebufferAttachmentParameter: invalid parameter");
}
} else {
NS_WARNING("Unknown framebuffer attachment type?");
return NS_ERROR_FAILURE;
}
*retval = wrval.forget().get();

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

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