RenderCompositorOGLSWGL.cpp (16317B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * 5 * License, v. 2.0. If a copy of the MPL was not distributed with this 6 * file, 7 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 8 9 #include "RenderCompositorOGLSWGL.h" 10 11 #include "GLContext.h" 12 #include "GLContextEGL.h" 13 #include "mozilla/layers/BuildConstants.h" 14 #include "mozilla/layers/CompositorOGL.h" 15 #include "mozilla/layers/Effects.h" 16 #include "mozilla/layers/TextureHostOGL.h" 17 #include "mozilla/widget/CompositorWidget.h" 18 #include "OGLShaderProgram.h" 19 20 #ifdef MOZ_WIDGET_ANDROID 21 # include "mozilla/java/GeckoSurfaceTextureWrappers.h" 22 # include "mozilla/layers/AndroidHardwareBuffer.h" 23 # include "mozilla/webrender/RenderAndroidHardwareBufferTextureHost.h" 24 # include "mozilla/webrender/RenderAndroidSurfaceTextureHost.h" 25 # include "mozilla/widget/AndroidCompositorWidget.h" 26 # include <android/native_window.h> 27 # include <android/native_window_jni.h> 28 #endif 29 30 #ifdef MOZ_WIDGET_GTK 31 # include "mozilla/widget/GtkCompositorWidget.h" 32 # include <gdk/gdk.h> 33 # ifdef MOZ_X11 34 # include <gdk/gdkx.h> 35 # endif 36 #endif 37 38 namespace mozilla { 39 using namespace layers; 40 using namespace gfx; 41 namespace wr { 42 43 extern LazyLogModule gRenderThreadLog; 44 #define LOG(...) MOZ_LOG(gRenderThreadLog, LogLevel::Debug, (__VA_ARGS__)) 45 46 UniquePtr<RenderCompositor> RenderCompositorOGLSWGL::Create( 47 const RefPtr<widget::CompositorWidget>& aWidget, nsACString& aError) { 48 if (!aWidget->GetCompositorOptions().AllowSoftwareWebRenderOGL()) { 49 return nullptr; 50 } 51 52 RefPtr<Compositor> compositor; 53 #ifdef MOZ_WIDGET_ANDROID 54 RefPtr<gl::GLContext> context = 55 RenderThread::Get()->SingletonGLForCompositorOGL(); 56 if (!context) { 57 gfxCriticalNote << "SingletonGL does not exist for SWGL"; 58 return nullptr; 59 } 60 auto programs = RenderThread::Get()->GetProgramsForCompositorOGL(); 61 if (!programs) { 62 gfxCriticalNote << "Failed to get Programs for CompositorOGL for SWGL"; 63 return nullptr; 64 } 65 66 nsCString log; 67 RefPtr<CompositorOGL> compositorOGL; 68 compositorOGL = new CompositorOGL(aWidget, /* aSurfaceWidth */ -1, 69 /* aSurfaceHeight */ -1, 70 /* aUseExternalSurfaceSize */ true); 71 if (!compositorOGL->Initialize(context, programs, &log)) { 72 gfxCriticalNote << "Failed to initialize CompositorOGL for SWGL: " 73 << log.get(); 74 return nullptr; 75 } 76 compositor = compositorOGL; 77 #elif defined(MOZ_WIDGET_GTK) 78 nsCString log; 79 RefPtr<CompositorOGL> compositorOGL; 80 compositorOGL = new CompositorOGL(aWidget); 81 if (!compositorOGL->Initialize(&log)) { 82 gfxCriticalNote << "Failed to initialize CompositorOGL for SWGL: " 83 << log.get(); 84 return nullptr; 85 } 86 compositor = compositorOGL; 87 #endif 88 89 if (!compositor) { 90 return nullptr; 91 } 92 93 void* ctx = wr_swgl_create_context(); 94 if (!ctx) { 95 gfxCriticalNote << "Failed SWGL context creation for WebRender"; 96 return nullptr; 97 } 98 99 return MakeUnique<RenderCompositorOGLSWGL>(compositor, aWidget, ctx); 100 } 101 102 RenderCompositorOGLSWGL::RenderCompositorOGLSWGL( 103 Compositor* aCompositor, const RefPtr<widget::CompositorWidget>& aWidget, 104 void* aContext) 105 : RenderCompositorLayersSWGL(aCompositor, aWidget, aContext) { 106 LOG("RenderCompositorOGLSWGL::RenderCompositorOGLSWGL()"); 107 } 108 109 RenderCompositorOGLSWGL::~RenderCompositorOGLSWGL() { 110 LOG("RRenderCompositorOGLSWGL::~RenderCompositorOGLSWGL()"); 111 #ifdef MOZ_WIDGET_ANDROID 112 java::GeckoSurfaceTexture::DestroyUnused((int64_t)GetGLContext()); 113 DestroyEGLSurface(); 114 #endif 115 } 116 117 gl::GLContext* RenderCompositorOGLSWGL::GetGLContext() { 118 return mCompositor->AsCompositorOGL()->gl(); 119 } 120 121 bool RenderCompositorOGLSWGL::MakeCurrent() { 122 GetGLContext()->MakeCurrent(); 123 #ifdef MOZ_WIDGET_ANDROID 124 if (GetGLContext()->GetContextType() == gl::GLContextType::EGL) { 125 gl::GLContextEGL::Cast(GetGLContext())->SetEGLSurfaceOverride(mEGLSurface); 126 } 127 #endif 128 RenderCompositorLayersSWGL::MakeCurrent(); 129 return true; 130 } 131 132 EGLSurface RenderCompositorOGLSWGL::CreateEGLSurface() { 133 MOZ_ASSERT(GetGLContext()->GetContextType() == gl::GLContextType::EGL); 134 135 EGLSurface surface = EGL_NO_SURFACE; 136 surface = gl::GLContextEGL::CreateEGLSurfaceForCompositorWidget( 137 mWidget, gl::GLContextEGL::Cast(GetGLContext())->mSurfaceConfig); 138 if (surface == EGL_NO_SURFACE) { 139 const auto* renderThread = RenderThread::Get(); 140 gfxCriticalNote << "Failed to create EGLSurface. " 141 << renderThread->RendererCount() << " renderers, " 142 << renderThread->ActiveRendererCount() << " active."; 143 } 144 145 // The subsequent render after creating a new surface must be a full render. 146 mFullRender = true; 147 148 return surface; 149 } 150 151 void RenderCompositorOGLSWGL::DestroyEGLSurface() { 152 MOZ_ASSERT(GetGLContext()->GetContextType() == gl::GLContextType::EGL); 153 154 const auto& gle = gl::GLContextEGL::Cast(GetGLContext()); 155 const auto& egl = gle->mEgl; 156 157 // Release EGLSurface of back buffer before calling ResizeBuffers(). 158 if (mEGLSurface) { 159 gle->SetEGLSurfaceOverride(EGL_NO_SURFACE); 160 gl::GLContextEGL::DestroySurface(*egl, mEGLSurface); 161 mEGLSurface = EGL_NO_SURFACE; 162 } 163 } 164 165 bool RenderCompositorOGLSWGL::BeginFrame() { 166 MOZ_ASSERT(!mInFrame); 167 RenderCompositorLayersSWGL::BeginFrame(); 168 169 #ifdef MOZ_WIDGET_ANDROID 170 java::GeckoSurfaceTexture::DestroyUnused((int64_t)GetGLContext()); 171 GetGLContext() 172 ->MakeCurrent(); // DestroyUnused can change the current context! 173 #endif 174 175 return true; 176 } 177 178 RenderedFrameId RenderCompositorOGLSWGL::EndFrame( 179 const nsTArray<DeviceIntRect>& aDirtyRects) { 180 mFullRender = false; 181 182 return RenderCompositorLayersSWGL::EndFrame(aDirtyRects); 183 } 184 185 void RenderCompositorOGLSWGL::HandleExternalImage( 186 RenderTextureHost* aExternalImage, FrameSurface& aFrameSurface) { 187 MOZ_ASSERT(aExternalImage); 188 189 // We need to hold the texture source separately from the effect, 190 // since the effect doesn't hold a strong reference. 191 RefPtr<TextureSource> layer = 192 aExternalImage->CreateTextureSource(mCompositor); 193 if (layer) { 194 RefPtr<TexturedEffect> texturedEffect = CreateTexturedEffect( 195 aExternalImage->GetFormat(), layer, aFrameSurface.mFilter, 196 /* isAlphaPremultiplied */ true); 197 198 auto size = layer->GetSize(); 199 gfx::Rect drawRect(0.0, 0.0, float(size.width), float(size.height)); 200 201 EffectChain effect; 202 effect.mPrimaryEffect = texturedEffect; 203 mCompositor->DrawQuad(drawRect, aFrameSurface.mClipRect, effect, 1.0, 204 aFrameSurface.mTransform, drawRect); 205 } 206 } 207 208 void RenderCompositorOGLSWGL::GetCompositorCapabilities( 209 CompositorCapabilities* aCaps) { 210 RenderCompositor::GetCompositorCapabilities(aCaps); 211 212 // max_update_rects are not yet handled properly 213 aCaps->max_update_rects = 0; 214 } 215 216 bool RenderCompositorOGLSWGL::RequestFullRender() { return mFullRender; } 217 218 void RenderCompositorOGLSWGL::Pause() { 219 #ifdef MOZ_WIDGET_ANDROID 220 DestroyEGLSurface(); 221 #elif defined(MOZ_WIDGET_GTK) 222 mCompositor->Pause(); 223 #endif 224 } 225 226 bool RenderCompositorOGLSWGL::Resume() { 227 #ifdef MOZ_WIDGET_ANDROID 228 // Destroy EGLSurface if it exists. 229 DestroyEGLSurface(); 230 231 auto size = GetBufferSize(); 232 GLint maxTextureSize = 0; 233 GetGLContext()->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, 234 (GLint*)&maxTextureSize); 235 236 // When window size is too big, hardware buffer allocation could fail. 237 if (maxTextureSize < size.width || maxTextureSize < size.height) { 238 gfxCriticalNote << "Too big ANativeWindow size(" << size.width << ", " 239 << size.height << ") MaxTextureSize " << maxTextureSize; 240 return false; 241 } 242 243 mEGLSurface = CreateEGLSurface(); 244 if (mEGLSurface == EGL_NO_SURFACE) { 245 // Often when we fail to create an EGL surface it is because the 246 // Java Surface we have been provided is invalid. Therefore the on 247 // the first occurence we don't raise a WebRenderError and instead 248 // just return failure. This allows the widget a chance to request 249 // a new Java Surface. On subsequent failures, raising the 250 // WebRenderError will result in the compositor being recreated, 251 // falling back through webrender configurations, and eventually 252 // crashing if we still do not succeed. 253 if (!mHandlingNewSurfaceError) { 254 mHandlingNewSurfaceError = true; 255 } else { 256 RenderThread::Get()->HandleWebRenderError(WebRenderError::NEW_SURFACE); 257 } 258 return false; 259 } 260 mHandlingNewSurfaceError = false; 261 262 gl::GLContextEGL::Cast(GetGLContext())->SetEGLSurfaceOverride(mEGLSurface); 263 mCompositor->SetDestinationSurfaceSize(size.ToUnknownSize()); 264 #elif defined(MOZ_WIDGET_GTK) 265 bool resumed = mCompositor->Resume(); 266 if (!resumed) { 267 RenderThread::Get()->HandleWebRenderError(WebRenderError::NEW_SURFACE); 268 return false; 269 } 270 #endif 271 return true; 272 } 273 274 bool RenderCompositorOGLSWGL::IsPaused() { 275 #ifdef MOZ_WIDGET_ANDROID 276 return mEGLSurface == EGL_NO_SURFACE; 277 #else 278 return false; 279 #endif 280 } 281 282 LayoutDeviceIntSize RenderCompositorOGLSWGL::GetBufferSize() { 283 return mWidget->GetClientSize(); 284 } 285 286 UniquePtr<RenderCompositorLayersSWGL::Tile> 287 RenderCompositorOGLSWGL::DoCreateTile(Surface* aSurface) { 288 auto source = MakeRefPtr<TextureImageTextureSourceOGL>( 289 mCompositor->AsCompositorOGL(), layers::TextureFlags::NO_FLAGS); 290 291 return MakeUnique<TileOGL>(std::move(source), aSurface->TileSize()); 292 } 293 294 bool RenderCompositorOGLSWGL::MaybeReadback( 295 const gfx::IntSize& aReadbackSize, const wr::ImageFormat& aReadbackFormat, 296 const Range<uint8_t>& aReadbackBuffer, bool* aNeedsYFlip) { 297 #ifdef MOZ_WIDGET_ANDROID 298 MOZ_ASSERT(aReadbackFormat == wr::ImageFormat::RGBA8); 299 const GLenum format = LOCAL_GL_RGBA; 300 #else 301 MOZ_ASSERT(aReadbackFormat == wr::ImageFormat::BGRA8); 302 const GLenum format = LOCAL_GL_BGRA; 303 #endif 304 305 GetGLContext()->fReadPixels(0, 0, aReadbackSize.width, aReadbackSize.height, 306 format, LOCAL_GL_UNSIGNED_BYTE, 307 &aReadbackBuffer[0]); 308 309 if (aNeedsYFlip) { 310 *aNeedsYFlip = true; 311 } 312 313 return true; 314 } 315 316 // This is a DataSourceSurface that represents a 0-based PBO for GLTextureImage. 317 class PBOUnpackSurface : public gfx::DataSourceSurface { 318 public: 319 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PBOUnpackSurface, override) 320 321 explicit PBOUnpackSurface(const gfx::IntSize& aSize) : mSize(aSize) {} 322 323 uint8_t* GetData() override { return nullptr; } 324 int32_t Stride() override { return mSize.width * sizeof(uint32_t); } 325 gfx::SurfaceType GetType() const override { 326 return gfx::SurfaceType::DATA_ALIGNED; 327 } 328 gfx::IntSize GetSize() const override { return mSize; } 329 gfx::SurfaceFormat GetFormat() const override { 330 return gfx::SurfaceFormat::B8G8R8A8; 331 } 332 333 // PBO offsets need to start from a 0 address, but DataSourceSurface::Map 334 // checks for failure by comparing the address against nullptr. Override Map 335 // to work around this. 336 bool Map(MapType, MappedSurface* aMappedSurface) override { 337 aMappedSurface->mData = GetData(); 338 aMappedSurface->mStride = Stride(); 339 return true; 340 } 341 342 void Unmap() override {} 343 344 private: 345 gfx::IntSize mSize; 346 }; 347 348 RenderCompositorOGLSWGL::TileOGL::TileOGL( 349 RefPtr<layers::TextureImageTextureSourceOGL>&& aTexture, 350 const gfx::IntSize& aSize) 351 : mTexture(aTexture) { 352 auto* gl = mTexture->gl(); 353 if (gl && gl->HasPBOState() && gl->MakeCurrent()) { 354 mSurface = new PBOUnpackSurface(aSize); 355 // Create a PBO large enough to encompass any valid rects within the tile. 356 gl->fGenBuffers(1, &mPBO); 357 gl->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, mPBO); 358 gl->fBufferData(LOCAL_GL_PIXEL_UNPACK_BUFFER, 359 mSurface->Stride() * aSize.height, nullptr, 360 LOCAL_GL_DYNAMIC_DRAW); 361 gl->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, 0); 362 } else { 363 // Couldn't allocate a PBO, so just use a memory surface instead. 364 mSurface = gfx::Factory::CreateDataSourceSurface( 365 aSize, gfx::SurfaceFormat::B8G8R8A8); 366 } 367 } 368 369 RenderCompositorOGLSWGL::TileOGL::~TileOGL() { 370 if (mPBO) { 371 auto* gl = mTexture->gl(); 372 if (gl && gl->MakeCurrent()) { 373 gl->fDeleteBuffers(1, &mPBO); 374 mPBO = 0; 375 } 376 } 377 } 378 379 layers::DataTextureSource* 380 RenderCompositorOGLSWGL::TileOGL::GetTextureSource() { 381 return mTexture.get(); 382 } 383 384 bool RenderCompositorOGLSWGL::TileOGL::Map(wr::DeviceIntRect aDirtyRect, 385 wr::DeviceIntRect aValidRect, 386 void** aData, int32_t* aStride) { 387 if (mPBO) { 388 auto* gl = mTexture->gl(); 389 if (!gl) { 390 return false; 391 } 392 // Map the PBO, but only within the range of the buffer that spans from the 393 // linear start offset to the linear end offset. Since we don't care about 394 // the previous contents of the buffer, we can just tell OpenGL to 395 // invalidate the entire buffer, even though we're only mapping a sub-range. 396 gl->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, mPBO); 397 size_t stride = mSurface->Stride(); 398 size_t offset = 399 stride * aValidRect.min.y + aValidRect.min.x * sizeof(uint32_t); 400 size_t length = stride * (aValidRect.height() - 1) + 401 (aValidRect.width()) * sizeof(uint32_t); 402 void* data = gl->fMapBufferRange( 403 LOCAL_GL_PIXEL_UNPACK_BUFFER, offset, length, 404 LOCAL_GL_MAP_WRITE_BIT | LOCAL_GL_MAP_INVALIDATE_BUFFER_BIT); 405 gl->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, 0); 406 if (!data) { 407 return false; 408 } 409 *aData = data; 410 *aStride = stride; 411 } else { 412 // No PBO is available, so just directly write to the memory surface. 413 gfx::DataSourceSurface::MappedSurface map; 414 if (!mSurface->Map(gfx::DataSourceSurface::READ_WRITE, &map)) { 415 return false; 416 } 417 // Verify that we're not somehow using a PBOUnpackSurface. 418 MOZ_ASSERT(map.mData != nullptr); 419 // glTex(Sub)Image on ES doesn't support arbitrary strides without 420 // the EXT_unpack_subimage extension. To avoid needing to make a 421 // copy of the data we'll always draw it with stride = bpp*width 422 // unless we're uploading the entire texture. 423 if (!mTexture->IsValid()) { 424 // If we don't have a texture we need to position our 425 // data in the correct spot because we're going to upload 426 // the entire surface 427 *aData = map.mData + aValidRect.min.y * map.mStride + 428 aValidRect.min.x * sizeof(uint32_t); 429 430 *aStride = map.mStride; 431 mSubSurface = nullptr; 432 } else { 433 // Otherwise, we can just use the top left as a scratch space 434 *aData = map.mData; 435 *aStride = aDirtyRect.width() * BytesPerPixel(mSurface->GetFormat()); 436 mSubSurface = Factory::CreateWrappingDataSourceSurface( 437 (uint8_t*)*aData, *aStride, 438 IntSize(aDirtyRect.width(), aDirtyRect.height()), 439 mSurface->GetFormat()); 440 } 441 } 442 return true; 443 } 444 445 void RenderCompositorOGLSWGL::TileOGL::Unmap(const gfx::IntRect& aDirtyRect) { 446 nsIntRegion dirty(aDirtyRect); 447 if (mPBO) { 448 // If there is a PBO, it must be unmapped before it can be sourced from. 449 // Leave the PBO bound before the call to Update so that the texture uploads 450 // will source from it. 451 auto* gl = mTexture->gl(); 452 if (!gl) { 453 return; 454 } 455 gl->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, mPBO); 456 gl->fUnmapBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER); 457 mTexture->Update(mSurface, &dirty); 458 gl->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, 0); 459 } else { 460 if (mSubSurface) { 461 mSurface->Unmap(); 462 // Our subsurface has a stride = aDirtyRect.width 463 // We use a negative offset to move it to match 464 // the dirty rect's top-left. These two offsets 465 // will cancel each other out by the time we reach 466 // TexSubImage. 467 IntPoint srcOffset = {0, 0}; 468 IntPoint dstOffset = aDirtyRect.TopLeft(); 469 // adjust the dirty region to be relative to the dstOffset 470 dirty.MoveBy(-dstOffset); 471 mTexture->Update(mSubSurface, &dirty, &srcOffset, &dstOffset); 472 mSubSurface = nullptr; 473 } else { 474 mSurface->Unmap(); 475 mTexture->Update(mSurface, &dirty); 476 } 477 } 478 } 479 480 } // namespace wr 481 } // namespace mozilla