Bug 882523 - Support OMTC on Mac in non-accelerated mode using OpenGL. r=nrc, r=mattwoodrow

This commit is contained in:
Markus Stange 2013-07-08 21:21:05 -07:00
parent fed7d5f0ff
commit 68c124a82c
18 changed files with 819 additions and 335 deletions

View File

@ -2026,13 +2026,137 @@ GLContext::BlitTextureImage(TextureImage *aSrc, const nsIntRect& aSrcRect,
}
static unsigned int
DataOffset(gfxImageSurface *aSurf, const nsIntPoint &aPoint)
DataOffset(const nsIntPoint &aPoint, int32_t aStride, gfxASurface::gfxImageFormat aFormat)
{
unsigned int data = aPoint.y * aSurf->Stride();
data += aPoint.x * gfxASurface::BytePerPixelFromFormat(aSurf->Format());
unsigned int data = aPoint.y * aStride;
data += aPoint.x * gfxASurface::BytePerPixelFromFormat(aFormat);
return data;
}
GLContext::SurfaceFormat
GLContext::UploadImageDataToTexture(unsigned char* aData,
int32_t aStride,
gfxASurface::gfxImageFormat aFormat,
const nsIntRegion& aDstRegion,
GLuint& aTexture,
bool aOverwrite,
bool aPixelBuffer,
GLenum aTextureUnit,
GLenum aTextureTarget)
{
bool textureInited = aOverwrite ? false : true;
MakeCurrent();
fActiveTexture(aTextureUnit);
if (!aTexture) {
fGenTextures(1, &aTexture);
fBindTexture(aTextureTarget, aTexture);
fTexParameteri(aTextureTarget,
LOCAL_GL_TEXTURE_MIN_FILTER,
LOCAL_GL_LINEAR);
fTexParameteri(aTextureTarget,
LOCAL_GL_TEXTURE_MAG_FILTER,
LOCAL_GL_LINEAR);
fTexParameteri(aTextureTarget,
LOCAL_GL_TEXTURE_WRAP_S,
LOCAL_GL_CLAMP_TO_EDGE);
fTexParameteri(aTextureTarget,
LOCAL_GL_TEXTURE_WRAP_T,
LOCAL_GL_CLAMP_TO_EDGE);
textureInited = false;
} else {
fBindTexture(aTextureTarget, aTexture);
}
nsIntRegion paintRegion;
if (!textureInited) {
paintRegion = nsIntRegion(aDstRegion.GetBounds());
} else {
paintRegion = aDstRegion;
}
GLenum format;
GLenum type;
int32_t pixelSize = gfxASurface::BytePerPixelFromFormat(aFormat);
SurfaceFormat surfaceFormat;
switch (aFormat) {
case gfxASurface::ImageFormatARGB32:
format = LOCAL_GL_RGBA;
type = LOCAL_GL_UNSIGNED_BYTE;
surfaceFormat = FORMAT_B8G8R8A8;
break;
case gfxASurface::ImageFormatRGB24:
// Treat RGB24 surfaces as RGBA32 except for the shader
// program used.
format = LOCAL_GL_RGBA;
type = LOCAL_GL_UNSIGNED_BYTE;
surfaceFormat = FORMAT_B8G8R8X8;
break;
case gfxASurface::ImageFormatRGB16_565:
format = LOCAL_GL_RGB;
type = LOCAL_GL_UNSIGNED_SHORT_5_6_5;
surfaceFormat = FORMAT_R5G6B5;
break;
case gfxASurface::ImageFormatA8:
format = LOCAL_GL_LUMINANCE;
type = LOCAL_GL_UNSIGNED_BYTE;
// We don't have a specific luminance shader
surfaceFormat = FORMAT_A8;
break;
default:
NS_ASSERTION(false, "Unhandled image surface format!");
format = 0;
type = 0;
surfaceFormat = FORMAT_UNKNOWN;
}
nsIntRegionRectIterator iter(paintRegion);
const nsIntRect *iterRect;
// Top left point of the region's bounding rectangle.
nsIntPoint topLeft = paintRegion.GetBounds().TopLeft();
while ((iterRect = iter.Next())) {
// The inital data pointer is at the top left point of the region's
// bounding rectangle. We need to find the offset of this rect
// within the region and adjust the data pointer accordingly.
unsigned char *rectData =
aData + DataOffset(iterRect->TopLeft() - topLeft, aStride, aFormat);
NS_ASSERTION(textureInited || (iterRect->x == 0 && iterRect->y == 0),
"Must be uploading to the origin when we don't have an existing texture");
if (textureInited && CanUploadSubTextures()) {
TexSubImage2D(aTextureTarget,
0,
iterRect->x,
iterRect->y,
iterRect->width,
iterRect->height,
aStride,
pixelSize,
format,
type,
rectData);
} else {
TexImage2D(aTextureTarget,
0,
format,
iterRect->width,
iterRect->height,
aStride,
pixelSize,
0,
format,
type,
rectData);
}
}
return surfaceFormat;
}
GLContext::SurfaceFormat
GLContext::UploadSurfaceToTexture(gfxASurface *aSurface,
const nsIntRegion& aDstRegion,
@ -2040,38 +2164,9 @@ GLContext::UploadSurfaceToTexture(gfxASurface *aSurface,
bool aOverwrite,
const nsIntPoint& aSrcPoint,
bool aPixelBuffer,
GLenum aTextureUnit)
GLenum aTextureUnit,
GLenum aTextureTarget)
{
bool textureInited = aOverwrite ? false : true;
MakeCurrent();
fActiveTexture(aTextureUnit);
if (!aTexture) {
fGenTextures(1, &aTexture);
fBindTexture(LOCAL_GL_TEXTURE_2D, aTexture);
fTexParameteri(LOCAL_GL_TEXTURE_2D,
LOCAL_GL_TEXTURE_MIN_FILTER,
LOCAL_GL_LINEAR);
fTexParameteri(LOCAL_GL_TEXTURE_2D,
LOCAL_GL_TEXTURE_MAG_FILTER,
LOCAL_GL_LINEAR);
fTexParameteri(LOCAL_GL_TEXTURE_2D,
LOCAL_GL_TEXTURE_WRAP_S,
LOCAL_GL_CLAMP_TO_EDGE);
fTexParameteri(LOCAL_GL_TEXTURE_2D,
LOCAL_GL_TEXTURE_WRAP_T,
LOCAL_GL_CLAMP_TO_EDGE);
textureInited = false;
} else {
fBindTexture(LOCAL_GL_TEXTURE_2D, aTexture);
}
nsIntRegion paintRegion;
if (!textureInited) {
paintRegion = nsIntRegion(aDstRegion.GetBounds());
} else {
paintRegion = aDstRegion;
}
nsRefPtr<gfxImageSurface> imageSurface = aSurface->GetAsImageSurface();
unsigned char* data = NULL;
@ -2101,94 +2196,56 @@ GLContext::UploadSurfaceToTexture(gfxASurface *aSurface,
if (!aPixelBuffer) {
data = imageSurface->Data();
}
data += DataOffset(imageSurface, aSrcPoint);
data += DataOffset(aSrcPoint, imageSurface->Stride(),
imageSurface->Format());
}
MOZ_ASSERT(imageSurface);
imageSurface->Flush();
GLenum format;
GLenum type;
int32_t pixelSize = gfxASurface::BytePerPixelFromFormat(imageSurface->Format());
SurfaceFormat surfaceFormat;
return UploadImageDataToTexture(data,
imageSurface->Stride(),
imageSurface->Format(),
aDstRegion, aTexture, aOverwrite,
aPixelBuffer, aTextureUnit, aTextureTarget);
}
switch (imageSurface->Format()) {
case gfxASurface::ImageFormatARGB32:
format = LOCAL_GL_RGBA;
type = LOCAL_GL_UNSIGNED_BYTE;
surfaceFormat = FORMAT_B8G8R8A8;
break;
case gfxASurface::ImageFormatRGB24:
// Treat RGB24 surfaces as RGBA32 except for the shader
// program used.
format = LOCAL_GL_RGBA;
type = LOCAL_GL_UNSIGNED_BYTE;
surfaceFormat = FORMAT_B8G8R8X8;
break;
case gfxASurface::ImageFormatRGB16_565:
format = LOCAL_GL_RGB;
type = LOCAL_GL_UNSIGNED_SHORT_5_6_5;
surfaceFormat = FORMAT_R5G6B5;
break;
case gfxASurface::ImageFormatA8:
format = LOCAL_GL_LUMINANCE;
type = LOCAL_GL_UNSIGNED_BYTE;
surfaceFormat = FORMAT_A8;
break;
static gfxASurface::gfxImageFormat
ImageFormatForSurfaceFormat(gfx::SurfaceFormat aFormat)
{
switch (aFormat) {
case gfx::FORMAT_B8G8R8A8:
return gfxASurface::ImageFormatARGB32;
case gfx::FORMAT_B8G8R8X8:
return gfxASurface::ImageFormatRGB24;
case gfx::FORMAT_R5G6B5:
return gfxASurface::ImageFormatRGB16_565;
case gfx::FORMAT_A8:
return gfxASurface::ImageFormatA8;
default:
NS_ASSERTION(false, "Unhandled image surface format!");
format = 0;
type = 0;
surfaceFormat = FORMAT_UNKNOWN;
return gfxASurface::ImageFormatUnknown;
}
}
int32_t stride = imageSurface->Stride();
nsIntRegionRectIterator iter(paintRegion);
const nsIntRect *iterRect;
// Top left point of the region's bounding rectangle.
nsIntPoint topLeft = paintRegion.GetBounds().TopLeft();
while ((iterRect = iter.Next())) {
// The inital data pointer is at the top left point of the region's
// bounding rectangle. We need to find the offset of this rect
// within the region and adjust the data pointer accordingly.
unsigned char *rectData =
data + DataOffset(imageSurface, iterRect->TopLeft() - topLeft);
NS_ASSERTION(textureInited || (iterRect->x == 0 && iterRect->y == 0),
"Must be uploading to the origin when we don't have an existing texture");
if (textureInited && CanUploadSubTextures()) {
TexSubImage2D(LOCAL_GL_TEXTURE_2D,
0,
iterRect->x,
iterRect->y,
iterRect->width,
iterRect->height,
stride,
pixelSize,
format,
type,
rectData);
} else {
TexImage2D(LOCAL_GL_TEXTURE_2D,
0,
format,
iterRect->width,
iterRect->height,
stride,
pixelSize,
0,
format,
type,
rectData);
}
}
return surfaceFormat;
GLContext::SurfaceFormat
GLContext::UploadSurfaceToTexture(gfx::DataSourceSurface *aSurface,
const nsIntRegion& aDstRegion,
GLuint& aTexture,
bool aOverwrite,
const nsIntPoint& aSrcPoint,
bool aPixelBuffer,
GLenum aTextureUnit,
GLenum aTextureTarget)
{
unsigned char* data = aPixelBuffer ? NULL : aSurface->GetData();
int32_t stride = aSurface->Stride();
gfxASurface::gfxImageFormat format =
ImageFormatForSurfaceFormat(aSurface->GetFormat());
data += DataOffset(aSrcPoint, stride, format);
return UploadImageDataToTexture(data, stride, format,
aDstRegion, aTexture, aOverwrite,
aPixelBuffer, aTextureUnit,
aTextureTarget);
}
static GLint GetAddressAlignment(ptrdiff_t aAddress)

View File

@ -62,6 +62,7 @@ namespace android {
namespace mozilla {
namespace gfx {
class SharedSurface;
class DataSourceSurface;
struct SurfaceCaps;
}
@ -866,7 +867,7 @@ public:
* The aDstPoint parameter is ignored if no texture was provided
* or aOverwrite is true.
*
* \param aSurface Surface to upload.
* \param aData Image data to upload.
* \param aDstRegion Region of texture to upload to.
* \param aTexture Texture to use, or 0 to have one created for you.
* \param aOverwrite Over an existing texture with a new one.
@ -881,14 +882,39 @@ public:
* texture unit being active.
* \return Surface format of this texture.
*/
SurfaceFormat UploadImageDataToTexture(unsigned char* aData,
int32_t aStride,
gfxASurface::gfxImageFormat aFormat,
const nsIntRegion& aDstRegion,
GLuint& aTexture,
bool aOverwrite = false,
bool aPixelBuffer = false,
GLenum aTextureUnit = LOCAL_GL_TEXTURE0,
GLenum aTextureTarget = LOCAL_GL_TEXTURE_2D);
/**
* Convenience wrapper around UploadImageDataToTexture for gfxASurfaces.
*/
SurfaceFormat UploadSurfaceToTexture(gfxASurface *aSurface,
const nsIntRegion& aDstRegion,
GLuint& aTexture,
bool aOverwrite = false,
const nsIntPoint& aSrcPoint = nsIntPoint(0, 0),
bool aPixelBuffer = false,
GLenum aTextureUnit = LOCAL_GL_TEXTURE0);
GLenum aTextureUnit = LOCAL_GL_TEXTURE0,
GLenum aTextureTarget = LOCAL_GL_TEXTURE_2D);
/**
* Same as above, for DataSourceSurfaces.
*/
SurfaceFormat UploadSurfaceToTexture(gfx::DataSourceSurface *aSurface,
const nsIntRegion& aDstRegion,
GLuint& aTexture,
bool aOverwrite = false,
const nsIntPoint& aSrcPoint = nsIntPoint(0, 0),
bool aPixelBuffer = false,
GLenum aTextureUnit = LOCAL_GL_TEXTURE0,
GLenum aTextureTarget = LOCAL_GL_TEXTURE_2D);
void TexImage2D(GLenum target, GLint level, GLint internalformat,
GLsizei width, GLsizei height, GLsizei stride,

View File

@ -187,10 +187,15 @@ BasicCompositor::BasicCompositor(nsIWidget *aWidget)
BasicCompositor::~BasicCompositor()
{
Destroy();
MOZ_COUNT_DTOR(BasicCompositor);
}
void BasicCompositor::Destroy()
{
mWidget->CleanupRemoteDrawing();
mWidget = nullptr;
}
TemporaryRef<CompositingRenderTarget>
BasicCompositor::CreateRenderTarget(const IntRect& aRect, SurfaceInitMode aInit)
{
@ -357,6 +362,8 @@ BasicCompositor::BeginFrame(const gfx::Rect *aClipRectIn,
// If we have a copy target, then we don't have a widget-provided mDrawTarget (currently). Create a dummy
// placeholder so that CreateRenderTarget() works.
mDrawTarget = gfxPlatform::GetPlatform()->CreateOffscreenDrawTarget(IntSize(1,1), FORMAT_B8G8R8A8);
} else {
mDrawTarget = mWidget->StartRemoteDrawing();
}
if (!mDrawTarget) {
if (aRenderBoundsOut) {
@ -395,13 +402,28 @@ BasicCompositor::EndFrame()
mCopyTarget->SetOperator(gfxContext::OPERATOR_SOURCE);
mCopyTarget->SetSource(thebes);
mCopyTarget->Paint();
mCopyTarget = nullptr;
} else {
// Most platforms require us to buffer drawing to the widget surface.
// That's why we don't draw to mDrawTarget directly.
RefPtr<SourceSurface> source = mRenderTarget->mDrawTarget->Snapshot();
mDrawTarget->DrawSurface(source,
Rect(0, 0, mWidgetSize.width, mWidgetSize.height),
Rect(0, 0, mWidgetSize.width, mWidgetSize.height),
DrawSurfaceOptions(),
DrawOptions());
mWidget->EndRemoteDrawing();
}
mDrawTarget = nullptr;
mRenderTarget = nullptr;
}
void
BasicCompositor::AbortFrame()
{
mDrawTarget->PopClip();
mRenderTarget->mDrawTarget->PopClip();
mDrawTarget = nullptr;
mRenderTarget = nullptr;
}
}

View File

@ -34,7 +34,7 @@ public:
virtual bool Initialize() MOZ_OVERRIDE { return true; };
virtual void Destroy() MOZ_OVERRIDE { };
virtual void Destroy() MOZ_OVERRIDE;
virtual TextureFactoryIdentifier GetTextureFactoryIdentifier() MOZ_OVERRIDE
{

View File

@ -55,7 +55,7 @@ public:
virtual void FlushRendering() MOZ_OVERRIDE;
virtual bool NeedsWidgetInvalidation() MOZ_OVERRIDE { return Compositor::GetBackend() == LAYERS_BASIC; }
virtual bool NeedsWidgetInvalidation() MOZ_OVERRIDE { return false; }
ShadowableLayer* Hold(Layer* aLayer);

View File

@ -126,6 +126,14 @@ ProgramProfileOGL::GetProfileFor(ShaderProgramType aType,
AddCommonTextureArgs(result);
result.mTextureCount = 1;
break;
case BGRARectLayerProgramType:
MOZ_ASSERT(aMask == MaskNone, "BGRARectLayerProgramType can't handle masks.");
result.mVertexShaderString = sLayerVS;
result.mFragmentShaderString = sBGRARectTextureLayerFS;
AddCommonArgs(result);
AddCommonTextureArgs(result);
result.mTextureCount = 1;
break;
case RGBAExternalLayerProgramType:
if (aMask == Mask3d) {
result.mVertexShaderString = sLayerMask3DVS;

View File

@ -37,6 +37,7 @@ enum ShaderProgramType {
RGBXLayerProgramType,
BGRXLayerProgramType,
RGBARectLayerProgramType,
BGRARectLayerProgramType,
RGBAExternalLayerProgramType,
ColorLayerProgramType,
YCbCrLayerProgramType,
@ -126,6 +127,10 @@ struct ProgramProfileOGL
aType == Copy2DRectProgramType))
return false;
if (aMask != MaskNone &&
aType == BGRARectLayerProgramType)
return false;
return aMask != Mask3d ||
aType == RGBARectLayerProgramType ||
aType == RGBALayerProgramType;

View File

@ -473,6 +473,34 @@ gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n\
#endif\n\
";
static const char sBGRARectTextureLayerFS[] = "/* sBGRARectTextureLayerFS */\n\
#extension GL_ARB_texture_rectangle : enable\n\
/* Fragment Shader */\n\
#ifdef GL_ES\n\
#ifdef MEDIUMP_SHADER\n\
precision mediump float;\n\
#else\n\
precision lowp float;\n\
#endif\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 sampler2DRect uTexture;\n\
uniform vec2 uTexCoordMultiplier;\n\
void main()\n\
{\n\
gl_FragColor = texture2DRect(uTexture, vec2(vTexCoord * uTexCoordMultiplier)).bgra * uLayerOpacity;\n\
}\n\
";
static const char sRGBAExternalTextureLayerFS[] = "/* sRGBAExternalTextureLayerFS */\n\
#extension GL_OES_EGL_image_external : require\n\
/* Fragment Shader */\n\

View File

@ -257,6 +257,22 @@ void main()
#endif
@end
// Single texture in BGRA format, but with a Rect texture.
// nsChildView needs this for old Mac hardware.
@shader sBGRARectTextureLayerFS
#extension GL_ARB_texture_rectangle : enable
$LAYER_FRAGMENT<>$
uniform sampler2DRect uTexture;
uniform vec2 uTexCoordMultiplier;
void main()
{
gl_FragColor = texture2DRect(uTexture, vec2(vTexCoord * uTexCoordMultiplier)).bgra * uLayerOpacity;
}
@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

View File

@ -577,6 +577,12 @@ gfxUtils::ClipToRegion(gfxContext* aContext, const nsIntRegion& aRegion)
ClipToRegionInternal(aContext, aRegion, false);
}
/*static*/ void
gfxUtils::ClipToRegion(DrawTarget* aTarget, const nsIntRegion& aRegion)
{
ClipToRegionInternal(aTarget, aRegion, false);
}
/*static*/ void
gfxUtils::ClipToRegionSnapped(gfxContext* aContext, const nsIntRegion& aRegion)
{

View File

@ -66,13 +66,18 @@ public:
*/
static void ClipToRegion(gfxContext* aContext, const nsIntRegion& aRegion);
/**
* Clip aTarget to the region aRegion.
*/
static void ClipToRegion(mozilla::gfx::DrawTarget* aTarget, const nsIntRegion& aRegion);
/**
* Clip aContext to the region aRegion, snapping the rectangles.
*/
static void ClipToRegionSnapped(gfxContext* aContext, const nsIntRegion& aRegion);
/**
* Clip aContext to the region aRegion, snapping the rectangles.
* Clip aTarget to the region aRegion, snapping the rectangles.
*/
static void ClipToRegionSnapped(mozilla::gfx::DrawTarget* aTarget, const nsIntRegion& aRegion);

View File

@ -84,11 +84,12 @@ class nsChildView;
class nsCocoaWindow;
union nsPluginPort;
namespace mozilla {
namespace gl {
class TextureImage;
namespace {
class GLPresenter;
class RectTextureImage;
}
namespace mozilla {
namespace layers {
class GLManager;
}
@ -572,6 +573,10 @@ public:
return nsCocoaUtils::DevPixelsToCocoaPoints(aRect, BackingScaleFactor());
}
mozilla::TemporaryRef<mozilla::gfx::DrawTarget> StartRemoteDrawing() MOZ_OVERRIDE;
void EndRemoteDrawing() MOZ_OVERRIDE;
void CleanupRemoteDrawing() MOZ_OVERRIDE;
protected:
void ReportMoveEvent();
@ -590,7 +595,10 @@ protected:
return widget.forget();
}
void DoRemoteComposition(const nsIntRect& aRenderRect);
// Overlay drawing functions for OpenGL drawing
void DrawWindowOverlay(mozilla::layers::GLManager* aManager, nsIntRect aRect);
void MaybeDrawResizeIndicator(mozilla::layers::GLManager* aManager, const nsIntRect& aRect);
void MaybeDrawRoundedCorners(mozilla::layers::GLManager* aManager, const nsIntRect& aRect);
void MaybeDrawTitlebar(mozilla::layers::GLManager* aManager, const nsIntRect& aRect);
@ -599,10 +607,6 @@ protected:
// determined by mDirtyTitlebarRegion.
void UpdateTitlebarImageBuffer();
// Upload the contents of mTitlebarImageBuffer to mTitlebarImage on the
// compositor thread, as determined by mUpdatedTitlebarRegion.
void UpdateTitlebarImage(mozilla::layers::GLManager* aManager, const nsIntRect& aRect);
nsIntRect RectContainingTitlebarControls();
nsIWidget* GetWidgetForListenerEvents();
@ -640,14 +644,13 @@ protected:
// transaction. Accessed from any thread, protected by mEffectsLock.
nsIntRegion mUpdatedTitlebarRegion;
nsRefPtr<gfxQuartzSurface> mTitlebarImageBuffer;
mozilla::RefPtr<mozilla::gfx::DrawTarget> mTitlebarImageBuffer;
// Compositor thread only
bool mFailedResizerImage;
bool mFailedCornerMaskImage;
nsRefPtr<mozilla::gl::TextureImage> mResizerImage;
nsRefPtr<mozilla::gl::TextureImage> mCornerMaskImage;
nsRefPtr<mozilla::gl::TextureImage> mTitlebarImage;
nsAutoPtr<RectTextureImage> mResizerImage;
nsAutoPtr<RectTextureImage> mCornerMaskImage;
nsAutoPtr<RectTextureImage> mTitlebarImage;
nsAutoPtr<RectTextureImage> mBasicCompositorImage;
// The area of mTitlebarImageBuffer that has changed and needs to be
// uploaded to to mTitlebarImage. Main thread only.
@ -667,6 +670,10 @@ protected:
NP_CGContext mPluginCGContext;
nsIPluginInstanceOwner* mPluginInstanceOwner; // [WEAK]
// Used in OMTC BasicLayers mode. Presents the BasicCompositor result
// surface to the screen using an OpenGL context.
nsAutoPtr<GLPresenter> mGLPresenter;
static uint32_t sLastInputEventCount;
};

View File

@ -55,9 +55,13 @@
#include "ClientLayerManager.h"
#include "mozilla/layers/LayerManagerComposite.h"
#include "GLTextureImage.h"
#include "GLContextProvider.h"
#include "mozilla/layers/GLManager.h"
#include "mozilla/layers/CompositorCocoaWidgetHelper.h"
#include "mozilla/layers/CompositorOGL.h"
#include "mozilla/layers/BasicCompositor.h"
#include "gfxUtils.h"
#include "mozilla/gfx/2D.h"
#ifdef ACCESSIBILITY
#include "nsAccessibilityService.h"
#include "mozilla/a11y/Platform.h"
@ -243,6 +247,103 @@ void EnsureLogInitialized()
#endif // PR_LOGGING
}
namespace {
// Manages a texture which can resize dynamically, binds to the
// LOCAL_GL_TEXTURE_RECTANGLE_ARB texture target and is automatically backed
// by a power-of-two size GL texture. The latter two features are used for
// compatibility with older Mac hardware which we block GL layers on.
// RectTextureImages are used both for accelerated GL layers drawing and for
// OMTC BasicLayers drawing.
class RectTextureImage {
public:
RectTextureImage(GLContext* aGLContext)
: mGLContext(aGLContext)
, mTexture(0)
, mInUpdate(false)
{}
virtual ~RectTextureImage();
TemporaryRef<gfx::DrawTarget>
BeginUpdate(const nsIntSize& aNewSize,
const nsIntRegion& aDirtyRegion = nsIntRegion());
void EndUpdate(bool aKeepSurface = false);
void UpdateIfNeeded(const nsIntSize& aNewSize,
const nsIntRegion& aDirtyRegion,
void (^aCallback)(gfx::DrawTarget*, const nsIntRegion&))
{
RefPtr<gfx::DrawTarget> drawTarget = BeginUpdate(aNewSize, aDirtyRegion);
if (drawTarget) {
aCallback(drawTarget, GetUpdateRegion());
EndUpdate();
}
}
nsIntRegion GetUpdateRegion() {
MOZ_ASSERT(mInUpdate, "update region only valid during update");
return mUpdateRegion;
}
void Draw(mozilla::layers::GLManager* aManager,
const nsIntPoint& aLocation,
const gfx3DMatrix& aTransform = gfx3DMatrix());
protected:
nsIntSize TextureSizeForSize(const nsIntSize& aSize);
RefPtr<gfx::DrawTarget> mUpdateDrawTarget;
GLContext* mGLContext;
nsIntRegion mUpdateRegion;
nsIntSize mUsedSize;
nsIntSize mBufferSize;
nsIntSize mTextureSize;
GLuint mTexture;
bool mInUpdate;
};
// Used for OpenGL drawing from the compositor thread for OMTC BasicLayers.
// We need to use OpenGL for this because there seems to be no other robust
// way of drawing from a secondary thread without locking, which would cause
// deadlocks in our setup. See bug 882523.
class GLPresenter : public GLManager
{
public:
static GLPresenter* CreateForWindow(nsIWidget* aWindow)
{
nsRefPtr<GLContext> context = gl::GLContextProvider::CreateForWindow(aWindow);
return context ? new GLPresenter(context) : nullptr;
}
GLPresenter(GLContext* aContext);
virtual ~GLPresenter();
virtual GLContext* gl() const MOZ_OVERRIDE { return mGLContext; }
virtual ShaderProgramOGL* GetProgram(ShaderProgramType aType) MOZ_OVERRIDE
{
MOZ_ASSERT(aType == BGRARectLayerProgramType, "unexpected program type");
return mBGRARectProgram;
}
virtual void BindAndDrawQuad(ShaderProgramOGL *aProg) MOZ_OVERRIDE;
void BeginFrame(nsIntSize aRenderSize);
void EndFrame();
NSOpenGLContext* GetNSOpenGLContext()
{
return static_cast<NSOpenGLContext*>(
mGLContext->GetNativeData(GLContext::NativeGLContext));
}
protected:
nsRefPtr<mozilla::gl::GLContext> mGLContext;
nsAutoPtr<mozilla::layers::ShaderProgramOGL> mBGRARectProgram;
GLuint mQuadVBO;
};
} // unnamed namespace
#pragma mark -
nsChildView::nsChildView() : nsBaseWidget()
@ -253,8 +354,6 @@ nsChildView::nsChildView() : nsBaseWidget()
, mShowsResizeIndicator(false)
, mHasRoundedBottomCorners(false)
, mIsCoveringTitlebar(false)
, mFailedResizerImage(false)
, mFailedCornerMaskImage(false)
, mBackingScaleFactor(0.0)
, mVisible(false)
, mDrawing(false)
@ -1387,8 +1486,7 @@ NS_IMETHODIMP nsChildView::Invalidate(const nsIntRect &aRect)
if (!mView || !mVisible)
return NS_OK;
NS_ASSERTION(GetLayerManager()->GetBackendType() != LAYERS_CLIENT ||
Compositor::GetBackend() == LAYERS_BASIC,
NS_ASSERTION(GetLayerManager()->GetBackendType() != LAYERS_CLIENT,
"Shouldn't need to invalidate with accelerated OMTC layers!");
if ([NSView focusView]) {
@ -1419,11 +1517,20 @@ nsChildView::ComputeShouldAccelerate(bool aDefault)
bool
nsChildView::ShouldUseOffMainThreadCompositing()
{
// OMTC doesn't work with Basic Layers on OS X right now. Once it works, we'll
// still want to disable it for certain kinds of windows (e.g. popups).
return nsBaseWidget::ShouldUseOffMainThreadCompositing() &&
(ComputeShouldAccelerate(mUseLayersAcceleration) ||
Preferences::GetBool("layers.offmainthreadcomposition.prefer-basic", false));
// When acceleration is off, default to false, but allow force-enabling
// using the layers.offmainthreadcomposition.prefer-basic pref.
if (!ComputeShouldAccelerate(mUseLayersAcceleration) &&
!Preferences::GetBool("layers.offmainthreadcomposition.prefer-basic", false)) {
return false;
}
// Don't use OMTC (which requires OpenGL) for transparent windows or for
// popup windows.
if (!mView || ![[mView window] isOpaque] ||
[[mView window] isKindOfClass:[PopupWindow class]])
return false;
return nsBaseWidget::ShouldUseOffMainThreadCompositing();
}
inline uint16_t COLOR8TOCOLOR16(uint8_t color8)
@ -1908,26 +2015,25 @@ void
nsChildView::DrawWindowOverlay(LayerManager* aManager, nsIntRect aRect)
{
nsAutoPtr<GLManager> manager(GLManager::CreateGLManager(aManager));
if (!manager) {
return;
if (manager) {
DrawWindowOverlay(manager, aRect);
}
}
manager->gl()->PushScissorRect(aRect);
MaybeDrawTitlebar(manager, aRect);
MaybeDrawResizeIndicator(manager, aRect);
MaybeDrawRoundedCorners(manager, aRect);
manager->gl()->PopScissorRect();
void
nsChildView::DrawWindowOverlay(GLManager* aManager, nsIntRect aRect)
{
MaybeDrawTitlebar(aManager, aRect);
MaybeDrawResizeIndicator(aManager, aRect);
MaybeDrawRoundedCorners(aManager, aRect);
}
static void
ClearRegion(gfxASurface* aSurface, nsIntRegion aRegion)
ClearRegion(gfx::DrawTarget *aDT, nsIntRegion aRegion)
{
nsRefPtr<gfxContext> ctx = new gfxContext(aSurface);
gfxUtils::ClipToRegion(ctx, aRegion);
ctx->SetOperator(gfxContext::OPERATOR_CLEAR);
ctx->Paint();
gfxUtils::ClipToRegion(aDT, aRegion);
aDT->ClearRect(gfx::Rect(0, 0, aDT->GetSize().width, aDT->GetSize().height));
aDT->PopClip();
}
static void
@ -1967,66 +2073,21 @@ void
nsChildView::MaybeDrawResizeIndicator(GLManager* aManager, const nsIntRect& aRect)
{
MutexAutoLock lock(mEffectsLock);
if (!mShowsResizeIndicator || mFailedResizerImage) {
if (!mShowsResizeIndicator) {
return;
}
if (!mResizerImage) {
mResizerImage =
aManager->gl()->CreateTextureImage(nsIntSize(mResizeIndicatorRect.width,
mResizeIndicatorRect.height),
gfxASurface::CONTENT_COLOR_ALPHA,
LOCAL_GL_CLAMP_TO_EDGE,
TextureImage::UseNearestFilter);
// Creation of texture images can fail.
if (!mResizerImage)
return;
nsIntRegion update(nsIntRect(0, 0, mResizeIndicatorRect.width, mResizeIndicatorRect.height));
gfxASurface *asurf = mResizerImage->BeginUpdate(update);
if (!asurf) {
mResizerImage = nullptr;
return;
}
// We need a Quartz surface because DrawResizer wants a CGContext.
if (asurf->GetType() != gfxASurface::SurfaceTypeQuartz) {
NS_WARN_IF_FALSE(FALSE, "mResizerImage's surface is not Quartz");
mResizerImage->EndUpdate();
mResizerImage = nullptr;
mFailedResizerImage = true;
return;
}
ClearRegion(asurf, update);
nsRefPtr<gfxQuartzSurface> image = static_cast<gfxQuartzSurface*>(asurf);
DrawResizer(image->GetCGContext());
mResizerImage->EndUpdate();
mResizerImage = new RectTextureImage(aManager->gl());
}
NS_ABORT_IF_FALSE(mResizerImage, "Must have a texture allocated by now!");
nsIntSize size = mResizeIndicatorRect.Size();
mResizerImage->UpdateIfNeeded(size, nsIntRegion(), ^(gfx::DrawTarget* drawTarget, const nsIntRegion& updateRegion) {
ClearRegion(drawTarget, updateRegion);
DrawResizer(static_cast<CGContextRef>(drawTarget->GetNativeSurface(gfx::NATIVE_SURFACE_CGCONTEXT)));
});
float bottomX = aRect.XMost();
float bottomY = aRect.YMost();
TextureImage::ScopedBindTexture texBind(mResizerImage, LOCAL_GL_TEXTURE0);
ShaderProgramOGL *program =
aManager->GetProgram(mResizerImage->GetTextureFormat());
program->Activate();
program->SetLayerQuadRect(nsIntRect(bottomX - resizeIndicatorWidth,
bottomY - resizeIndicatorHeight,
resizeIndicatorWidth,
resizeIndicatorHeight));
program->SetLayerTransform(gfx3DMatrix());
program->SetLayerOpacity(1.0);
program->SetRenderOffset(nsIntPoint(0,0));
program->SetTextureUnit(0);
aManager->BindAndDrawQuad(program);
mResizerImage->Draw(aManager, mResizeIndicatorRect.TopLeft());
}
// Draw the highlight line at the top of the titlebar.
@ -2066,12 +2127,14 @@ nsChildView::UpdateTitlebarImageBuffer()
nsIntRegion dirtyTitlebarRegion = mDirtyTitlebarRegion;
mDirtyTitlebarRegion.SetEmpty();
gfx::IntSize titlebarSize(mTitlebarRect.width, mTitlebarRect.height);
if (!mTitlebarImageBuffer ||
mTitlebarImageBuffer->GetSize() != mTitlebarRect.Size()) {
mTitlebarImageBuffer->GetSize() != titlebarSize) {
dirtyTitlebarRegion = mTitlebarRect;
mTitlebarImageBuffer = new gfxQuartzSurface(mTitlebarRect.Size(),
gfxASurface::ImageFormatARGB32);
mTitlebarImageBuffer =
gfx::Factory::CreateDrawTarget(gfx::BACKEND_COREGRAPHICS, titlebarSize,
gfx::FORMAT_B8G8R8A8);
}
if (dirtyTitlebarRegion.IsEmpty())
@ -2079,7 +2142,8 @@ nsChildView::UpdateTitlebarImageBuffer()
ClearRegion(mTitlebarImageBuffer, dirtyTitlebarRegion);
CGContextRef ctx = mTitlebarImageBuffer->GetCGContext();
CGContextRef ctx =
static_cast<CGContextRef>(mTitlebarImageBuffer->GetNativeSurface(gfx::NATIVE_SURFACE_CGCONTEXT));
CGContextSaveGState(ctx);
double scale = BackingScaleFactor();
@ -2151,45 +2215,6 @@ nsChildView::UpdateTitlebarImageBuffer()
mUpdatedTitlebarRegion.Or(mUpdatedTitlebarRegion, dirtyTitlebarRegion);
}
// When this method is entered, mEffectsLock is already being held.
void
nsChildView::UpdateTitlebarImage(GLManager* aManager, const nsIntRect& aRect)
{
nsIntRegion updatedTitlebarRegion;
updatedTitlebarRegion.And(mUpdatedTitlebarRegion, mTitlebarRect);
mUpdatedTitlebarRegion.SetEmpty();
if (!mTitlebarImage || mTitlebarImage->GetSize() != mTitlebarRect.Size()) {
updatedTitlebarRegion = mTitlebarRect;
mTitlebarImage =
aManager->gl()->CreateTextureImage(mTitlebarRect.Size(),
gfxASurface::CONTENT_COLOR_ALPHA,
LOCAL_GL_CLAMP_TO_EDGE,
TextureImage::UseNearestFilter);
// Creation of texture images can fail.
if (!mTitlebarImage)
return;
}
if (updatedTitlebarRegion.IsEmpty())
return;
gfxASurface *asurf = mTitlebarImage->BeginUpdate(updatedTitlebarRegion);
if (!asurf) {
mTitlebarImage = nullptr;
return;
}
nsRefPtr<gfxContext> ctx = new gfxContext(asurf);
ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
ctx->SetSource(mTitlebarImageBuffer);
ctx->Paint();
mTitlebarImage->EndUpdate();
}
// This method draws an overlay in the top of the window which contains the
// titlebar controls (e.g. close, min, zoom, fullscreen) and the titlebar
// highlight effect.
@ -2208,25 +2233,26 @@ nsChildView::MaybeDrawTitlebar(GLManager* aManager, const nsIntRect& aRect)
return;
}
UpdateTitlebarImage(aManager, aRect);
nsIntRegion updatedTitlebarRegion;
updatedTitlebarRegion.And(mUpdatedTitlebarRegion, mTitlebarRect);
mUpdatedTitlebarRegion.SetEmpty();
if (!mTitlebarImage) {
return;
mTitlebarImage = new RectTextureImage(aManager->gl());
}
TextureImage::ScopedBindTexture texBind(mTitlebarImage, LOCAL_GL_TEXTURE0);
mTitlebarImage->UpdateIfNeeded(mTitlebarRect.Size(), updatedTitlebarRegion,
^(gfx::DrawTarget* drawTarget, const nsIntRegion& updateRegion) {
RefPtr<gfx::SourceSurface> source = mTitlebarImageBuffer->Snapshot();
gfx::Rect rect(0, 0, mTitlebarRect.width, mTitlebarRect.height);
gfxUtils::ClipToRegion(drawTarget, updateRegion);
drawTarget->DrawSurface(source, rect, rect,
gfx::DrawSurfaceOptions(),
gfx::DrawOptions(1.0, gfx::OP_SOURCE));
drawTarget->PopClip();
});
ShaderProgramOGL *program =
aManager->GetProgram(mTitlebarImage->GetTextureFormat());
program->Activate();
program->SetLayerQuadRect(nsIntRect(nsIntPoint(0, 0),
mTitlebarImage->GetSize()));
program->SetLayerTransform(gfx3DMatrix());
program->SetLayerOpacity(1.0);
program->SetRenderOffset(nsIntPoint(0,0));
program->SetTextureUnit(0);
aManager->BindAndDrawQuad(program);
mTitlebarImage->Draw(aManager, mTitlebarRect.TopLeft());
}
static void
@ -2240,81 +2266,35 @@ void
nsChildView::MaybeDrawRoundedCorners(GLManager* aManager, const nsIntRect& aRect)
{
MutexAutoLock lock(mEffectsLock);
if (mFailedCornerMaskImage) {
return;
if (!mCornerMaskImage) {
mCornerMaskImage = new RectTextureImage(aManager->gl());
}
if (!mCornerMaskImage ||
mCornerMaskImage->GetSize().width != mDevPixelCornerRadius) {
mCornerMaskImage =
aManager->gl()->CreateTextureImage(nsIntSize(mDevPixelCornerRadius,
mDevPixelCornerRadius),
gfxASurface::CONTENT_COLOR_ALPHA,
LOCAL_GL_CLAMP_TO_EDGE,
TextureImage::UseNearestFilter);
// Creation of texture images can fail.
if (!mCornerMaskImage)
return;
nsIntRegion update(nsIntRect(0, 0, mDevPixelCornerRadius, mDevPixelCornerRadius));
gfxASurface *asurf = mCornerMaskImage->BeginUpdate(update);
if (!asurf) {
mCornerMaskImage = nullptr;
return;
}
if (asurf->GetType() != gfxASurface::SurfaceTypeQuartz) {
NS_WARNING("mCornerMaskImage's surface is not Quartz");
mCornerMaskImage->EndUpdate();
mCornerMaskImage = nullptr;
mFailedCornerMaskImage = true;
return;
}
ClearRegion(asurf, update);
nsRefPtr<gfxQuartzSurface> image = static_cast<gfxQuartzSurface*>(asurf);
DrawTopLeftCornerMask(image->GetCGContext(), mDevPixelCornerRadius);
mCornerMaskImage->EndUpdate();
}
NS_ABORT_IF_FALSE(mCornerMaskImage, "Must have a texture allocated by now!");
TextureImage::ScopedBindTexture texBind(mCornerMaskImage, LOCAL_GL_TEXTURE0);
ShaderProgramOGL *program = aManager->GetProgram(mCornerMaskImage->GetTextureFormat());
program->Activate();
program->SetLayerQuadRect(nsIntRect(nsIntPoint(0, 0),
mCornerMaskImage->GetSize()));
program->SetLayerOpacity(1.0);
program->SetRenderOffset(nsIntPoint(0,0));
program->SetTextureUnit(0);
nsIntSize size(mDevPixelCornerRadius, mDevPixelCornerRadius);
mCornerMaskImage->UpdateIfNeeded(size, nsIntRegion(), ^(gfx::DrawTarget* drawTarget, const nsIntRegion& updateRegion) {
ClearRegion(drawTarget, updateRegion);
DrawTopLeftCornerMask(static_cast<CGContextRef>(drawTarget->GetNativeSurface(gfx::NATIVE_SURFACE_CGCONTEXT)),
mDevPixelCornerRadius);
});
// Use operator destination in: multiply all 4 channels with source alpha.
aManager->gl()->fBlendFuncSeparate(LOCAL_GL_ZERO, LOCAL_GL_SRC_ALPHA,
LOCAL_GL_ZERO, LOCAL_GL_SRC_ALPHA);
gfx3DMatrix flipX = gfx3DMatrix::ScalingMatrix(-1, 1, 1);
gfx3DMatrix flipY = gfx3DMatrix::ScalingMatrix(1, -1, 1);
if (mIsCoveringTitlebar) {
// Mask the top corners.
program->SetLayerTransform(gfx3DMatrix::ScalingMatrix(1, 1, 1) *
gfx3DMatrix::Translation(0, 0, 0));
aManager->BindAndDrawQuad(program);
program->SetLayerTransform(gfx3DMatrix::ScalingMatrix(-1, 1, 1) *
gfx3DMatrix::Translation(aRect.width, 0, 0));
aManager->BindAndDrawQuad(program);
mCornerMaskImage->Draw(aManager, aRect.TopLeft());
mCornerMaskImage->Draw(aManager, aRect.TopRight(), flipX);
}
if (mHasRoundedBottomCorners) {
// Mask the bottom corners.
program->SetLayerTransform(gfx3DMatrix::ScalingMatrix(1, -1, 1) *
gfx3DMatrix::Translation(0, aRect.height, 0));
aManager->BindAndDrawQuad(program);
program->SetLayerTransform(gfx3DMatrix::ScalingMatrix(-1, -1, 1) *
gfx3DMatrix::Translation(aRect.width, aRect.height, 0));
aManager->BindAndDrawQuad(program);
mCornerMaskImage->Draw(aManager, aRect.BottomLeft(), flipY);
mCornerMaskImage->Draw(aManager, aRect.BottomRight(), flipY * flipX);
}
// Reset blend mode.
@ -2376,6 +2356,69 @@ nsChildView::UpdateThemeGeometries(const nsTArray<ThemeGeometry>& aThemeGeometri
[win setUnifiedToolbarHeight:DevPixelsToCocoaPoints(devUnifiedHeight)];
}
TemporaryRef<gfx::DrawTarget>
nsChildView::StartRemoteDrawing()
{
if (!mGLPresenter) {
mGLPresenter = GLPresenter::CreateForWindow(this);
if (!mGLPresenter) {
return nullptr;
}
}
nsIntRegion dirtyRegion = mBounds;
nsIntSize renderSize = mBounds.Size();
if (!mBasicCompositorImage) {
mBasicCompositorImage = new RectTextureImage(mGLPresenter->gl());
}
RefPtr<gfx::DrawTarget> drawTarget =
mBasicCompositorImage->BeginUpdate(renderSize, dirtyRegion);
if (!drawTarget) {
// Composite unchanged textures.
DoRemoteComposition(mBounds);
return nullptr;
}
return drawTarget;
}
void
nsChildView::EndRemoteDrawing()
{
mBasicCompositorImage->EndUpdate(true);
DoRemoteComposition(mBounds);
}
void
nsChildView::CleanupRemoteDrawing()
{
mBasicCompositorImage = nullptr;
mCornerMaskImage = nullptr;
mResizerImage = nullptr;
mTitlebarImage = nullptr;
mGLPresenter = nullptr;
}
void
nsChildView::DoRemoteComposition(const nsIntRect& aRenderRect)
{
[(ChildView*)mView preRender:mGLPresenter->GetNSOpenGLContext()];
mGLPresenter->BeginFrame(aRenderRect.Size());
// Draw the result from the basic compositor.
mBasicCompositorImage->Draw(mGLPresenter, nsIntPoint(0, 0));
// DrawWindowOverlay doesn't do anything for non-GL, so it didn't paint
// anything during the basic compositor transaction. Draw the overlay now.
DrawWindowOverlay(mGLPresenter, aRenderRect);
mGLPresenter->EndFrame();
}
#ifdef ACCESSIBILITY
already_AddRefed<a11y::Accessible>
nsChildView::GetDocumentAccessible()
@ -2399,6 +2442,211 @@ nsChildView::GetDocumentAccessible()
}
#endif
// RectTextureImage implementation
RectTextureImage::~RectTextureImage()
{
if (mTexture) {
mGLContext->MakeCurrent();
mGLContext->fDeleteTextures(1, &mTexture);
mTexture = 0;
}
}
nsIntSize
RectTextureImage::TextureSizeForSize(const nsIntSize& aSize)
{
return nsIntSize(gfx::NextPowerOfTwo(aSize.width),
gfx::NextPowerOfTwo(aSize.height));
}
TemporaryRef<gfx::DrawTarget>
RectTextureImage::BeginUpdate(const nsIntSize& aNewSize,
const nsIntRegion& aDirtyRegion)
{
MOZ_ASSERT(!mInUpdate, "Beginning update during update!");
mUpdateRegion = aDirtyRegion;
if (aNewSize != mUsedSize) {
mUsedSize = aNewSize;
mUpdateRegion = nsIntRect(nsIntPoint(0, 0), aNewSize);
}
if (mUpdateRegion.IsEmpty()) {
return nullptr;
}
nsIntSize neededBufferSize = TextureSizeForSize(mUsedSize);
if (!mUpdateDrawTarget || mBufferSize != neededBufferSize) {
gfx::IntSize size(neededBufferSize.width, neededBufferSize.height);
mUpdateDrawTarget =
gfx::Factory::CreateDrawTarget(gfx::BACKEND_COREGRAPHICS, size,
gfx::FORMAT_B8G8R8A8);
mBufferSize = neededBufferSize;
}
mInUpdate = true;
RefPtr<gfx::DrawTarget> drawTarget = mUpdateDrawTarget;
return drawTarget;
}
#define NSFoundationVersionWithProperStrideSupportForSubtextureUpload NSFoundationVersionNumber10_6_3
static bool
CanUploadSubtextures()
{
return NSFoundationVersionNumber >= NSFoundationVersionWithProperStrideSupportForSubtextureUpload;
}
void
RectTextureImage::EndUpdate(bool aKeepSurface)
{
MOZ_ASSERT(mInUpdate, "Ending update while not in update");
bool overwriteTexture = false;
nsIntRegion updateRegion = mUpdateRegion;
if (!mTexture || (mTextureSize != mBufferSize)) {
overwriteTexture = true;
mTextureSize = mBufferSize;
}
if (overwriteTexture || !CanUploadSubtextures()) {
updateRegion = nsIntRect(nsIntPoint(0, 0), mTextureSize);
}
RefPtr<gfx::SourceSurface> snapshot = mUpdateDrawTarget->Snapshot();
RefPtr<gfx::DataSourceSurface> dataSnapshot = snapshot->GetDataSurface();
mGLContext->UploadSurfaceToTexture(dataSnapshot,
updateRegion,
mTexture,
overwriteTexture,
updateRegion.GetBounds().TopLeft(),
false,
LOCAL_GL_TEXTURE0,
LOCAL_GL_TEXTURE_RECTANGLE_ARB);
if (!aKeepSurface) {
mUpdateDrawTarget = nullptr;
}
mInUpdate = false;
}
void
RectTextureImage::Draw(GLManager* aManager,
const nsIntPoint& aLocation,
const gfx3DMatrix& aTransform)
{
ShaderProgramOGL* program = aManager->GetProgram(BGRARectLayerProgramType);
aManager->gl()->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, mTexture);
program->Activate();
program->SetLayerQuadRect(nsIntRect(nsIntPoint(0, 0), mUsedSize));
program->SetLayerTransform(aTransform * gfx3DMatrix::Translation(aLocation.x, aLocation.y, 0));
program->SetLayerOpacity(1.0);
program->SetRenderOffset(nsIntPoint(0, 0));
program->SetTexCoordMultiplier(mUsedSize.width, mUsedSize.height);
program->SetTextureUnit(0);
aManager->BindAndDrawQuad(program);
aManager->gl()->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
}
// GLPresenter implementation
GLPresenter::GLPresenter(GLContext* aContext)
: mGLContext(aContext)
{
mGLContext->SetFlipped(true);
mGLContext->MakeCurrent();
mBGRARectProgram = new ShaderProgramOGL(mGLContext,
ProgramProfileOGL::GetProfileFor(BGRARectLayerProgramType, MaskNone));
// Create mQuadVBO.
mGLContext->fGenBuffers(1, &mQuadVBO);
mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO);
GLfloat vertices[] = {
/* First quad vertices */
0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
/* Then quad texcoords */
0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
};
mGLContext->fBufferData(LOCAL_GL_ARRAY_BUFFER, sizeof(vertices), vertices, LOCAL_GL_STATIC_DRAW);
mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
}
GLPresenter::~GLPresenter()
{
if (mQuadVBO) {
mGLContext->MakeCurrent();
mGLContext->fDeleteBuffers(1, &mQuadVBO);
mQuadVBO = 0;
}
}
void
GLPresenter::BindAndDrawQuad(ShaderProgramOGL* aProgram)
{
mGLContext->MakeCurrent();
GLuint vertAttribIndex = aProgram->AttribLocation(ShaderProgramOGL::VertexCoordAttrib);
GLuint texCoordAttribIndex = aProgram->AttribLocation(ShaderProgramOGL::TexCoordAttrib);
mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO);
mGLContext->fVertexAttribPointer(vertAttribIndex, 2,
LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0,
(GLvoid*)0);
mGLContext->fEnableVertexAttribArray(vertAttribIndex);
mGLContext->fVertexAttribPointer(texCoordAttribIndex, 2,
LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0,
(GLvoid*) (sizeof(float)*4*2));
mGLContext->fEnableVertexAttribArray(texCoordAttribIndex);
mGLContext->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
mGLContext->fDisableVertexAttribArray(vertAttribIndex);
mGLContext->fDisableVertexAttribArray(texCoordAttribIndex);
}
void
GLPresenter::BeginFrame(nsIntSize aRenderSize)
{
mGLContext->MakeCurrent();
mGLContext->fViewport(0, 0, aRenderSize.width, aRenderSize.height);
// Matrix to transform (0, 0, width, height) to viewport space (-1.0, 1.0,
// 2, 2) and flip the contents.
gfxMatrix viewMatrix;
viewMatrix.Translate(-gfxPoint(1.0, -1.0));
viewMatrix.Scale(2.0f / float(aRenderSize.width), 2.0f / float(aRenderSize.height));
viewMatrix.Scale(1.0f, -1.0f);
gfx3DMatrix matrix3d = gfx3DMatrix::From2D(viewMatrix);
matrix3d._33 = 0.0f;
mBGRARectProgram->CheckAndSetProjectionMatrix(matrix3d);
// Default blend function implements "OVER"
mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
LOCAL_GL_ONE, LOCAL_GL_ONE);
mGLContext->fEnable(LOCAL_GL_BLEND);
mGLContext->fClearColor(0.0, 0.0, 0.0, 0.0);
mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT);
mGLContext->fEnable(LOCAL_GL_TEXTURE_RECTANGLE_ARB);
}
void
GLPresenter::EndFrame()
{
mGLContext->SwapBuffers();
mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
}
#pragma mark -
@implementation ChildView
@ -3075,10 +3323,6 @@ NSEvent* gLastDragMouseDownEvent = nil;
painted = mGeckoChild->PaintWindow(region);
} else if (mGeckoChild->GetLayerManager()->GetBackendType() == LAYERS_CLIENT) {
// We only need this so that we actually get DidPaintWindow fired
if (Compositor::GetBackend() == LAYERS_BASIC) {
ClientLayerManager *manager = static_cast<ClientLayerManager*>(mGeckoChild->GetLayerManager());
manager->SetShadowTarget(targetContext);
}
painted = mGeckoChild->PaintWindow(region);
}

