forked from mirrors/gecko-dev
		
	 cbf0e5ea15
			
		
	
	
		cbf0e5ea15
		
	
	
	
	
		
			
			By removing the async mode, remote texture implementation becomes simpler. Differential Revision: https://phabricator.services.mozilla.com/D197323
		
			
				
	
	
		
			508 lines
		
	
	
	
		
			17 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			508 lines
		
	
	
	
		
			17 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | |
| /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 | |
| /* This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  *
 | |
|  * License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
|  * file,
 | |
|  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 | |
| 
 | |
| #include "RenderCompositorOGLSWGL.h"
 | |
| 
 | |
| #include "GLContext.h"
 | |
| #include "GLContextEGL.h"
 | |
| #include "mozilla/layers/BuildConstants.h"
 | |
| #include "mozilla/layers/CompositorOGL.h"
 | |
| #include "mozilla/layers/Effects.h"
 | |
| #include "mozilla/layers/TextureHostOGL.h"
 | |
| #include "mozilla/widget/CompositorWidget.h"
 | |
| #include "OGLShaderProgram.h"
 | |
| 
 | |
| #ifdef MOZ_WIDGET_ANDROID
 | |
| #  include "mozilla/java/GeckoSurfaceTextureWrappers.h"
 | |
| #  include "mozilla/layers/AndroidHardwareBuffer.h"
 | |
| #  include "mozilla/webrender/RenderAndroidHardwareBufferTextureHost.h"
 | |
| #  include "mozilla/webrender/RenderAndroidSurfaceTextureHost.h"
 | |
| #  include "mozilla/widget/AndroidCompositorWidget.h"
 | |
| #  include <android/native_window.h>
 | |
| #  include <android/native_window_jni.h>
 | |
| #endif
 | |
| 
 | |
| #ifdef MOZ_WIDGET_GTK
 | |
| #  include "mozilla/widget/GtkCompositorWidget.h"
 | |
| #  include <gdk/gdk.h>
 | |
| #  ifdef MOZ_X11
 | |
| #    include <gdk/gdkx.h>
 | |
| #  endif
 | |
| #endif
 | |
| 
 | |
| namespace mozilla {
 | |
| using namespace layers;
 | |
| using namespace gfx;
 | |
| namespace wr {
 | |
| 
 | |
| extern LazyLogModule gRenderThreadLog;
 | |
| #define LOG(...) MOZ_LOG(gRenderThreadLog, LogLevel::Debug, (__VA_ARGS__))
 | |
| 
 | |
| UniquePtr<RenderCompositor> RenderCompositorOGLSWGL::Create(
 | |
|     const RefPtr<widget::CompositorWidget>& aWidget, nsACString& aError) {
 | |
|   if (!aWidget->GetCompositorOptions().AllowSoftwareWebRenderOGL()) {
 | |
|     return nullptr;
 | |
|   }
 | |
| 
 | |
|   RefPtr<Compositor> compositor;
 | |
| #ifdef MOZ_WIDGET_ANDROID
 | |
|   RefPtr<gl::GLContext> context =
 | |
|       RenderThread::Get()->SingletonGLForCompositorOGL();
 | |
|   if (!context) {
 | |
|     gfxCriticalNote << "SingletonGL does not exist for SWGL";
 | |
|     return nullptr;
 | |
|   }
 | |
|   auto programs = RenderThread::Get()->GetProgramsForCompositorOGL();
 | |
|   if (!programs) {
 | |
|     gfxCriticalNote << "Failed to get Programs for CompositorOGL for SWGL";
 | |
|     return nullptr;
 | |
|   }
 | |
| 
 | |
|   nsCString log;
 | |
|   RefPtr<CompositorOGL> compositorOGL;
 | |
|   compositorOGL = new CompositorOGL(aWidget, /* aSurfaceWidth */ -1,
 | |
|                                     /* aSurfaceHeight */ -1,
 | |
|                                     /* aUseExternalSurfaceSize */ true);
 | |
|   if (!compositorOGL->Initialize(context, programs, &log)) {
 | |
|     gfxCriticalNote << "Failed to initialize CompositorOGL for SWGL: "
 | |
|                     << log.get();
 | |
|     return nullptr;
 | |
|   }
 | |
|   compositor = compositorOGL;
 | |
| #elif defined(MOZ_WIDGET_GTK)
 | |
|   nsCString log;
 | |
|   RefPtr<CompositorOGL> compositorOGL;
 | |
|   compositorOGL = new CompositorOGL(aWidget);
 | |
