зеркало из https://github.com/mozilla/pjs.git
Bug 716439; load a mask texture in the OGL backend. r=BenWa
This commit is contained in:
Родитель
33123a1cd3
Коммит
a82db9af35
|
@ -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();
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче