diff --git a/gfx/gl/GLContext.cpp b/gfx/gl/GLContext.cpp index 35b702df10c..9f15bf0e025 100644 --- a/gfx/gl/GLContext.cpp +++ b/gfx/gl/GLContext.cpp @@ -2026,21 +2026,23 @@ 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; } ShaderProgramType -GLContext::UploadSurfaceToTexture(gfxASurface *aSurface, - const nsIntRegion& aDstRegion, - GLuint& aTexture, - bool aOverwrite, - const nsIntPoint& aSrcPoint, - bool aPixelBuffer, - GLenum aTextureUnit) +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(); @@ -2048,22 +2050,22 @@ GLContext::UploadSurfaceToTexture(gfxASurface *aSurface, if (!aTexture) { fGenTextures(1, &aTexture); - fBindTexture(LOCAL_GL_TEXTURE_2D, aTexture); - fTexParameteri(LOCAL_GL_TEXTURE_2D, + fBindTexture(aTextureTarget, aTexture); + fTexParameteri(aTextureTarget, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR); - fTexParameteri(LOCAL_GL_TEXTURE_2D, + fTexParameteri(aTextureTarget, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR); - fTexParameteri(LOCAL_GL_TEXTURE_2D, + fTexParameteri(aTextureTarget, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE); - fTexParameteri(LOCAL_GL_TEXTURE_2D, + fTexParameteri(aTextureTarget, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE); textureInited = false; } else { - fBindTexture(LOCAL_GL_TEXTURE_2D, aTexture); + fBindTexture(aTextureTarget, aTexture); } nsIntRegion paintRegion; @@ -2073,46 +2075,11 @@ GLContext::UploadSurfaceToTexture(gfxASurface *aSurface, paintRegion = aDstRegion; } - nsRefPtr imageSurface = aSurface->GetAsImageSurface(); - unsigned char* data = NULL; - - if (!imageSurface || - (imageSurface->Format() != gfxASurface::ImageFormatARGB32 && - imageSurface->Format() != gfxASurface::ImageFormatRGB24 && - imageSurface->Format() != gfxASurface::ImageFormatRGB16_565 && - imageSurface->Format() != gfxASurface::ImageFormatA8)) { - // We can't get suitable pixel data for the surface, make a copy - nsIntRect bounds = aDstRegion.GetBounds(); - imageSurface = - new gfxImageSurface(gfxIntSize(bounds.width, bounds.height), - gfxASurface::ImageFormatARGB32); - - nsRefPtr context = new gfxContext(imageSurface); - - context->Translate(-gfxPoint(aSrcPoint.x, aSrcPoint.y)); - context->SetSource(aSurface); - context->Paint(); - data = imageSurface->Data(); - NS_ASSERTION(!aPixelBuffer, - "Must be using an image compatible surface with pixel buffers!"); - } else { - // If a pixel buffer is bound the data pointer parameter is relative - // to the start of the data block. - if (!aPixelBuffer) { - data = imageSurface->Data(); - } - data += DataOffset(imageSurface, aSrcPoint); - } - - MOZ_ASSERT(imageSurface); - imageSurface->Flush(); - GLenum format; GLenum type; - int32_t pixelSize = gfxASurface::BytePerPixelFromFormat(imageSurface->Format()); + int32_t pixelSize = gfxASurface::BytePerPixelFromFormat(aFormat); ShaderProgramType shader; - - switch (imageSurface->Format()) { + switch (aFormat) { case gfxASurface::ImageFormatARGB32: format = LOCAL_GL_RGBA; type = LOCAL_GL_UNSIGNED_BYTE; @@ -2143,7 +2110,11 @@ GLContext::UploadSurfaceToTexture(gfxASurface *aSurface, shader = ShaderProgramType(0); } - int32_t stride = imageSurface->Stride(); + if (aTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB) { + MOZ_ASSERT(aFormat == gfxASurface::ImageFormatARGB32, + "unexpected format for rect texture"); + shader = BGRARectLayerProgramType; + } nsIntRegionRectIterator iter(paintRegion); const nsIntRect *iterRect; @@ -2156,30 +2127,30 @@ GLContext::UploadSurfaceToTexture(gfxASurface *aSurface, // 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); + 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(LOCAL_GL_TEXTURE_2D, + TexSubImage2D(aTextureTarget, 0, iterRect->x, iterRect->y, iterRect->width, iterRect->height, - stride, + aStride, pixelSize, format, type, rectData); } else { - TexImage2D(LOCAL_GL_TEXTURE_2D, + TexImage2D(aTextureTarget, 0, format, iterRect->width, iterRect->height, - stride, + aStride, pixelSize, 0, format, @@ -2192,6 +2163,97 @@ GLContext::UploadSurfaceToTexture(gfxASurface *aSurface, return shader; } +ShaderProgramType +GLContext::UploadSurfaceToTexture(gfxASurface *aSurface, + const nsIntRegion& aDstRegion, + GLuint& aTexture, + bool aOverwrite, + const nsIntPoint& aSrcPoint, + bool aPixelBuffer, + GLenum aTextureUnit, + GLenum aTextureTarget) +{ + + nsRefPtr imageSurface = aSurface->GetAsImageSurface(); + unsigned char* data = NULL; + + if (!imageSurface || + (imageSurface->Format() != gfxASurface::ImageFormatARGB32 && + imageSurface->Format() != gfxASurface::ImageFormatRGB24 && + imageSurface->Format() != gfxASurface::ImageFormatRGB16_565 && + imageSurface->Format() != gfxASurface::ImageFormatA8)) { + // We can't get suitable pixel data for the surface, make a copy + nsIntRect bounds = aDstRegion.GetBounds(); + imageSurface = + new gfxImageSurface(gfxIntSize(bounds.width, bounds.height), + gfxASurface::ImageFormatARGB32); + + nsRefPtr context = new gfxContext(imageSurface); + + context->Translate(-gfxPoint(aSrcPoint.x, aSrcPoint.y)); + context->SetSource(aSurface); + context->Paint(); + data = imageSurface->Data(); + NS_ASSERTION(!aPixelBuffer, + "Must be using an image compatible surface with pixel buffers!"); + } else { + // If a pixel buffer is bound the data pointer parameter is relative + // to the start of the data block. + if (!aPixelBuffer) { + data = imageSurface->Data(); + } + data += DataOffset(aSrcPoint, imageSurface->Stride(), + imageSurface->Format()); + } + + MOZ_ASSERT(imageSurface); + imageSurface->Flush(); + + return UploadImageDataToTexture(data, + imageSurface->Stride(), + imageSurface->Format(), + aDstRegion, aTexture, aOverwrite, + aPixelBuffer, aTextureUnit, aTextureTarget); +} + +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: + return gfxASurface::ImageFormatUnknown; + } +} + +ShaderProgramType +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) { if (!(aAddress & 0x7)) { diff --git a/gfx/gl/GLContext.h b/gfx/gl/GLContext.h index df8190d0441..c91ba55e20d 100644 --- a/gfx/gl/GLContext.h +++ b/gfx/gl/GLContext.h @@ -61,6 +61,7 @@ namespace android { namespace mozilla { namespace gfx { class SharedSurface; + class DataSourceSurface; struct SurfaceCaps; } @@ -864,7 +865,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. @@ -879,14 +880,39 @@ public: * texture unit being active. * \return Shader program needed to render this texture. */ + ShaderProgramType 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. + */ ShaderProgramType 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. + */ + ShaderProgramType 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, diff --git a/gfx/gl/GLContextTypes.h b/gfx/gl/GLContextTypes.h index 8b1b6f62483..b8f2b8e8111 100644 --- a/gfx/gl/GLContextTypes.h +++ b/gfx/gl/GLContextTypes.h @@ -22,6 +22,7 @@ enum ShaderProgramType { RGBXLayerProgramType, BGRXLayerProgramType, RGBARectLayerProgramType, + BGRARectLayerProgramType, RGBAExternalLayerProgramType, ColorLayerProgramType, YCbCrLayerProgramType, diff --git a/gfx/layers/basic/BasicCompositor.cpp b/gfx/layers/basic/BasicCompositor.cpp index 72cbc1d2793..0e11ceb8fe7 100644 --- a/gfx/layers/basic/BasicCompositor.cpp +++ b/gfx/layers/basic/BasicCompositor.cpp @@ -95,6 +95,7 @@ BasicCompositor::BasicCompositor(nsIWidget *aWidget) BasicCompositor::~BasicCompositor() { + mWidget->CleanupRemoteDrawing(); Destroy(); MOZ_COUNT_DTOR(BasicCompositor); } @@ -265,6 +266,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) { @@ -303,6 +306,17 @@ BasicCompositor::EndFrame() mCopyTarget->SetOperator(gfxContext::OPERATOR_SOURCE); mCopyTarget->SetSource(thebes); mCopyTarget->Paint(); + } else { + // Most platforms require us to buffer drawing to the widget surface. + // That's why we don't draw to mDrawTarget directly. + RefPtr source = mRenderTarget->mDrawTarget->Snapshot(); + mDrawTarget->DrawSurface(source, + Rect(0, 0, mWidgetSize.width, mWidgetSize.height), + Rect(0, 0, mWidgetSize.width, mWidgetSize.height), + DrawSurfaceOptions(), + DrawOptions()); + mDrawTarget = nullptr; + mWidget->EndRemoteDrawing(); } } diff --git a/gfx/layers/client/ClientLayerManager.h b/gfx/layers/client/ClientLayerManager.h index ef630073dce..9a05ed0d069 100644 --- a/gfx/layers/client/ClientLayerManager.h +++ b/gfx/layers/client/ClientLayerManager.h @@ -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); diff --git a/gfx/layers/opengl/LayerManagerOGLProgram.cpp b/gfx/layers/opengl/LayerManagerOGLProgram.cpp index 00cd3d00c93..4e2ee1bd931 100644 --- a/gfx/layers/opengl/LayerManagerOGLProgram.cpp +++ b/gfx/layers/opengl/LayerManagerOGLProgram.cpp @@ -126,6 +126,14 @@ ProgramProfileOGL::GetProfileFor(gl::ShaderProgramType aType, AddCommonTextureArgs(result); result.mTextureCount = 1; break; + case gl::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 gl::RGBAExternalLayerProgramType: if (aMask == Mask3d) { result.mVertexShaderString = sLayerMask3DVS; diff --git a/gfx/layers/opengl/LayerManagerOGLProgram.h b/gfx/layers/opengl/LayerManagerOGLProgram.h index 5b97516630e..0ef7f3feb6b 100644 --- a/gfx/layers/opengl/LayerManagerOGLProgram.h +++ b/gfx/layers/opengl/LayerManagerOGLProgram.h @@ -60,6 +60,10 @@ struct ProgramProfileOGL aType == gl::Copy2DRectProgramType)) return false; + if (aMask != MaskNone && + aType == gl::BGRARectLayerProgramType) + return false; + return aMask != Mask3d || aType == gl::RGBARectLayerProgramType || aType == gl::RGBALayerProgramType; diff --git a/gfx/layers/opengl/LayerManagerOGLShaders.h b/gfx/layers/opengl/LayerManagerOGLShaders.h index ffe7ae36fd5..242f1c99ff9 100644 --- a/gfx/layers/opengl/LayerManagerOGLShaders.h +++ b/gfx/layers/opengl/LayerManagerOGLShaders.h @@ -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\ diff --git a/gfx/layers/opengl/LayerManagerOGLShaders.txt b/gfx/layers/opengl/LayerManagerOGLShaders.txt index bc9e3f67e9d..88e44971dd8 100644 --- a/gfx/layers/opengl/LayerManagerOGLShaders.txt +++ b/gfx/layers/opengl/LayerManagerOGLShaders.txt @@ -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 diff --git a/gfx/thebes/gfxUtils.cpp b/gfx/thebes/gfxUtils.cpp index fe91597954b..fa42a352149 100644 --- a/gfx/thebes/gfxUtils.cpp +++ b/gfx/thebes/gfxUtils.cpp @@ -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) { diff --git a/gfx/thebes/gfxUtils.h b/gfx/thebes/gfxUtils.h index 21115122702..7f57f9708aa 100644 --- a/gfx/thebes/gfxUtils.h +++ b/gfx/thebes/gfxUtils.h @@ -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); diff --git a/widget/cocoa/nsChildView.h b/widget/cocoa/nsChildView.h index db19a1fa57b..e25b292aa82 100644 --- a/widget/cocoa/nsChildView.h +++ b/widget/cocoa/nsChildView.h @@ -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 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 mTitlebarImageBuffer; + mozilla::RefPtr mTitlebarImageBuffer; // Compositor thread only - bool mFailedResizerImage; - bool mFailedCornerMaskImage; - nsRefPtr mResizerImage; - nsRefPtr mCornerMaskImage; - nsRefPtr mTitlebarImage; + nsAutoPtr mResizerImage; + nsAutoPtr mCornerMaskImage; + nsAutoPtr mTitlebarImage; + nsAutoPtr 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 mGLPresenter; + static uint32_t sLastInputEventCount; }; diff --git a/widget/cocoa/nsChildView.mm b/widget/cocoa/nsChildView.mm index fce7541b79b..cb7d90a1751 100644 --- a/widget/cocoa/nsChildView.mm +++ b/widget/cocoa/nsChildView.mm @@ -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 + 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 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 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 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(gl::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( + mGLContext->GetNativeData(GLContext::NativeGLContext)); + } + +protected: + nsRefPtr mGLContext; + nsAutoPtr 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 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 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 image = static_cast(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(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->GetShaderProgramType()); - 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(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 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 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->GetShaderProgramType()); - 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 image = static_cast(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->GetShaderProgramType()); - 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(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& aThemeGeometri [win setUnifiedToolbarHeight:DevPixelsToCocoaPoints(devUnifiedHeight)]; } +TemporaryRef +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 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 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 +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 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 snapshot = mUpdateDrawTarget->Snapshot(); + RefPtr 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(gl::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(gl::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(mGeckoChild->GetLayerManager()); - manager->SetShadowTarget(targetContext); - } painted = mGeckoChild->PaintWindow(region); } diff --git a/widget/gtk2/nsWindow.cpp b/widget/gtk2/nsWindow.cpp index 45caa5d7282..804ed8fc058 100644 --- a/widget/gtk2/nsWindow.cpp +++ b/widget/gtk2/nsWindow.cpp @@ -5973,6 +5973,24 @@ nsWindow::GetSurfaceForGdkDrawable(GdkDrawable* aDrawable, } #endif +#if defined(MOZ_WIDGET_GTK2) +TemporaryRef +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) diff --git a/widget/gtk2/nsWindow.h b/widget/gtk2/nsWindow.h index c2507f4ac45..e73bc4b3243 100644 --- a/widget/gtk2/nsWindow.h +++ b/widget/gtk2/nsWindow.h @@ -195,6 +195,10 @@ public: guint aTime, gpointer aData); +#if defined(MOZ_WIDGET_GTK2) + mozilla::TemporaryRef StartRemoteDrawing() MOZ_OVERRIDE; +#endif + private: void NativeResize(int32_t aWidth, int32_t aHeight, diff --git a/widget/nsIWidget.h b/widget/nsIWidget.h index a8a25388cf4..b2cc65ece02 100644 --- a/widget/nsIWidget.h +++ b/widget/nsIWidget.h @@ -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 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 diff --git a/widget/xpwidgets/nsBaseWidget.cpp b/widget/xpwidgets/nsBaseWidget.cpp index 762ea16a03c..eda80a04c13 100644 --- a/widget/xpwidgets/nsBaseWidget.cpp +++ b/widget/xpwidgets/nsBaseWidget.cpp @@ -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 nsBaseWidget::StartRemoteDrawing() +{ + return nullptr; +} + //------------------------------------------------------------------------- // // Return the used device context diff --git a/widget/xpwidgets/nsBaseWidget.h b/widget/xpwidgets/nsBaseWidget.h index c6cf80dfaa1..ffd1c4cd0c2 100644 --- a/widget/xpwidgets/nsBaseWidget.h +++ b/widget/xpwidgets/nsBaseWidget.h @@ -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 StartRemoteDrawing(); + virtual void EndRemoteDrawing() { }; + virtual void CleanupRemoteDrawing() { }; virtual void UpdateThemeGeometries(const nsTArray& aThemeGeometries) {} virtual gfxASurface* GetThebesSurface(); NS_IMETHOD SetModal(bool aModal);