Bug 1691109 [wpt PR 27513] - Increase timeout duration for wpt/fetch/api/basic/keepal...
[gecko.git] / gfx / layers / LayerScope.cpp
blob69c0e9eaff149534955f649b090145777b473a7e
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"
11 #include "Effects.h"
12 #include "Layers.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"
25 #include "gfxUtils.h"
27 #include "nsIWidget.h"
29 #include "GLContext.h"
30 #include "GLContextProvider.h"
31 #include "GLReadTexImageHelper.h"
33 #include <memory>
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"
43 #include "nsNetCID.h"
44 #include "nsIOutputStream.h"
45 #include "nsIAsyncInputStream.h"
46 #include "nsProxyRelease.h"
47 #include <list>
49 // Undo the damage done by mozzconf.h
50 #undef compress
51 #include "mozilla/Compression.h"
53 // Undo the damage done by X11
54 #ifdef Status
55 # undef Status
56 #endif
57 // Protocol buffer (generated automatically)
58 #include "protobuf/LayerScopePacket.pb.h"
60 namespace mozilla {
61 namespace layers {
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;
70 class DebugGLData;
73 * Manage Websocket connections
75 class LayerScopeWebSocketManager {
76 public:
77 LayerScopeWebSocketManager();
78 ~LayerScopeWebSocketManager();
80 void RemoveAllConnections() {
81 MOZ_ASSERT(NS_IsMainThread());
83 MutexAutoLock lock(mHandlerMutex);
84 mHandlers.Clear();
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
91 RemoveConnection(i);
95 return true;
98 bool IsConnected() {
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();
108 private:
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
124 // viewer side.
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 {
135 public:
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 {
145 return NS_OK;
148 private:
149 virtual ~SocketListener() = default;
153 * This class handle websocket protocol which included
154 * handshake and data frame's header
156 class SocketHandler : public nsIInputStreamCallback {
157 public:
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;
168 private:
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);
180 private:
181 enum SocketStateType { NoHandshake, HandshakeSuccess, HandshakeFailed };
182 SocketStateType mState;
184 nsCOMPtr<nsIOutputStream> mOutputStream;
185 nsCOMPtr<nsIAsyncInputStream> mInputStream;
186 nsCOMPtr<nsISocketTransport> mTransport;
187 bool mConnected;
190 nsTArray<RefPtr<SocketHandler> > mHandlers;
191 nsCOMPtr<nsIThread> mDebugSenderThread;
192 RefPtr<DebugDataSender> mCurrentSender;
193 nsCOMPtr<nsIServerSocket> mServerSocket;
195 // Keep mHandlers accessing thread safe.
196 Mutex mHandlerMutex;
199 NS_IMPL_ISUPPORTS(LayerScopeWebSocketManager::SocketListener,
200 nsIServerSocketListener);
201 NS_IMPL_ISUPPORTS(LayerScopeWebSocketManager::SocketHandler,
202 nsIInputStreamCallback);
204 class DrawSession {
205 public:
206 DrawSession() : mOffsetX(0.0), mOffsetY(0.0), mRects(0) {}
208 float mOffsetX;
209 float mOffsetY;
210 gfx::Matrix4x4 mMVMatrix;
211 size_t mRects;
212 gfx::Rect mLayerRects[4];
213 gfx::Rect mTextureRects[4];
214 std::list<GLuint> mTexIDs;
217 class ContentMonitor {
218 public:
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);
239 return true;
242 if (decltype(mChangedHosts)::NoIndex != mChangedHosts.IndexOf(host)) {
243 return true;
246 return false;
249 void Empty() {
250 mSeenHosts.SetLength(0);
251 mChangedHosts.SetLength(0);
254 private:
255 THArray mSeenHosts;
256 THArray mChangedHosts;
260 * Hold all singleton objects used by LayerScope.
262 class LayerScopeManager {
263 public:
264 void CreateServerSocket() {
265 // WebSocketManager must be created on the main thread.
266 if (NS_IsMainThread()) {
267 mWebSocketManager = mozilla::MakeUnique<LayerScopeWebSocketManager>();
268 } else {
269 // Dispatch creation to main thread, and make sure we
270 // dispatch this only once after booting
271 static bool dispatched = false;
272 if (dispatched) {
273 return;
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");
280 dispatched = true;
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) {}
313 private:
314 friend class CreateServerSocketRunnable;
315 class CreateServerSocketRunnable : public Runnable {
316 public:
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>();
323 return NS_OK;
326 private:
327 LayerScopeManager* mLayerScopeManager;
330 mozilla::UniquePtr<LayerScopeWebSocketManager> mWebSocketManager;
331 mozilla::UniquePtr<DrawSession> mSession;
332 mozilla::UniquePtr<ContentMonitor> mContentMonitor;
333 double mScale;
336 LayerScopeManager gLayerScopeManager;
339 * The static helper functions that set data into the packet
340 * 1. DumpRect
341 * 2. DumpFilter
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);
356 break;
357 case SamplingFilter::LINEAR:
358 aTexturePacket->set_mfilter(TexturePacket::LINEAR);
359 break;
360 case SamplingFilter::POINT:
361 aTexturePacket->set_mfilter(TexturePacket::POINT);
362 break;
363 default:
364 MOZ_ASSERT(false,
365 "Can't dump unexpected mSamplingFilter to texture packet!");
366 break;
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> {
379 public:
380 explicit DebugGLData(Packet::DataType aDataType) : mDataType(aDataType) {}
382 virtual ~DebugGLData() = default;
384 virtual bool Write() = 0;
386 protected:
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 {
400 public:
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 {
408 Packet packet;
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);
419 protected:
420 int64_t mFrameStamp;
423 class DebugGLTextureData final : public DebugGLData {
424 public:
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)),
430 mTarget(target),
431 mName(name),
432 mContextAddress(reinterpret_cast<intptr_t>(cx)),
433 mDatasize(0),
434 mIsMask(aIsMask),
435 mPacket(std::move(aPacket)) {
436 // pre-packing
437 // DataSourceSurface may have locked buffer,
438 // so we should compress now, and then it could
439 // be unlocked outside.
440 pack(img);
443 bool Write() override { return WriteToStream(*mPacket); }
445 private:
446 void pack(DataSourceSurface* aImage) {
447 mPacket->set_type(mDataType);
449 TexturePacket* tp = mPacket->mutable_texture();
450 tp->set_layerref(mLayerRef);
451 tp->set_name(mName);
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);
457 if (aImage) {
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());
470 if (ndatasize > 0) {
471 mDatasize = ndatasize;
472 tp->set_dataformat((1 << 16 | tp->dataformat()));
473 tp->set_data(compresseddata.get(), mDatasize);
474 } else {
475 NS_WARNING("Compress data failed");
476 tp->set_data(map.GetData(), mDatasize);
478 } else {
479 NS_WARNING("Couldn't new compressed data.");
480 tp->set_data(map.GetData(), mDatasize);
482 } else {
483 tp->set_width(0);
484 tp->set_height(0);
485 tp->set_stride(0);
489 protected:
490 uint64_t mLayerRef;
491 GLenum mTarget;
492 GLuint mName;
493 intptr_t mContextAddress;
494 uint32_t mDatasize;
495 bool mIsMask;
497 // Packet data
498 UniquePtr<Packet> mPacket;
501 class DebugGLColorData final : public DebugGLData {
502 public:
503 DebugGLColorData(void* layerRef, const DeviceColor& color, int width,
504 int height)
505 : DebugGLData(Packet::COLOR),
506 mLayerRef(reinterpret_cast<uint64_t>(layerRef)),
507 mColor(color.ToABGR()),
508 mSize(width, height) {}
510 bool Write() override {
511 Packet packet;
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);
523 protected:
524 uint64_t mLayerRef;
525 uint32_t mColor;
526 IntSize mSize;
529 class DebugGLLayersData final : public DebugGLData {
530 public:
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);
539 protected:
540 UniquePtr<Packet> mPacket;
543 class DebugGLMetaData final : public DebugGLData {
544 public:
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 {
552 Packet packet;
553 packet.set_type(mDataType);
555 MetaPacket* mp = packet.mutable_meta();
556 mp->set_composedbyhwc(mComposedByHwc);
558 return WriteToStream(packet);
561 protected:
562 bool mComposedByHwc;
565 class DebugGLDrawData final : public DebugGLData {
566 public:
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),
572 mOffsetX(aOffsetX),
573 mOffsetY(aOffsetY),
574 mMVMatrix(aMVMatrix),
575 mRects(aRects),
576 mTexIDs(aTexIDs),
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 {
585 Packet packet;
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++) {
602 // Vertex
603 DumpRect(dp->add_layerrect(), mLayerRects[i]);
604 // UV
605 DumpRect(dp->add_texturerect(), mTextureRects[i]);
608 for (GLuint texId : mTexIDs) {
609 dp->add_texids(texId);
612 return WriteToStream(packet);
615 protected:
616 float mOffsetX;
617 float mOffsetY;
618 gfx::Matrix4x4 mMVMatrix;
619 size_t mRects;
620 gfx::Rect mLayerRects[4];
621 gfx::Rect mTextureRects[4];
622 std::list<GLuint> mTexIDs;
623 uint64_t mLayerRef;
626 class DebugDataSender {
627 public:
628 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DebugDataSender)
630 // Append a DebugData into mList on mThread
631 class AppendTask : public nsIRunnable {
632 public:
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);
639 return NS_OK;
642 private:
643 virtual ~AppendTask() = default;
645 DebugGLData* mData;
646 // Keep a strong reference to DebugDataSender to prevent this object
647 // accessing mHost on mThread, when it's been destroyed on the main
648 // thread.
649 RefPtr<DebugDataSender> mHost;
652 // Clear all DebugData in mList on mThead.
653 class ClearTask : public nsIRunnable {
654 public:
655 NS_DECL_THREADSAFE_ISUPPORTS
656 explicit ClearTask(DebugDataSender* host) : mHost(host) {}
658 NS_IMETHOD Run() override {
659 mHost->RemoveData();
660 return NS_OK;
663 private:
664 virtual ~ClearTask() = default;
666 RefPtr<DebugDataSender> mHost;
669 // Send all DebugData in mList via websocket, and then, clean up
670 // mList on mThread.
671 class SendTask : public nsIRunnable {
672 public:
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);
682 if (!d->Write()) {
683 gLayerScopeManager.DestroyServerSocket();
684 break;
688 // Cleanup.
689 mHost->RemoveData();
690 return NS_OK;
693 private:
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); }
709 protected:
710 virtual ~DebugDataSender() = default;
711 void RemoveData() {
712 MOZ_ASSERT(mThread->SerialEventTarget()->IsOnCurrentThread());
713 if (mList.isEmpty()) return;
715 DebugGLData* d;
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
730 * 1. SendLayer
731 * 2. SendEffectChain
732 * 1. SendTexturedEffect
733 * -> SendTextureSource
734 * 2. SendMaskEffect
735 * -> SendTextureSource
736 * 3. SendYCbCrEffect
737 * -> SendTextureSource
738 * 4. SendColor
740 class SenderHelper {
741 // Sender public APIs
742 public:
743 static void SendLayer(LayerComposite* aLayer, int aWidth, int aHeight);
745 static void SendEffectChain(gl::GLContext* aGLContext,
746 const EffectChain& aEffectChain, int aWidth = 0,
747 int aHeight = 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
760 private:
761 static void SendColor(void* aLayerRef, const DeviceColor& aColor, int aWidth,
762 int aHeight);
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);
777 // Data fields
778 private:
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()) {
801 return;
804 switch (aLayer->GetLayer()->GetType()) {
805 case Layer::TYPE_COLOR: {
806 EffectChain effect;
807 aLayer->GenEffectChain(effect);
809 LayerScope::DrawBegin();
810 LayerScope::DrawEnd(nullptr, effect, aWidth, aHeight);
811 break;
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();
823 EffectChain effect;
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);
831 break;
833 case Layer::TYPE_CONTAINER:
834 default:
835 break;
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);
850 GLuint texID = 0;
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);
861 return texID;
864 void SenderHelper::SendTextureSource(GLContext* aGLContext, void* aLayerRef,
865 TextureSourceOGL* aSource, bool aFlipY,
866 bool aIsMask, UniquePtr<Packet> aPacket) {
867 MOZ_ASSERT(aGLContext);
868 if (!aGLContext) {
869 return;
871 GLuint texID = GetTextureID(aGLContext, aSource);
872 if (HasTextureIdBeenSent(texID)) {
873 return;
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
900 // attributes.
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,
907 std::move(packet));
910 void SenderHelper::SendTexturedEffect(GLContext* aGLContext, void* aLayerRef,
911 const TexturedEffect* aEffect) {
912 TextureSourceOGL* source = aEffect->mTexture->AsSourceOGL();
913 if (!source) {
914 return;
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();
924 if (!source) {
925 return;
928 // Expose packet creation here, so we could dump secondary mask effect
929 // attributes.
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,
940 std::move(packet));
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,
960 int aHeight) {
961 if (!sLayersBufferSendable) return;
963 const Effect* primaryEffect = aEffectChain.mPrimaryEffect;
964 MOZ_ASSERT(primaryEffect);
966 if (!primaryEffect) {
967 return;
970 switch (primaryEffect->mType) {
971 case EffectTypes::RGB: {
972 const TexturedEffect* texturedEffect =
973 static_cast<const TexturedEffect*>(primaryEffect);
974 SendTexturedEffect(aGLContext, aEffectChain.mLayerRef, texturedEffect);
975 break;
977 case EffectTypes::YCBCR: {
978 const EffectYCbCr* yCbCrEffect =
979 static_cast<const EffectYCbCr*>(primaryEffect);
980 SendYCbCrEffect(aGLContext, aEffectChain.mLayerRef, yCbCrEffect);
981 break;
983 case EffectTypes::SOLID_COLOR: {
984 const EffectSolidColor* solidColorEffect =
985 static_cast<const EffectSolidColor*>(primaryEffect);
986 SendColor(aEffectChain.mLayerRef, solidColorEffect->mColor, aWidth,
987 aHeight);
988 break;
990 case EffectTypes::COMPONENT_ALPHA:
991 case EffectTypes::RENDER_TARGET:
992 default:
993 break;
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()) {
1005 return;
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,
1029 uint32_t aSize) {
1030 if (mState == NoHandshake) {
1031 // Not yet handshake, just return true in case of
1032 // LayerScope remove this handle
1033 return true;
1034 } else if (mState == HandshakeFailed) {
1035 return false;
1038 if (!mOutputStream) {
1039 return false;
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;
1047 if (aSize <= 125) {
1048 wsHeaderSize = 2;
1049 wsHeader[1] = aSize;
1050 } else if (aSize < 65536) {
1051 wsHeaderSize = 4;
1052 wsHeader[1] = 0x7E;
1053 NetworkEndian::writeUint16(wsHeader + 2, aSize);
1054 } else {
1055 wsHeaderSize = 10;
1056 wsHeader[1] = 0x7F;
1057 NetworkEndian::writeUint64(wsHeader + 2, aSize);
1060 // Send WebSocket header
1061 nsresult rv;
1062 uint32_t cnt;
1063 rv = mOutputStream->Write(reinterpret_cast<char*>(wsHeader), wsHeaderSize,
1064 &cnt);
1065 if (NS_FAILED(rv)) return false;
1067 uint32_t written = 0;
1068 while (written < aSize) {
1069 uint32_t cnt;
1070 rv = mOutputStream->Write(reinterpret_cast<char*>(aPtr) + written,
1071 aSize - written, &cnt);
1072 if (NS_FAILED(rv)) return false;
1074 written += cnt;
1077 return true;
1080 NS_IMETHODIMP
1081 LayerScopeWebSocketManager::SocketHandler::OnInputStreamReady(
1082 nsIAsyncInputStream* aStream) {
1083 MOZ_ASSERT(mInputStream);
1085 if (!mInputStream) {
1086 return NS_OK;
1089 if (!mConnected) {
1090 nsTArray<nsCString> protocolString;
1091 ReadInputStreamData(protocolString);
1093 if (WebSocketHandshake(protocolString)) {
1094 mState = HandshakeSuccess;
1095 mConnected = true;
1096 mInputStream->AsyncWait(this, 0, 0, GetCurrentEventTarget());
1097 } else {
1098 mState = HandshakeFailed;
1100 return NS_OK;
1101 } else {
1102 return HandleSocketMessage(aStream);
1106 void LayerScopeWebSocketManager::SocketHandler::ReadInputStreamData(
1107 nsTArray<nsCString>& aProtocolString) {
1108 nsLineBuffer<char> lineBuffer;
1109 nsCString line;
1110 bool more = true;
1111 do {
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) {
1122 nsresult rv;
1123 bool isWebSocket = false;
1124 nsCString version;
1125 nsCString wsKey;
1126 nsCString protocol;
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)) !=
1134 0) {
1135 return false;
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")) {
1146 isWebSocket = true;
1147 } else if (key.EqualsIgnoreCase("sec-websocket-version")) {
1148 version = value;
1149 } else if (key.EqualsIgnoreCase("sec-websocket-key")) {
1150 wsKey = value;
1151 } else if (key.EqualsIgnoreCase("sec-websocket-protocol")) {
1152 protocol = value;
1157 if (!isWebSocket) {
1158 return false;
1161 if (!(version.EqualsLiteral("7") || version.EqualsLiteral("8") ||
1162 version.EqualsLiteral("13"))) {
1163 return false;
1166 if (!(protocol.EqualsIgnoreCase("binary"))) {
1167 return false;
1170 if (!mOutputStream) {
1171 return false;
1174 // Client request is valid. Start to generate and send server response.
1175 nsAutoCString guid("258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
1176 nsAutoCString res;
1177 SHA1Sum sha1;
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)) {
1189 return false;
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) {
1196 uint32_t cnt;
1197 rv = mOutputStream->Write(const_cast<char*>(response.get()) + written,
1198 size - written, &cnt);
1199 if (NS_FAILED(rv)) return false;
1201 written += cnt;
1203 mOutputStream->Flush();
1205 return true;
1208 nsresult LayerScopeWebSocketManager::SocketHandler::HandleSocketMessage(
1209 nsIAsyncInputStream* aStream) {
1210 // The reading and parsing of this input stream is customized for layer
1211 // viewer.
1212 const uint32_t cPacketSize = 1024;
1213 char buffer[cPacketSize];
1214 uint32_t count = 0;
1215 nsresult rv = NS_OK;
1217 do {
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());
1224 return NS_OK;
1227 if (NS_FAILED(rv)) {
1228 break;
1231 if (count == 0) {
1232 // NS_BASE_STREAM_CLOSED
1233 CloseConnection();
1234 break;
1237 rv = ProcessInput(reinterpret_cast<uint8_t*>(buffer), count);
1238 } while (NS_SUCCEEDED(rv) && mInputStream);
1239 return rv;
1242 nsresult LayerScopeWebSocketManager::SocketHandler::ProcessInput(
1243 uint8_t* aBuffer, uint32_t aCount) {
1244 uint32_t avail = aCount;
1246 // Decode Websocket data frame
1247 if (avail <= 2) {
1248 NS_WARNING("Packet size is less than 2 bytes");
1249 return NS_OK;
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
1257 if (!finBit) {
1258 NS_WARNING(
1259 "We cannot handle multi-fragments messages in Layerscope websocket "
1260 "parser.");
1261 return NS_OK;
1264 // Second byte, data length
1265 uint8_t maskBit = aBuffer[1] & 0x80; // 1000 0000
1266 int64_t payloadLength64 = aBuffer[1] & 0x7F; // 0111 1111
1268 if (!maskBit) {
1269 NS_WARNING("Client to Server should set the mask bit");
1270 return NS_OK;
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
1279 framingLength += 2;
1280 if (avail < framingLength) {
1281 return NS_OK;
1284 payloadLength64 = aBuffer[2] << 8 | aBuffer[3];
1285 } else {
1286 // 64 bit length
1287 framingLength += 8;
1288 if (avail < framingLength) {
1289 return NS_OK;
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");
1309 return NS_OK;
1312 // Apply mask
1313 uint32_t mask = NetworkEndian::readUint32(payload - 4);
1314 ApplyMask(mask, payload, payloadLength);
1316 if (opcode == 0x8) {
1317 // opcode == 0x8 means connection close
1318 CloseConnection();
1319 return NS_BASE_STREAM_CLOSED;
1322 if (!HandleDataFrame(payload, payloadLength)) {
1323 NS_WARNING("Cannot decode payload data by the protocol buffer");
1326 return NS_OK;
1329 void LayerScopeWebSocketManager::SocketHandler::ApplyMask(uint32_t aMask,
1330 uint8_t* aData,
1331 uint64_t aLen) {
1332 if (!aData || aLen == 0) {
1333 return;
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);
1342 aData++;
1343 aLen--;
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++) {
1351 *iData ^= aMask;
1353 aMask = NetworkEndian::readUint32(&aMask);
1354 aData = (uint8_t*)iData;
1355 aLen = aLen % 4;
1357 // There maybe up to 3 trailing bytes that need to be dealt with
1358 // individually
1359 while (aLen) {
1360 *aData ^= aMask >> 24;
1361 aMask = RotateLeft(aMask, 8);
1362 aData++;
1363 aLen--;
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");
1375 return false;
1378 switch (p->type()) {
1379 case CommandPacket::LAYERS_TREE:
1380 if (p->has_value()) {
1381 SenderHelper::SetLayersTreeSendable(p->value());
1383 break;
1385 case CommandPacket::LAYERS_BUFFER:
1386 if (p->has_value()) {
1387 SenderHelper::SetLayersBufferSendable(p->value());
1389 break;
1391 case CommandPacket::NO_OP:
1392 default:
1393 NS_WARNING("Invalid message type");
1394 break;
1396 return true;
1399 void LayerScopeWebSocketManager::SocketHandler::CloseConnection() {
1400 gLayerScopeManager.GetSocketManager()->CleanDebugData();
1401 if (mInputStream) {
1402 mInputStream->AsyncWait(nullptr, 0, 0, nullptr);
1403 mInputStream = nullptr;
1405 if (mOutputStream) {
1406 mOutputStream = nullptr;
1408 if (mTransport) {
1409 mTransport->Close(NS_BASE_STREAM_CLOSED);
1410 mTransport = nullptr;
1412 mConnected = false;
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();
1460 return NS_OK;
1463 // ----------------------------------------------
1464 // LayerScope implementation
1465 // ----------------------------------------------
1466 /*static*/
1467 void LayerScope::Init() {
1468 if (!StaticPrefs::gfx_layerscope_enabled() || XRE_IsGPUProcess()) {
1469 return;
1472 gLayerScopeManager.CreateServerSocket();
1475 /*static*/
1476 void LayerScope::DrawBegin() {
1477 if (!CheckSendable()) {
1478 return;
1481 gLayerScopeManager.NewDrawSession();
1484 /*static*/
1485 void LayerScope::SetRenderOffset(float aX, float aY) {
1486 if (!CheckSendable()) {
1487 return;
1490 gLayerScopeManager.CurrentSession().mOffsetX = aX;
1491 gLayerScopeManager.CurrentSession().mOffsetY = aY;
1494 /*static*/
1495 void LayerScope::SetLayerTransform(const gfx::Matrix4x4& aMatrix) {
1496 if (!CheckSendable()) {
1497 return;
1500 gLayerScopeManager.CurrentSession().mMVMatrix = aMatrix;
1503 /*static*/
1504 void LayerScope::SetDrawRects(size_t aRects, const gfx::Rect* aLayerRects,
1505 const gfx::Rect* aTextureRects) {
1506 if (!CheckSendable()) {
1507 return;
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];
1521 /*static*/
1522 void LayerScope::DrawEnd(gl::GLContext* aGLContext,
1523 const EffectChain& aEffectChain, int aWidth,
1524 int aHeight) {
1525 // Protect this public function
1526 if (!CheckSendable()) {
1527 return;
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));
1542 /*static*/
1543 void LayerScope::SendLayer(LayerComposite* aLayer, int aWidth, int aHeight) {
1544 // Protect this public function
1545 if (!CheckSendable()) {
1546 return;
1548 SenderHelper::SendLayer(aLayer, aWidth, aHeight);
1551 /*static*/
1552 void LayerScope::SendLayerDump(UniquePtr<Packet> aPacket) {
1553 // Protect this public function
1554 if (!CheckSendable() || !SenderHelper::GetLayersTreeSendable()) {
1555 return;
1557 gLayerScopeManager.GetSocketManager()->AppendDebugData(
1558 new DebugGLLayersData(std::move(aPacket)));
1561 /*static*/
1562 bool LayerScope::CheckSendable() {
1563 // Only compositor threads check LayerScope status
1564 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread() || gIsGtest);
1566 if (!StaticPrefs::gfx_layerscope_enabled()) {
1567 return false;
1569 if (!gLayerScopeManager.GetSocketManager()) {
1570 Init();
1571 return false;
1573 if (!gLayerScopeManager.GetSocketManager()->IsConnected()) {
1574 return false;
1576 return true;
1579 /*static*/
1580 void LayerScope::CleanLayer() {
1581 if (CheckSendable()) {
1582 gLayerScopeManager.GetSocketManager()->CleanDebugData();
1586 /*static*/
1587 void LayerScope::SetHWComposed() {
1588 if (CheckSendable()) {
1589 gLayerScopeManager.GetSocketManager()->AppendDebugData(
1590 new DebugGLMetaData(Packet::META, true));
1594 /*static*/
1595 void LayerScope::SetPixelScale(double devPixelsPerCSSPixel) {
1596 gLayerScopeManager.SetPixelScale(devPixelsPerCSSPixel);
1599 // ----------------------------------------------
1600 // LayerScopeAutoFrame implementation
1601 // ----------------------------------------------
1602 LayerScopeAutoFrame::LayerScopeAutoFrame(int64_t aFrameStamp) {
1603 // Do Begin Frame
1604 BeginFrame(aFrameStamp);
1607 LayerScopeAutoFrame::~LayerScopeAutoFrame() {
1608 // Do End Frame
1609 EndFrame();
1612 void LayerScopeAutoFrame::BeginFrame(int64_t aFrameStamp) {
1613 if (!LayerScope::CheckSendable()) {
1614 return;
1616 SenderHelper::ClearSentTextureIds();
1618 gLayerScopeManager.GetSocketManager()->AppendDebugData(
1619 new DebugGLFrameStatusData(Packet::FRAMESTART, aFrameStamp));
1622 void LayerScopeAutoFrame::EndFrame() {
1623 if (!LayerScope::CheckSendable()) {
1624 return;
1627 gLayerScopeManager.GetSocketManager()->AppendDebugData(
1628 new DebugGLFrameStatusData(Packet::FRAMEEND));
1629 gLayerScopeManager.GetSocketManager()->DispatchDebugData();
1632 } // namespace layers
1633 } // namespace mozilla