|   if (!compositorOGL->Initialize(&log)) {
 | |
|     gfxCriticalNote << "Failed to initialize CompositorOGL for SWGL: "
 | |
|                     << log.get();
 | |
|     return nullptr;
 | |
|   }
 | |
|   compositor = compositorOGL;
 | |
| #endif
 | |
| 
 | |
|   if (!compositor) {
 | |
|     return nullptr;
 | |
|   }
 | |
| 
 | |
|   void* ctx = wr_swgl_create_context();
 | |
|   if (!ctx) {
 | |
|     gfxCriticalNote << "Failed SWGL context creation for WebRender";
 | |
|     return nullptr;
 | |
|   }
 | |
| 
 | |
|   return MakeUnique<RenderCompositorOGLSWGL>(compositor, aWidget, ctx);
 | |
| }
 | |
| 
 | |
| RenderCompositorOGLSWGL::RenderCompositorOGLSWGL(
 | |
|     Compositor* aCompositor, const RefPtr<widget::CompositorWidget>& aWidget,
 | |
|     void* aContext)
 | |
|     : RenderCompositorLayersSWGL(aCompositor, aWidget, aContext) {
 | |
|   LOG("RenderCompositorOGLSWGL::RenderCompositorOGLSWGL()");
 | |
| }
 | |
| 
 | |
| RenderCompositorOGLSWGL::~RenderCompositorOGLSWGL() {
 | |
|   LOG("RRenderCompositorOGLSWGL::~RenderCompositorOGLSWGL()");
 | |
| #ifdef MOZ_WIDGET_ANDROID
 | |
|   java::GeckoSurfaceTexture::DestroyUnused((int64_t)GetGLContext());
 | |
|   DestroyEGLSurface();
 | |
| #endif
 | |
| }
 | |
| 
 | |
| gl::GLContext* RenderCompositorOGLSWGL::GetGLContext() {
 | |
|   return mCompositor->AsCompositorOGL()->gl();
 | |
| }
 | |
| 
 | |