View File

@ -5973,6 +5973,24 @@ nsWindow::GetSurfaceForGdkDrawable(GdkDrawable* aDrawable,
}
#endif
#if defined(MOZ_WIDGET_GTK2)
TemporaryRef<gfx::DrawTarget>
nsWindow::StartRemoteDrawing()
{
gfxASurface *surf = GetThebesSurface();
if (!surf) {
return nullptr;
}
gfx::IntSize size(surf->GetSize().width, surf->GetSize().height);
if (size.width <= 0 || size.height <= 0) {
return nullptr;
}
return gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(surf, size);
}
#endif
// return the gfxASurface for rendering to this widget
gfxASurface*
#if defined(MOZ_WIDGET_GTK2)

View File

@ -195,6 +195,10 @@ public:
guint aTime,
gpointer aData);
#if defined(MOZ_WIDGET_GTK2)
mozilla::TemporaryRef<mozilla::gfx::DrawTarget> StartRemoteDrawing() MOZ_OVERRIDE;
#endif
private:
void NativeResize(int32_t aWidth,
int32_t aHeight,

View File

@ -22,6 +22,7 @@
#include "nsTArray.h"
#include "nsXULAppAPI.h"
#include "mozilla/layers/LayersTypes.h"
#include "mozilla/RefPtr.h"
// forward declarations
class nsFontMetrics;
@ -47,6 +48,9 @@ class CompositorChild;
class LayerManager;
class PLayerTransactionChild;
}
namespace gfx {
class DrawTarget;
}
}
/**
@ -92,8 +96,8 @@ typedef nsEventStatus (* EVENT_CALLBACK)(nsGUIEvent *event);
#endif
#define NS_IWIDGET_IID \
{ 0x5b9152, 0x56c8, 0x4a2d, \
{ 0x94, 0x9e, 0xec, 0xf5, 0x3, 0x83, 0x3d, 0x48 } }
{ 0xa2900e47, 0x0021, 0x441c, \
{ 0x9e, 0x94, 0xd5, 0x61, 0x5a, 0x31, 0x5d, 0x7a } }
/*
* Window shadow styles
@ -1192,6 +1196,31 @@ class nsIWidget : public nsISupports {
*/
virtual void DrawWindowOverlay(LayerManager* aManager, nsIntRect aRect) = 0;
/**
* Return a DrawTarget for the window which can be composited into.
*
* Called by BasicCompositor on the compositor thread for OMTC drawing
* before each composition.
*/
virtual mozilla::TemporaryRef<mozilla::gfx::DrawTarget> StartRemoteDrawing() = 0;
/**
* Ensure that what was painted into the DrawTarget returned from
* StartRemoteDrawing reaches the screen.
*
* Called by BasicCompositor on the compositor thread for OMTC drawing
* after each composition.
*/
virtual void EndRemoteDrawing() = 0;
/**
* Clean up any resources used by Start/EndRemoteDrawing.
*
* Called by BasicCompositor on the compositor thread for OMTC drawing
* when the compositor is destroyed.
*/
virtual void CleanupRemoteDrawing() = 0;
/**
* Called when Gecko knows which themed widgets exist in this window.
* The passed array contains an entry for every themed widget of the right

View File

@ -38,6 +38,7 @@
#include "mozilla/Attributes.h"
#include "nsContentUtils.h"
#include "gfxPlatform.h"
#include "mozilla/gfx/2D.h"
#ifdef ACCESSIBILITY
#include "nsAccessibilityService.h"
@ -1031,6 +1032,11 @@ CompositorChild* nsBaseWidget::GetRemoteRenderer()
return mCompositorChild;
}
TemporaryRef<mozilla::gfx::DrawTarget> nsBaseWidget::StartRemoteDrawing()
{
return nullptr;
}
//-------------------------------------------------------------------------
//
// Return the used device context

View File

@ -137,6 +137,9 @@ public:
virtual void PreRender(LayerManager* aManager) {}
virtual void DrawWindowUnderlay(LayerManager* aManager, nsIntRect aRect) {}
virtual void DrawWindowOverlay(LayerManager* aManager, nsIntRect aRect) {}
virtual mozilla::TemporaryRef<mozilla::gfx::DrawTarget> StartRemoteDrawing();
virtual void EndRemoteDrawing() { };
virtual void CleanupRemoteDrawing() { };
virtual void UpdateThemeGeometries(const nsTArray<ThemeGeometry>& aThemeGeometries) {}
virtual gfxASurface* GetThebesSurface();
NS_IMETHOD SetModal(bool aModal);