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 
Create(const RefPtr<widget::CompositorWidget> & aWidget,nsACString & aError)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 
RenderCompositorLayersSWGL(Compositor * aCompositor,const RefPtr<widget::CompositorWidget> & aWidget,void * aContext)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 
~RenderCompositorLayersSWGL()51 RenderCompositorLayersSWGL::~RenderCompositorLayersSWGL() {
52   wr_swgl_destroy_context(mContext);
53 }
54 
MakeCurrent()55 bool RenderCompositorLayersSWGL::MakeCurrent() {
56   wr_swgl_make_current(mContext);
57   return true;
58 }
59 
BeginFrame()60 bool RenderCompositorLayersSWGL::BeginFrame() {
61   MOZ_ASSERT(!mInFrame);
62   MakeCurrent();
63   mInFrame = true;
64   return true;
65 }
66 
CancelFrame()67 void RenderCompositorLayersSWGL::CancelFrame() {
68   MOZ_ASSERT(mInFrame);
69   mInFrame = false;
70   if (mCompositingStarted) {
71     mCompositor->CancelFrame();
72     mCompositingStarted = false;
73   }
74 }
75 
StartCompositing(wr::ColorF aClearColor,const wr::DeviceIntRect * aDirtyRects,size_t aNumDirtyRects,const wr::DeviceIntRect * aOpaqueRects,size_t aNumOpaqueRects)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 
CompositorEndFrame()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<TexturedEffect> texturedEffect =
136           new EffectRGB(it->second->GetTextureSource(),
137                         /* aPremultiplied */ true, frameSurface.mFilter);
138       if (surface->mIsOpaque) {
139         texturedEffect->mPremultipliedCopy = true;
140       }
141 
142       texturedEffect->mTextureCoords =
143           gfx::Rect(it->second->mValidRect.x / surface->mTileSize.width,
144                     it->second->mValidRect.y / surface->mTileSize.height,
145                     it->second->mValidRect.width / surface->mTileSize.width,
146                     it->second->mValidRect.height / surface->mTileSize.height);
147 
148       EffectChain effect;
149       effect.mPrimaryEffect = texturedEffect;
150       mCompositor->DrawQuad(drawRect, frameSurface.mClipRect, effect, 1.0,
151                             frameSurface.mTransform, drawRect);
152     }
153 
154     if (surface->mExternalImage) {
155       HandleExternalImage(surface->mExternalImage, frameSurface);
156     }
157   }
158 }
159 
EndFrame(const nsTArray<DeviceIntRect> & aDirtyRects)160 RenderedFrameId RenderCompositorLayersSWGL::EndFrame(
161     const nsTArray<DeviceIntRect>& aDirtyRects) {
162   MOZ_ASSERT(mInFrame);
163   mInFrame = false;
164   if (mCompositingStarted) {
165     mCompositor->EndFrame();
166     mCompositingStarted = false;
167   }
168   return GetNextRenderFrameId();
169 }
170 
GetBufferSize()171 LayoutDeviceIntSize RenderCompositorLayersSWGL::GetBufferSize() {
172   return mWidget->GetClientSize();
173 }
174 
Bind(wr::NativeTileId aId,wr::DeviceIntPoint * aOffset,uint32_t * aFboId,wr::DeviceIntRect aDirtyRect,wr::DeviceIntRect aValidRect)175 void RenderCompositorLayersSWGL::Bind(wr::NativeTileId aId,
176                                       wr::DeviceIntPoint* aOffset,
177                                       uint32_t* aFboId,
178                                       wr::DeviceIntRect aDirtyRect,
179                                       wr::DeviceIntRect aValidRect) {
180   MOZ_RELEASE_ASSERT(false);
181 }
182 
Unbind()183 void RenderCompositorLayersSWGL::Unbind() { MOZ_RELEASE_ASSERT(false); }
184 
MapTile(wr::NativeTileId aId,wr::DeviceIntRect aDirtyRect,wr::DeviceIntRect aValidRect,void ** aData,int32_t * aStride)185 bool RenderCompositorLayersSWGL::MapTile(wr::NativeTileId aId,
186                                          wr::DeviceIntRect aDirtyRect,
187                                          wr::DeviceIntRect aValidRect,
188                                          void** aData, int32_t* aStride) {
189   auto surfaceCursor = mSurfaces.find(aId.surface_id);
190   MOZ_RELEASE_ASSERT(surfaceCursor != mSurfaces.end());
191   Surface* surface = surfaceCursor->second.get();
192 
193   auto layerCursor = surface->mTiles.find(TileKey(aId.x, aId.y));
194   MOZ_RELEASE_ASSERT(layerCursor != surface->mTiles.end());
195 
196   mCurrentTile = layerCursor->second.get();
197   mCurrentTileId = aId;
198   mCurrentTileDirty = gfx::IntRect(aDirtyRect.min.x, aDirtyRect.min.y,
199                                    aDirtyRect.width(), aDirtyRect.height());
200 
201   if (!mCurrentTile->Map(aDirtyRect, aValidRect, aData, aStride)) {
202     gfxCriticalNote << "MapTile failed aValidRect: "
203                     << gfx::Rect(aValidRect.min.x, aValidRect.min.y,
204                                  aValidRect.width(), aValidRect.height());
205     return false;
206   }
207 
208   // Store the new valid rect, so that we can composite only those pixels
209   mCurrentTile->mValidRect = gfx::Rect(aValidRect.min.x, aValidRect.min.y,
210                                        aValidRect.width(), aValidRect.height());
211   return true;
212 }
213 
UnmapTile()214 void RenderCompositorLayersSWGL::UnmapTile() {
215   mCurrentTile->Unmap(mCurrentTileDirty);
216   mCurrentTile = nullptr;
217 }
218 
CreateSurface(wr::NativeSurfaceId aId,wr::DeviceIntPoint aVirtualOffset,wr::DeviceIntSize aTileSize,bool aIsOpaque)219 void RenderCompositorLayersSWGL::CreateSurface(
220     wr::NativeSurfaceId aId, wr::DeviceIntPoint aVirtualOffset,
221     wr::DeviceIntSize aTileSize, bool aIsOpaque) {
222   MOZ_RELEASE_ASSERT(mSurfaces.find(aId) == mSurfaces.end());
223   auto surface = DoCreateSurface(aTileSize, aIsOpaque);
224   mSurfaces.insert({aId, std::move(surface)});
225 }
226 
227 UniquePtr<RenderCompositorLayersSWGL::Surface>
DoCreateSurface(wr::DeviceIntSize aTileSize,bool aIsOpaque)228 RenderCompositorLayersSWGL::DoCreateSurface(wr::DeviceIntSize aTileSize,
229                                             bool aIsOpaque) {
230   return MakeUnique<Surface>(aTileSize, aIsOpaque);
231 }
232 
CreateExternalSurface(wr::NativeSurfaceId aId,bool aIsOpaque)233 void RenderCompositorLayersSWGL::CreateExternalSurface(wr::NativeSurfaceId aId,
234                                                        bool aIsOpaque) {
235   MOZ_RELEASE_ASSERT(mSurfaces.find(aId) == mSurfaces.end());
236   auto surface = MakeUnique<Surface>(wr::DeviceIntSize{}, aIsOpaque);
237   surface->mIsExternal = true;
238   mSurfaces.insert({aId, std::move(surface)});
239 }
240 
DestroySurface(NativeSurfaceId aId)241 void RenderCompositorLayersSWGL::DestroySurface(NativeSurfaceId aId) {
242   auto surfaceCursor = mSurfaces.find(aId);
243   MOZ_RELEASE_ASSERT(surfaceCursor != mSurfaces.end());
244   mSurfaces.erase(surfaceCursor);
245 }
246 
CreateTile(wr::NativeSurfaceId aId,int32_t aX,int32_t aY)247 void RenderCompositorLayersSWGL::CreateTile(wr::NativeSurfaceId aId, int32_t aX,
248                                             int32_t aY) {
249   auto surfaceCursor = mSurfaces.find(aId);
250   MOZ_RELEASE_ASSERT(surfaceCursor != mSurfaces.end());
251   Surface* surface = surfaceCursor->second.get();
252   MOZ_RELEASE_ASSERT(!surface->mIsExternal);
253 
254   auto tile = DoCreateTile(surface);
255   surface->mTiles.insert({TileKey(aX, aY), std::move(tile)});
256 }
257 
DestroyTile(wr::NativeSurfaceId aId,int32_t aX,int32_t aY)258 void RenderCompositorLayersSWGL::DestroyTile(wr::NativeSurfaceId aId,
259                                              int32_t aX, int32_t aY) {
260   auto surfaceCursor = mSurfaces.find(aId);
261   MOZ_RELEASE_ASSERT(surfaceCursor != mSurfaces.end());
262   Surface* surface = surfaceCursor->second.get();
263   MOZ_RELEASE_ASSERT(!surface->mIsExternal);
264 
265   auto layerCursor = surface->mTiles.find(TileKey(aX, aY));
266   MOZ_RELEASE_ASSERT(layerCursor != surface->mTiles.end());
267   surface->mTiles.erase(layerCursor);
268 }
269 
AttachExternalImage(wr::NativeSurfaceId aId,wr::ExternalImageId aExternalImage)270 void RenderCompositorLayersSWGL::AttachExternalImage(
271     wr::NativeSurfaceId aId, wr::ExternalImageId aExternalImage) {
272   RenderTextureHost* image =
273       RenderThread::Get()->GetRenderTexture(aExternalImage);
274   MOZ_ASSERT(image);
275   if (!image) {
276     gfxCriticalNoteOnce
277         << "Failed to get RenderTextureHost for D3D11SWGL extId:"
278         << AsUint64(aExternalImage);
279     return;
280   }
281 #if defined(XP_WIN)
282   MOZ_RELEASE_ASSERT(image->AsRenderDXGITextureHost() ||
283                      image->AsRenderDXGIYCbCrTextureHost());
284 #elif defined(ANDROID)
285   MOZ_RELEASE_ASSERT(image->AsRenderAndroidSurfaceTextureHost());
286 #endif
287 
288   auto surfaceCursor = mSurfaces.find(aId);
289   MOZ_RELEASE_ASSERT(surfaceCursor != mSurfaces.end());
290 
291   Surface* surface = surfaceCursor->second.get();
292   surface->mExternalImage = image;
293   MOZ_RELEASE_ASSERT(surface->mTiles.empty());
294   MOZ_RELEASE_ASSERT(surface->mIsExternal);
295 }
296 
297 // static
ToSamplingFilter(wr::ImageRendering aImageRendering)298 gfx::SamplingFilter RenderCompositorLayersSWGL::ToSamplingFilter(
299     wr::ImageRendering aImageRendering) {
300   if (aImageRendering == wr::ImageRendering::Auto) {
301     return gfx::SamplingFilter::LINEAR;
302   }
303   return gfx::SamplingFilter::POINT;
304 }
305 
AddSurface(wr::NativeSurfaceId aId,const wr::CompositorSurfaceTransform & aTransform,wr::DeviceIntRect aClipRect,wr::ImageRendering aImageRendering)306 void RenderCompositorLayersSWGL::AddSurface(
307     wr::NativeSurfaceId aId, const wr::CompositorSurfaceTransform& aTransform,
308     wr::DeviceIntRect aClipRect, wr::ImageRendering aImageRendering) {
309   gfx::Matrix4x4 transform(
310       aTransform.m11, aTransform.m12, aTransform.m13, aTransform.m14,
311       aTransform.m21, aTransform.m22, aTransform.m23, aTransform.m24,
312       aTransform.m31, aTransform.m32, aTransform.m33, aTransform.m34,
313       aTransform.m41, aTransform.m42, aTransform.m43, aTransform.m44);
314 
315   gfx::IntRect clipRect(aClipRect.min.x, aClipRect.min.y, aClipRect.width(),
316                         aClipRect.height());
317 
318   mFrameSurfaces.AppendElement(FrameSurface{aId, transform, clipRect,
319                                             ToSamplingFilter(aImageRendering)});
320 }
321 
MaybeRequestAllowFrameRecording(bool aWillRecord)322 void RenderCompositorLayersSWGL::MaybeRequestAllowFrameRecording(
323     bool aWillRecord) {
324   mCompositor->RequestAllowFrameRecording(aWillRecord);
325 }
326 
327 class WindowLMC : public profiler_screenshots::Window {
328  public:
WindowLMC(Compositor * aCompositor)329   explicit WindowLMC(Compositor* aCompositor) : mCompositor(aCompositor) {}
330 
331   already_AddRefed<profiler_screenshots::RenderSource> GetWindowContents(
332       const gfx::IntSize& aWindowSize) override;
333   already_AddRefed<profiler_screenshots::DownscaleTarget> CreateDownscaleTarget(
334       const gfx::IntSize& aSize) override;
335   already_AddRefed<profiler_screenshots::AsyncReadbackBuffer>
336   CreateAsyncReadbackBuffer(const gfx::IntSize& aSize) override;
337 
338  protected:
339   Compositor* mCompositor;
340 };
341 
342 class RenderSourceLMC : public profiler_screenshots::RenderSource {
343  public:
RenderSourceLMC(CompositingRenderTarget * aRT)344   explicit RenderSourceLMC(CompositingRenderTarget* aRT)
345       : RenderSource(aRT->GetSize()), mRT(aRT) {}
346 
RenderTarget()347   const auto& RenderTarget() { return mRT; }
348 
349  protected:
~RenderSourceLMC()350   virtual ~RenderSourceLMC() {}
351 
352   RefPtr<CompositingRenderTarget> mRT;
353 };
354 
355 class DownscaleTargetLMC : public profiler_screenshots::DownscaleTarget {
356  public:
DownscaleTargetLMC(CompositingRenderTarget * aRT,Compositor * aCompositor)357   explicit DownscaleTargetLMC(CompositingRenderTarget* aRT,
358                               Compositor* aCompositor)
359       : profiler_screenshots::DownscaleTarget(aRT->GetSize()),
360         mRenderSource(new RenderSourceLMC(aRT)),
361         mCompositor(aCompositor) {}
362 
AsRenderSource()363   already_AddRefed<profiler_screenshots::RenderSource> AsRenderSource()
364       override {
365     return do_AddRef(mRenderSource);
366   }
367 
DownscaleFrom(profiler_screenshots::RenderSource * aSource,const IntRect & aSourceRect,const IntRect & aDestRect)368   bool DownscaleFrom(profiler_screenshots::RenderSource* aSource,
369                      const IntRect& aSourceRect,
370                      const IntRect& aDestRect) override {
371     MOZ_RELEASE_ASSERT(aSourceRect.TopLeft() == IntPoint());
372     MOZ_RELEASE_ASSERT(aDestRect.TopLeft() == IntPoint());
373     RefPtr<CompositingRenderTarget> previousTarget =
374         mCompositor->GetCurrentRenderTarget();
375 
376     mCompositor->SetRenderTarget(mRenderSource->RenderTarget());
377     bool result = mCompositor->BlitRenderTarget(
378         static_cast<RenderSourceLMC*>(aSource)->RenderTarget(),
379         aSourceRect.Size(), aDestRect.Size());
380 
381     // Restore the old render target.
382     mCompositor->SetRenderTarget(previousTarget);
383 
384     return result;
385   }
386 
387  protected:
~DownscaleTargetLMC()388   virtual ~DownscaleTargetLMC() {}
389 
390   RefPtr<RenderSourceLMC> mRenderSource;
391   Compositor* mCompositor;
392 };
393 
394 class AsyncReadbackBufferLMC
395     : public profiler_screenshots::AsyncReadbackBuffer {
396  public:
AsyncReadbackBufferLMC(mozilla::layers::AsyncReadbackBuffer * aARB,Compositor * aCompositor)397   AsyncReadbackBufferLMC(mozilla::layers::AsyncReadbackBuffer* aARB,
398                          Compositor* aCompositor)
399       : profiler_screenshots::AsyncReadbackBuffer(aARB->GetSize()),
400         mARB(aARB),
401         mCompositor(aCompositor) {}
CopyFrom(profiler_screenshots::RenderSource * aSource)402   void CopyFrom(profiler_screenshots::RenderSource* aSource) override {
403     mCompositor->ReadbackRenderTarget(
404         static_cast<RenderSourceLMC*>(aSource)->RenderTarget(), mARB);
405   }
MapAndCopyInto(DataSourceSurface * aSurface,const IntSize & aReadSize)406   bool MapAndCopyInto(DataSourceSurface* aSurface,
407                       const IntSize& aReadSize) override {
408     return mARB->MapAndCopyInto(aSurface, aReadSize);
409   }
410 
411  protected:
~AsyncReadbackBufferLMC()412   virtual ~AsyncReadbackBufferLMC() {}
413 
414   RefPtr<mozilla::layers::AsyncReadbackBuffer> mARB;
415   Compositor* mCompositor;
416 };
417 
418 already_AddRefed<profiler_screenshots::RenderSource>
GetWindowContents(const gfx::IntSize & aWindowSize)419 WindowLMC::GetWindowContents(const gfx::IntSize& aWindowSize) {
420   RefPtr<CompositingRenderTarget> rt = mCompositor->GetWindowRenderTarget();
421   if (!rt) {
422     return nullptr;
423   }
424   return MakeAndAddRef<RenderSourceLMC>(rt);
425 }
426 
427 already_AddRefed<profiler_screenshots::DownscaleTarget>
CreateDownscaleTarget(const gfx::IntSize & aSize)428 WindowLMC::CreateDownscaleTarget(const gfx::IntSize& aSize) {
429   RefPtr<CompositingRenderTarget> rt =
430       mCompositor->CreateRenderTarget(IntRect({}, aSize), INIT_MODE_NONE);
431   return MakeAndAddRef<DownscaleTargetLMC>(rt, mCompositor);
432 }
433 
434 already_AddRefed<profiler_screenshots::AsyncReadbackBuffer>
CreateAsyncReadbackBuffer(const gfx::IntSize & aSize)435 WindowLMC::CreateAsyncReadbackBuffer(const gfx::IntSize& aSize) {
436   RefPtr<AsyncReadbackBuffer> carb =
437       mCompositor->CreateAsyncReadbackBuffer(aSize);
438   if (!carb) {
439     return nullptr;
440   }
441   return MakeAndAddRef<AsyncReadbackBufferLMC>(carb, mCompositor);
442 }
443 
MaybeRecordFrame(layers::CompositionRecorder & aRecorder)444 bool RenderCompositorLayersSWGL::MaybeRecordFrame(
445     layers::CompositionRecorder& aRecorder) {
446   WindowLMC window(mCompositor);
447   gfx::IntSize size = GetBufferSize().ToUnknownSize();
448   RefPtr<layers::profiler_screenshots::RenderSource> snapshot =
449       window.GetWindowContents(size);
450   if (!snapshot) {
451     return true;
452   }
453 
454   RefPtr<layers::profiler_screenshots::AsyncReadbackBuffer> buffer =
455       window.CreateAsyncReadbackBuffer(size);
456   buffer->CopyFrom(snapshot);
457 
458   RefPtr<layers::RecordedFrame> frame =
459       new RenderCompositorRecordedFrame(TimeStamp::Now(), std::move(buffer));
460   aRecorder.RecordFrame(frame);
461   return false;
462 }
463 
MaybeGrabScreenshot(const gfx::IntSize & aWindowSize)464 bool RenderCompositorLayersSWGL::MaybeGrabScreenshot(
465     const gfx::IntSize& aWindowSize) {
466   if (!mCompositingStarted) {
467     return true;
468   }
469   WindowLMC window(mCompositor);
470   mProfilerScreenshotGrabber.MaybeGrabScreenshot(window, aWindowSize);
471   return true;
472 }
473 
MaybeProcessScreenshotQueue()474 bool RenderCompositorLayersSWGL::MaybeProcessScreenshotQueue() {
475   mProfilerScreenshotGrabber.MaybeProcessQueue();
476   return true;
477 }
478 
479 }  // namespace wr
480 }  // namespace mozilla
481