RenderCompositorLayersSWGL.cpp (17375B)
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 "RenderCompositorLayersSWGL.h" 10 11 #include "GLContext.h" 12 #include "GLContextEGL.h" 13 #include "mozilla/layers/BuildConstants.h" 14 #include "mozilla/layers/Effects.h" 15 #include "mozilla/layers/TextureHostOGL.h" 16 #include "mozilla/widget/CompositorWidget.h" 17 #include "RenderCompositorRecordedFrame.h" 18 19 #if defined(XP_WIN) 20 # include "mozilla/webrender/RenderCompositorD3D11SWGL.h" 21 #else 22 # include "mozilla/webrender/RenderCompositorOGLSWGL.h" 23 #endif 24 25 namespace mozilla { 26 using namespace layers; 27 using namespace gfx; 28 29 namespace wr { 30 31 UniquePtr<RenderCompositor> RenderCompositorLayersSWGL::Create( 32 const RefPtr<widget::CompositorWidget>& aWidget, nsACString& aError) { 33 #ifdef XP_WIN 34 return RenderCompositorD3D11SWGL::Create(aWidget, aError); 35 #else 36 return RenderCompositorOGLSWGL::Create(aWidget, aError); 37 #endif 38 } 39 40 RenderCompositorLayersSWGL::RenderCompositorLayersSWGL( 41 Compositor* aCompositor, const RefPtr<widget::CompositorWidget>& aWidget, 42 void* aContext) 43 : RenderCompositor(aWidget), 44 mCompositor(aCompositor), 45 mContext(aContext), 46 mCurrentTileId(wr::NativeTileId()) { 47 MOZ_ASSERT(mCompositor); 48 MOZ_ASSERT(mContext); 49 } 50 51 RenderCompositorLayersSWGL::~RenderCompositorLayersSWGL() { 52 wr_swgl_destroy_context(mContext); 53 } 54 55 bool RenderCompositorLayersSWGL::MakeCurrent() { 56 wr_swgl_make_current(mContext); 57 return true; 58 } 59 60 bool RenderCompositorLayersSWGL::BeginFrame() { 61 MOZ_ASSERT(!mInFrame); 62 MakeCurrent(); 63 mInFrame = true; 64 return true; 65 } 66 67 void RenderCompositorLayersSWGL::CancelFrame() { 68 MOZ_ASSERT(mInFrame); 69 mInFrame = false; 70 if (mCompositingStarted) { 71 mCompositor->CancelFrame(); 72 mCompositingStarted = false; 73 } 74 } 75 76 void RenderCompositorLayersSWGL::StartCompositing( 77 wr::ColorF aClearColor, const wr::DeviceIntRect* aDirtyRects, 78 size_t aNumDirtyRects, const wr::DeviceIntRect* aOpaqueRects, 79 size_t aNumOpaqueRects) { 80 MOZ_RELEASE_ASSERT(!mCompositingStarted); 81 82 if (!mInFrame || aNumDirtyRects == 0) { 83 return; 84 } 85 86 gfx::IntRect bounds(gfx::IntPoint(0, 0), GetBufferSize().ToUnknownSize()); 87 nsIntRegion dirty; 88 89 MOZ_RELEASE_ASSERT(aNumDirtyRects > 0); 90 for (size_t i = 0; i < aNumDirtyRects; i++) { 91 const auto& rect = aDirtyRects[i]; 92 dirty.OrWith( 93 gfx::IntRect(rect.min.x, rect.min.y, rect.width(), rect.height())); 94 } 95 dirty.AndWith(bounds); 96 97 nsIntRegion opaque(bounds); 98 opaque.SubOut(mWidget->GetTransparentRegion().ToUnknownRegion()); 99 for (size_t i = 0; i < aNumOpaqueRects; i++) { 100 const auto& rect = aOpaqueRects[i]; 101 opaque.OrWith( 102 gfx::IntRect(rect.min.x, rect.min.y, rect.width(), rect.height())); 103 } 104 105 mCompositor->SetClearColor(gfx::DeviceColor(aClearColor.r, aClearColor.g, 106 aClearColor.b, aClearColor.a)); 107 108 if (!mCompositor->BeginFrameForWindow(dirty, Nothing(), bounds, opaque)) { 109 return; 110 } 111 mCompositingStarted = true; 112 } 113 114 void RenderCompositorLayersSWGL::CompositorEndFrame() { 115 nsTArray<FrameSurface> frameSurfaces = std::move(mFrameSurfaces); 116 117 if (!mCompositingStarted) { 118 return; 119 } 120 121 for (auto& frameSurface : frameSurfaces) { 122 auto surfaceCursor = mSurfaces.find(frameSurface.mId); 123 MOZ_RELEASE_ASSERT(surfaceCursor != mSurfaces.end()); 124 Surface* surface = surfaceCursor->second.get(); 125 126 for (auto it = surface->mTiles.begin(); it != surface->mTiles.end(); ++it) { 127 if (!it->second->IsValid()) { 128 continue; 129 } 130 131 gfx::Point tileOffset(it->first.mX * surface->mTileSize.width, 132 it->first.mY * surface->mTileSize.height); 133 gfx::Rect drawRect = it->second->mValidRect + tileOffset; 134 135 RefPtr<EffectRoundedClip> clipEffect; 136 137 if (!frameSurface.mRoundedClipRadii.IsEmpty()) { 138 clipEffect = new EffectRoundedClip(frameSurface.mRoundedClipRect, 139 frameSurface.mRoundedClipRadii); 140 } 141 142 RefPtr<TexturedEffect> texturedEffect = 143 new EffectRGB(it->second->GetTextureSource(), 144 /* aPremultiplied */ true, frameSurface.mFilter); 145 // TODO(gw): Enable premul copy on tiles that aren't affected 146 // by the rounded clip. 147 if (surface->mIsOpaque && !clipEffect) { 148 texturedEffect->mPremultipliedCopy = true; 149 } 150 151 texturedEffect->mTextureCoords = 152 gfx::Rect(it->second->mValidRect.x / surface->mTileSize.width, 153 it->second->mValidRect.y / surface->mTileSize.height, 154 it->second->mValidRect.width / surface->mTileSize.width, 155 it->second->mValidRect.height / surface->mTileSize.height); 156 157 EffectChain effect; 158 effect.mPrimaryEffect = texturedEffect; 159 effect.mRoundedClipEffect = clipEffect; 160 mCompositor->DrawQuad(drawRect, frameSurface.mClipRect, effect, 1.0, 161 frameSurface.mTransform, drawRect); 162 } 163 164 if (surface->mExternalImage) { 165 HandleExternalImage(surface->mExternalImage, frameSurface); 166 } 167 } 168 } 169 170 RenderedFrameId RenderCompositorLayersSWGL::EndFrame( 171 const nsTArray<DeviceIntRect>& aDirtyRects) { 172 MOZ_ASSERT(mInFrame); 173 mInFrame = false; 174 if (mCompositingStarted) { 175 mCompositor->EndFrame(); 176 mCompositingStarted = false; 177 } 178 return GetNextRenderFrameId(); 179 } 180 181 LayoutDeviceIntSize RenderCompositorLayersSWGL::GetBufferSize() { 182 return mWidget->GetClientSize(); 183 } 184 185 void RenderCompositorLayersSWGL::Bind(wr::NativeTileId aId, 186 wr::DeviceIntPoint* aOffset, 187 uint32_t* aFboId, 188 wr::DeviceIntRect aDirtyRect, 189 wr::DeviceIntRect aValidRect) { 190 MOZ_RELEASE_ASSERT(false); 191 } 192 193 void RenderCompositorLayersSWGL::Unbind() { MOZ_RELEASE_ASSERT(false); } 194 195 bool RenderCompositorLayersSWGL::MapTile(wr::NativeTileId aId, 196 wr::DeviceIntRect aDirtyRect, 197 wr::DeviceIntRect aValidRect, 198 void** aData, int32_t* aStride) { 199 auto surfaceCursor = mSurfaces.find(aId.surface_id); 200 MOZ_RELEASE_ASSERT(surfaceCursor != mSurfaces.end()); 201 Surface* surface = surfaceCursor->second.get(); 202 203 auto layerCursor = surface->mTiles.find(TileKey(aId.x, aId.y)); 204 MOZ_RELEASE_ASSERT(layerCursor != surface->mTiles.end()); 205 206 mCurrentTile = layerCursor->second.get(); 207 mCurrentTileId = aId; 208 mCurrentTileDirty = gfx::IntRect(aDirtyRect.min.x, aDirtyRect.min.y, 209 aDirtyRect.width(), aDirtyRect.height()); 210 211 if (!mCurrentTile->Map(aDirtyRect, aValidRect, aData, aStride)) { 212 gfxCriticalNote << "MapTile failed aValidRect: " 213 << gfx::Rect(aValidRect.min.x, aValidRect.min.y, 214 aValidRect.width(), aValidRect.height()); 215 return false; 216 } 217 218 // Store the new valid rect, so that we can composite only those pixels 219 mCurrentTile->mValidRect = gfx::Rect(aValidRect.min.x, aValidRect.min.y, 220 aValidRect.width(), aValidRect.height()); 221 return true; 222 } 223 224 void RenderCompositorLayersSWGL::UnmapTile() { 225 mCurrentTile->Unmap(mCurrentTileDirty); 226 mCurrentTile = nullptr; 227 } 228 229 void RenderCompositorLayersSWGL::CreateSurface( 230 wr::NativeSurfaceId aId, wr::DeviceIntPoint aVirtualOffset, 231 wr::DeviceIntSize aTileSize, bool aIsOpaque) { 232 MOZ_RELEASE_ASSERT(mSurfaces.find(aId) == mSurfaces.end()); 233 auto surface = DoCreateSurface(aTileSize, aIsOpaque); 234 mSurfaces.insert({aId, std::move(surface)}); 235 } 236 237 UniquePtr<RenderCompositorLayersSWGL::Surface> 238 RenderCompositorLayersSWGL::DoCreateSurface(wr::DeviceIntSize aTileSize, 239 bool aIsOpaque) { 240 return MakeUnique<Surface>(aTileSize, aIsOpaque); 241 } 242 243 void RenderCompositorLayersSWGL::CreateExternalSurface(wr::NativeSurfaceId aId, 244 bool aIsOpaque) { 245 MOZ_RELEASE_ASSERT(mSurfaces.find(aId) == mSurfaces.end()); 246 auto surface = MakeUnique<Surface>(wr::DeviceIntSize{}, aIsOpaque); 247 surface->mIsExternal = true; 248 mSurfaces.insert({aId, std::move(surface)}); 249 } 250 251 void RenderCompositorLayersSWGL::DestroySurface(NativeSurfaceId aId) { 252 auto surfaceCursor = mSurfaces.find(aId); 253 MOZ_RELEASE_ASSERT(surfaceCursor != mSurfaces.end()); 254 mSurfaces.erase(surfaceCursor); 255 } 256 257 void RenderCompositorLayersSWGL::CreateTile(wr::NativeSurfaceId aId, int32_t aX, 258 int32_t aY) { 259 auto surfaceCursor = mSurfaces.find(aId); 260 MOZ_RELEASE_ASSERT(surfaceCursor != mSurfaces.end()); 261 Surface* surface = surfaceCursor->second.get(); 262 MOZ_RELEASE_ASSERT(!surface->mIsExternal); 263 264 auto tile = DoCreateTile(surface); 265 surface->mTiles.insert({TileKey(aX, aY), std::move(tile)}); 266 } 267 268 void RenderCompositorLayersSWGL::DestroyTile(wr::NativeSurfaceId aId, 269 int32_t aX, int32_t aY) { 270 auto surfaceCursor = mSurfaces.find(aId); 271 MOZ_RELEASE_ASSERT(surfaceCursor != mSurfaces.end()); 272 Surface* surface = surfaceCursor->second.get(); 273 MOZ_RELEASE_ASSERT(!surface->mIsExternal); 274 275 auto layerCursor = surface->mTiles.find(TileKey(aX, aY)); 276 MOZ_RELEASE_ASSERT(layerCursor != surface->mTiles.end()); 277 surface->mTiles.erase(layerCursor); 278 } 279 280 void RenderCompositorLayersSWGL::AttachExternalImage( 281 wr::NativeSurfaceId aId, wr::ExternalImageId aExternalImage) { 282 RenderTextureHost* image = 283 RenderThread::Get()->GetRenderTexture(aExternalImage); 284 MOZ_ASSERT(image); 285 if (!image) { 286 gfxCriticalNoteOnce 287 << "Failed to get RenderTextureHost for D3D11SWGL extId:" 288 << AsUint64(aExternalImage); 289 return; 290 } 291 #if defined(XP_WIN) 292 MOZ_RELEASE_ASSERT(image->AsRenderDXGITextureHost() || 293 image->AsRenderDXGIYCbCrTextureHost()); 294 #elif defined(ANDROID) 295 MOZ_RELEASE_ASSERT(image->AsRenderAndroidHardwareBufferTextureHost() || 296 image->AsRenderAndroidSurfaceTextureHost() || 297 image->AsRenderEGLImageTextureHost()); 298 #endif 299 300 auto surfaceCursor = mSurfaces.find(aId); 301 MOZ_RELEASE_ASSERT(surfaceCursor != mSurfaces.end()); 302 303 Surface* surface = surfaceCursor->second.get(); 304 surface->mExternalImage = image; 305 MOZ_RELEASE_ASSERT(surface->mTiles.empty()); 306 MOZ_RELEASE_ASSERT(surface->mIsExternal); 307 } 308 309 // static 310 gfx::SamplingFilter RenderCompositorLayersSWGL::ToSamplingFilter( 311 wr::ImageRendering aImageRendering) { 312 if (aImageRendering == wr::ImageRendering::Auto) { 313 return gfx::SamplingFilter::LINEAR; 314 } 315 return gfx::SamplingFilter::POINT; 316 } 317 318 void RenderCompositorLayersSWGL::AddSurface( 319 wr::NativeSurfaceId aId, const wr::CompositorSurfaceTransform& aTransform, 320 wr::DeviceIntRect aClipRect, wr::ImageRendering aImageRendering, 321 wr::DeviceIntRect aRoundedClipRect, wr::ClipRadius aClipRadius) { 322 float sx = aTransform.scale.x; 323 float sy = aTransform.scale.y; 324 float tx = aTransform.offset.x; 325 float ty = aTransform.offset.y; 326 gfx::Matrix4x4 transform(sx, 0.0, 0.0, 0.0, 0.0, sy, 0.0, 0.0, 0.0, 0.0, 1.0, 327 0.0, tx, ty, 0.0, 1.0); 328 gfx::IntRect clipRect(aClipRect.min.x, aClipRect.min.y, aClipRect.width(), 329 aClipRect.height()); 330 331 gfx::Rect roundedClipRect(aRoundedClipRect.min.x, aRoundedClipRect.min.y, 332 aRoundedClipRect.width(), 333 aRoundedClipRect.height()); 334 gfx::RectCornerRadii radii(aClipRadius.top_left, aClipRadius.top_right, 335 aClipRadius.bottom_right, aClipRadius.bottom_left); 336 337 mFrameSurfaces.AppendElement(FrameSurface{aId, transform, clipRect, 338 ToSamplingFilter(aImageRendering), 339 roundedClipRect, radii}); 340 } 341 342 void RenderCompositorLayersSWGL::MaybeRequestAllowFrameRecording( 343 bool aWillRecord) { 344 mCompositor->RequestAllowFrameRecording(aWillRecord); 345 } 346 347 class WindowLMC : public profiler_screenshots::Window { 348 public: 349 explicit WindowLMC(Compositor* aCompositor) : mCompositor(aCompositor) {} 350 351 already_AddRefed<profiler_screenshots::RenderSource> GetWindowContents( 352 const gfx::IntSize& aWindowSize) override; 353 already_AddRefed<profiler_screenshots::DownscaleTarget> CreateDownscaleTarget( 354 const gfx::IntSize& aSize) override; 355 already_AddRefed<profiler_screenshots::AsyncReadbackBuffer> 356 CreateAsyncReadbackBuffer(const gfx::IntSize& aSize) override; 357 358 protected: 359 Compositor* mCompositor; 360 }; 361 362 class RenderSourceLMC : public profiler_screenshots::RenderSource { 363 public: 364 explicit RenderSourceLMC(CompositingRenderTarget* aRT) 365 : RenderSource(aRT->GetSize()), mRT(aRT) {} 366 367 const auto& RenderTarget() { return mRT; } 368 369 protected: 370 virtual ~RenderSourceLMC() {} 371 372 RefPtr<CompositingRenderTarget> mRT; 373 }; 374 375 class DownscaleTargetLMC : public profiler_screenshots::DownscaleTarget { 376 public: 377 explicit DownscaleTargetLMC(CompositingRenderTarget* aRT, 378 Compositor* aCompositor) 379 : profiler_screenshots::DownscaleTarget(aRT->GetSize()), 380 mRenderSource(new RenderSourceLMC(aRT)), 381 mCompositor(aCompositor) {} 382 383 already_AddRefed<profiler_screenshots::RenderSource> AsRenderSource() 384 override { 385 return do_AddRef(mRenderSource); 386 } 387 388 bool DownscaleFrom(profiler_screenshots::RenderSource* aSource, 389 const IntRect& aSourceRect, 390 const IntRect& aDestRect) override { 391 MOZ_RELEASE_ASSERT(aSourceRect.TopLeft() == IntPoint()); 392 MOZ_RELEASE_ASSERT(aDestRect.TopLeft() == IntPoint()); 393 RefPtr<CompositingRenderTarget> previousTarget = 394 mCompositor->GetCurrentRenderTarget(); 395 396 mCompositor->SetRenderTarget(mRenderSource->RenderTarget()); 397 bool result = mCompositor->BlitRenderTarget( 398 static_cast<RenderSourceLMC*>(aSource)->RenderTarget(), 399 aSourceRect.Size(), aDestRect.Size()); 400 401 // Restore the old render target. 402 mCompositor->SetRenderTarget(previousTarget); 403 404 return result; 405 } 406 407 protected: 408 virtual ~DownscaleTargetLMC() {} 409 410 RefPtr<RenderSourceLMC> mRenderSource; 411 Compositor* mCompositor; 412 }; 413 414 class AsyncReadbackBufferLMC 415 : public profiler_screenshots::AsyncReadbackBuffer { 416 public: 417 AsyncReadbackBufferLMC(mozilla::layers::AsyncReadbackBuffer* aARB, 418 Compositor* aCompositor) 419 : profiler_screenshots::AsyncReadbackBuffer(aARB->GetSize()), 420 mARB(aARB), 421 mCompositor(aCompositor) {} 422 void CopyFrom(profiler_screenshots::RenderSource* aSource) override { 423 mCompositor->ReadbackRenderTarget( 424 static_cast<RenderSourceLMC*>(aSource)->RenderTarget(), mARB); 425 } 426 bool MapAndCopyInto(DataSourceSurface* aSurface, 427 const IntSize& aReadSize) override { 428 return mARB->MapAndCopyInto(aSurface, aReadSize); 429 } 430 431 protected: 432 virtual ~AsyncReadbackBufferLMC() {} 433 434 RefPtr<mozilla::layers::AsyncReadbackBuffer> mARB; 435 Compositor* mCompositor; 436 }; 437 438 already_AddRefed<profiler_screenshots::RenderSource> 439 WindowLMC::GetWindowContents(const gfx::IntSize& aWindowSize) { 440 RefPtr<CompositingRenderTarget> rt = mCompositor->GetWindowRenderTarget(); 441 if (!rt) { 442 return nullptr; 443 } 444 return MakeAndAddRef<RenderSourceLMC>(rt); 445 } 446 447 already_AddRefed<profiler_screenshots::DownscaleTarget> 448 WindowLMC::CreateDownscaleTarget(const gfx::IntSize& aSize) { 449 RefPtr<CompositingRenderTarget> rt = 450 mCompositor->CreateRenderTarget(IntRect({}, aSize), INIT_MODE_NONE); 451 return MakeAndAddRef<DownscaleTargetLMC>(rt, mCompositor); 452 } 453 454 already_AddRefed<profiler_screenshots::AsyncReadbackBuffer> 455 WindowLMC::CreateAsyncReadbackBuffer(const gfx::IntSize& aSize) { 456 RefPtr<AsyncReadbackBuffer> carb = 457 mCompositor->CreateAsyncReadbackBuffer(aSize); 458 if (!carb) { 459 return nullptr; 460 } 461 return MakeAndAddRef<AsyncReadbackBufferLMC>(carb, mCompositor); 462 } 463 464 bool RenderCompositorLayersSWGL::MaybeRecordFrame( 465 layers::CompositionRecorder& aRecorder) { 466 WindowLMC window(mCompositor); 467 gfx::IntSize size = GetBufferSize().ToUnknownSize(); 468 RefPtr<layers::profiler_screenshots::RenderSource> snapshot = 469 window.GetWindowContents(size); 470 if (!snapshot) { 471 return true; 472 } 473 474 RefPtr<layers::profiler_screenshots::AsyncReadbackBuffer> buffer = 475 window.CreateAsyncReadbackBuffer(size); 476 buffer->CopyFrom(snapshot); 477 478 RefPtr<layers::RecordedFrame> frame = 479 new RenderCompositorRecordedFrame(TimeStamp::Now(), std::move(buffer)); 480 aRecorder.RecordFrame(frame); 481 return false; 482 } 483 484 bool RenderCompositorLayersSWGL::MaybeGrabScreenshot( 485 const gfx::IntSize& aWindowSize) { 486 if (!mCompositingStarted) { 487 return true; 488 } 489 WindowLMC window(mCompositor); 490 mProfilerScreenshotGrabber.MaybeGrabScreenshot(window, aWindowSize); 491 return true; 492 } 493 494 bool RenderCompositorLayersSWGL::MaybeProcessScreenshotQueue() { 495 mProfilerScreenshotGrabber.MaybeProcessQueue(); 496 return true; 497 } 498 499 } // namespace wr 500 } // namespace mozilla