Bug 716439; load a mask texture in the OGL backend. r=BenWa

This commit is contained in:
Nicholas Cameron 2012-03-19 09:08:49 +13:00
Родитель 33123a1cd3
Коммит a82db9af35
6 изменённых файлов: 162 добавлений и 4 удалений

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

@ -577,6 +577,97 @@ ImageLayerOGL::AllocateTexturesCairo(CairoImage *aImage)
aImage->SetBackendData(LayerManager::LAYERS_OPENGL, backendData.forget());
}
/*
* Returns a size that is larger than and closest to aSize where both
* width and height are powers of two.
* If the OpenGL setup is capable of using non-POT textures, then it
* will just return aSize.
*/
gfxIntSize CalculatePOTSize(const gfxIntSize& aSize, GLContext* gl)
{
if (gl->CanUploadNonPowerOfTwo())
return aSize;
return gfxIntSize(NextPowerOfTwo(aSize.width), NextPowerOfTwo(aSize.height));
}
bool
ImageLayerOGL::LoadAsTexture(GLuint aTextureUnit, gfxIntSize* aSize)
{
// this method shares a lot of code with RenderLayer, but it doesn't seem
// to be possible to factor it out into a helper method
if (!GetContainer()) {
return false;
}
AutoLockImage autoLock(GetContainer());
Image *image = autoLock.GetImage();
if (!image) {
return false;
}
if (image->GetFormat() != Image::CAIRO_SURFACE) {
return false;
}
CairoImage* cairoImage = static_cast<CairoImage*>(image);
if (!cairoImage->mSurface) {
return false;
}
CairoOGLBackendData *data = static_cast<CairoOGLBackendData*>(
cairoImage->GetBackendData(LayerManager::LAYERS_OPENGL));
if (!data) {
// allocate a new texture and save the details in the backend data
data = new CairoOGLBackendData;
data->mTextureSize = CalculatePOTSize(cairoImage->mSize, gl());
GLTexture &texture = data->mTexture;
texture.Allocate(mOGLManager->gl());
if (!texture.IsAllocated()) {
return false;
}
mozilla::gl::GLContext *texGL = texture.GetGLContext();
texGL->MakeCurrent();
GLuint texID = texture.GetTextureID();
data->mLayerProgram =
texGL->UploadSurfaceToTexture(cairoImage->mSurface,
nsIntRect(0,0,
data->mTextureSize.width,
data->mTextureSize.height),
texID, true, nsIntPoint(0,0), false,
aTextureUnit);
cairoImage->SetBackendData(LayerManager::LAYERS_OPENGL, data);
gl()->MakeCurrent();
gl()->fActiveTexture(aTextureUnit);
gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, texID);
gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER,
LOCAL_GL_LINEAR);
gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER,
LOCAL_GL_LINEAR);
gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S,
LOCAL_GL_CLAMP_TO_EDGE);
gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T,
LOCAL_GL_CLAMP_TO_EDGE);
} else {
gl()->fActiveTexture(aTextureUnit);
gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, data->mTexture.GetTextureID());
}
*aSize = data->mTextureSize;
return true;
}
ShadowImageLayerOGL::ShadowImageLayerOGL(LayerManagerOGL* aManager)
: ShadowImageLayer(aManager, nsnull)
, LayerOGL(aManager)

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

@ -135,11 +135,13 @@ public:
// LayerOGL Implementation
virtual void Destroy() { mDestroyed = true; }
virtual Layer* GetLayer();
virtual bool LoadAsTexture(GLuint aTextureUnit, gfxIntSize* aSize);
virtual void RenderLayer(int aPreviousFrameBuffer,
const nsIntPoint& aOffset);
virtual void CleanupResources() {}
void AllocateTexturesYCbCr(PlanarYCbCrImage *aImage);
void AllocateTexturesCairo(CairoImage *aImage);
@ -175,6 +177,7 @@ struct CairoOGLBackendData : public ImageBackendData
CairoOGLBackendData() : mLayerProgram(gl::RGBALayerProgramType) {}
GLTexture mTexture;
gl::ShaderProgramType mLayerProgram;
gfxIntSize mTextureSize;
};
class ShadowImageLayerOGL : public ShadowImageLayer,

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