| bool RenderCompositorOGLSWGL::MakeCurrent() {
 | |
|   GetGLContext()->MakeCurrent();
 | |
| #ifdef MOZ_WIDGET_ANDROID
 | |
|   if (GetGLContext()->GetContextType() == gl::GLContextType::EGL) {
 | |
|     gl::GLContextEGL::Cast(GetGLContext())->SetEGLSurfaceOverride(mEGLSurface);
 | |
|   }
 | |
| #endif
 | |
|   RenderCompositorLayersSWGL::MakeCurrent();
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| EGLSurface RenderCompositorOGLSWGL::CreateEGLSurface() {
 | |
|   MOZ_ASSERT(GetGLContext()->GetContextType() == gl::GLContextType::EGL);
 | |
| 
 | |
|   EGLSurface surface = EGL_NO_SURFACE;
 | |
|   surface = gl::GLContextEGL::CreateEGLSurfaceForCompositorWidget(
 | |
|       mWidget, gl::GLContextEGL::Cast(GetGLContext())->mSurfaceConfig);
 | |
|   if (surface == EGL_NO_SURFACE) {
 | |
|     const auto* renderThread = RenderThread::Get();
 | |
|     gfxCriticalNote << "Failed to create EGLSurface. "
 | |
|                     << renderThread->RendererCount() << " renderers, "
 | |
|                     << renderThread->ActiveRendererCount() << " active.";
 | |
|   }
 | |
| 
 | |
|   // The subsequent render after creating a new surface must be a full render.
 | |
|   mFullRender = true;
 | |
| 
 | |
|   return surface;
 | |
| }
 | |
| 
 | |
| void RenderCompositorOGLSWGL::DestroyEGLSurface() {
 | |
|   MOZ_ASSERT(GetGLContext()->GetContextType() == gl::GLContextType::EGL);
 | |
| 
 | |
|   const auto& gle = gl::GLContextEGL::Cast(GetGLContext());
 | |
|   const auto& egl = gle->mEgl;
 | |
| 
 | |
|   // Release EGLSurface of back buffer before calling ResizeBuffers().
 | |
|   if (mEGLSurface) {
 | |
|     gle->SetEGLSurfaceOverride(EGL_NO_SURFACE);
 | |
|     gl::GLContextEGL::DestroySurface(*egl, mEGLSurface);
 | |
|     mEGLSurface = EGL_NO_SURFACE;
 | |
|   }
 | |
| }
 | |
| 
 | |
| bool RenderCompositorOGLSWGL::BeginFrame() {
 | |
|   MOZ_ASSERT(!mInFrame);
 | |
|   RenderCompositorLayersSWGL::BeginFrame();
 | |
| 
 | |
| #ifdef MOZ_WIDGET_ANDROID
 | |
|   java::GeckoSurfaceTexture::DestroyUnused((int64_t)GetGLContext());
 | |
|   GetGLContext()
 | |
|       ->MakeCurrent();  // DestroyUnused can change the current context!
 | |
| #endif
 | |
| 
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| RenderedFrameId RenderCompositorOGLSWGL::EndFrame(
 | |
|     const nsTArray<DeviceIntRect>& aDirtyRects) {
 | |
|   mFullRender = false;
 | |
| 
 | |
|   return RenderCompositorLayersSWGL::EndFrame(aDirtyRects);
 | |
| }
 | |
| 
 | |
| void RenderCompositorOGLSWGL::HandleExternalImage(
 | |
|     RenderTextureHost* aExternalImage, FrameSurface& aFrameSurface) {
 | |
|   MOZ_ASSERT(aExternalImage);
 | |
| 
 | |
| #ifdef MOZ_WIDGET_ANDROID
 | |
|   GLenum target =
 | |
|       LOCAL_GL_TEXTURE_EXTERNAL;  // This is required by SurfaceTexture
 | |
|   GLenum wrapMode = LOCAL_GL_CLAMP_TO_EDGE;
 | |
| 
 | |
|   if (auto* host = aExternalImage->AsRenderAndroidSurfaceTextureHost()) {
 | |
|     host->UpdateTexImageIfNecessary();
 | |
| 
 | |
|     // We need to hold the texture source separately from the effect,
 | |
|     // since the effect doesn't hold a strong reference.
 | |
|     RefPtr<SurfaceTextureSource> layer = new SurfaceTextureSource(
 | |
|         (TextureSourceProvider*)mCompositor, host->mSurfTex, host->mFormat,
 | |
|         target, wrapMode, host->mSize, host->mTransformOverride);
 | |
|     RefPtr<TexturedEffect> texturedEffect =
 | |
|         CreateTexturedEffect(host->mFormat, layer, aFrameSurface.mFilter,
 | |
|                              /* isAlphaPremultiplied */ true);
 | |
| 
 | |
|     gfx::Rect drawRect(0, 0, host->mSize.width, host->mSize.height);
 | |
| 
 | |
|     EffectChain effect;
 | |
|     effect.mPrimaryEffect = texturedEffect;
 | |
|     mCompositor->DrawQuad(drawRect, aFrameSurface.mClipRect, effect, 1.0,
 | |
|                           aFrameSurface.mTransform, drawRect);
 | |
|   } else if (auto* host =
 | |
|                  aExternalImage->AsRenderAndroidHardwareBufferTextureHost()) {
 | |
|     // We need to hold the texture source separately from the effect,
 | |
|     // since the effect doesn't hold a strong reference.
 | |
|     RefPtr<AndroidHardwareBufferTextureSource> layer =
 | |
|         new AndroidHardwareBufferTextureSource(
 | |
|             (TextureSourceProvider*)mCompositor,
 | |
|             host->GetAndroidHardwareBuffer(),
 | |
|             host->GetAndroidHardwareBuffer()->mFormat, target, wrapMode,
 | |
|             host->GetSize());
 | |
|     RefPtr<TexturedEffect> texturedEffect = CreateTexturedEffect(
 | |
|         host->GetAndroidHardwareBuffer()->mFormat, layer, aFrameSurface.mFilter,
 | |
|         /* isAlphaPremultiplied */ true);
 | |
| 
 | |
|     gfx::Rect drawRect(0, 0, host->GetSize().width, host->GetSize().height);
 | |
| 
 | |
|     EffectChain effect;
 | |
|     effect.mPrimaryEffect = texturedEffect;
 | |
|     mCompositor->DrawQuad(drawRect, aFrameSurface.mClipRect, effect, 1.0,
 | |
|                           aFrameSurface.mTransform, drawRect);
 | |
|   }
 | |
| #endif
 | |
| }
 | |
| 
 | |
| void RenderCompositorOGLSWGL::GetCompositorCapabilities(
 | |
|     CompositorCapabilities* aCaps) {
 | |
|   RenderCompositor::GetCompositorCapabilities(aCaps);
 | |
| 
 | |
|   // max_update_rects are not yet handled properly
 | |
|   aCaps->max_update_rects = 0;
 | |
| }
 | |
| 
 | |
| bool RenderCompositorOGLSWGL::RequestFullRender() { return mFullRender; }
 | |
| 
 | |
| void RenderCompositorOGLSWGL::Pause() {
 | |
| #ifdef MOZ_WIDGET_ANDROID
 | |
|   DestroyEGLSurface();
 | |
| #elif defined(MOZ_WIDGET_GTK)
 | |
|   mCompositor->Pause();
 | |
| #endif
 | |
| }
 | |
| 
 | |
| bool RenderCompositorOGLSWGL::Resume() {
 | |
| #ifdef MOZ_WIDGET_ANDROID
 | |
|   // Destroy EGLSurface if it exists.
 | |
|   DestroyEGLSurface();
 | |
| 
 | |
|   auto size = GetBufferSize();
 | |
|   GLint maxTextureSize = 0;
 | |
|   GetGLContext()->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE,
 | |
|                                (GLint*)&maxTextureSize);
 | |
| 
 | |
|   // When window size is too big, hardware buffer allocation could fail.
 | |
|   if (maxTextureSize < size.width || maxTextureSize < size.height) {
 | |
|     gfxCriticalNote << "Too big ANativeWindow size(" << size.width << ", "
 | |
|                     << size.height << ") MaxTextureSize " << maxTextureSize;
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   mEGLSurface = CreateEGLSurface();
 | |
|   if (mEGLSurface == EGL_NO_SURFACE) {
 | |
|     // Often when we fail to create an EGL surface it is because the
 | |
|     // Java Surface we have been provided is invalid. Therefore the on
 | |
|     // the first occurence we don't raise a WebRenderError and instead
 | |
|     // just return failure. This allows the widget a chance to request
 | |
|     // a new Java Surface. On subsequent failures, raising the
 | |
|     // WebRenderError will result in the compositor being recreated,
 | |
|     // falling back through webrender configurations, and eventually
 | |
|     // crashing if we still do not succeed.
 | |
|     if (!mHandlingNewSurfaceError) {
 | |
|       mHandlingNewSurfaceError = true;
 | |
|     } else {
 | |
|       RenderThread::Get()->HandleWebRenderError(WebRenderError::NEW_SURFACE);
 | |
|     }
 | |
|     return false;
 | |
|   }
 | |
|   mHandlingNewSurfaceError = false;
 | |
| 
 | |
|   gl::GLContextEGL::Cast(GetGLContext())->SetEGLSurfaceOverride(mEGLSurface);
 | |
|   mCompositor->SetDestinationSurfaceSize(size.ToUnknownSize());
 | |
| #elif defined(MOZ_WIDGET_GTK)
 | |
|   bool resumed = mCompositor->Resume();
 | |
|   if (!resumed) {
 | |
|     RenderThread::Get()->HandleWebRenderError(WebRenderError::NEW_SURFACE);
 | |
|     return false;
 | |
|   }
 | |
| #endif
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| bool RenderCompositorOGLSWGL::IsPaused() {
 | |
| #ifdef MOZ_WIDGET_ANDROID
 | |
|   return mEGLSurface == EGL_NO_SURFACE;
 | |
| #endif
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| LayoutDeviceIntSize RenderCompositorOGLSWGL::GetBufferSize() {
 | |
|   return mWidget->GetClientSize();
 | |
| }
 | |
| 
 | |
| UniquePtr<RenderCompositorLayersSWGL::Tile>
 | |
| RenderCompositorOGLSWGL::DoCreateTile(Surface* aSurface) {
 | |
|   auto source = MakeRefPtr<TextureImageTextureSourceOGL>(
 | |
|       mCompositor->AsCompositorOGL(), layers::TextureFlags::NO_FLAGS);
 | |
| 
 | |
|   return MakeUnique<TileOGL>(std::move(source), aSurface->TileSize());
 | |
| }
 | |
| 
 | |
| bool RenderCompositorOGLSWGL::MaybeReadback(
 | |
|     const gfx::IntSize& aReadbackSize, const wr::ImageFormat& aReadbackFormat,
 | |
|     const Range<uint8_t>& aReadbackBuffer, bool* aNeedsYFlip) {
 | |
| #ifdef MOZ_WIDGET_ANDROID
 | |
|   MOZ_ASSERT(aReadbackFormat == wr::ImageFormat::RGBA8);
 | |
|   const GLenum format = LOCAL_GL_RGBA;
 | |
| #else
 | |
|   MOZ_ASSERT(aReadbackFormat == wr::ImageFormat::BGRA8);
 | |
|   const GLenum format = LOCAL_GL_BGRA;
 | |
| #endif
 | |
| 
 | |
|   GetGLContext()->fReadPixels(0, 0, aReadbackSize.width, aReadbackSize.height,
 | |
|                               format, LOCAL_GL_UNSIGNED_BYTE,
 | |
|                               &aReadbackBuffer[0]);
 | |
| 
 | |
|   if (aNeedsYFlip) {
 | |
|     *aNeedsYFlip = true;
 | |
|   }
 | |
| 
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // This is a DataSourceSurface that represents a 0-based PBO for GLTextureImage.
 | |
| class PBOUnpackSurface : public gfx::DataSourceSurface {
 | |
|  public:
 | |
|   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PBOUnpackSurface, override)
 | |
| 
 | |
|   explicit PBOUnpackSurface(const gfx::IntSize& aSize) : mSize(aSize) {}
 | |
| 
 | |
|   uint8_t* GetData() override { return nullptr; }
 | |
|   int32_t Stride() override { return mSize.width * sizeof(uint32_t); }
 | |
|   gfx::SurfaceType GetType() const override {
 | |
|     return gfx::SurfaceType::DATA_ALIGNED;
 | |
|   }
 | |
|   gfx::IntSize GetSize() const override { return mSize; }
 | |
|   gfx::SurfaceFormat GetFormat() const override {
 | |
|     return gfx::SurfaceFormat::B8G8R8A8;
 | |
|   }
 | |
| 
 | |
|   // PBO offsets need to start from a 0 address, but DataSourceSurface::Map
 | |
|   // checks for failure by comparing the address against nullptr. Override Map
 | |
|   // to work around this.
 | |
|   bool Map(MapType, MappedSurface* aMappedSurface) override {
 | |
|     aMappedSurface->mData = GetData();
 | |
|     aMappedSurface->mStride = Stride();
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   void Unmap() override {}
 | |
| 
 | |
|  private:
 | |
|   gfx::IntSize mSize;
 | |
| };
 | |
| 
 | |
| RenderCompositorOGLSWGL::TileOGL::TileOGL(
 | |
|     RefPtr<layers::TextureImageTextureSourceOGL>&& aTexture,
 | |
|     const gfx::IntSize& aSize)
 | |
|     : mTexture(aTexture) {
 | |
|   auto* gl = mTexture->gl();
 | |
|   if (gl && gl->HasPBOState() && gl->MakeCurrent()) {
 | |
|     mSurface = new PBOUnpackSurface(aSize);
 | |
|     // Create a PBO large enough to encompass any valid rects within the tile.
 | |
|     gl->fGenBuffers(1, &mPBO);
 | |
|     gl->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, mPBO);
 | |
|     gl->fBufferData(LOCAL_GL_PIXEL_UNPACK_BUFFER,
 | |
|                     mSurface->Stride() * aSize.height, nullptr,
 | |
|                     LOCAL_GL_DYNAMIC_DRAW);
 | |
|     gl->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, 0);
 | |
|   } else {
 | |
|     // Couldn't allocate a PBO, so just use a memory surface instead.
 | |
|     mSurface = gfx::Factory::CreateDataSourceSurface(
 | |
|         aSize, gfx::SurfaceFormat::B8G8R8A8);
 | |
|   }
 | |
| }
 | |
| 
 | |
| RenderCompositorOGLSWGL::TileOGL::~TileOGL() {
 | |
|   if (mPBO) {
 | |
|     auto* gl = mTexture->gl();
 | |
|     if (gl && gl->MakeCurrent()) {
 | |
|       gl->fDeleteBuffers(1, &mPBO);
 | |
|       mPBO = 0;
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| layers::DataTextureSource*
 | |
| RenderCompositorOGLSWGL::TileOGL::GetTextureSource() {
 | |
|   return mTexture.get();
 | |
| }
 | |
| 
 | |
| bool RenderCompositorOGLSWGL::TileOGL::Map(wr::DeviceIntRect aDirtyRect,
 | |
|                                            wr::DeviceIntRect aValidRect,
 | |
|                                            void** aData, int32_t* aStride) {
 | |
|   if (mPBO) {
 | |
|     auto* gl = mTexture->gl();
 | |
|     if (!gl) {
 | |
|       return false;
 | |
|     }
 | |
|     // Map the PBO, but only within the range of the buffer that spans from the
 | |
|     // linear start offset to the linear end offset. Since we don't care about
 | |
|     // the previous contents of the buffer, we can just tell OpenGL to
 | |
|     // invalidate the entire buffer, even though we're only mapping a sub-range.
 | |
|     gl->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, mPBO);
 | |
|     size_t stride = mSurface->Stride();
 | |
|     size_t offset =
 | |
|         stride * aValidRect.min.y + aValidRect.min.x * sizeof(uint32_t);
 | |
|     size_t length = stride * (aValidRect.height() - 1) +
 | |
|                     (aValidRect.width()) * sizeof(uint32_t);
 | |
|     void* data = gl->fMapBufferRange(
 | |
|         LOCAL_GL_PIXEL_UNPACK_BUFFER, offset, length,
 | |
|         LOCAL_GL_MAP_WRITE_BIT | LOCAL_GL_MAP_INVALIDATE_BUFFER_BIT);
 | |
|     gl->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, 0);
 | |
|     if (!data) {
 | |
|       return false;
 | |
|     }
 | |
|     *aData = data;
 | |
|     *aStride = stride;
 | |
|   } else {
 | |
|     // No PBO is available, so just directly write to the memory surface.
 | |
|     gfx::DataSourceSurface::MappedSurface map;
 | |
|     if (!mSurface->Map(gfx::DataSourceSurface::READ_WRITE, &map)) {
 | |
|       return false;
 | |
|     }
 | |
|     // Verify that we're not somehow using a PBOUnpackSurface.
 | |
|     MOZ_ASSERT(map.mData != nullptr);
 | |
|     // glTex(Sub)Image on ES doesn't support arbitrary strides without
 | |
|     // the EXT_unpack_subimage extension. To avoid needing to make a
 | |
|     // copy of the data we'll always draw it with stride = bpp*width
 | |
|     // unless we're uploading the entire texture.
 | |
|     if (!mTexture->IsValid()) {
 | |
|       // If we don't have a texture we need to position our
 | |
|       // data in the correct spot because we're going to upload
 | |
|       // the entire surface
 | |
|       *aData = map.mData + aValidRect.min.y * map.mStride +
 | |
|                aValidRect.min.x * sizeof(uint32_t);
 | |
| 
 | |
|       *aStride = map.mStride;
 | |
|       mSubSurface = nullptr;
 | |
|     } else {
 | |
|       // Otherwise, we can just use the top left as a scratch space
 | |
|       *aData = map.mData;
 | |
|       *aStride = aDirtyRect.width() * BytesPerPixel(mSurface->GetFormat());
 | |
|       mSubSurface = Factory::CreateWrappingDataSourceSurface(
 | |
|           (uint8_t*)*aData, *aStride,
 | |
|           IntSize(aDirtyRect.width(), aDirtyRect.height()),
 | |
|           mSurface->GetFormat());
 | |
|     }
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| void RenderCompositorOGLSWGL::TileOGL::Unmap(const gfx::IntRect& aDirtyRect) {
 | |
|   nsIntRegion dirty(aDirtyRect);
 | |
|   if (mPBO) {
 | |
|     // If there is a PBO, it must be unmapped before it can be sourced from.
 | |
|     // Leave the PBO bound before the call to Update so that the texture uploads
 | |
|     // will source from it.
 | |
|     auto* gl = mTexture->gl();
 | |
|     if (!gl) {
 | |
|       return;
 | |
|     }
 | |
|     gl->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, mPBO);
 | |
|     gl->fUnmapBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER);
 | |
|     mTexture->Update(mSurface, &dirty);
 | |
|     gl->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, 0);
 | |
|   } else {
 | |
|     if (mSubSurface) {
 | |
|       mSurface->Unmap();
 | |
|       // Our subsurface has a stride = aDirtyRect.width
 | |
|       // We use a negative offset to move it to match
 | |
|       // the dirty rect's top-left. These two offsets
 | |
|       // will cancel each other out by the time we reach
 | |
|       // TexSubImage.
 | |
|       IntPoint srcOffset = {0, 0};
 | |
|       IntPoint dstOffset = aDirtyRect.TopLeft();
 | |
|       // adjust the dirty region to be relative to the dstOffset
 | |
|       dirty.MoveBy(-dstOffset);
 | |
|       mTexture->Update(mSubSurface, &dirty, &srcOffset, &dstOffset);
 | |
|       mSubSurface = nullptr;
 | |
|     } else {
 | |
|       mSurface->Unmap();
 | |
|       mTexture->Update(mSurface, &dirty);
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| }  // namespace wr
 | |
| }  // namespace mozilla
 |