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"
12 #include "mozilla/EndianUtils.h"
13 #include "mozilla/MathAlgorithms.h"
14 #include "mozilla/Preferences.h"
15 #include "mozilla/StaticPrefs_gfx.h"
16 #include "mozilla/TimeStamp.h"
18 #include "mozilla/layers/CompositorOGL.h"
19 #include "mozilla/layers/CompositorThread.h"
20 #include "mozilla/layers/LayerManagerComposite.h"
21 #include "mozilla/layers/TextureHostOGL.h"
23 #include "gfxContext.h"
26 #include "nsIWidget.h"
28 #include "GLContext.h"
29 #include "GLContextProvider.h"
30 #include "GLReadTexImageHelper.h"
33 #include "mozilla/LinkedList.h"
34 #include "mozilla/Base64.h"
35 #include "mozilla/SHA1.h"
36 #include "mozilla/StaticPtr.h"
37 #include "nsThreadUtils.h"
38 #include "nsISocketTransport.h"
39 #include "nsIServerSocket.h"
40 #include "nsReadLine.h"
42 #include "nsIOutputStream.h"
43 #include "nsIAsyncInputStream.h"
44 #include "nsProxyRelease.h"
47 // Undo the damage done by mozzconf.h
49 #include "mozilla/Compression.h"
51 // Undo the damage done by X11
55 // Protocol buffer (generated automatically)
56 #include "protobuf/LayerScopePacket.pb.h"
61 using namespace mozilla::Compression
;
62 using namespace mozilla::gfx
;
63 using namespace mozilla::gl
;
64 using namespace mozilla
;
65 using namespace layerscope
;
67 class DebugDataSender
;
71 * Manage Websocket connections
73 class LayerScopeWebSocketManager
{
75 LayerScopeWebSocketManager();
76 ~LayerScopeWebSocketManager();
78 void RemoveAllConnections() {
79 MOZ_ASSERT(NS_IsMainThread());
81 MutexAutoLock
lock(mHandlerMutex
);
85 bool WriteAll(void* ptr
, uint32_t size
) {
86 for (int32_t i
= mHandlers
.Length() - 1; i
>= 0; --i
) {
87 if (!mHandlers
[i
]->WriteToStream(ptr
, size
)) {
88 // Send failed, remove this handler
97 // This funtion can be called in both main thread and compositor thread.
98 MutexAutoLock
lock(mHandlerMutex
);
99 return (mHandlers
.Length() != 0) ? true : false;
102 void AppendDebugData(DebugGLData
* aDebugData
);
103 void CleanDebugData();
104 void DispatchDebugData();
107 void AddConnection(nsISocketTransport
* aTransport
) {
108 MOZ_ASSERT(NS_IsMainThread());
109 MOZ_ASSERT(aTransport
);
111 MutexAutoLock
lock(mHandlerMutex
);
113 RefPtr
<SocketHandler
> temp
= new SocketHandler();
114 temp
->OpenStream(aTransport
);
115 mHandlers
.AppendElement(temp
.get());
118 void RemoveConnection(uint32_t aIndex
) {
119 // TBD: RemoveConnection is executed on the compositor thread and
120 // AddConntection is executed on the main thread, which might be
121 // a problem if a user disconnect and connect readlly quickly at
124 // We should dispatch RemoveConnection onto main thead.
125 MOZ_ASSERT(aIndex
< mHandlers
.Length());
127 MutexAutoLock
lock(mHandlerMutex
);
128 mHandlers
.RemoveElementAt(aIndex
);
131 friend class SocketListener
;
132 class SocketListener
: public nsIServerSocketListener
{
134 NS_DECL_THREADSAFE_ISUPPORTS
136 SocketListener() = default;
138 /* nsIServerSocketListener */
139 NS_IMETHOD
OnSocketAccepted(nsIServerSocket
* aServ
,
140 nsISocketTransport
* aTransport
) override
;
141 NS_IMETHOD
OnStopListening(nsIServerSocket
* aServ
,
142 nsresult aStatus
) override
{
147 virtual ~SocketListener() = default;
151 * This class handle websocket protocol which included
152 * handshake and data frame's header
154 class SocketHandler
: public nsIInputStreamCallback
{
156 NS_DECL_THREADSAFE_ISUPPORTS
158 SocketHandler() : mState(NoHandshake
), mConnected(false) {}
160 void OpenStream(nsISocketTransport
* aTransport
);
161 bool WriteToStream(void* aPtr
, uint32_t aSize
);
163 // nsIInputStreamCallback
164 NS_IMETHOD
OnInputStreamReady(nsIAsyncInputStream
* aStream
) override
;
167 virtual ~SocketHandler() { CloseConnection(); }
169 void ReadInputStreamData(nsTArray
<nsCString
>& aProtocolString
);
170 bool WebSocketHandshake(nsTArray
<nsCString
>& aProtocolString
);
171 void ApplyMask(uint32_t aMask
, uint8_t* aData
, uint64_t aLen
);
172 bool HandleDataFrame(uint8_t* aData
, uint32_t aSize
);
173 void CloseConnection();
175 nsresult
HandleSocketMessage(nsIAsyncInputStream
* aStream
);
176 nsresult
ProcessInput(uint8_t* aBuffer
, uint32_t aCount
);
179 enum SocketStateType
{ NoHandshake
, HandshakeSuccess
, HandshakeFailed
};
180 SocketStateType mState
;
182 nsCOMPtr
<nsIOutputStream
> mOutputStream
;
183 nsCOMPtr
<nsIAsyncInputStream
> mInputStream
;
184 nsCOMPtr
<nsISocketTransport
> mTransport
;
188 nsTArray
<RefPtr
<SocketHandler
> > mHandlers
;
189 nsCOMPtr
<nsIThread
> mDebugSenderThread
;
190 RefPtr
<DebugDataSender
> mCurrentSender
;
191 nsCOMPtr
<nsIServerSocket
> mServerSocket
;
193 // Keep mHandlers accessing thread safe.
197 NS_IMPL_ISUPPORTS(LayerScopeWebSocketManager::SocketListener
,
198 nsIServerSocketListener
);
199 NS_IMPL_ISUPPORTS(LayerScopeWebSocketManager::SocketHandler
,
200 nsIInputStreamCallback
);
204 DrawSession() : mOffsetX(0.0), mOffsetY(0.0), mRects(0) {}
208 gfx::Matrix4x4 mMVMatrix
;
210 gfx::Rect mLayerRects
[4];
211 gfx::Rect mTextureRects
[4];
212 std::list
<GLuint
> mTexIDs
;
215 class ContentMonitor
{
217 using THArray
= nsTArray
<const TextureHost
*>;
219 // Notify the content of a TextureHost was changed.
220 void SetChangedHost(const TextureHost
* host
) {
221 if (THArray::NoIndex
== mChangedHosts
.IndexOf(host
)) {
222 mChangedHosts
.AppendElement(host
);
226 // Clear changed flag of a host.
227 void ClearChangedHost(const TextureHost
* host
) {
228 if (THArray::NoIndex
!= mChangedHosts
.IndexOf(host
)) {
229 mChangedHosts
.RemoveElement(host
);
233 // Return true iff host is a new one or the content of it had been changed.
234 bool IsChangedOrNew(const TextureHost
* host
) {
235 if (THArray::NoIndex
== mSeenHosts
.IndexOf(host
)) {
236 mSeenHosts
.AppendElement(host
);
240 if (decltype(mChangedHosts
)::NoIndex
!= mChangedHosts
.IndexOf(host
)) {
248 mSeenHosts
.SetLength(0);
249 mChangedHosts
.SetLength(0);
254 THArray mChangedHosts
;
258 * Hold all singleton objects used by LayerScope.
260 class LayerScopeManager
{
262 void CreateServerSocket() {
263 // WebSocketManager must be created on the main thread.
264 if (NS_IsMainThread()) {
265 mWebSocketManager
= mozilla::MakeUnique
<LayerScopeWebSocketManager
>();
267 // Dispatch creation to main thread, and make sure we
268 // dispatch this only once after booting
269 static bool dispatched
= false;
274 DebugOnly
<nsresult
> rv
=
275 NS_DispatchToMainThread(new CreateServerSocketRunnable(this));
276 MOZ_ASSERT(NS_SUCCEEDED(rv
),
277 "Failed to dispatch WebSocket Creation to main thread");
282 void DestroyServerSocket() {
283 // Destroy Web Server Socket
284 if (mWebSocketManager
) {
285 mWebSocketManager
->RemoveAllConnections();
289 LayerScopeWebSocketManager
* GetSocketManager() {
290 return mWebSocketManager
.get();
293 ContentMonitor
* GetContentMonitor() {
294 if (!mContentMonitor
.get()) {
295 mContentMonitor
= mozilla::MakeUnique
<ContentMonitor
>();
298 return mContentMonitor
.get();
301 void NewDrawSession() { mSession
= mozilla::MakeUnique
<DrawSession
>(); }
303 DrawSession
& CurrentSession() { return *mSession
; }
305 void SetPixelScale(double scale
) { mScale
= scale
; }
307 double GetPixelScale() const { return mScale
; }
309 LayerScopeManager() : mScale(1.0) {}
312 friend class CreateServerSocketRunnable
;
313 class CreateServerSocketRunnable
: public Runnable
{
315 explicit CreateServerSocketRunnable(LayerScopeManager
* aLayerScopeManager
)
316 : Runnable("layers::LayerScopeManager::CreateServerSocketRunnable"),
317 mLayerScopeManager(aLayerScopeManager
) {}
318 NS_IMETHOD
Run() override
{
319 mLayerScopeManager
->mWebSocketManager
=
320 mozilla::MakeUnique
<LayerScopeWebSocketManager
>();
325 LayerScopeManager
* mLayerScopeManager
;
328 mozilla::UniquePtr
<LayerScopeWebSocketManager
> mWebSocketManager
;
329 mozilla::UniquePtr
<DrawSession
> mSession
;
330 mozilla::UniquePtr
<ContentMonitor
> mContentMonitor
;
334 LayerScopeManager gLayerScopeManager
;
337 * The static helper functions that set data into the packet
341 template <typename T
>
342 static void DumpRect(T
* aPacketRect
, const Rect
& aRect
) {
343 aPacketRect
->set_x(aRect
.X());
344 aPacketRect
->set_y(aRect
.Y());
345 aPacketRect
->set_w(aRect
.Width());
346 aPacketRect
->set_h(aRect
.Height());
349 static void DumpFilter(TexturePacket
* aTexturePacket
,
350 const SamplingFilter aSamplingFilter
) {
351 switch (aSamplingFilter
) {
352 case SamplingFilter::GOOD
:
353 aTexturePacket
->set_mfilter(TexturePacket::GOOD
);
355 case SamplingFilter::LINEAR
:
356 aTexturePacket
->set_mfilter(TexturePacket::LINEAR
);
358 case SamplingFilter::POINT
:
359 aTexturePacket
->set_mfilter(TexturePacket::POINT
);
363 "Can't dump unexpected mSamplingFilter to texture packet!");
369 * DebugGLData is the base class of
370 * 1. DebugGLFrameStatusData (Frame start/end packet)
371 * 2. DebugGLColorData (Color data packet)
372 * 3. DebugGLTextureData (Texture data packet)
373 * 4. DebugGLLayersData (Layers Tree data packet)
374 * 5. DebugGLMetaData (Meta data packet)
376 class DebugGLData
: public LinkedListElement
<DebugGLData
> {
378 explicit DebugGLData(Packet::DataType aDataType
) : mDataType(aDataType
) {}
380 virtual ~DebugGLData() = default;
382 virtual bool Write() = 0;
385 static bool WriteToStream(Packet
& aPacket
) {
386 if (!gLayerScopeManager
.GetSocketManager()) return true;
388 size_t size
= aPacket
.ByteSizeLong();
389 auto data
= MakeUnique
<uint8_t[]>(size
);
390 aPacket
.SerializeToArray(data
.get(), size
);
391 return gLayerScopeManager
.GetSocketManager()->WriteAll(data
.get(), size
);
394 Packet::DataType mDataType
;
397 class DebugGLFrameStatusData final
: public DebugGLData
{
399 DebugGLFrameStatusData(Packet::DataType aDataType
, int64_t aValue
)
400 : DebugGLData(aDataType
), mFrameStamp(aValue
) {}
402 explicit DebugGLFrameStatusData(Packet::DataType aDataType
)
403 : DebugGLData(aDataType
), mFrameStamp(0) {}
405 bool Write() override
{
407 packet
.set_type(mDataType
);
409 FramePacket
* fp
= packet
.mutable_frame();
410 fp
->set_value(static_cast<uint64_t>(mFrameStamp
));
412 fp
->set_scale(gLayerScopeManager
.GetPixelScale());
414 return WriteToStream(packet
);
421 class DebugGLTextureData final
: public DebugGLData
{
423 DebugGLTextureData(GLContext
* cx
, void* layerRef
, GLenum target
, GLuint name
,
424 DataSourceSurface
* img
, bool aIsMask
,
425 UniquePtr
<Packet
> aPacket
)
426 : DebugGLData(Packet::TEXTURE
),
427 mLayerRef(reinterpret_cast<uint64_t>(layerRef
)),
430 mContextAddress(reinterpret_cast<intptr_t>(cx
)),
433 mPacket(std::move(aPacket
)) {
435 // DataSourceSurface may have locked buffer,
436 // so we should compress now, and then it could
437 // be unlocked outside.
441 bool Write() override
{ return WriteToStream(*mPacket
); }
444 void pack(DataSourceSurface
* aImage
) {
445 mPacket
->set_type(mDataType
);
447 TexturePacket
* tp
= mPacket
->mutable_texture();
448 tp
->set_layerref(mLayerRef
);
450 tp
->set_target(mTarget
);
451 tp
->set_dataformat(LOCAL_GL_RGBA
);
452 tp
->set_glcontext(static_cast<uint64_t>(mContextAddress
));
453 tp
->set_ismask(mIsMask
);
456 DataSourceSurface::ScopedMap
map(aImage
, DataSourceSurface::READ
);
457 tp
->set_width(aImage
->GetSize().width
);
458 tp
->set_height(aImage
->GetSize().height
);
459 tp
->set_stride(map
.GetStride());
461 mDatasize
= aImage
->GetSize().height
* map
.GetStride();
463 auto compresseddata
=
464 MakeUnique
<char[]>(LZ4::maxCompressedSize(mDatasize
));
465 if (compresseddata
) {
466 int ndatasize
= LZ4::compress((char*)map
.GetData(), mDatasize
,
467 compresseddata
.get());
469 mDatasize
= ndatasize
;
470 tp
->set_dataformat((1 << 16 | tp
->dataformat()));
471 tp
->set_data(compresseddata
.get(), mDatasize
);
473 NS_WARNING("Compress data failed");
474 tp
->set_data(map
.GetData(), mDatasize
);
477 NS_WARNING("Couldn't new compressed data.");
478 tp
->set_data(map
.GetData(), mDatasize
);
491 intptr_t mContextAddress
;
496 UniquePtr
<Packet
> mPacket
;
499 class DebugGLColorData final
: public DebugGLData
{
501 DebugGLColorData(void* layerRef
, const DeviceColor
& color
, int width
,
503 : DebugGLData(Packet::COLOR
),
504 mLayerRef(reinterpret_cast<uint64_t>(layerRef
)),
505 mColor(color
.ToABGR()),
506 mSize(width
, height
) {}
508 bool Write() override
{
510 packet
.set_type(mDataType
);
512 ColorPacket
* cp
= packet
.mutable_color();
513 cp
->set_layerref(mLayerRef
);
514 cp
->set_color(mColor
);
515 cp
->set_width(mSize
.width
);
516 cp
->set_height(mSize
.height
);
518 return WriteToStream(packet
);
527 class DebugGLLayersData final
: public DebugGLData
{
529 explicit DebugGLLayersData(UniquePtr
<Packet
> aPacket
)
530 : DebugGLData(Packet::LAYERS
), mPacket(std::move(aPacket
)) {}
532 bool Write() override
{
533 mPacket
->set_type(mDataType
);
534 return WriteToStream(*mPacket
);
538 UniquePtr
<Packet
> mPacket
;
541 class DebugGLMetaData final
: public DebugGLData
{
543 DebugGLMetaData(Packet::DataType aDataType
, bool aValue
)
544 : DebugGLData(aDataType
), mComposedByHwc(aValue
) {}
546 explicit DebugGLMetaData(Packet::DataType aDataType
)
547 : DebugGLData(aDataType
), mComposedByHwc(false) {}
549 bool Write() override
{
551 packet
.set_type(mDataType
);
553 MetaPacket
* mp
= packet
.mutable_meta();
554 mp
->set_composedbyhwc(mComposedByHwc
);
556 return WriteToStream(packet
);
563 class DebugGLDrawData final
: public DebugGLData
{
565 DebugGLDrawData(float aOffsetX
, float aOffsetY
,
566 const gfx::Matrix4x4
& aMVMatrix
, size_t aRects
,
567 const gfx::Rect
* aLayerRects
, const gfx::Rect
* aTextureRects
,
568 const std::list
<GLuint
>& aTexIDs
, void* aLayerRef
)
569 : DebugGLData(Packet::DRAW
),
572 mMVMatrix(aMVMatrix
),
575 mLayerRef(reinterpret_cast<uint64_t>(aLayerRef
)) {
576 for (size_t i
= 0; i
< mRects
; i
++) {
577 mLayerRects
[i
] = aLayerRects
[i
];
578 mTextureRects
[i
] = aTextureRects
[i
];
582 bool Write() override
{
584 packet
.set_type(mDataType
);
586 DrawPacket
* dp
= packet
.mutable_draw();
587 dp
->set_layerref(mLayerRef
);
589 dp
->set_offsetx(mOffsetX
);
590 dp
->set_offsety(mOffsetY
);
592 auto element
= reinterpret_cast<Float
*>(&mMVMatrix
);
593 for (int i
= 0; i
< 16; i
++) {
594 dp
->add_mvmatrix(*element
++);
596 dp
->set_totalrects(mRects
);
598 MOZ_ASSERT(mRects
> 0 && mRects
< 4);
599 for (size_t i
= 0; i
< mRects
; i
++) {
601 DumpRect(dp
->add_layerrect(), mLayerRects
[i
]);
603 DumpRect(dp
->add_texturerect(), mTextureRects
[i
]);
606 for (GLuint texId
: mTexIDs
) {
607 dp
->add_texids(texId
);
610 return WriteToStream(packet
);
616 gfx::Matrix4x4 mMVMatrix
;
618 gfx::Rect mLayerRects
[4];
619 gfx::Rect mTextureRects
[4];
620 std::list
<GLuint
> mTexIDs
;
624 class DebugDataSender
{
626 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DebugDataSender
)
628 // Append a DebugData into mList on mThread
629 class AppendTask
: public nsIRunnable
{
631 NS_DECL_THREADSAFE_ISUPPORTS
633 AppendTask(DebugDataSender
* host
, DebugGLData
* d
) : mData(d
), mHost(host
) {}
635 NS_IMETHOD
Run() override
{
636 mHost
->mList
.insertBack(mData
);
641 virtual ~AppendTask() = default;
644 // Keep a strong reference to DebugDataSender to prevent this object
645 // accessing mHost on mThread, when it's been destroyed on the main
647 RefPtr
<DebugDataSender
> mHost
;
650 // Clear all DebugData in mList on mThead.
651 class ClearTask
: public nsIRunnable
{
653 NS_DECL_THREADSAFE_ISUPPORTS
654 explicit ClearTask(DebugDataSender
* host
) : mHost(host
) {}
656 NS_IMETHOD
Run() override
{
662 virtual ~ClearTask() = default;
664 RefPtr
<DebugDataSender
> mHost
;
667 // Send all DebugData in mList via websocket, and then, clean up
669 class SendTask
: public nsIRunnable
{
671 NS_DECL_THREADSAFE_ISUPPORTS
673 explicit SendTask(DebugDataSender
* host
) : mHost(host
) {}
675 NS_IMETHOD
Run() override
{
676 // Sendout all appended debug data.
677 DebugGLData
* d
= nullptr;
678 while ((d
= mHost
->mList
.popFirst()) != nullptr) {
679 UniquePtr
<DebugGLData
> cleaner(d
);
681 gLayerScopeManager
.DestroyServerSocket();
692 virtual ~SendTask() = default;
694 RefPtr
<DebugDataSender
> mHost
;
697 explicit DebugDataSender(nsIThread
* thread
) : mThread(thread
) {}
699 void Append(DebugGLData
* d
) {
700 mThread
->Dispatch(new AppendTask(this, d
), NS_DISPATCH_NORMAL
);
703 void Cleanup() { mThread
->Dispatch(new ClearTask(this), NS_DISPATCH_NORMAL
); }
705 void Send() { mThread
->Dispatch(new SendTask(this), NS_DISPATCH_NORMAL
); }
708 virtual ~DebugDataSender() = default;
710 MOZ_ASSERT(mThread
->SerialEventTarget()->IsOnCurrentThread());
711 if (mList
.isEmpty()) return;
714 while ((d
= mList
.popFirst()) != nullptr) delete d
;
717 // We can only modify or aceess mList on mThread.
718 LinkedList
<DebugGLData
> mList
;
719 nsCOMPtr
<nsIThread
> mThread
;
722 NS_IMPL_ISUPPORTS(DebugDataSender::AppendTask
, nsIRunnable
);
723 NS_IMPL_ISUPPORTS(DebugDataSender::ClearTask
, nsIRunnable
);
724 NS_IMPL_ISUPPORTS(DebugDataSender::SendTask
, nsIRunnable
);
727 * LayerScope SendXXX Structure
730 * 1. SendTexturedEffect
731 * -> SendTextureSource
733 * -> SendTextureSource
735 * -> SendTextureSource
739 // Sender public APIs
741 static void SendLayer(LayerComposite
* aLayer
, int aWidth
, int aHeight
);
743 static void SendEffectChain(gl::GLContext
* aGLContext
,
744 const EffectChain
& aEffectChain
, int aWidth
= 0,
747 static void SetLayersTreeSendable(bool aSet
) { sLayersTreeSendable
= aSet
; }
749 static void SetLayersBufferSendable(bool aSet
) {
750 sLayersBufferSendable
= aSet
;
753 static bool GetLayersTreeSendable() { return sLayersTreeSendable
; }
755 static void ClearSentTextureIds();
757 // Sender private functions
759 static void SendColor(void* aLayerRef
, const DeviceColor
& aColor
, int aWidth
,
761 static void SendTextureSource(GLContext
* aGLContext
, void* aLayerRef
,
762 TextureSourceOGL
* aSource
, bool aFlipY
,
763 bool aIsMask
, UniquePtr
<Packet
> aPacket
);
764 static void SetAndSendTexture(GLContext
* aGLContext
, void* aLayerRef
,
765 TextureSourceOGL
* aSource
,
766 const TexturedEffect
* aEffect
);
767 static void SendTexturedEffect(GLContext
* aGLContext
, void* aLayerRef
,
768 const TexturedEffect
* aEffect
);
769 static void SendMaskEffect(GLContext
* aGLContext
, void* aLayerRef
,
770 const EffectMask
* aEffect
);
771 static void SendYCbCrEffect(GLContext
* aGLContext
, void* aLayerRef
,
772 const EffectYCbCr
* aEffect
);
773 static GLuint
GetTextureID(GLContext
* aGLContext
, TextureSourceOGL
* aSource
);
774 static bool HasTextureIdBeenSent(GLuint aTextureId
);
777 static bool sLayersTreeSendable
;
778 static bool sLayersBufferSendable
;
779 static std::vector
<GLuint
> sSentTextureIds
;
782 bool SenderHelper::sLayersTreeSendable
= true;
783 bool SenderHelper::sLayersBufferSendable
= true;
784 std::vector
<GLuint
> SenderHelper::sSentTextureIds
;
786 // ----------------------------------------------
787 // SenderHelper implementation
788 // ----------------------------------------------
789 void SenderHelper::ClearSentTextureIds() { sSentTextureIds
.clear(); }
791 bool SenderHelper::HasTextureIdBeenSent(GLuint aTextureId
) {
792 return std::find(sSentTextureIds
.begin(), sSentTextureIds
.end(),
793 aTextureId
) != sSentTextureIds
.end();
796 void SenderHelper::SendLayer(LayerComposite
* aLayer
, int aWidth
, int aHeight
) {
797 MOZ_ASSERT(aLayer
&& aLayer
->GetLayer());
798 if (!aLayer
|| !aLayer
->GetLayer()) {
802 switch (aLayer
->GetLayer()->GetType()) {
803 case Layer::TYPE_COLOR
: {
805 aLayer
->GenEffectChain(effect
);
807 LayerScope::DrawBegin();
808 LayerScope::DrawEnd(nullptr, effect
, aWidth
, aHeight
);
811 case Layer::TYPE_IMAGE
:
812 case Layer::TYPE_CANVAS
:
813 case Layer::TYPE_PAINTED
: {
814 // Get CompositableHost and Compositor
815 CompositableHost
* compHost
= aLayer
->GetCompositableHost();
816 TextureSourceProvider
* provider
= compHost
->GetTextureSourceProvider();
817 Compositor
* comp
= provider
->AsCompositor();
818 // Send EffectChain only for CompositorOGL
819 if (LayersBackend::LAYERS_OPENGL
== comp
->GetBackendType()) {
820 CompositorOGL
* compOGL
= comp
->AsCompositorOGL();
822 // Generate primary effect (lock and gen)
823 AutoLockCompositableHost
lock(compHost
);
824 aLayer
->GenEffectChain(effect
);
826 LayerScope::DrawBegin();
827 LayerScope::DrawEnd(compOGL
->gl(), effect
, aWidth
, aHeight
);
831 case Layer::TYPE_CONTAINER
:
837 void SenderHelper::SendColor(void* aLayerRef
, const DeviceColor
& aColor
,
838 int aWidth
, int aHeight
) {
839 gLayerScopeManager
.GetSocketManager()->AppendDebugData(
840 new DebugGLColorData(aLayerRef
, aColor
, aWidth
, aHeight
));
843 GLuint
SenderHelper::GetTextureID(GLContext
* aGLContext
,
844 TextureSourceOGL
* aSource
) {
845 GLenum textureTarget
= aSource
->GetTextureTarget();
846 aSource
->BindTexture(LOCAL_GL_TEXTURE0
, gfx::SamplingFilter::LINEAR
);
849 // This is horrid hack. It assumes that aGLContext matches the context
850 // aSource has bound to.
851 if (textureTarget
== LOCAL_GL_TEXTURE_2D
) {
852 aGLContext
->GetUIntegerv(LOCAL_GL_TEXTURE_BINDING_2D
, &texID
);
853 } else if (textureTarget
== LOCAL_GL_TEXTURE_EXTERNAL
) {
854 aGLContext
->GetUIntegerv(LOCAL_GL_TEXTURE_BINDING_EXTERNAL
, &texID
);
855 } else if (textureTarget
== LOCAL_GL_TEXTURE_RECTANGLE
) {
856 aGLContext
->GetUIntegerv(LOCAL_GL_TEXTURE_BINDING_RECTANGLE
, &texID
);
862 void SenderHelper::SendTextureSource(GLContext
* aGLContext
, void* aLayerRef
,
863 TextureSourceOGL
* aSource
, bool aFlipY
,
864 bool aIsMask
, UniquePtr
<Packet
> aPacket
) {
865 MOZ_ASSERT(aGLContext
);
869 GLuint texID
= GetTextureID(aGLContext
, aSource
);
870 if (HasTextureIdBeenSent(texID
)) {
874 GLenum textureTarget
= aSource
->GetTextureTarget();
875 ShaderConfigOGL config
=
876 ShaderConfigFromTargetAndFormat(textureTarget
, aSource
->GetFormat());
877 int shaderConfig
= config
.mFeatures
;
879 gfx::IntSize size
= aSource
->GetSize();
881 // By sending 0 to ReadTextureImage rely upon aSource->BindTexture binding
882 // texture correctly. texID is used for tracking in DebugGLTextureData.
883 RefPtr
<DataSourceSurface
> img
=
884 aGLContext
->ReadTexImageHelper()->ReadTexImage(0, textureTarget
, size
,
885 shaderConfig
, aFlipY
);
886 gLayerScopeManager
.GetSocketManager()->AppendDebugData(
887 new DebugGLTextureData(aGLContext
, aLayerRef
, textureTarget
, texID
, img
,
888 aIsMask
, std::move(aPacket
)));
890 sSentTextureIds
.push_back(texID
);
891 gLayerScopeManager
.CurrentSession().mTexIDs
.push_back(texID
);
894 void SenderHelper::SetAndSendTexture(GLContext
* aGLContext
, void* aLayerRef
,
895 TextureSourceOGL
* aSource
,
896 const TexturedEffect
* aEffect
) {
897 // Expose packet creation here, so we could dump primary texture effect
899 auto packet
= MakeUnique
<layerscope::Packet
>();
900 layerscope::TexturePacket
* texturePacket
= packet
->mutable_texture();
901 texturePacket
->set_mpremultiplied(aEffect
->mPremultiplied
);
902 DumpFilter(texturePacket
, aEffect
->mSamplingFilter
);
903 DumpRect(texturePacket
->mutable_mtexturecoords(), aEffect
->mTextureCoords
);
904 SendTextureSource(aGLContext
, aLayerRef
, aSource
, false, false,
908 void SenderHelper::SendTexturedEffect(GLContext
* aGLContext
, void* aLayerRef
,
909 const TexturedEffect
* aEffect
) {
910 TextureSourceOGL
* source
= aEffect
->mTexture
->AsSourceOGL();
915 // Fallback texture sending path.
916 SetAndSendTexture(aGLContext
, aLayerRef
, source
, aEffect
);
919 void SenderHelper::SendMaskEffect(GLContext
* aGLContext
, void* aLayerRef
,
920 const EffectMask
* aEffect
) {
921 TextureSourceOGL
* source
= aEffect
->mMaskTexture
->AsSourceOGL();
926 // Expose packet creation here, so we could dump secondary mask effect
928 auto packet
= MakeUnique
<layerscope::Packet
>();
929 TexturePacket::EffectMask
* mask
= packet
->mutable_texture()->mutable_mask();
930 mask
->mutable_msize()->set_w(aEffect
->mSize
.width
);
931 mask
->mutable_msize()->set_h(aEffect
->mSize
.height
);
932 auto element
= reinterpret_cast<const Float
*>(&(aEffect
->mMaskTransform
));
933 for (int i
= 0; i
< 16; i
++) {
934 mask
->mutable_mmasktransform()->add_m(*element
++);
937 SendTextureSource(aGLContext
, aLayerRef
, source
, false, true,
941 void SenderHelper::SendYCbCrEffect(GLContext
* aGLContext
, void* aLayerRef
,
942 const EffectYCbCr
* aEffect
) {
943 TextureSource
* sourceYCbCr
= aEffect
->mTexture
;
944 if (!sourceYCbCr
) return;
946 const int Y
= 0, Cb
= 1, Cr
= 2;
947 TextureSourceOGL
* sources
[] = {sourceYCbCr
->GetSubSource(Y
)->AsSourceOGL(),
948 sourceYCbCr
->GetSubSource(Cb
)->AsSourceOGL(),
949 sourceYCbCr
->GetSubSource(Cr
)->AsSourceOGL()};
951 for (auto source
: sources
) {
952 SetAndSendTexture(aGLContext
, aLayerRef
, source
, aEffect
);
956 void SenderHelper::SendEffectChain(GLContext
* aGLContext
,
957 const EffectChain
& aEffectChain
, int aWidth
,
959 if (!sLayersBufferSendable
) return;
961 const Effect
* primaryEffect
= aEffectChain
.mPrimaryEffect
;
962 MOZ_ASSERT(primaryEffect
);
964 if (!primaryEffect
) {
968 switch (primaryEffect
->mType
) {
969 case EffectTypes::RGB
: {
970 const TexturedEffect
* texturedEffect
=
971 static_cast<const TexturedEffect
*>(primaryEffect
);
972 SendTexturedEffect(aGLContext
, aEffectChain
.mLayerRef
, texturedEffect
);
975 case EffectTypes::YCBCR
: {
976 const EffectYCbCr
* yCbCrEffect
=
977 static_cast<const EffectYCbCr
*>(primaryEffect
);
978 SendYCbCrEffect(aGLContext
, aEffectChain
.mLayerRef
, yCbCrEffect
);
981 case EffectTypes::SOLID_COLOR
: {
982 const EffectSolidColor
* solidColorEffect
=
983 static_cast<const EffectSolidColor
*>(primaryEffect
);
984 SendColor(aEffectChain
.mLayerRef
, solidColorEffect
->mColor
, aWidth
,
988 case EffectTypes::COMPONENT_ALPHA
:
989 case EffectTypes::RENDER_TARGET
:
994 if (aEffectChain
.mSecondaryEffects
[EffectTypes::MASK
]) {
995 const EffectMask
* effectMask
= static_cast<const EffectMask
*>(
996 aEffectChain
.mSecondaryEffects
[EffectTypes::MASK
].get());
997 SendMaskEffect(aGLContext
, aEffectChain
.mLayerRef
, effectMask
);
1001 void LayerScope::ContentChanged(TextureHost
* host
) {
1002 if (!CheckSendable()) {
1006 gLayerScopeManager
.GetContentMonitor()->SetChangedHost(host
);
1009 // ----------------------------------------------
1010 // SocketHandler implementation
1011 // ----------------------------------------------
1012 void LayerScopeWebSocketManager::SocketHandler::OpenStream(
1013 nsISocketTransport
* aTransport
) {
1014 MOZ_ASSERT(aTransport
);
1016 mTransport
= aTransport
;
1017 mTransport
->OpenOutputStream(nsITransport::OPEN_BLOCKING
, 0, 0,
1018 getter_AddRefs(mOutputStream
));
1020 nsCOMPtr
<nsIInputStream
> debugInputStream
;
1021 mTransport
->OpenInputStream(0, 0, 0, getter_AddRefs(debugInputStream
));
1022 mInputStream
= do_QueryInterface(debugInputStream
);
1023 mInputStream
->AsyncWait(this, 0, 0, GetCurrentThreadEventTarget());
1026 bool LayerScopeWebSocketManager::SocketHandler::WriteToStream(void* aPtr
,
1028 if (mState
== NoHandshake
) {
1029 // Not yet handshake, just return true in case of
1030 // LayerScope remove this handle
1032 } else if (mState
== HandshakeFailed
) {
1036 if (!mOutputStream
) {
1040 // Generate WebSocket header
1041 uint8_t wsHeader
[10];
1042 int wsHeaderSize
= 0;
1043 const uint8_t opcode
= 0x2;
1044 wsHeader
[0] = 0x80 | (opcode
& 0x0f); // FIN + opcode;
1047 wsHeader
[1] = aSize
;
1048 } else if (aSize
< 65536) {
1051 NetworkEndian::writeUint16(wsHeader
+ 2, aSize
);
1055 NetworkEndian::writeUint64(wsHeader
+ 2, aSize
);
1058 // Send WebSocket header
1061 rv
= mOutputStream
->Write(reinterpret_cast<char*>(wsHeader
), wsHeaderSize
,
1063 if (NS_FAILED(rv
)) return false;
1065 uint32_t written
= 0;
1066 while (written
< aSize
) {
1068 rv
= mOutputStream
->Write(reinterpret_cast<char*>(aPtr
) + written
,
1069 aSize
- written
, &cnt
);
1070 if (NS_FAILED(rv
)) return false;
1079 LayerScopeWebSocketManager::SocketHandler::OnInputStreamReady(
1080 nsIAsyncInputStream
* aStream
) {
1081 MOZ_ASSERT(mInputStream
);
1083 if (!mInputStream
) {
1088 nsTArray
<nsCString
> protocolString
;
1089 ReadInputStreamData(protocolString
);
1091 if (WebSocketHandshake(protocolString
)) {
1092 mState
= HandshakeSuccess
;
1094 mInputStream
->AsyncWait(this, 0, 0, GetCurrentThreadEventTarget());
1096 mState
= HandshakeFailed
;
1100 return HandleSocketMessage(aStream
);
1104 void LayerScopeWebSocketManager::SocketHandler::ReadInputStreamData(
1105 nsTArray
<nsCString
>& aProtocolString
) {
1106 nsLineBuffer
<char> lineBuffer
;
1110 NS_ReadLine(mInputStream
.get(), &lineBuffer
, line
, &more
);
1112 if (line
.Length() > 0) {
1113 aProtocolString
.AppendElement(line
);
1115 } while (more
&& line
.Length() > 0);
1118 bool LayerScopeWebSocketManager::SocketHandler::WebSocketHandshake(
1119 nsTArray
<nsCString
>& aProtocolString
) {
1121 bool isWebSocket
= false;
1126 // Validate WebSocket client request.
1127 if (aProtocolString
.Length() == 0) return false;
1129 // Check that the HTTP method is GET
1130 const char* HTTP_METHOD
= "GET ";
1131 if (strncmp(aProtocolString
[0].get(), HTTP_METHOD
, strlen(HTTP_METHOD
)) !=
1136 for (uint32_t i
= 1; i
< aProtocolString
.Length(); ++i
) {
1137 const char* line
= aProtocolString
[i
].get();
1138 const char* prop_pos
= strchr(line
, ':');
1139 if (prop_pos
!= nullptr) {
1140 nsCString
key(line
, prop_pos
- line
);
1141 nsCString
value(prop_pos
+ 2);
1142 if (key
.EqualsIgnoreCase("upgrade") &&
1143 value
.EqualsIgnoreCase("websocket")) {
1145 } else if (key
.EqualsIgnoreCase("sec-websocket-version")) {
1147 } else if (key
.EqualsIgnoreCase("sec-websocket-key")) {
1149 } else if (key
.EqualsIgnoreCase("sec-websocket-protocol")) {
1159 if (!(version
.EqualsLiteral("7") || version
.EqualsLiteral("8") ||
1160 version
.EqualsLiteral("13"))) {
1164 if (!(protocol
.EqualsIgnoreCase("binary"))) {
1168 if (!mOutputStream
) {
1172 // Client request is valid. Start to generate and send server response.
1173 nsAutoCString
guid("258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
1176 nsCString
combined(wsKey
+ guid
);
1177 sha1
.update(combined
.get(), combined
.Length());
1178 uint8_t digest
[SHA1Sum::kHashSize
]; // SHA1 digests are 20 bytes long.
1179 sha1
.finish(digest
);
1180 nsCString
newString(reinterpret_cast<char*>(digest
), SHA1Sum::kHashSize
);
1181 rv
= Base64Encode(newString
, res
);
1182 if (NS_FAILED(rv
)) {
1185 nsCString
response("HTTP/1.1 101 Switching Protocols\r\n");
1186 response
.AppendLiteral("Upgrade: websocket\r\n");
1187 response
.AppendLiteral("Connection: Upgrade\r\n");
1188 response
.Append(nsCString("Sec-WebSocket-Accept: ") + res
+
1190 response
.AppendLiteral("Sec-WebSocket-Protocol: binary\r\n\r\n");
1191 uint32_t written
= 0;
1192 uint32_t size
= response
.Length();
1193 while (written
< size
) {
1195 rv
= mOutputStream
->Write(const_cast<char*>(response
.get()) + written
,
1196 size
- written
, &cnt
);
1197 if (NS_FAILED(rv
)) return false;
1201 mOutputStream
->Flush();
1206 nsresult
LayerScopeWebSocketManager::SocketHandler::HandleSocketMessage(
1207 nsIAsyncInputStream
* aStream
) {
1208 // The reading and parsing of this input stream is customized for layer
1210 const uint32_t cPacketSize
= 1024;
1211 char buffer
[cPacketSize
];
1213 nsresult rv
= NS_OK
;
1216 rv
= mInputStream
->Read((char*)buffer
, cPacketSize
, &count
);
1218 // TODO: combine packets if we have to read more than once
1220 if (rv
== NS_BASE_STREAM_WOULD_BLOCK
) {
1221 mInputStream
->AsyncWait(this, 0, 0, GetCurrentThreadEventTarget());
1225 if (NS_FAILED(rv
)) {
1230 // NS_BASE_STREAM_CLOSED
1235 rv
= ProcessInput(reinterpret_cast<uint8_t*>(buffer
), count
);
1236 } while (NS_SUCCEEDED(rv
) && mInputStream
);
1240 nsresult
LayerScopeWebSocketManager::SocketHandler::ProcessInput(
1241 uint8_t* aBuffer
, uint32_t aCount
) {
1242 uint32_t avail
= aCount
;
1244 // Decode Websocket data frame
1246 NS_WARNING("Packet size is less than 2 bytes");
1250 // First byte, data type, only care the opcode
1251 // rsvBits: aBuffer[0] & 0x70 (0111 0000)
1252 uint8_t finBit
= aBuffer
[0] & 0x80; // 1000 0000
1253 uint8_t opcode
= aBuffer
[0] & 0x0F; // 0000 1111
1257 "We cannot handle multi-fragments messages in Layerscope websocket "
1262 // Second byte, data length
1263 uint8_t maskBit
= aBuffer
[1] & 0x80; // 1000 0000
1264 int64_t payloadLength64
= aBuffer
[1] & 0x7F; // 0111 1111
1267 NS_WARNING("Client to Server should set the mask bit");
1271 uint32_t framingLength
= 2 + 4; // 4 for masks
1273 if (payloadLength64
< 126) {
1274 if (avail
< framingLength
) return NS_OK
;
1275 } else if (payloadLength64
== 126) {
1276 // 16 bit length field
1278 if (avail
< framingLength
) {
1282 payloadLength64
= aBuffer
[2] << 8 | aBuffer
[3];
1286 if (avail
< framingLength
) {
1290 if (aBuffer
[2] & 0x80) {
1291 // Section 4.2 says that the most significant bit MUST be
1292 // 0. (i.e. this is really a 63 bit value)
1293 NS_WARNING("High bit of 64 bit length set");
1294 return NS_ERROR_ILLEGAL_VALUE
;
1297 // copy this in case it is unaligned
1298 payloadLength64
= NetworkEndian::readInt64(aBuffer
+ 2);
1301 uint8_t* payload
= aBuffer
+ framingLength
;
1302 avail
-= framingLength
;
1304 uint32_t payloadLength
= static_cast<uint32_t>(payloadLength64
);
1305 if (avail
< payloadLength
) {
1306 NS_WARNING("Packet size mismatch the payload length");
1311 uint32_t mask
= NetworkEndian::readUint32(payload
- 4);
1312 ApplyMask(mask
, payload
, payloadLength
);
1314 if (opcode
== 0x8) {
1315 // opcode == 0x8 means connection close
1317 return NS_BASE_STREAM_CLOSED
;
1320 if (!HandleDataFrame(payload
, payloadLength
)) {
1321 NS_WARNING("Cannot decode payload data by the protocol buffer");
1327 void LayerScopeWebSocketManager::SocketHandler::ApplyMask(uint32_t aMask
,
1330 if (!aData
|| aLen
== 0) {
1334 // Optimally we want to apply the mask 32 bits at a time,
1335 // but the buffer might not be alligned. So we first deal with
1336 // 0 to 3 bytes of preamble individually
1337 while (aLen
&& (reinterpret_cast<uintptr_t>(aData
) & 3)) {
1338 *aData
^= aMask
>> 24;
1339 aMask
= RotateLeft(aMask
, 8);
1344 // perform mask on full words of data
1345 uint32_t* iData
= reinterpret_cast<uint32_t*>(aData
);
1346 uint32_t* end
= iData
+ (aLen
>> 2);
1347 NetworkEndian::writeUint32(&aMask
, aMask
);
1348 for (; iData
< end
; iData
++) {
1351 aMask
= NetworkEndian::readUint32(&aMask
);
1352 aData
= (uint8_t*)iData
;
1355 // There maybe up to 3 trailing bytes that need to be dealt with
1358 *aData
^= aMask
>> 24;
1359 aMask
= RotateLeft(aMask
, 8);
1365 bool LayerScopeWebSocketManager::SocketHandler::HandleDataFrame(
1366 uint8_t* aData
, uint32_t aSize
) {
1367 // Handle payload data by protocol buffer
1368 auto p
= MakeUnique
<CommandPacket
>();
1369 p
->ParseFromArray(static_cast<void*>(aData
), aSize
);
1371 if (!p
->has_type()) {
1372 MOZ_ASSERT(false, "Protocol buffer decoding failed or cannot recongize it");
1376 switch (p
->type()) {
1377 case CommandPacket::LAYERS_TREE
:
1378 if (p
->has_value()) {
1379 SenderHelper::SetLayersTreeSendable(p
->value());
1383 case CommandPacket::LAYERS_BUFFER
:
1384 if (p
->has_value()) {
1385 SenderHelper::SetLayersBufferSendable(p
->value());
1389 case CommandPacket::NO_OP
:
1391 NS_WARNING("Invalid message type");
1397 void LayerScopeWebSocketManager::SocketHandler::CloseConnection() {
1398 gLayerScopeManager
.GetSocketManager()->CleanDebugData();
1400 mInputStream
->AsyncWait(nullptr, 0, 0, nullptr);
1401 mInputStream
= nullptr;
1403 if (mOutputStream
) {
1404 mOutputStream
= nullptr;
1407 mTransport
->Close(NS_BASE_STREAM_CLOSED
);
1408 mTransport
= nullptr;
1413 // ----------------------------------------------
1414 // LayerScopeWebSocketManager implementation
1415 // ----------------------------------------------
1416 LayerScopeWebSocketManager::LayerScopeWebSocketManager()
1417 : mHandlerMutex("LayerScopeWebSocketManager::mHandlerMutex") {
1418 NS_NewNamedThread("LayerScope", getter_AddRefs(mDebugSenderThread
));
1420 mServerSocket
= do_CreateInstance(NS_SERVERSOCKET_CONTRACTID
);
1421 int port
= StaticPrefs::gfx_layerscope_port();
1422 mServerSocket
->Init(port
, false, -1);
1423 mServerSocket
->AsyncListen(new SocketListener
);
1426 LayerScopeWebSocketManager::~LayerScopeWebSocketManager() {
1427 mServerSocket
->Close();
1430 void LayerScopeWebSocketManager::AppendDebugData(DebugGLData
* aDebugData
) {
1431 if (!mCurrentSender
) {
1432 mCurrentSender
= new DebugDataSender(mDebugSenderThread
);
1435 mCurrentSender
->Append(aDebugData
);
1438 void LayerScopeWebSocketManager::CleanDebugData() {
1439 if (mCurrentSender
) {
1440 mCurrentSender
->Cleanup();
1444 void LayerScopeWebSocketManager::DispatchDebugData() {
1445 MOZ_ASSERT(mCurrentSender
.get() != nullptr);
1447 mCurrentSender
->Send();
1448 mCurrentSender
= nullptr;
1451 NS_IMETHODIMP
LayerScopeWebSocketManager::SocketListener::OnSocketAccepted(
1452 nsIServerSocket
* aServ
, nsISocketTransport
* aTransport
) {
1453 if (!gLayerScopeManager
.GetSocketManager()) return NS_OK
;
1455 printf_stderr("*** LayerScope: Accepted connection\n");
1456 gLayerScopeManager
.GetSocketManager()->AddConnection(aTransport
);
1457 gLayerScopeManager
.GetContentMonitor()->Empty();
1461 // ----------------------------------------------
1462 // LayerScope implementation
1463 // ----------------------------------------------
1465 void LayerScope::Init() {
1466 if (!StaticPrefs::gfx_layerscope_enabled() || XRE_IsGPUProcess()) {
1470 gLayerScopeManager
.CreateServerSocket();
1474 void LayerScope::DrawBegin() {
1475 if (!CheckSendable()) {
1479 gLayerScopeManager
.NewDrawSession();
1483 void LayerScope::SetRenderOffset(float aX
, float aY
) {
1484 if (!CheckSendable()) {
1488 gLayerScopeManager
.CurrentSession().mOffsetX
= aX
;
1489 gLayerScopeManager
.CurrentSession().mOffsetY
= aY
;
1493 void LayerScope::SetLayerTransform(const gfx::Matrix4x4
& aMatrix
) {
1494 if (!CheckSendable()) {
1498 gLayerScopeManager
.CurrentSession().mMVMatrix
= aMatrix
;
1502 void LayerScope::SetDrawRects(size_t aRects
, const gfx::Rect
* aLayerRects
,
1503 const gfx::Rect
* aTextureRects
) {
1504 if (!CheckSendable()) {
1508 MOZ_ASSERT(aRects
> 0 && aRects
<= 4);
1509 MOZ_ASSERT(aLayerRects
);
1511 gLayerScopeManager
.CurrentSession().mRects
= aRects
;
1513 for (size_t i
= 0; i
< aRects
; i
++) {
1514 gLayerScopeManager
.CurrentSession().mLayerRects
[i
] = aLayerRects
[i
];
1515 gLayerScopeManager
.CurrentSession().mTextureRects
[i
] = aTextureRects
[i
];
1520 void LayerScope::DrawEnd(gl::GLContext
* aGLContext
,
1521 const EffectChain
& aEffectChain
, int aWidth
,
1523 // Protect this public function
1524 if (!CheckSendable()) {
1528 // 1. Send textures.
1529 SenderHelper::SendEffectChain(aGLContext
, aEffectChain
, aWidth
, aHeight
);
1531 // 2. Send parameters of draw call, such as uniforms and attributes of
1532 // vertex adnd fragment shader.
1533 DrawSession
& draws
= gLayerScopeManager
.CurrentSession();
1534 gLayerScopeManager
.GetSocketManager()->AppendDebugData(
1535 new DebugGLDrawData(draws
.mOffsetX
, draws
.mOffsetY
, draws
.mMVMatrix
,
1536 draws
.mRects
, draws
.mLayerRects
, draws
.mTextureRects
,
1537 draws
.mTexIDs
, aEffectChain
.mLayerRef
));
1541 void LayerScope::SendLayer(LayerComposite
* aLayer
, int aWidth
, int aHeight
) {
1542 // Protect this public function
1543 if (!CheckSendable()) {
1546 SenderHelper::SendLayer(aLayer
, aWidth
, aHeight
);
1550 void LayerScope::SendLayerDump(UniquePtr
<Packet
> aPacket
) {
1551 // Protect this public function
1552 if (!CheckSendable() || !SenderHelper::GetLayersTreeSendable()) {
1555 gLayerScopeManager
.GetSocketManager()->AppendDebugData(
1556 new DebugGLLayersData(std::move(aPacket
)));
1560 bool LayerScope::CheckSendable() {
1561 // Only compositor threads check LayerScope status
1562 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread() || gIsGtest
);
1564 if (!StaticPrefs::gfx_layerscope_enabled()) {
1567 if (!gLayerScopeManager
.GetSocketManager()) {
1571 if (!gLayerScopeManager
.GetSocketManager()->IsConnected()) {
1578 void LayerScope::CleanLayer() {
1579 if (CheckSendable()) {
1580 gLayerScopeManager
.GetSocketManager()->CleanDebugData();
1585 void LayerScope::SetHWComposed() {
1586 if (CheckSendable()) {
1587 gLayerScopeManager
.GetSocketManager()->AppendDebugData(
1588 new DebugGLMetaData(Packet::META
, true));
1593 void LayerScope::SetPixelScale(double devPixelsPerCSSPixel
) {
1594 gLayerScopeManager
.SetPixelScale(devPixelsPerCSSPixel
);
1597 // ----------------------------------------------
1598 // LayerScopeAutoFrame implementation
1599 // ----------------------------------------------
1600 LayerScopeAutoFrame::LayerScopeAutoFrame(int64_t aFrameStamp
) {
1602 BeginFrame(aFrameStamp
);
1605 LayerScopeAutoFrame::~LayerScopeAutoFrame() {
1610 void LayerScopeAutoFrame::BeginFrame(int64_t aFrameStamp
) {
1611 if (!LayerScope::CheckSendable()) {
1614 SenderHelper::ClearSentTextureIds();
1616 gLayerScopeManager
.GetSocketManager()->AppendDebugData(
1617 new DebugGLFrameStatusData(Packet::FRAMESTART
, aFrameStamp
));
1620 void LayerScopeAutoFrame::EndFrame() {
1621 if (!LayerScope::CheckSendable()) {
1625 gLayerScopeManager
.GetSocketManager()->AppendDebugData(
1626 new DebugGLFrameStatusData(Packet::FRAMEEND
));
1627 gLayerScopeManager
.GetSocketManager()->DispatchDebugData();
1630 } // namespace layers
1631 } // namespace mozilla