Bug 774552 - Draw GraphicBuffer directly. r=roc,BenWa

This commit is contained in:
Kan-Ru Chen
2012-07-17 10:12:58 +08:00
parent a3b31d18c5
commit 495d867d3a
8 changed files with 293 additions and 40 deletions

View File

@@ -55,6 +55,7 @@ enum ShaderProgramType {
RGBXLayerProgramType,
BGRXLayerProgramType,
RGBARectLayerProgramType,
RGBAExternalLayerProgramType,
ColorLayerProgramType,
YCbCrLayerProgramType,
ComponentAlphaPass1ProgramType,
@@ -740,6 +741,7 @@ public:
*/
void ApplyFilterToBoundTexture(gfxPattern::GraphicsFilter aFilter);
virtual bool BindExternalBuffer(GLuint texture, void* buffer) { return false; }
/*
* Offscreen support API

View File

@@ -44,6 +44,7 @@ using namespace android;
# define EGL_NATIVE_BUFFER_ANDROID 0x3140
# define EGL_IMAGE_PRESERVED_KHR 0x30D2
# define GL_TEXTURE_EXTERNAL_OES 0x8D65
# endif
@@ -403,6 +404,26 @@ public:
return true;
}
bool BindExternalBuffer(GLuint texture, void* buffer)
{
#if defined(MOZ_WIDGET_GONK)
EGLint attrs[] = {
EGL_IMAGE_PRESERVED_KHR, LOCAL_EGL_TRUE,
LOCAL_EGL_NONE, LOCAL_EGL_NONE
};
EGLImage image = sEGLLibrary.fCreateImage(EGL_DISPLAY(),
EGL_NO_CONTEXT,
EGL_NATIVE_BUFFER_ANDROID,
buffer, attrs);
sEGLLibrary.fImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, image);
fBindTexture(GL_TEXTURE_EXTERNAL_OES, texture);
sEGLLibrary.fDestroyImage(EGL_DISPLAY(), image);
return true;
#else
return false;
#endif
}
bool MakeCurrentImpl(bool aForce = false) {
bool succeeded = true;

View File

@@ -46,6 +46,10 @@ ImageFactory::CreateImage(const Image::Format *aFormats,
#ifdef XP_MACOSX
} else if (FormatInList(aFormats, aNumFormats, Image::MAC_IO_SURFACE)) {
img = new MacIOSurfaceImage();
#endif
#ifdef MOZ_WIDGET_GONK
} else if (FormatInList(aFormats, aNumFormats, Image::GONK_IO_SURFACE)) {
img = new GonkIOSurfaceImage();
#endif
}
return img.forget();

View File

@@ -27,6 +27,9 @@ struct ID3D10ShaderResourceView;
typedef void* HANDLE;
#endif
#ifdef MOZ_WIDGET_GONK
# include <ui/GraphicBuffer.h>
#endif
namespace mozilla {
@@ -106,6 +109,13 @@ public:
*/
MAC_IO_SURFACE,
/**
* The GONK_IO_SURFACE format creates a GonkIOSurfaceImage.
*
* It wraps an GraphicBuffer object and binds it directly to a GL texture.
*/
GONK_IO_SURFACE,
/**
* An bitmap image that can be shared with a remote process.
*/
@@ -924,6 +934,82 @@ private:
};
#endif
#ifdef MOZ_WIDGET_GONK
/**
* The gralloc buffer maintained by android GraphicBuffer can be
* shared between the compositor thread and the producer thread. The
* mGraphicBuffer is owned by the producer thread, but when it is
* wrapped by GraphicBufferLocked and passed to the compositor, the
* buffer content is guaranteed to not change until Unlock() is
* called. Each producer must maintain their own buffer queue and
* implement the GraphicBufferLocked::Unlock() interface.
*/
class GraphicBufferLocked {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GraphicBufferLocked)
public:
GraphicBufferLocked(android::GraphicBuffer* aGraphicBuffer)
: mGraphicBuffer(aGraphicBuffer)
{}
virtual ~GraphicBufferLocked() {}
virtual void Unlock() {}
virtual void* GetNativeBuffer()
{
return mGraphicBuffer->getNativeBuffer();
}
protected:
android::GraphicBuffer* mGraphicBuffer;
};
class THEBES_API GonkIOSurfaceImage : public Image {
public:
struct Data {
nsRefPtr<GraphicBufferLocked> mGraphicBuffer;
gfxIntSize mPicSize;
};
GonkIOSurfaceImage()
: Image(NULL, GONK_IO_SURFACE)
, mSize(0, 0)
{}
virtual ~GonkIOSurfaceImage()
{
mGraphicBuffer->Unlock();
}
virtual void SetData(const Data& aData)
{
mGraphicBuffer = aData.mGraphicBuffer;
mSize = aData.mPicSize;
}
virtual gfxIntSize GetSize()
{
return mSize;
}
virtual already_AddRefed<gfxASurface> GetAsSurface()
{
// We need to fix this and return a ASurface at some point.
return nsnull;
}
void* GetNativeBuffer()
{
return mGraphicBuffer->GetNativeBuffer();
}
private:
nsRefPtr<GraphicBufferLocked> mGraphicBuffer;
gfxIntSize mSize;
};
#endif
class RemoteBitmapImage : public Image {
public:
RemoteBitmapImage() : Image(NULL, REMOTE_IMAGE_BITMAP) {}

View File

@@ -176,6 +176,23 @@ AllocateTextureIOSurface(MacIOSurfaceImage *aIOImage, mozilla::gl::GLContext* aG
}
#endif
#ifdef MOZ_WIDGET_GONK
struct THEBES_API GonkIOSurfaceImageOGLBackendData : public ImageBackendData
{
GLTexture mTexture;
};
void
AllocateTextureIOSurface(GonkIOSurfaceImage *aIOImage, mozilla::gl::GLContext* aGL)
{
nsAutoPtr<GonkIOSurfaceImageOGLBackendData> backendData(
new GonkIOSurfaceImageOGLBackendData);
backendData->mTexture.Allocate(aGL);
aIOImage->SetBackendData(LayerManager::LAYERS_OPENGL, backendData.forget());
}
#endif
Layer*
ImageLayerOGL::GetLayer()
{
@@ -297,8 +314,6 @@ ImageLayerOGL::RenderLayer(int,
}
gl()->MakeCurrent();
unsigned int iwidth = cairoImage->mSize.width;
unsigned int iheight = cairoImage->mSize.height;
gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, data->mTexture.GetTextureID());
@@ -321,51 +336,21 @@ ImageLayerOGL::RenderLayer(int,
gl()->ApplyFilterToBoundTexture(mFilter);
program->Activate();
// The following uniform controls the scaling of the vertex coords.
// Instead of setting the scale here and using coords in the range [0,1], we
// set an identity transform and use pixel coordinates below
program->SetLayerQuadRect(nsIntRect(0, 0, 1, 1));
program->SetLayerQuadRect(nsIntRect(0, 0,
cairoImage->GetSize().width,
cairoImage->GetSize().height));
program->SetLayerTransform(GetEffectiveTransform());
program->SetLayerOpacity(GetEffectiveOpacity());
program->SetRenderOffset(aOffset);
program->SetTextureUnit(0);
program->LoadMask(GetMaskLayer());
nsIntRect rect = GetVisibleRegion().GetBounds();
mOGLManager->BindAndDrawQuadWithTextureRect(program,
GetVisibleRegion().GetBounds(),
nsIntSize(cairoImage->GetSize().width,
cairoImage->GetSize().height));
GLContext::RectTriangles triangleBuffer;
float tex_offset_u = float(rect.x % iwidth) / iwidth;
float tex_offset_v = float(rect.y % iheight) / iheight;
triangleBuffer.addRect(rect.x, rect.y,
rect.x + rect.width, rect.y + rect.height,
tex_offset_u, tex_offset_v,
tex_offset_u + float(rect.width) / float(iwidth),
tex_offset_v + float(rect.height) / float(iheight));
GLuint vertAttribIndex =
program->AttribLocation(ShaderProgramOGL::VertexCoordAttrib);
GLuint texCoordAttribIndex =
program->AttribLocation(ShaderProgramOGL::TexCoordAttrib);
NS_ASSERTION(texCoordAttribIndex != GLuint(-1), "no texture coords?");
gl()->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
gl()->fVertexAttribPointer(vertAttribIndex, 2,
LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0,
triangleBuffer.vertexPointer());
gl()->fVertexAttribPointer(texCoordAttribIndex, 2,
LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0,
triangleBuffer.texCoordPointer());
{
gl()->fEnableVertexAttribArray(texCoordAttribIndex);
{
gl()->fEnableVertexAttribArray(vertAttribIndex);
gl()->fDrawArrays(LOCAL_GL_TRIANGLES, 0, triangleBuffer.elements());
gl()->fDisableVertexAttribArray(vertAttribIndex);
}
gl()->fDisableVertexAttribArray(texCoordAttribIndex);
}
#if defined(MOZ_WIDGET_GTK2) && !defined(MOZ_PLATFORM_MAEMO)
if (cairoImage->mSurface && pixmap) {
sGLXLibrary.ReleaseTexImage(pixmap);
@@ -427,6 +412,45 @@ ImageLayerOGL::RenderLayer(int,
mOGLManager->BindAndDrawQuad(program);
gl()->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
#endif
#ifdef MOZ_WIDGET_GONK
} else if (image->GetFormat() == Image::GONK_IO_SURFACE) {
GonkIOSurfaceImage *ioImage = static_cast<GonkIOSurfaceImage*>(image);
if (!ioImage) {
return;
}
gl()->MakeCurrent();
gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
if (!ioImage->GetBackendData(LayerManager::LAYERS_OPENGL)) {
AllocateTextureIOSurface(ioImage, gl());
}
GonkIOSurfaceImageOGLBackendData *data =
static_cast<GonkIOSurfaceImageOGLBackendData*>(ioImage->GetBackendData(LayerManager::LAYERS_OPENGL));
gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
gl()->BindExternalBuffer(data->mTexture.GetTextureID(), ioImage->GetNativeBuffer());
ShaderProgramOGL *program = mOGLManager->GetProgram(RGBAExternalLayerProgramType, GetMaskLayer());
gl()->ApplyFilterToBoundTexture(mFilter);
program->Activate();
program->SetLayerQuadRect(nsIntRect(0, 0,
ioImage->GetSize().width,
ioImage->GetSize().height));
program->SetLayerTransform(GetEffectiveTransform());
program->SetLayerOpacity(GetEffectiveOpacity());
program->SetRenderOffset(aOffset);
program->SetTextureUnit(0);
program->LoadMask(GetMaskLayer());
mOGLManager->BindAndDrawQuadWithTextureRect(program,
GetVisibleRegion().GetBounds(),
nsIntSize(ioImage->GetSize().width,
ioImage->GetSize().height));
#endif
}
GetContainer()->NotifyPaintedImage(image);

View File

@@ -104,6 +104,21 @@ ProgramProfileOGL::GetProfileFor(gl::ShaderProgramType aType,
AddCommonTextureArgs(result);
result.mTextureCount = 1;
break;
case gl::RGBAExternalLayerProgramType:
if (aMask == Mask3d) {
result.mVertexShaderString = sLayerMask3DVS;
result.mFragmentShaderString = sRGBAExternalTextureLayerMask3DFS;
} else if (aMask == Mask2d) {
result.mVertexShaderString = sLayerMaskVS;
result.mFragmentShaderString = sRGBAExternalTextureLayerMaskFS;
} else {
result.mVertexShaderString = sLayerVS;
result.mFragmentShaderString = sRGBAExternalTextureLayerFS;
}
AddCommonArgs(result);
AddCommonTextureArgs(result);
result.mTextureCount = 1;
break;
case gl::ColorLayerProgramType:
if (aMask == Mask2d) {
result.mVertexShaderString = sLayerMaskVS;
@@ -327,7 +342,7 @@ ShaderProgramOGL::CreateProgram(const char *aVertexShaderString,
mProgram = result;
return true;
}
bool
ShaderProgramOGL::LoadMask(Layer* aMaskLayer)
{

View File

@@ -341,6 +341,88 @@ gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n\
#endif\n\
";
static const char sRGBAExternalTextureLayerFS[] = "/* sRGBAExternalTextureLayerFS */\n\
#extension GL_OES_EGL_image_external : require\n\
/* Fragment Shader */\n\
#ifdef GL_ES\n\
precision lowp float;\n\
#endif\n\
\n\
#ifndef NO_LAYER_OPACITY\n\
uniform float uLayerOpacity;\n\
#endif\n\
#ifdef GL_ES // for tiling, texcoord can be greater than the lowfp range\n\
varying mediump vec2 vTexCoord;\n\
#else\n\
varying vec2 vTexCoord;\n\
#endif\n\
\n\
uniform samplerExternalOES uTexture;\n\
void main()\n\
{\n\
float mask = 1.0;\n\
\n\
gl_FragColor = texture2D(uTexture, vTexCoord) * uLayerOpacity * mask;\n\
}\n\
";
static const char sRGBAExternalTextureLayerMaskFS[] = "/* sRGBAExternalTextureLayerMaskFS */\n\
#extension GL_OES_EGL_image_external : require\n\
/* Fragment Shader */\n\
#ifdef GL_ES\n\
precision lowp float;\n\
#endif\n\
\n\
#ifndef NO_LAYER_OPACITY\n\
uniform float uLayerOpacity;\n\
#endif\n\
#ifdef GL_ES // for tiling, texcoord can be greater than the lowfp range\n\
varying mediump vec2 vTexCoord;\n\
#else\n\
varying vec2 vTexCoord;\n\
#endif\n\
\n\
varying vec2 vMaskCoord;\n\
uniform sampler2D uMaskTexture;\n\
\n\
uniform samplerExternalOES uTexture;\n\
void main()\n\
{\n\
float mask = texture2D(uMaskTexture, vMaskCoord).r;\n\
\n\
gl_FragColor = texture2D(uTexture, vTexCoord) * uLayerOpacity * mask;\n\
}\n\
";
static const char sRGBAExternalTextureLayerMask3DFS[] = "/* sRGBAExternalTextureLayerMask3DFS */\n\
#extension GL_OES_EGL_image_external : require\n\
/* Fragment Shader */\n\
#ifdef GL_ES\n\
precision lowp float;\n\
#endif\n\
\n\
#ifndef NO_LAYER_OPACITY\n\
uniform float uLayerOpacity;\n\
#endif\n\
#ifdef GL_ES // for tiling, texcoord can be greater than the lowfp range\n\
varying mediump vec2 vTexCoord;\n\
#else\n\
varying vec2 vTexCoord;\n\
#endif\n\
\n\
varying vec3 vMaskCoord;\n\
uniform sampler2D uMaskTexture;\n\
\n\
uniform samplerExternalOES uTexture;\n\
void main()\n\
{\n\
vec2 maskCoords = vMaskCoord.xy / vMaskCoord.z;\n\
float mask = texture2D(uMaskTexture, maskCoords).r;\n\
\n\
gl_FragColor = texture2D(uTexture, vTexCoord) * uLayerOpacity * mask;\n\
}\n\
";
static const char sBGRATextureLayerFS[] = "/* sBGRATextureLayerFS */\n\
/* Fragment Shader */\n\
#ifdef GL_ES\n\

View File

@@ -236,6 +236,25 @@ void main()
#endif
@end
// Single texture in RGBA format, but uses external image. External
// image is an EGLImage which have internal formats not otherwise
// supported by OpenGL ES. It is up to the implementation exactly what
// formats are accepted. It is specified in the OES_EGL_image_external
// extension.
@shader sRGBAExternalTextureLayer<mask:,Mask,Mask3D>FS
#extension GL_OES_EGL_image_external : require
$LAYER_FRAGMENT<mask>$
uniform samplerExternalOES uTexture;
void main()
{
$FRAGMENT_CALC_MASK<mask>$
gl_FragColor = texture2D(uTexture, vTexCoord) * uLayerOpacity * mask;
}
@end
// Single texture in BGRA format (via swizzle)
@shader sBGRATextureLayer<mask:,Mask>FS
$LAYER_FRAGMENT<mask>$