@ -342,6 +342,8 @@ public:
GLenum aWrapMode = LOCAL_GL_REPEAT,
bool aFlipped = false);
virtual gfxASurface::gfxImageFormat MaskImageFormat()
{ return gfxASurface::ImageFormatARGB32; }
#ifdef MOZ_LAYERS_HAVE_LOG
virtual const char* Name() const { return "OGL"; }
@ -522,6 +524,22 @@ public:
GLContext *gl() const { return mOGLManager->gl(); }
virtual void CleanupResources() = 0;
/*
* Loads the result of rendering the layer as an OpenGL texture in aTextureUnit.
* Will try to use an existing texture if possible, or a temporary
* one if not. It is the callee's responsibility to release the texture.
* Will return true if a texture could be constructed and loaded, false otherwise.
* The texture will not be transformed, i.e., it will be in the same coord
* space as this.
* Any layer that can be used as a mask layer should override this method.
* aSize will contain the size of the image.
*/
virtual bool LoadAsTexture(GLuint aTextureUnit, gfxIntSize* aSize)
{
NS_WARNING("LoadAsTexture called without being overriden");
return false;
}
protected:
LayerManagerOGL *mOGLManager;
bool mDestroyed;

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

@ -331,7 +331,39 @@ ShaderProgramOGL::CheckAndSetProjectionMatrix(const gfx3DMatrix& aMatrix)
SetProjectionMatrix(aMatrix);
}
}
bool
ShaderProgramOGL::LoadMask(Layer* aMaskLayer)
{
if (!aMaskLayer) {
return false;
}
gfxIntSize size;
if (!static_cast<LayerOGL*>(aMaskLayer->ImplData())
->LoadAsTexture(LOCAL_GL_TEXTURE0 + mProfile.mTextureCount - 1, &size)){
return false;
}
SetUniform(mProfile.LookupUniformLocation("uMaskTexture"),
(GLint)(mProfile.mTextureCount - 1));
gfxMatrix maskTransform;
bool isMask2D = aMaskLayer->GetEffectiveTransform().CanDraw2D(&maskTransform);
NS_ASSERTION(isMask2D, "How did we end up with a 3D transform here?!");
gfxRect bounds = gfxRect(gfxPoint(), size);
bounds = maskTransform.TransformBounds(bounds);
gfx3DMatrix m;
m._11 = 1.0f/bounds.width;
m._22 = 1.0f/bounds.height;
m._41 = float(-bounds.x)/bounds.width;
m._42 = float(-bounds.y)/bounds.height;
SetMatrixUniform(mProfile.LookupUniformLocation("uMaskQuadTransform"), m);
return true;
}
} /* layers */
} /* mozilla */

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

@ -211,6 +211,20 @@ public:
return mTexCoordMultiplierUniformLocation;
}
/**
* aLayer is the mask layer to use for rendering, or null, if there is no
* mask layer.
* If aLayer is non-null, then the result of rendering aLayer is stored as
* as a texture to be used by the shader. It is stored in the next available
* texture unit, as determined by the texture unit requirements for the
* shader.
* Any other features of the mask layer required by the shader are also
* loaded to graphics memory. In particular the transform used to move from
* the layer's coordinates to the mask's coordinates is loaded; this must be
* a 2D transform.
*/
bool LoadMask(Layer* aLayer);
/**
* The following set of methods set a uniform argument to the shader program.
* Not all uniforms may be set for all programs, and such uses will throw

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

@ -2761,9 +2761,9 @@ ContainerState::SetupMaskLayer(Layer *aLayer, const FrameLayerBuilder::Clip& aCl
return;
}
nsRefPtr<gfxASurface> surface =
aLayer->Manager()->CreateOptimalSurface(boundingRect.Size(),
aLayer->Manager()->MaskImageFormat());
nsRefPtr<gfxASurface> surface =
aLayer->Manager()->CreateOptimalSurface(boundingRect.Size(),
aLayer->Manager()->MaskImageFormat());
// fail if we can't get the right surface
if (!surface || surface->CairoStatus()) {
@ -2780,7 +2780,7 @@ ContainerState::SetupMaskLayer(Layer *aLayer, const FrameLayerBuilder::Clip& aCl
scale.Scale(mParameters.mXScale, mParameters.mYScale);
context->Multiply(scale);
// useful for debugging
// useful for debugging, make masked areas semi-opaque
//context->SetColor(gfxRGBA(0, 0, 0, 0.3));
//context->Paint();