1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=4 sw=2 sts=2 et: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /* This must occur *after* layers/PLayers.h to avoid typedefs conflicts. */
8 #include "LayerScope.h"
10 #include "nsAppRunner.h"
13 #include "mozilla/EndianUtils.h"
14 #include "mozilla/MathAlgorithms.h"
15 #include "mozilla/Preferences.h"
16 #include "mozilla/StaticPrefs_gfx.h"
17 #include "mozilla/TimeStamp.h"
19 #include "mozilla/layers/CompositorOGL.h"
20 #include "mozilla/layers/CompositorThread.h"
21 #include "mozilla/layers/LayerManagerComposite.h"
22 #include "mozilla/layers/TextureHostOGL.h"
24 #include "gfxContext.h"
27 #include "nsIWidget.h"
29 #include "GLContext.h"
30 #include "GLContextProvider.h"
31 #include "GLReadTexImageHelper.h"
34 #include "mozilla/LinkedList.h"
35 #include "mozilla/Base64.h"
36 #include "mozilla/SHA1.h"
37 #include "mozilla/StaticPtr.h"
38 #include "nsComponentManagerUtils.h"
39 #include "nsThreadUtils.h"
40 #include "nsISocketTransport.h"
41 #include "nsIServerSocket.h"
42 #include "nsReadLine.h"
44 #include "nsIOutputStream.h"
45 #include "nsIAsyncInputStream.h"
46 #include "nsProxyRelease.h"
49 // Undo the damage done by mozzconf.h
51 #include "mozilla/Compression.h"
53 // Undo the damage done by X11
57 // Protocol buffer (generated automatically)
58 #include "protobuf/LayerScopePacket.pb.h"
63 using namespace mozilla::Compression
;
64 using namespace mozilla::gfx
;
65 using namespace mozilla::gl
;
66 using namespace mozilla
;
67 using namespace layerscope
;
69 class DebugDataSender
;
73 * Manage Websocket connections
75 class LayerScopeWebSocketManager
{
77 LayerScopeWebSocketManager();
78 ~LayerScopeWebSocketManager();
80 void RemoveAllConnections() {
81 MOZ_ASSERT(NS_IsMainThread());
83 MutexAutoLock
lock(mHandlerMutex
);
87 bool WriteAll(void* ptr
, uint32_t size
) {
88 for (int32_t i
= mHandlers
.Length() - 1; i
>= 0; --i
) {
89 if (!mHandlers
[i
]->WriteToStream(ptr
, size
)) {
90 // Send failed, remove this handler
99 // This funtion can be called in both main thread and compositor thread.
100 MutexAutoLock
lock(mHandlerMutex
);
101 return (mHandlers
.Length() != 0) ? true : false;
104 void AppendDebugData(DebugGLData
* aDebugData
);
105 void CleanDebugData();
106 void DispatchDebugData();
109 void AddConnection(nsISocketTransport
* aTransport
) {
110 MOZ_ASSERT(NS_IsMainThread());
111 MOZ_ASSERT(aTransport
);
113 MutexAutoLock
lock(mHandlerMutex
);
115 RefPtr
<SocketHandler
> temp
= new SocketHandler();
116 temp
->OpenStream(aTransport
);
117 mHandlers
.AppendElement(temp
.get());
120 void RemoveConnection(uint32_t aIndex
) {
121 // TBD: RemoveConnection is executed on the compositor thread and
122 // AddConntection is executed on the main thread, which might be
123 // a problem if a user disconnect and connect readlly quickly at
126 // We should dispatch RemoveConnection onto main thead.
127 MOZ_ASSERT(aIndex
< mHandlers
.Length());
129 MutexAutoLock
lock(mHandlerMutex
);
130 mHandlers
.RemoveElementAt(aIndex
);
133 friend class SocketListener
;
134 class SocketListener
: public nsIServerSocketListener
{
136 NS_DECL_THREADSAFE_ISUPPORTS
138 SocketListener() = default;
140 /* nsIServerSocketListener */
141 NS_IMETHOD
OnSocketAccepted(nsIServerSocket
* aServ
,
142 nsISocketTransport
* aTransport
) override
;
143 NS_IMETHOD
OnStopListening(nsIServerSocket
* aServ
,
144 nsresult aStatus
) override
{
149 virtual ~SocketListener() = default;
153 * This class handle websocket protocol which included
154 * handshake and data frame's header
156 class SocketHandler
: public nsIInputStreamCallback
{
158 NS_DECL_THREADSAFE_ISUPPORTS
160 SocketHandler() : mState(NoHandshake
), mConnected(false) {}
162 void OpenStream(nsISocketTransport
* aTransport
);
163 bool WriteToStream(void* aPtr
, uint32_t aSize
);
165 // nsIInputStreamCallback
166 NS_IMETHOD
OnInputStreamReady(nsIAsyncInputStream
* aStream
) override
;
169 virtual ~SocketHandler() { CloseConnection(); }
171 void ReadInputStreamData(nsTArray
<nsCString
>& aProtocolString
);
172 bool WebSocketHandshake(nsTArray
<nsCString
>& aProtocolString
);
173 void ApplyMask(uint32_t aMask
, uint8_t* aData
, uint64_t aLen
);
174 bool HandleDataFrame(uint8_t* aData
, uint32_t aSize
);
175 void CloseConnection();
177 nsresult
HandleSocketMessage(nsIAsyncInputStream
* aStream
);
178 nsresult
ProcessInput(uint8_t* aBuffer
, uint32_t aCount
);
181 enum SocketStateType
{ NoHandshake
, HandshakeSuccess
, HandshakeFailed
};
182 SocketStateType mState
;
184 nsCOMPtr
<nsIOutputStream
> mOutputStream
;
185 nsCOMPtr
<nsIAsyncInputStream
> mInputStream
;
186 nsCOMPtr
<nsISocketTransport
> mTransport
;
190 nsTArray
<RefPtr
<SocketHandler
> > mHandlers
;
191 nsCOMPtr
<nsIThread
> mDebugSenderThread
;
192 RefPtr
<DebugDataSender
> mCurrentSender
;
193 nsCOMPtr
<nsIServerSocket
> mServerSocket
;
195 // Keep mHandlers accessing thread safe.
199 NS_IMPL_ISUPPORTS(LayerScopeWebSocketManager::SocketListener
,
200 nsIServerSocketListener
);
201 NS_IMPL_ISUPPORTS(LayerScopeWebSocketManager::SocketHandler
,
202 nsIInputStreamCallback
);
206 DrawSession() : mOffsetX(0.0), mOffsetY(0.0), mRects(0) {}
210 gfx::Matrix4x4 mMVMatrix
;
212 gfx::Rect mLayerRects
[4];
213 gfx::Rect mTextureRects
[4];
214 std::list
<GLuint
> mTexIDs
;
217 class ContentMonitor
{
219 using THArray
= nsTArray
<const TextureHost
*>;
221 // Notify the content of a TextureHost was changed.
222 void SetChangedHost(const TextureHost
* host
) {
223 if (THArray::NoIndex
== mChangedHosts
.IndexOf(host
)) {
224 mChangedHosts
.AppendElement(host
);
228 // Clear changed flag of a host.
229 void ClearChangedHost(const TextureHost
* host
) {
230 if (THArray::NoIndex
!= mChangedHosts
.IndexOf(host
)) {
231 mChangedHosts
.RemoveElement(host
);
235 // Return true iff host is a new one or the content of it had been changed.
236 bool IsChangedOrNew(const TextureHost
* host
) {
237 if (THArray::NoIndex
== mSeenHosts
.IndexOf(host
)) {
238 mSeenHosts
.AppendElement(host
);
242 if (decltype(mChangedHosts
)::NoIndex
!= mChangedHosts
.IndexOf(host
)) {
250 mSeenHosts
.SetLength(0);
251 mChangedHosts
.SetLength(0);
256 THArray mChangedHosts
;
260 * Hold all singleton objects used by LayerScope.
262 class LayerScopeManager
{
264 void CreateServerSocket() {
265 // WebSocketManager must be created on the main thread.
266 if (NS_IsMainThread()) {
267 mWebSocketManager
= mozilla::MakeUnique
<LayerScopeWebSocketManager
>();
269 // Dispatch creation to main thread, and make sure we
270 // dispatch this only once after booting
271 static bool dispatched
= false;
276 DebugOnly
<nsresult
> rv
=
277 NS_DispatchToMainThread(new CreateServerSocketRunnable(this));
278 MOZ_ASSERT(NS_SUCCEEDED(rv
),
279 "Failed to dispatch WebSocket Creation to main thread");
284 void DestroyServerSocket() {
285 // Destroy Web Server Socket
286 if (mWebSocketManager
) {
287 mWebSocketManager
->RemoveAllConnections();
291 LayerScopeWebSocketManager
* GetSocketManager() {
292 return mWebSocketManager
.get();
295 ContentMonitor
* GetContentMonitor() {
296 if (!mContentMonitor
.get()) {
297 mContentMonitor
= mozilla::MakeUnique
<ContentMonitor
>();
300 return mContentMonitor
.get();
303 void NewDrawSession() { mSession
= mozilla::MakeUnique
<DrawSession
>(); }
305 DrawSession
& CurrentSession() { return *mSession
; }
307 void SetPixelScale(double scale
) { mScale
= scale
; }
309 double GetPixelScale() const { return mScale
; }
311 LayerScopeManager() : mScale(1.0) {}
314 friend class CreateServerSocketRunnable
;
315 class CreateServerSocketRunnable
: public Runnable
{
317 explicit CreateServerSocketRunnable(LayerScopeManager
* aLayerScopeManager
)
318 : Runnable("layers::LayerScopeManager::CreateServerSocketRunnable"),
319 mLayerScopeManager(aLayerScopeManager
) {}
320 NS_IMETHOD
Run() override
{
321 mLayerScopeManager
->mWebSocketManager
=
322 mozilla::MakeUnique
<LayerScopeWebSocketManager
>();
327 LayerScopeManager
* mLayerScopeManager
;
330 mozilla::UniquePtr
<LayerScopeWebSocketManager
> mWebSocketManager
;
331 mozilla::UniquePtr
<DrawSession
> mSession
;
332 mozilla::UniquePtr
<ContentMonitor
> mContentMonitor
;
336 LayerScopeManager gLayerScopeManager
;
339 * The static helper functions that set data into the packet
343 template <typename T
>
344 static void DumpRect(T
* aPacketRect
, const Rect
& aRect
) {
345 aPacketRect
->set_x(aRect
.X());
346 aPacketRect
->set_y(aRect
.Y());
347 aPacketRect
->set_w(aRect
.Width());
348 aPacketRect
->set_h(aRect
.Height());
351 static void DumpFilter(TexturePacket
* aTexturePacket
,
352 const SamplingFilter aSamplingFilter
) {
353 switch (aSamplingFilter
) {
354 case SamplingFilter::GOOD
:
355 aTexturePacket
->set_mfilter(TexturePacket::GOOD
);
357 case SamplingFilter::LINEAR
:
358 aTexturePacket
->set_mfilter(TexturePacket::LINEAR
);
360 case SamplingFilter::POINT
:
361 aTexturePacket
->set_mfilter(TexturePacket::POINT
);
365 "Can't dump unexpected mSamplingFilter to texture packet!");
371 * DebugGLData is the base class of
372 * 1. DebugGLFrameStatusData (Frame start/end packet)
373 * 2. DebugGLColorData (Color data packet)
374 * 3. DebugGLTextureData (Texture data packet)
375 * 4. DebugGLLayersData (Layers Tree data packet)
376 * 5. DebugGLMetaData (Meta data packet)
378 class DebugGLData
: public LinkedListElement
<DebugGLData
> {
380 explicit DebugGLData(Packet::DataType aDataType
) : mDataType(aDataType
) {}
382 virtual ~DebugGLData() = default;
384 virtual bool Write() = 0;
387 static bool WriteToStream(Packet
& aPacket
) {
388 if (!gLayerScopeManager
.GetSocketManager()) return true;
390 size_t size
= aPacket
.ByteSizeLong();
391 auto data
= MakeUnique
<uint8_t[]>(size
);
392 aPacket
.SerializeToArray(data
.get(), size
);
393 return gLayerScopeManager
.GetSocketManager()->WriteAll(data
.get(), size
);
396 Packet::DataType mDataType
;
399 class DebugGLFrameStatusData final
: public DebugGLData
{
401 DebugGLFrameStatusData(Packet::DataType aDataType
, int64_t aValue
)
402 : DebugGLData(aDataType
), mFrameStamp(aValue
) {}
404 explicit DebugGLFrameStatusData(Packet::DataType aDataType
)
405 : DebugGLData(aDataType
), mFrameStamp(0) {}
407 bool Write() override
{
409 packet
.set_type(mDataType
);
411 FramePacket
* fp
= packet
.mutable_frame();
412 fp
->set_value(static_cast<uint64_t>(mFrameStamp
));
414 fp
->set_scale(gLayerScopeManager
.GetPixelScale());
416 return WriteToStream(packet
);
423 class DebugGLTextureData final
: public DebugGLData
{
425 DebugGLTextureData(GLContext
* cx
, void* layerRef
, GLenum target
, GLuint name
,
426 DataSourceSurface
* img
, bool aIsMask
,
427 UniquePtr
<Packet
> aPacket
)
428 : DebugGLData(Packet::TEXTURE
),
429 mLayerRef(reinterpret_cast<uint64_t>(layerRef
)),
432 mContextAddress(reinterpret_cast<intptr_t>(cx
)),
435 mPacket(std::move(aPacket
)) {
437 // DataSourceSurface may have locked buffer,
438 // so we should compress now, and then it could
439 // be unlocked outside.
443 bool Write() override
{ return WriteToStream(*mPacket
); }
446 void pack(DataSourceSurface
* aImage
) {
447 mPacket
->set_type(mDataType
);
449 TexturePacket
* tp
= mPacket
->mutable_texture();
450 tp
->set_layerref(mLayerRef
);
452 tp
->set_target(mTarget
);
453 tp
->set_dataformat(LOCAL_GL_RGBA
);
454 tp
->set_glcontext(static_cast<uint64_t>(mContextAddress
));
455 tp
->set_ismask(mIsMask
);
458 DataSourceSurface::ScopedMap
map(aImage
, DataSourceSurface::READ
);
459 tp
->set_width(aImage
->GetSize().width
);
460 tp
->set_height(aImage
->GetSize().height
);
461 tp
->set_stride(map
.GetStride());
463 mDatasize
= aImage
->GetSize().height
* map
.GetStride();
465 auto compresseddata
=
466 MakeUnique
<char[]>(LZ4::maxCompressedSize(mDatasize
));
467 if (compresseddata
) {
468 int ndatasize
= LZ4::compress((char*)map
.GetData(), mDatasize
,
469 compresseddata
.get());
471 mDatasize
= ndatasize
;
472 tp
->set_dataformat((1 << 16 | tp
->dataformat()));
473 tp
->set_data(compresseddata
.get(), mDatasize
);
475 NS_WARNING("Compress data failed");
476 tp
->set_data(map
.GetData(), mDatasize
);
479 NS_WARNING("Couldn't new compressed data.");
480 tp
->set_data(map
.GetData(), mDatasize
);
493 intptr_t mContextAddress
;
498 UniquePtr
<Packet
> mPacket
;
501 class DebugGLColorData final
: public DebugGLData
{
503 DebugGLColorData(void* layerRef
, const DeviceColor
& color
, int width
,
505 : DebugGLData(Packet::COLOR
),
506 mLayerRef(reinterpret_cast<uint64_t>(layerRef
)),
507 mColor(color
.ToABGR()),
508 mSize(width
, height
) {}
510 bool Write() override
{
512 packet
.set_type(mDataType
);
514 ColorPacket
* cp
= packet
.mutable_color();
515 cp
->set_layerref(mLayerRef
);
516 cp
->set_color(mColor
);
517 cp
->set_width(mSize
.width
);
518 cp
->set_height(mSize
.height
);
520 return WriteToStream(packet
);
529 class DebugGLLayersData final
: public DebugGLData
{
531 explicit DebugGLLayersData(UniquePtr
<Packet
> aPacket
)
532 : DebugGLData(Packet::LAYERS
), mPacket(std::move(aPacket
)) {}
534 bool Write() override
{
535 mPacket
->set_type(mDataType
);
536 return WriteToStream(*mPacket
);
540 UniquePtr
<Packet
> mPacket
;
543 class DebugGLMetaData final
: public DebugGLData
{
545 DebugGLMetaData(Packet::DataType aDataType
, bool aValue
)
546 : DebugGLData(aDataType
), mComposedByHwc(aValue
) {}
548 explicit DebugGLMetaData(Packet::DataType aDataType
)
549 : DebugGLData(aDataType
), mComposedByHwc(false) {}
551 bool Write() override
{
553 packet
.set_type(mDataType
);
555 MetaPacket
* mp
= packet
.mutable_meta();
556 mp
->set_composedbyhwc(mComposedByHwc
);
558 return WriteToStream(packet
);
565 class DebugGLDrawData final
: public DebugGLData
{
567 DebugGLDrawData(float aOffsetX
, float aOffsetY
,
568 const gfx::Matrix4x4
& aMVMatrix
, size_t aRects
,
569 const gfx::Rect
* aLayerRects
, const gfx::Rect
* aTextureRects
,
570 const std::list
<GLuint
>& aTexIDs
, void* aLayerRef
)
571 : DebugGLData(Packet::DRAW
),
574 mMVMatrix(aMVMatrix
),
577 mLayerRef(reinterpret_cast<uint64_t>(aLayerRef
)) {
578 for (size_t i
= 0; i
< mRects
; i
++) {
579 mLayerRects
[i
] = aLayerRects
[i
];
580 mTextureRects
[i
] = aTextureRects
[i
];
584 bool Write() override
{
586 packet
.set_type(mDataType
);
588 DrawPacket
* dp
= packet
.mutable_draw();
589 dp
->set_layerref(mLayerRef
);
591 dp
->set_offsetx(mOffsetX
);
592 dp
->set_offsety(mOffsetY
);
594 auto element
= reinterpret_cast<Float
*>(&mMVMatrix
);
595 for (int i
= 0; i
< 16; i
++) {
596 dp
->add_mvmatrix(*element
++);
598 dp
->set_totalrects(mRects
);
600 MOZ_ASSERT(mRects
> 0 && mRects
< 4);
601 for (size_t i
= 0; i
< mRects
; i
++) {
603 DumpRect(dp
->add_layerrect(), mLayerRects
[i
]);
605 DumpRect(dp
->add_texturerect(), mTextureRects
[i
]);
608 for (GLuint texId
: mTexIDs
) {
609 dp
->add_texids(texId
);
612 return WriteToStream(packet
);
618 gfx::Matrix4x4 mMVMatrix
;
620 gfx::Rect mLayerRects
[4];
621 gfx::Rect mTextureRects
[4];
622 std::list
<GLuint
> mTexIDs
;
626 class DebugDataSender
{
628 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DebugDataSender
)
630 // Append a DebugData into mList on mThread
631 class AppendTask
: public nsIRunnable
{
633 NS_DECL_THREADSAFE_ISUPPORTS
635 AppendTask(DebugDataSender
* host
, DebugGLData
* d
) : mData(d
), mHost(host
) {}
637 NS_IMETHOD
Run() override
{
638 mHost
->mList
.insertBack(mData
);
643 virtual ~AppendTask() = default;
646 // Keep a strong reference to DebugDataSender to prevent this object
647 // accessing mHost on mThread, when it's been destroyed on the main
649 RefPtr
<DebugDataSender
> mHost
;
652 // Clear all DebugData in mList on mThead.
653 class ClearTask
: public nsIRunnable
{
655 NS_DECL_THREADSAFE_ISUPPORTS
656 explicit ClearTask(DebugDataSender
* host
) : mHost(host
) {}
658 NS_IMETHOD
Run() override
{
664 virtual ~ClearTask() = default;
666 RefPtr
<DebugDataSender
> mHost
;
669 // Send all DebugData in mList via websocket, and then, clean up
671 class SendTask
: public nsIRunnable
{
673 NS_DECL_THREADSAFE_ISUPPORTS
675 explicit SendTask(DebugDataSender
* host
) : mHost(host
) {}
677 NS_IMETHOD
Run() override
{
678 // Sendout all appended debug data.
679 DebugGLData
* d
= nullptr;
680 while ((d
= mHost
->mList
.popFirst()) != nullptr) {
681 UniquePtr
<DebugGLData
> cleaner(d
);
683 gLayerScopeManager
.DestroyServerSocket();
694 virtual ~SendTask() = default;
696 RefPtr
<DebugDataSender
> mHost
;
699 explicit DebugDataSender(nsIThread
* thread
) : mThread(thread
) {}
701 void Append(DebugGLData
* d
) {
702 mThread
->Dispatch(new AppendTask(this, d
), NS_DISPATCH_NORMAL
);
705 void Cleanup() { mThread
->Dispatch(new ClearTask(this), NS_DISPATCH_NORMAL
); }
707 void Send() { mThread
->Dispatch(new SendTask(this), NS_DISPATCH_NORMAL
); }
710 virtual ~DebugDataSender() = default;
712 MOZ_ASSERT(mThread
->SerialEventTarget()->IsOnCurrentThread());
713 if (mList
.isEmpty()) return;
716 while ((d
= mList
.popFirst()) != nullptr) delete d
;
719 // We can only modify or aceess mList on mThread.
720 LinkedList
<DebugGLData
> mList
;
721 nsCOMPtr
<nsIThread
> mThread
;
724 NS_IMPL_ISUPPORTS(DebugDataSender::AppendTask
, nsIRunnable
);
725 NS_IMPL_ISUPPORTS(DebugDataSender::ClearTask
, nsIRunnable
);
726 NS_IMPL_ISUPPORTS(DebugDataSender::SendTask
, nsIRunnable
);
729 * LayerScope SendXXX Structure
732 * 1. SendTexturedEffect
733 * -> SendTextureSource
735 * -> SendTextureSource
737 * -> SendTextureSource
741 // Sender public APIs
743 static void SendLayer(LayerComposite
* aLayer
, int aWidth
, int aHeight
);
745 static void SendEffectChain(gl::GLContext
* aGLContext
,
746 const EffectChain
& aEffectChain
, int aWidth
= 0,
749 static void SetLayersTreeSendable(bool aSet
) { sLayersTreeSendable
= aSet
; }
751 static void SetLayersBufferSendable(bool aSet
) {
752 sLayersBufferSendable
= aSet
;
755 static bool GetLayersTreeSendable() { return sLayersTreeSendable
; }
757 static void ClearSentTextureIds();
759 // Sender private functions
761 static void SendColor(void* aLayerRef
, const DeviceColor
& aColor
, int aWidth
,
763 static void SendTextureSource(GLContext
* aGLContext
, void* aLayerRef
,
764 TextureSourceOGL
* aSource
, bool aFlipY
,
765 bool aIsMask
, UniquePtr
<Packet
> aPacket
);
766 static void SetAndSendTexture(GLContext
* aGLContext
, void* aLayerRef
,
767 TextureSourceOGL
* aSource
,
768 const TexturedEffect
* aEffect
);
769 static void SendTexturedEffect(GLContext
* aGLContext
, void* aLayerRef
,
770 const TexturedEffect
* aEffect
);
771 static void SendMaskEffect(GLContext
* aGLContext
, void* aLayerRef
,
772 const EffectMask
* aEffect
);
773 static void SendYCbCrEffect(GLContext
* aGLContext
, void* aLayerRef
,
774 const EffectYCbCr
* aEffect
);
775 static GLuint
GetTextureID(GLContext
* aGLContext
, TextureSourceOGL
* aSource
);
776 static bool HasTextureIdBeenSent(GLuint aTextureId
);
779 static bool sLayersTreeSendable
;
780 static bool sLayersBufferSendable
;
781 static std::vector
<GLuint
> sSentTextureIds
;
784 bool SenderHelper::sLayersTreeSendable
= true;
785 bool SenderHelper::sLayersBufferSendable
= true;
786 std::vector
<GLuint
> SenderHelper::sSentTextureIds
;
788 // ----------------------------------------------
789 // SenderHelper implementation
790 // ----------------------------------------------
791 void SenderHelper::ClearSentTextureIds() { sSentTextureIds
.clear(); }
793 bool SenderHelper::HasTextureIdBeenSent(GLuint aTextureId
) {
794 return std::find(sSentTextureIds
.begin(), sSentTextureIds
.end(),
795 aTextureId
) != sSentTextureIds
.end();
798 void SenderHelper::SendLayer(LayerComposite
* aLayer
, int aWidth
, int aHeight
) {
799 MOZ_ASSERT(aLayer
&& aLayer
->GetLayer());
800 if (!aLayer
|| !aLayer
->GetLayer()) {
804 switch (aLayer
->GetLayer()->GetType()) {
805 case Layer::TYPE_COLOR
: {
807 aLayer
->GenEffectChain(effect
);
809 LayerScope::DrawBegin();
810 LayerScope::DrawEnd(nullptr, effect
, aWidth
, aHeight
);
813 case Layer::TYPE_IMAGE
:
814 case Layer::TYPE_CANVAS
:
815 case Layer::TYPE_PAINTED
: {
816 // Get CompositableHost and Compositor
817 CompositableHost
* compHost
= aLayer
->GetCompositableHost();
818 TextureSourceProvider
* provider
= compHost
->GetTextureSourceProvider();
819 Compositor
* comp
= provider
->AsCompositor();
820 // Send EffectChain only for CompositorOGL
821 if (LayersBackend::LAYERS_OPENGL
== comp
->GetBackendType()) {
822 CompositorOGL
* compOGL
= comp
->AsCompositorOGL();
824 // Generate primary effect (lock and gen)
825 AutoLockCompositableHost
lock(compHost
);
826 aLayer
->GenEffectChain(effect
);
828 LayerScope::DrawBegin();
829 LayerScope::DrawEnd(compOGL
->gl(), effect
, aWidth
, aHeight
);
833 case Layer::TYPE_CONTAINER
:
839 void SenderHelper::SendColor(void* aLayerRef
, const DeviceColor
& aColor
,
840 int aWidth
, int aHeight
) {
841 gLayerScopeManager
.GetSocketManager()->AppendDebugData(
842 new DebugGLColorData(aLayerRef
, aColor
, aWidth
, aHeight
));
845 GLuint
SenderHelper::GetTextureID(GLContext
* aGLContext
,
846 TextureSourceOGL
* aSource
) {
847 GLenum textureTarget
= aSource
->GetTextureTarget();
848 aSource
->BindTexture(LOCAL_GL_TEXTURE0
, gfx::SamplingFilter::LINEAR
);
851 // This is horrid hack. It assumes that aGLContext matches the context
852 // aSource has bound to.
853 if (textureTarget
== LOCAL_GL_TEXTURE_2D
) {
854 aGLContext
->GetUIntegerv(LOCAL_GL_TEXTURE_BINDING_2D
, &texID
);
855 } else if (textureTarget
== LOCAL_GL_TEXTURE_EXTERNAL
) {
856 aGLContext
->GetUIntegerv(LOCAL_GL_TEXTURE_BINDING_EXTERNAL
, &texID
);
857 } else if (textureTarget
== LOCAL_GL_TEXTURE_RECTANGLE
) {
858 aGLContext
->GetUIntegerv(LOCAL_GL_TEXTURE_BINDING_RECTANGLE
, &texID
);
864 void SenderHelper::SendTextureSource(GLContext
* aGLContext
, void* aLayerRef
,
865 TextureSourceOGL
* aSource
, bool aFlipY
,
866 bool aIsMask
, UniquePtr
<Packet
> aPacket
) {
867 MOZ_ASSERT(aGLContext
);
871 GLuint texID
= GetTextureID(aGLContext
, aSource
);
872 if (HasTextureIdBeenSent(texID
)) {
876 GLenum textureTarget
= aSource
->GetTextureTarget();
877 ShaderConfigOGL config
=
878 ShaderConfigFromTargetAndFormat(textureTarget
, aSource
->GetFormat());
879 int shaderConfig
= config
.mFeatures
;
881 gfx::IntSize size
= aSource
->GetSize();
883 // By sending 0 to ReadTextureImage rely upon aSource->BindTexture binding
884 // texture correctly. texID is used for tracking in DebugGLTextureData.
885 RefPtr
<DataSourceSurface
> img
=
886 aGLContext
->ReadTexImageHelper()->ReadTexImage(0, textureTarget
, size
,
887 shaderConfig
, aFlipY
);
888 gLayerScopeManager
.GetSocketManager()->AppendDebugData(
889 new DebugGLTextureData(aGLContext
, aLayerRef
, textureTarget
, texID
, img
,
890 aIsMask
, std::move(aPacket
)));
892 sSentTextureIds
.push_back(texID
);
893 gLayerScopeManager
.CurrentSession().mTexIDs
.push_back(texID
);
896 void SenderHelper::SetAndSendTexture(GLContext
* aGLContext
, void* aLayerRef
,
897 TextureSourceOGL
* aSource
,
898 const TexturedEffect
* aEffect
) {
899 // Expose packet creation here, so we could dump primary texture effect
901 auto packet
= MakeUnique
<layerscope::Packet
>();
902 layerscope::TexturePacket
* texturePacket
= packet
->mutable_texture();
903 texturePacket
->set_mpremultiplied(aEffect
->mPremultiplied
);
904 DumpFilter(texturePacket
, aEffect
->mSamplingFilter
);
905 DumpRect(texturePacket
->mutable_mtexturecoords(), aEffect
->mTextureCoords
);
906 SendTextureSource(aGLContext
, aLayerRef
, aSource
, false, false,
910 void SenderHelper::SendTexturedEffect(GLContext
* aGLContext
, void* aLayerRef
,
911 const TexturedEffect
* aEffect
) {
912 TextureSourceOGL
* source
= aEffect
->mTexture
->AsSourceOGL();
917 // Fallback texture sending path.
918 SetAndSendTexture(aGLContext
, aLayerRef
, source
, aEffect
);
921 void SenderHelper::SendMaskEffect(GLContext
* aGLContext
, void* aLayerRef
,
922 const EffectMask
* aEffect
) {
923 TextureSourceOGL
* source
= aEffect
->mMaskTexture
->AsSourceOGL();
928 // Expose packet creation here, so we could dump secondary mask effect
930 auto packet
= MakeUnique
<layerscope::Packet
>();
931 TexturePacket::EffectMask
* mask
= packet
->mutable_texture()->mutable_mask();
932 mask
->mutable_msize()->set_w(aEffect
->mSize
.width
);
933 mask
->mutable_msize()->set_h(aEffect
->mSize
.height
);
934 auto element
= reinterpret_cast<const Float
*>(&(aEffect
->mMaskTransform
));
935 for (int i
= 0; i
< 16; i
++) {
936 mask
->mutable_mmasktransform()->add_m(*element
++);
939 SendTextureSource(aGLContext
, aLayerRef
, source
, false, true,
943 void SenderHelper::SendYCbCrEffect(GLContext
* aGLContext
, void* aLayerRef
,
944 const EffectYCbCr
* aEffect
) {
945 TextureSource
* sourceYCbCr
= aEffect
->mTexture
;
946 if (!sourceYCbCr
) return;
948 const int Y
= 0, Cb
= 1, Cr
= 2;
949 TextureSourceOGL
* sources
[] = {sourceYCbCr
->GetSubSource(Y
)->AsSourceOGL(),
950 sourceYCbCr
->GetSubSource(Cb
)->AsSourceOGL(),
951 sourceYCbCr
->GetSubSource(Cr
)->AsSourceOGL()};
953 for (auto source
: sources
) {
954 SetAndSendTexture(aGLContext
, aLayerRef
, source
, aEffect
);
958 void SenderHelper::SendEffectChain(GLContext
* aGLContext
,
959 const EffectChain
& aEffectChain
, int aWidth
,
961 if (!sLayersBufferSendable
) return;
963 const Effect
* primaryEffect
= aEffectChain
.mPrimaryEffect
;
964 MOZ_ASSERT(primaryEffect
);
966 if (!primaryEffect
) {
970 switch (primaryEffect
->mType
) {
971 case EffectTypes::RGB
: {
972 const TexturedEffect
* texturedEffect
=
973 static_cast<const TexturedEffect
*>(primaryEffect
);
974 SendTexturedEffect(aGLContext
, aEffectChain
.mLayerRef
, texturedEffect
);
977 case EffectTypes::YCBCR
: {
978 const EffectYCbCr
* yCbCrEffect
=
979 static_cast<const EffectYCbCr
*>(primaryEffect
);
980 SendYCbCrEffect(aGLContext
, aEffectChain
.mLayerRef
, yCbCrEffect
);
983 case EffectTypes::SOLID_COLOR
: {
984 const EffectSolidColor
* solidColorEffect
=
985 static_cast<const EffectSolidColor
*>(primaryEffect
);
986 SendColor(aEffectChain
.mLayerRef
, solidColorEffect
->mColor
, aWidth
,
990 case EffectTypes::COMPONENT_ALPHA
:
991 case EffectTypes::RENDER_TARGET
:
996 if (aEffectChain
.mSecondaryEffects
[EffectTypes::MASK
]) {
997 const EffectMask
* effectMask
= static_cast<const EffectMask
*>(
998 aEffectChain
.mSecondaryEffects
[EffectTypes::MASK
].get());
999 SendMaskEffect(aGLContext
, aEffectChain
.mLayerRef
, effectMask
);
1003 void LayerScope::ContentChanged(TextureHost
* host
) {
1004 if (!CheckSendable()) {
1008 gLayerScopeManager
.GetContentMonitor()->SetChangedHost(host
);
1011 // ----------------------------------------------
1012 // SocketHandler implementation
1013 // ----------------------------------------------
1014 void LayerScopeWebSocketManager::SocketHandler::OpenStream(
1015 nsISocketTransport
* aTransport
) {
1016 MOZ_ASSERT(aTransport
);
1018 mTransport
= aTransport
;
1019 mTransport
->OpenOutputStream(nsITransport::OPEN_BLOCKING
, 0, 0,
1020 getter_AddRefs(mOutputStream
));
1022 nsCOMPtr
<nsIInputStream
> debugInputStream
;
1023 mTransport
->OpenInputStream(0, 0, 0, getter_AddRefs(debugInputStream
));
1024 mInputStream
= do_QueryInterface(debugInputStream
);
1025 mInputStream
->AsyncWait(this, 0, 0, GetCurrentEventTarget());
1028 bool LayerScopeWebSocketManager::SocketHandler::WriteToStream(void* aPtr
,
1030 if (mState
== NoHandshake
) {
1031 // Not yet handshake, just return true in case of
1032 // LayerScope remove this handle
1034 } else if (mState
== HandshakeFailed
) {
1038 if (!mOutputStream
) {
1042 // Generate WebSocket header
1043 uint8_t wsHeader
[10];
1044 int wsHeaderSize
= 0;
1045 const uint8_t opcode
= 0x2;
1046 wsHeader
[0] = 0x80 | (opcode
& 0x0f); // FIN + opcode;
1049 wsHeader
[1] = aSize
;
1050 } else if (aSize
< 65536) {
1053 NetworkEndian::writeUint16(wsHeader
+ 2, aSize
);
1057 NetworkEndian::writeUint64(wsHeader
+ 2, aSize
);
1060 // Send WebSocket header
1063 rv
= mOutputStream
->Write(reinterpret_cast<char*>(wsHeader
), wsHeaderSize
,
1065 if (NS_FAILED(rv
)) return false;
1067 uint32_t written
= 0;
1068 while (written
< aSize
) {
1070 rv
= mOutputStream
->Write(reinterpret_cast<char*>(aPtr
) + written
,
1071 aSize
- written
, &cnt
);
1072 if (NS_FAILED(rv
)) return false;
1081 LayerScopeWebSocketManager::SocketHandler::OnInputStreamReady(
1082 nsIAsyncInputStream
* aStream
) {
1083 MOZ_ASSERT(mInputStream
);
1085 if (!mInputStream
) {
1090 nsTArray
<nsCString
> protocolString
;
1091 ReadInputStreamData(protocolString
);
1093 if (WebSocketHandshake(protocolString
)) {
1094 mState
= HandshakeSuccess
;
1096 mInputStream
->AsyncWait(this, 0, 0, GetCurrentEventTarget());
1098 mState
= HandshakeFailed
;
1102 return HandleSocketMessage(aStream
);
1106 void LayerScopeWebSocketManager::SocketHandler::ReadInputStreamData(
1107 nsTArray
<nsCString
>& aProtocolString
) {
1108 nsLineBuffer
<char> lineBuffer
;
1112 NS_ReadLine(mInputStream
.get(), &lineBuffer
, line
, &more
);
1114 if (line
.Length() > 0) {
1115 aProtocolString
.AppendElement(line
);
1117 } while (more
&& line
.Length() > 0);
1120 bool LayerScopeWebSocketManager::SocketHandler::WebSocketHandshake(
1121 nsTArray
<nsCString
>& aProtocolString
) {
1123 bool isWebSocket
= false;
1128 // Validate WebSocket client request.
1129 if (aProtocolString
.Length() == 0) return false;
1131 // Check that the HTTP method is GET
1132 const char* HTTP_METHOD
= "GET ";
1133 if (strncmp(aProtocolString
[0].get(), HTTP_METHOD
, strlen(HTTP_METHOD
)) !=
1138 for (uint32_t i
= 1; i
< aProtocolString
.Length(); ++i
) {
1139 const char* line
= aProtocolString
[i
].get();
1140 const char* prop_pos
= strchr(line
, ':');
1141 if (prop_pos
!= nullptr) {
1142 nsCString
key(line
, prop_pos
- line
);
1143 nsCString
value(prop_pos
+ 2);
1144 if (key
.EqualsIgnoreCase("upgrade") &&
1145 value
.EqualsIgnoreCase("websocket")) {
1147 } else if (key
.EqualsIgnoreCase("sec-websocket-version")) {
1149 } else if (key
.EqualsIgnoreCase("sec-websocket-key")) {
1151 } else if (key
.EqualsIgnoreCase("sec-websocket-protocol")) {
1161 if (!(version
.EqualsLiteral("7") || version
.EqualsLiteral("8") ||
1162 version
.EqualsLiteral("13"))) {
1166 if (!(protocol
.EqualsIgnoreCase("binary"))) {
1170 if (!mOutputStream
) {
1174 // Client request is valid. Start to generate and send server response.
1175 nsAutoCString
guid("258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
1178 nsCString
combined(wsKey
+ guid
);
1179 sha1
.update(combined
.get(), combined
.Length());
1180 uint8_t digest
[SHA1Sum::kHashSize
]; // SHA1 digests are 20 bytes long.
1181 sha1
.finish(digest
);
1182 nsCString
newString(reinterpret_cast<char*>(digest
), SHA1Sum::kHashSize
);
1183 nsCString
response("HTTP/1.1 101 Switching Protocols\r\n");
1184 response
.AppendLiteral("Upgrade: websocket\r\n");
1185 response
.AppendLiteral("Connection: Upgrade\r\n");
1186 response
.AppendLiteral("Sec-WebSocket-Accept: ");
1187 rv
= Base64EncodeAppend(newString
, response
);
1188 if (NS_FAILED(rv
)) {
1191 response
.AppendLiteral("\r\n");
1192 response
.AppendLiteral("Sec-WebSocket-Protocol: binary\r\n\r\n");
1193 uint32_t written
= 0;
1194 uint32_t size
= response
.Length();
1195 while (written
< size
) {
1197 rv
= mOutputStream
->Write(const_cast<char*>(response
.get()) + written
,
1198 size
- written
, &cnt
);
1199 if (NS_FAILED(rv
)) return false;
1203 mOutputStream
->Flush();
1208 nsresult
LayerScopeWebSocketManager::SocketHandler::HandleSocketMessage(
1209 nsIAsyncInputStream
* aStream
) {
1210 // The reading and parsing of this input stream is customized for layer
1212 const uint32_t cPacketSize
= 1024;
1213 char buffer
[cPacketSize
];
1215 nsresult rv
= NS_OK
;
1218 rv
= mInputStream
->Read((char*)buffer
, cPacketSize
, &count
);
1220 // TODO: combine packets if we have to read more than once
1222 if (rv
== NS_BASE_STREAM_WOULD_BLOCK
) {
1223 mInputStream
->AsyncWait(this, 0, 0, GetCurrentEventTarget());
1227 if (NS_FAILED(rv
)) {
1232 // NS_BASE_STREAM_CLOSED
1237 rv
= ProcessInput(reinterpret_cast<uint8_t*>(buffer
), count
);
1238 } while (NS_SUCCEEDED(rv
) && mInputStream
);
1242 nsresult
LayerScopeWebSocketManager::SocketHandler::ProcessInput(
1243 uint8_t* aBuffer
, uint32_t aCount
) {
1244 uint32_t avail
= aCount
;
1246 // Decode Websocket data frame
1248 NS_WARNING("Packet size is less than 2 bytes");
1252 // First byte, data type, only care the opcode
1253 // rsvBits: aBuffer[0] & 0x70 (0111 0000)
1254 uint8_t finBit
= aBuffer
[0] & 0x80; // 1000 0000
1255 uint8_t opcode
= aBuffer
[0] & 0x0F; // 0000 1111
1259 "We cannot handle multi-fragments messages in Layerscope websocket "
1264 // Second byte, data length
1265 uint8_t maskBit
= aBuffer
[1] & 0x80; // 1000 0000
1266 int64_t payloadLength64
= aBuffer
[1] & 0x7F; // 0111 1111
1269 NS_WARNING("Client to Server should set the mask bit");
1273 uint32_t framingLength
= 2 + 4; // 4 for masks
1275 if (payloadLength64
< 126) {
1276 if (avail
< framingLength
) return NS_OK
;
1277 } else if (payloadLength64
== 126) {
1278 // 16 bit length field
1280 if (avail
< framingLength
) {
1284 payloadLength64
= aBuffer
[2] << 8 | aBuffer
[3];
1288 if (avail
< framingLength
) {
1292 if (aBuffer
[2] & 0x80) {
1293 // Section 4.2 says that the most significant bit MUST be
1294 // 0. (i.e. this is really a 63 bit value)
1295 NS_WARNING("High bit of 64 bit length set");
1296 return NS_ERROR_ILLEGAL_VALUE
;
1299 // copy this in case it is unaligned
1300 payloadLength64
= NetworkEndian::readInt64(aBuffer
+ 2);
1303 uint8_t* payload
= aBuffer
+ framingLength
;
1304 avail
-= framingLength
;
1306 uint32_t payloadLength
= static_cast<uint32_t>(payloadLength64
);
1307 if (avail
< payloadLength
) {
1308 NS_WARNING("Packet size mismatch the payload length");
1313 uint32_t mask
= NetworkEndian::readUint32(payload
- 4);
1314 ApplyMask(mask
, payload
, payloadLength
);
1316 if (opcode
== 0x8) {
1317 // opcode == 0x8 means connection close
1319 return NS_BASE_STREAM_CLOSED
;
1322 if (!HandleDataFrame(payload
, payloadLength
)) {
1323 NS_WARNING("Cannot decode payload data by the protocol buffer");
1329 void LayerScopeWebSocketManager::SocketHandler::ApplyMask(uint32_t aMask
,
1332 if (!aData
|| aLen
== 0) {
1336 // Optimally we want to apply the mask 32 bits at a time,
1337 // but the buffer might not be alligned. So we first deal with
1338 // 0 to 3 bytes of preamble individually
1339 while (aLen
&& (reinterpret_cast<uintptr_t>(aData
) & 3)) {
1340 *aData
^= aMask
>> 24;
1341 aMask
= RotateLeft(aMask
, 8);
1346 // perform mask on full words of data
1347 uint32_t* iData
= reinterpret_cast<uint32_t*>(aData
);
1348 uint32_t* end
= iData
+ (aLen
>> 2);
1349 NetworkEndian::writeUint32(&aMask
, aMask
);
1350 for (; iData
< end
; iData
++) {
1353 aMask
= NetworkEndian::readUint32(&aMask
);
1354 aData
= (uint8_t*)iData
;
1357 // There maybe up to 3 trailing bytes that need to be dealt with
1360 *aData
^= aMask
>> 24;
1361 aMask
= RotateLeft(aMask
, 8);
1367 bool LayerScopeWebSocketManager::SocketHandler::HandleDataFrame(
1368 uint8_t* aData
, uint32_t aSize
) {
1369 // Handle payload data by protocol buffer
1370 auto p
= MakeUnique
<CommandPacket
>();
1371 p
->ParseFromArray(static_cast<void*>(aData
), aSize
);
1373 if (!p
->has_type()) {
1374 MOZ_ASSERT(false, "Protocol buffer decoding failed or cannot recongize it");
1378 switch (p
->type()) {
1379 case CommandPacket::LAYERS_TREE
:
1380 if (p
->has_value()) {
1381 SenderHelper::SetLayersTreeSendable(p
->value());
1385 case CommandPacket::LAYERS_BUFFER
:
1386 if (p
->has_value()) {
1387 SenderHelper::SetLayersBufferSendable(p
->value());
1391 case CommandPacket::NO_OP
:
1393 NS_WARNING("Invalid message type");
1399 void LayerScopeWebSocketManager::SocketHandler::CloseConnection() {
1400 gLayerScopeManager
.GetSocketManager()->CleanDebugData();
1402 mInputStream
->AsyncWait(nullptr, 0, 0, nullptr);
1403 mInputStream
= nullptr;
1405 if (mOutputStream
) {
1406 mOutputStream
= nullptr;
1409 mTransport
->Close(NS_BASE_STREAM_CLOSED
);
1410 mTransport
= nullptr;
1415 // ----------------------------------------------
1416 // LayerScopeWebSocketManager implementation
1417 // ----------------------------------------------
1418 LayerScopeWebSocketManager::LayerScopeWebSocketManager()
1419 : mHandlerMutex("LayerScopeWebSocketManager::mHandlerMutex") {
1420 NS_NewNamedThread("LayerScope", getter_AddRefs(mDebugSenderThread
));
1422 mServerSocket
= do_CreateInstance(NS_SERVERSOCKET_CONTRACTID
);
1423 int port
= StaticPrefs::gfx_layerscope_port();
1424 mServerSocket
->Init(port
, false, -1);
1425 mServerSocket
->AsyncListen(new SocketListener
);
1428 LayerScopeWebSocketManager::~LayerScopeWebSocketManager() {
1429 mServerSocket
->Close();
1432 void LayerScopeWebSocketManager::AppendDebugData(DebugGLData
* aDebugData
) {
1433 if (!mCurrentSender
) {
1434 mCurrentSender
= new DebugDataSender(mDebugSenderThread
);
1437 mCurrentSender
->Append(aDebugData
);
1440 void LayerScopeWebSocketManager::CleanDebugData() {
1441 if (mCurrentSender
) {
1442 mCurrentSender
->Cleanup();
1446 void LayerScopeWebSocketManager::DispatchDebugData() {
1447 MOZ_ASSERT(mCurrentSender
.get() != nullptr);
1449 mCurrentSender
->Send();
1450 mCurrentSender
= nullptr;
1453 NS_IMETHODIMP
LayerScopeWebSocketManager::SocketListener::OnSocketAccepted(
1454 nsIServerSocket
* aServ
, nsISocketTransport
* aTransport
) {
1455 if (!gLayerScopeManager
.GetSocketManager()) return NS_OK
;
1457 printf_stderr("*** LayerScope: Accepted connection\n");
1458 gLayerScopeManager
.GetSocketManager()->AddConnection(aTransport
);
1459 gLayerScopeManager
.GetContentMonitor()->Empty();
1463 // ----------------------------------------------
1464 // LayerScope implementation
1465 // ----------------------------------------------
1467 void LayerScope::Init() {
1468 if (!StaticPrefs::gfx_layerscope_enabled() || XRE_IsGPUProcess()) {
1472 gLayerScopeManager
.CreateServerSocket();
1476 void LayerScope::DrawBegin() {
1477 if (!CheckSendable()) {
1481 gLayerScopeManager
.NewDrawSession();
1485 void LayerScope::SetRenderOffset(float aX
, float aY
) {
1486 if (!CheckSendable()) {
1490 gLayerScopeManager
.CurrentSession().mOffsetX
= aX
;
1491 gLayerScopeManager
.CurrentSession().mOffsetY
= aY
;
1495 void LayerScope::SetLayerTransform(const gfx::Matrix4x4
& aMatrix
) {
1496 if (!CheckSendable()) {
1500 gLayerScopeManager
.CurrentSession().mMVMatrix
= aMatrix
;
1504 void LayerScope::SetDrawRects(size_t aRects
, const gfx::Rect
* aLayerRects
,
1505 const gfx::Rect
* aTextureRects
) {
1506 if (!CheckSendable()) {
1510 MOZ_ASSERT(aRects
> 0 && aRects
<= 4);
1511 MOZ_ASSERT(aLayerRects
);
1513 gLayerScopeManager
.CurrentSession().mRects
= aRects
;
1515 for (size_t i
= 0; i
< aRects
; i
++) {
1516 gLayerScopeManager
.CurrentSession().mLayerRects
[i
] = aLayerRects
[i
];
1517 gLayerScopeManager
.CurrentSession().mTextureRects
[i
] = aTextureRects
[i
];
1522 void LayerScope::DrawEnd(gl::GLContext
* aGLContext
,
1523 const EffectChain
& aEffectChain
, int aWidth
,
1525 // Protect this public function
1526 if (!CheckSendable()) {
1530 // 1. Send textures.
1531 SenderHelper::SendEffectChain(aGLContext
, aEffectChain
, aWidth
, aHeight
);
1533 // 2. Send parameters of draw call, such as uniforms and attributes of
1534 // vertex adnd fragment shader.
1535 DrawSession
& draws
= gLayerScopeManager
.CurrentSession();
1536 gLayerScopeManager
.GetSocketManager()->AppendDebugData(
1537 new DebugGLDrawData(draws
.mOffsetX
, draws
.mOffsetY
, draws
.mMVMatrix
,
1538 draws
.mRects
, draws
.mLayerRects
, draws
.mTextureRects
,
1539 draws
.mTexIDs
, aEffectChain
.mLayerRef
));
1543 void LayerScope::SendLayer(LayerComposite
* aLayer
, int aWidth
, int aHeight
) {
1544 // Protect this public function
1545 if (!CheckSendable()) {
1548 SenderHelper::SendLayer(aLayer
, aWidth
, aHeight
);
1552 void LayerScope::SendLayerDump(UniquePtr
<Packet
> aPacket
) {
1553 // Protect this public function
1554 if (!CheckSendable() || !SenderHelper::GetLayersTreeSendable()) {
1557 gLayerScopeManager
.GetSocketManager()->AppendDebugData(
1558 new DebugGLLayersData(std::move(aPacket
)));
1562 bool LayerScope::CheckSendable() {
1563 // Only compositor threads check LayerScope status
1564 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread() || gIsGtest
);
1566 if (!StaticPrefs::gfx_layerscope_enabled()) {
1569 if (!gLayerScopeManager
.GetSocketManager()) {
1573 if (!gLayerScopeManager
.GetSocketManager()->IsConnected()) {
1580 void LayerScope::CleanLayer() {
1581 if (CheckSendable()) {
1582 gLayerScopeManager
.GetSocketManager()->CleanDebugData();
1587 void LayerScope::SetHWComposed() {
1588 if (CheckSendable()) {
1589 gLayerScopeManager
.GetSocketManager()->AppendDebugData(
1590 new DebugGLMetaData(Packet::META
, true));
1595 void LayerScope::SetPixelScale(double devPixelsPerCSSPixel
) {
1596 gLayerScopeManager
.SetPixelScale(devPixelsPerCSSPixel
);
1599 // ----------------------------------------------
1600 // LayerScopeAutoFrame implementation
1601 // ----------------------------------------------
1602 LayerScopeAutoFrame::LayerScopeAutoFrame(int64_t aFrameStamp
) {
1604 BeginFrame(aFrameStamp
);
1607 LayerScopeAutoFrame::~LayerScopeAutoFrame() {
1612 void LayerScopeAutoFrame::BeginFrame(int64_t aFrameStamp
) {
1613 if (!LayerScope::CheckSendable()) {
1616 SenderHelper::ClearSentTextureIds();
1618 gLayerScopeManager
.GetSocketManager()->AppendDebugData(
1619 new DebugGLFrameStatusData(Packet::FRAMESTART
, aFrameStamp
));
1622 void LayerScopeAutoFrame::EndFrame() {
1623 if (!LayerScope::CheckSendable()) {
1627 gLayerScopeManager
.GetSocketManager()->AppendDebugData(
1628 new DebugGLFrameStatusData(Packet::FRAMEEND
));
1629 gLayerScopeManager
.GetSocketManager()->DispatchDebugData();
1632 } // namespace layers
1633 } // namespace mozilla