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/. */
6
7 /* This must occur *after* layers/PLayers.h to avoid typedefs conflicts. */
8 #include "LayerScope.h"
9
10 #include "nsAppRunner.h"
11 #include "Effects.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"
17
18 #include "mozilla/layers/CompositorOGL.h"
19 #include "mozilla/layers/CompositorThread.h"
20 #include "mozilla/layers/LayerManagerComposite.h"
21 #include "mozilla/layers/TextureHostOGL.h"
22
23 #include "gfxContext.h"
24 #include "gfxUtils.h"
25
26 #include "nsIWidget.h"
27
28 #include "GLContext.h"
29 #include "GLContextProvider.h"
30 #include "GLReadTexImageHelper.h"
31
32 #include <memory>
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"
41 #include "nsNetCID.h"
42 #include "nsIOutputStream.h"
43 #include "nsIAsyncInputStream.h"
44 #include "nsProxyRelease.h"
45 #include <list>
46
47 // Undo the damage done by mozzconf.h
48 #undef compress
49 #include "mozilla/Compression.h"
50
51 // Undo the damage done by X11
52 #ifdef Status
53 # undef Status
54 #endif
55 // Protocol buffer (generated automatically)
56 #include "protobuf/LayerScopePacket.pb.h"
57
58 namespace mozilla {
59 namespace layers {
60
61 using namespace mozilla::Compression;
62 using namespace mozilla::gfx;
63 using namespace mozilla::gl;
64 using namespace mozilla;
65 using namespace layerscope;
66
67 class DebugDataSender;
68 class DebugGLData;
69
70 /*
71 * Manage Websocket connections
72 */
73 class LayerScopeWebSocketManager {
74 public:
75 LayerScopeWebSocketManager();
76 ~LayerScopeWebSocketManager();
77
RemoveAllConnections()78 void RemoveAllConnections() {
79 MOZ_ASSERT(NS_IsMainThread());
80
81 MutexAutoLock lock(mHandlerMutex);
82 mHandlers.Clear();
83 }
84
WriteAll(void * ptr,uint32_t size)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
89 RemoveConnection(i);
90 }
91 }
92
93 return true;
94 }
95
IsConnected()96 bool IsConnected() {
97 // This funtion can be called in both main thread and compositor thread.
98 MutexAutoLock lock(mHandlerMutex);
99 return (mHandlers.Length() != 0) ? true : false;
100 }
101
102 void AppendDebugData(DebugGLData* aDebugData);
103 void CleanDebugData();
104 void DispatchDebugData();
105
106 private:
AddConnection(nsISocketTransport * aTransport)107 void AddConnection(nsISocketTransport* aTransport) {
108 MOZ_ASSERT(NS_IsMainThread());
109 MOZ_ASSERT(aTransport);
110
111 MutexAutoLock lock(mHandlerMutex);
112
113 RefPtr<SocketHandler> temp = new SocketHandler();
114 temp->OpenStream(aTransport);
115 mHandlers.AppendElement(temp.get());
116 }
117
RemoveConnection(uint32_t aIndex)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
122 // viewer side.
123
124 // We should dispatch RemoveConnection onto main thead.
125 MOZ_ASSERT(aIndex < mHandlers.Length());
126
127 MutexAutoLock lock(mHandlerMutex);
128 mHandlers.RemoveElementAt(aIndex);
129 }
130
131 friend class SocketListener;
132 class SocketListener : public nsIServerSocketListener {
133 public:
134 NS_DECL_THREADSAFE_ISUPPORTS
135
136 SocketListener() = default;
137
138 /* nsIServerSocketListener */
139 NS_IMETHOD OnSocketAccepted(nsIServerSocket* aServ,
140 nsISocketTransport* aTransport) override;
OnStopListening(nsIServerSocket * aServ,nsresult aStatus)141 NS_IMETHOD OnStopListening(nsIServerSocket* aServ,
142 nsresult aStatus) override {
143 return NS_OK;
144 }
145
146 private:
147 virtual ~SocketListener() = default;
148 };
149
150 /*
151 * This class handle websocket protocol which included
152 * handshake and data frame's header
153 */
154 class SocketHandler : public nsIInputStreamCallback {
155 public:
156 NS_DECL_THREADSAFE_ISUPPORTS
157
SocketHandler()158 SocketHandler() : mState(NoHandshake), mConnected(false) {}
159
160 void OpenStream(nsISocketTransport* aTransport);
161 bool WriteToStream(void* aPtr, uint32_t aSize);
162
163 // nsIInputStreamCallback
164 NS_IMETHOD OnInputStreamReady(nsIAsyncInputStream* aStream) override;
165
166 private:
~SocketHandler()167 virtual ~SocketHandler() { CloseConnection(); }
168
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();
174
175 nsresult HandleSocketMessage(nsIAsyncInputStream* aStream);
176 nsresult ProcessInput(uint8_t* aBuffer, uint32_t aCount);
177
178 private:
179 enum SocketStateType { NoHandshake, HandshakeSuccess, HandshakeFailed };
180 SocketStateType mState;
181
182 nsCOMPtr<nsIOutputStream> mOutputStream;
183 nsCOMPtr<nsIAsyncInputStream> mInputStream;
184 nsCOMPtr<nsISocketTransport> mTransport;
185 bool mConnected;
186 };
187
188 nsTArray<RefPtr<SocketHandler> > mHandlers;
189 nsCOMPtr<nsIThread> mDebugSenderThread;
190 RefPtr<DebugDataSender> mCurrentSender;
191 nsCOMPtr<nsIServerSocket> mServerSocket;
192
193 // Keep mHandlers accessing thread safe.
194 Mutex mHandlerMutex;
195 };
196
197 NS_IMPL_ISUPPORTS(LayerScopeWebSocketManager::SocketListener,
198 nsIServerSocketListener);
199 NS_IMPL_ISUPPORTS(LayerScopeWebSocketManager::SocketHandler,
200 nsIInputStreamCallback);
201
202 class DrawSession {
203 public:
DrawSession()204 DrawSession() : mOffsetX(0.0), mOffsetY(0.0), mRects(0) {}
205
206 float mOffsetX;
207 float mOffsetY;
208 gfx::Matrix4x4 mMVMatrix;
209 size_t mRects;
210 gfx::Rect mLayerRects[4];
211 gfx::Rect mTextureRects[4];
212 std::list<GLuint> mTexIDs;
213 };
214
215 class ContentMonitor {
216 public:
217 using THArray = nsTArray<const TextureHost*>;
218
219 // Notify the content of a TextureHost was changed.
SetChangedHost(const TextureHost * host)220 void SetChangedHost(const TextureHost* host) {
221 if (THArray::NoIndex == mChangedHosts.IndexOf(host)) {
222 mChangedHosts.AppendElement(host);
223 }
224 }
225
226 // Clear changed flag of a host.
ClearChangedHost(const TextureHost * host)227 void ClearChangedHost(const TextureHost* host) {
228 if (THArray::NoIndex != mChangedHosts.IndexOf(host)) {
229 mChangedHosts.RemoveElement(host);
230 }
231 }
232
233 // Return true iff host is a new one or the content of it had been changed.
IsChangedOrNew(const TextureHost * host)234 bool IsChangedOrNew(const TextureHost* host) {
235 if (THArray::NoIndex == mSeenHosts.IndexOf(host)) {
236 mSeenHosts.AppendElement(host);
237 return true;
238 }
239
240 if (decltype(mChangedHosts)::NoIndex != mChangedHosts.IndexOf(host)) {
241 return true;
242 }
243
244 return false;
245 }
246
Empty()247 void Empty() {
248 mSeenHosts.SetLength(0);
249 mChangedHosts.SetLength(0);
250 }
251
252 private:
253 THArray mSeenHosts;
254 THArray mChangedHosts;
255 };
256
257 /*
258 * Hold all singleton objects used by LayerScope.
259 */
260 class LayerScopeManager {
261 public:
CreateServerSocket()262 void CreateServerSocket() {
263 // WebSocketManager must be created on the main thread.
264 if (NS_IsMainThread()) {
265 mWebSocketManager = mozilla::MakeUnique<LayerScopeWebSocketManager>();
266 } else {
267 // Dispatch creation to main thread, and make sure we
268 // dispatch this only once after booting
269 static bool dispatched = false;
270 if (dispatched) {
271 return;
272 }
273
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");
278 dispatched = true;
279 }
280 }
281
DestroyServerSocket()282 void DestroyServerSocket() {
283 // Destroy Web Server Socket
284 if (mWebSocketManager) {
285 mWebSocketManager->RemoveAllConnections();
286 }
287 }
288
GetSocketManager()289 LayerScopeWebSocketManager* GetSocketManager() {
290 return mWebSocketManager.get();
291 }
292
GetContentMonitor()293 ContentMonitor* GetContentMonitor() {
294 if (!mContentMonitor.get()) {
295 mContentMonitor = mozilla::MakeUnique<ContentMonitor>();
296 }
297
298 return mContentMonitor.get();
299 }
300
NewDrawSession()301 void NewDrawSession() { mSession = mozilla::MakeUnique<DrawSession>(); }
302
CurrentSession()303 DrawSession& CurrentSession() { return *mSession; }
304
SetPixelScale(double scale)305 void SetPixelScale(double scale) { mScale = scale; }
306
GetPixelScale() const307 double GetPixelScale() const { return mScale; }
308
LayerScopeManager()309 LayerScopeManager() : mScale(1.0) {}
310
311 private:
312 friend class CreateServerSocketRunnable;
313 class CreateServerSocketRunnable : public Runnable {
314 public:
CreateServerSocketRunnable(LayerScopeManager * aLayerScopeManager)315 explicit CreateServerSocketRunnable(LayerScopeManager* aLayerScopeManager)
316 : Runnable("layers::LayerScopeManager::CreateServerSocketRunnable"),
317 mLayerScopeManager(aLayerScopeManager) {}
Run()318 NS_IMETHOD Run() override {
319 mLayerScopeManager->mWebSocketManager =
320 mozilla::MakeUnique<LayerScopeWebSocketManager>();
321 return NS_OK;
322 }
323
324 private:
325 LayerScopeManager* mLayerScopeManager;
326 };
327
328 mozilla::UniquePtr<LayerScopeWebSocketManager> mWebSocketManager;
329 mozilla::UniquePtr<DrawSession> mSession;
330 mozilla::UniquePtr<ContentMonitor> mContentMonitor;
331 double mScale;
332 };
333
334 LayerScopeManager gLayerScopeManager;
335
336 /*
337 * The static helper functions that set data into the packet
338 * 1. DumpRect
339 * 2. DumpFilter
340 */
341 template <typename T>
DumpRect(T * aPacketRect,const Rect & aRect)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());
347 }
348
DumpFilter(TexturePacket * aTexturePacket,const SamplingFilter aSamplingFilter)349 static void DumpFilter(TexturePacket* aTexturePacket,
350 const SamplingFilter aSamplingFilter) {
351 switch (aSamplingFilter) {
352 case SamplingFilter::GOOD:
353 aTexturePacket->set_mfilter(TexturePacket::GOOD);
354 break;
355 case SamplingFilter::LINEAR:
356 aTexturePacket->set_mfilter(TexturePacket::LINEAR);
357 break;
358 case SamplingFilter::POINT:
359 aTexturePacket->set_mfilter(TexturePacket::POINT);
360 break;
361 default:
362 MOZ_ASSERT(false,
363 "Can't dump unexpected mSamplingFilter to texture packet!");
364 break;
365 }
366 }
367
368 /*
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)
375 */
376 class DebugGLData : public LinkedListElement<DebugGLData> {
377 public:
DebugGLData(Packet::DataType aDataType)378 explicit DebugGLData(Packet::DataType aDataType) : mDataType(aDataType) {}
379
380 virtual ~DebugGLData() = default;
381
382 virtual bool Write() = 0;
383
384 protected:
WriteToStream(Packet & aPacket)385 static bool WriteToStream(Packet& aPacket) {
386 if (!gLayerScopeManager.GetSocketManager()) return true;
387
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);
392 }
393
394 Packet::DataType mDataType;
395 };
396
397 class DebugGLFrameStatusData final : public DebugGLData {
398 public:
DebugGLFrameStatusData(Packet::DataType aDataType,int64_t aValue)399 DebugGLFrameStatusData(Packet::DataType aDataType, int64_t aValue)
400 : DebugGLData(aDataType), mFrameStamp(aValue) {}
401
DebugGLFrameStatusData(Packet::DataType aDataType)402 explicit DebugGLFrameStatusData(Packet::DataType aDataType)
403 : DebugGLData(aDataType), mFrameStamp(0) {}
404
Write()405 bool Write() override {
406 Packet packet;
407 packet.set_type(mDataType);
408
409 FramePacket* fp = packet.mutable_frame();
410 fp->set_value(static_cast<uint64_t>(mFrameStamp));
411
412 fp->set_scale(gLayerScopeManager.GetPixelScale());
413
414 return WriteToStream(packet);
415 }
416
417 protected:
418 int64_t mFrameStamp;
419 };
420
421 class DebugGLTextureData final : public DebugGLData {
422 public:
DebugGLTextureData(GLContext * cx,void * layerRef,GLenum target,GLuint name,DataSourceSurface * img,bool aIsMask,UniquePtr<Packet> aPacket)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)),
428 mTarget(target),
429 mName(name),
430 mContextAddress(reinterpret_cast<intptr_t>(cx)),
431 mDatasize(0),
432 mIsMask(aIsMask),
433 mPacket(std::move(aPacket)) {
434 // pre-packing
435 // DataSourceSurface may have locked buffer,
436 // so we should compress now, and then it could
437 // be unlocked outside.
438 pack(img);
439 }
440
Write()441 bool Write() override { return WriteToStream(*mPacket); }
442
443 private:
pack(DataSourceSurface * aImage)444 void pack(DataSourceSurface* aImage) {
445 mPacket->set_type(mDataType);
446
447 TexturePacket* tp = mPacket->mutable_texture();
448 tp->set_layerref(mLayerRef);
449 tp->set_name(mName);
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);
454
455 if (aImage) {
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());
460
461 mDatasize = aImage->GetSize().height * map.GetStride();
462
463 auto compresseddata =
464 MakeUnique<char[]>(LZ4::maxCompressedSize(mDatasize));
465 if (compresseddata) {
466 int ndatasize = LZ4::compress((char*)map.GetData(), mDatasize,
467 compresseddata.get());
468 if (ndatasize > 0) {
469 mDatasize = ndatasize;
470 tp->set_dataformat((1 << 16 | tp->dataformat()));
471 tp->set_data(compresseddata.get(), mDatasize);
472 } else {
473 NS_WARNING("Compress data failed");
474 tp->set_data(map.GetData(), mDatasize);
475 }
476 } else {
477 NS_WARNING("Couldn't new compressed data.");
478 tp->set_data(map.GetData(), mDatasize);
479 }
480 } else {
481 tp->set_width(0);
482 tp->set_height(0);
483 tp->set_stride(0);
484 }
485 }
486
487 protected:
488 uint64_t mLayerRef;
489 GLenum mTarget;
490 GLuint mName;
491 intptr_t mContextAddress;
492 uint32_t mDatasize;
493 bool mIsMask;
494
495 // Packet data
496 UniquePtr<Packet> mPacket;
497 };
498
499 class DebugGLColorData final : public DebugGLData {
500 public:
DebugGLColorData(void * layerRef,const DeviceColor & color,int width,int height)501 DebugGLColorData(void* layerRef, const DeviceColor& color, int width,
502 int height)
503 : DebugGLData(Packet::COLOR),
504 mLayerRef(reinterpret_cast<uint64_t>(layerRef)),
505 mColor(color.ToABGR()),
506 mSize(width, height) {}
507
Write()508 bool Write() override {
509 Packet packet;
510 packet.set_type(mDataType);
511
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);
517
518 return WriteToStream(packet);
519 }
520
521 protected:
522 uint64_t mLayerRef;
523 uint32_t mColor;
524 IntSize mSize;
525 };
526
527 class DebugGLLayersData final : public DebugGLData {
528 public:
DebugGLLayersData(UniquePtr<Packet> aPacket)529 explicit DebugGLLayersData(UniquePtr<Packet> aPacket)
530 : DebugGLData(Packet::LAYERS), mPacket(std::move(aPacket)) {}
531
Write()532 bool Write() override {
533 mPacket->set_type(mDataType);
534 return WriteToStream(*mPacket);
535 }
536
537 protected:
538 UniquePtr<Packet> mPacket;
539 };
540
541 class DebugGLMetaData final : public DebugGLData {
542 public:
DebugGLMetaData(Packet::DataType aDataType,bool aValue)543 DebugGLMetaData(Packet::DataType aDataType, bool aValue)
544 : DebugGLData(aDataType), mComposedByHwc(aValue) {}
545
DebugGLMetaData(Packet::DataType aDataType)546 explicit DebugGLMetaData(Packet::DataType aDataType)
547 : DebugGLData(aDataType), mComposedByHwc(false) {}
548
Write()549 bool Write() override {
550 Packet packet;
551 packet.set_type(mDataType);
552
553 MetaPacket* mp = packet.mutable_meta();
554 mp->set_composedbyhwc(mComposedByHwc);
555
556 return WriteToStream(packet);
557 }
558
559 protected:
560 bool mComposedByHwc;
561 };
562
563 class DebugGLDrawData final : public DebugGLData {
564 public:
DebugGLDrawData(float aOffsetX,float aOffsetY,const gfx::Matrix4x4 & aMVMatrix,size_t aRects,const gfx::Rect * aLayerRects,const gfx::Rect * aTextureRects,const std::list<GLuint> & aTexIDs,void * aLayerRef)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),
570 mOffsetX(aOffsetX),
571 mOffsetY(aOffsetY),
572 mMVMatrix(aMVMatrix),
573 mRects(aRects),
574 mTexIDs(aTexIDs),
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];
579 }
580 }
581
Write()582 bool Write() override {
583 Packet packet;
584 packet.set_type(mDataType);
585
586 DrawPacket* dp = packet.mutable_draw();
587 dp->set_layerref(mLayerRef);
588
589 dp->set_offsetx(mOffsetX);
590 dp->set_offsety(mOffsetY);
591
592 auto element = reinterpret_cast<Float*>(&mMVMatrix);
593 for (int i = 0; i < 16; i++) {
594 dp->add_mvmatrix(*element++);
595 }
596 dp->set_totalrects(mRects);
597
598 MOZ_ASSERT(mRects > 0 && mRects < 4);
599 for (size_t i = 0; i < mRects; i++) {
600 // Vertex
601 DumpRect(dp->add_layerrect(), mLayerRects[i]);
602 // UV
603 DumpRect(dp->add_texturerect(), mTextureRects[i]);
604 }
605
606 for (GLuint texId : mTexIDs) {
607 dp->add_texids(texId);
608 }
609
610 return WriteToStream(packet);
611 }
612
613 protected:
614 float mOffsetX;
615 float mOffsetY;
616 gfx::Matrix4x4 mMVMatrix;
617 size_t mRects;
618 gfx::Rect mLayerRects[4];
619 gfx::Rect mTextureRects[4];
620 std::list<GLuint> mTexIDs;
621 uint64_t mLayerRef;
622 };
623
624 class DebugDataSender {
625 public:
626 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DebugDataSender)
627
628 // Append a DebugData into mList on mThread
629 class AppendTask : public nsIRunnable {
630 public:
631 NS_DECL_THREADSAFE_ISUPPORTS
632
AppendTask(DebugDataSender * host,DebugGLData * d)633 AppendTask(DebugDataSender* host, DebugGLData* d) : mData(d), mHost(host) {}
634
Run()635 NS_IMETHOD Run() override {
636 mHost->mList.insertBack(mData);
637 return NS_OK;
638 }
639
640 private:
641 virtual ~AppendTask() = default;
642
643 DebugGLData* mData;
644 // Keep a strong reference to DebugDataSender to prevent this object
645 // accessing mHost on mThread, when it's been destroyed on the main
646 // thread.
647 RefPtr<DebugDataSender> mHost;
648 };
649
650 // Clear all DebugData in mList on mThead.
651 class ClearTask : public nsIRunnable {
652 public:
653 NS_DECL_THREADSAFE_ISUPPORTS
ClearTask(DebugDataSender * host)654 explicit ClearTask(DebugDataSender* host) : mHost(host) {}
655
Run()656 NS_IMETHOD Run() override {
657 mHost->RemoveData();
658 return NS_OK;
659 }
660
661 private:
662 virtual ~ClearTask() = default;
663
664 RefPtr<DebugDataSender> mHost;
665 };
666
667 // Send all DebugData in mList via websocket, and then, clean up
668 // mList on mThread.
669 class SendTask : public nsIRunnable {
670 public:
671 NS_DECL_THREADSAFE_ISUPPORTS
672
SendTask(DebugDataSender * host)673 explicit SendTask(DebugDataSender* host) : mHost(host) {}
674
Run()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);
680 if (!d->Write()) {
681 gLayerScopeManager.DestroyServerSocket();
682 break;
683 }
684 }
685
686 // Cleanup.
687 mHost->RemoveData();
688 return NS_OK;
689 }
690
691 private:
692 virtual ~SendTask() = default;
693
694 RefPtr<DebugDataSender> mHost;
695 };
696
DebugDataSender(nsIThread * thread)697 explicit DebugDataSender(nsIThread* thread) : mThread(thread) {}
698
Append(DebugGLData * d)699 void Append(DebugGLData* d) {
700 mThread->Dispatch(new AppendTask(this, d), NS_DISPATCH_NORMAL);
701 }
702
Cleanup()703 void Cleanup() { mThread->Dispatch(new ClearTask(this), NS_DISPATCH_NORMAL); }
704
Send()705 void Send() { mThread->Dispatch(new SendTask(this), NS_DISPATCH_NORMAL); }
706
707 protected:
708 virtual ~DebugDataSender() = default;
RemoveData()709 void RemoveData() {
710 MOZ_ASSERT(mThread->SerialEventTarget()->IsOnCurrentThread());
711 if (mList.isEmpty()) return;
712
713 DebugGLData* d;
714 while ((d = mList.popFirst()) != nullptr) delete d;
715 }
716
717 // We can only modify or aceess mList on mThread.
718 LinkedList<DebugGLData> mList;
719 nsCOMPtr<nsIThread> mThread;
720 };
721
722 NS_IMPL_ISUPPORTS(DebugDataSender::AppendTask, nsIRunnable);
723 NS_IMPL_ISUPPORTS(DebugDataSender::ClearTask, nsIRunnable);
724 NS_IMPL_ISUPPORTS(DebugDataSender::SendTask, nsIRunnable);
725
726 /*
727 * LayerScope SendXXX Structure
728 * 1. SendLayer
729 * 2. SendEffectChain
730 * 1. SendTexturedEffect
731 * -> SendTextureSource
732 * 2. SendMaskEffect
733 * -> SendTextureSource
734 * 3. SendYCbCrEffect
735 * -> SendTextureSource
736 * 4. SendColor
737 */
738 class SenderHelper {
739 // Sender public APIs
740 public:
741 static void SendLayer(LayerComposite* aLayer, int aWidth, int aHeight);
742
743 static void SendEffectChain(gl::GLContext* aGLContext,
744 const EffectChain& aEffectChain, int aWidth = 0,
745 int aHeight = 0);
746
SetLayersTreeSendable(bool aSet)747 static void SetLayersTreeSendable(bool aSet) { sLayersTreeSendable = aSet; }
748
SetLayersBufferSendable(bool aSet)749 static void SetLayersBufferSendable(bool aSet) {
750 sLayersBufferSendable = aSet;
751 }
752
GetLayersTreeSendable()753 static bool GetLayersTreeSendable() { return sLayersTreeSendable; }
754
755 static void ClearSentTextureIds();
756
757 // Sender private functions
758 private:
759 static void SendColor(void* aLayerRef, const DeviceColor& aColor, int aWidth,
760 int aHeight);
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);
775 // Data fields
776 private:
777 static bool sLayersTreeSendable;
778 static bool sLayersBufferSendable;
779 static std::vector<GLuint> sSentTextureIds;
780 };
781
782 bool SenderHelper::sLayersTreeSendable = true;
783 bool SenderHelper::sLayersBufferSendable = true;
784 std::vector<GLuint> SenderHelper::sSentTextureIds;
785
786 // ----------------------------------------------
787 // SenderHelper implementation
788 // ----------------------------------------------
ClearSentTextureIds()789 void SenderHelper::ClearSentTextureIds() { sSentTextureIds.clear(); }
790
HasTextureIdBeenSent(GLuint aTextureId)791 bool SenderHelper::HasTextureIdBeenSent(GLuint aTextureId) {
792 return std::find(sSentTextureIds.begin(), sSentTextureIds.end(),
793 aTextureId) != sSentTextureIds.end();
794 }
795
SendLayer(LayerComposite * aLayer,int aWidth,int aHeight)796 void SenderHelper::SendLayer(LayerComposite* aLayer, int aWidth, int aHeight) {
797 MOZ_ASSERT(aLayer && aLayer->GetLayer());
798 if (!aLayer || !aLayer->GetLayer()) {
799 return;
800 }
801
802 switch (aLayer->GetLayer()->GetType()) {
803 case Layer::TYPE_COLOR: {
804 EffectChain effect;
805 aLayer->GenEffectChain(effect);
806
807 LayerScope::DrawBegin();
808 LayerScope::DrawEnd(nullptr, effect, aWidth, aHeight);
809 break;
810 }
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();
821 EffectChain effect;
822 // Generate primary effect (lock and gen)
823 AutoLockCompositableHost lock(compHost);
824 aLayer->GenEffectChain(effect);
825
826 LayerScope::DrawBegin();
827 LayerScope::DrawEnd(compOGL->gl(), effect, aWidth, aHeight);
828 }
829 break;
830 }
831 case Layer::TYPE_CONTAINER:
832 default:
833 break;
834 }
835 }
836
SendColor(void * aLayerRef,const DeviceColor & aColor,int aWidth,int aHeight)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));
841 }
842
GetTextureID(GLContext * aGLContext,TextureSourceOGL * aSource)843 GLuint SenderHelper::GetTextureID(GLContext* aGLContext,
844 TextureSourceOGL* aSource) {
845 GLenum textureTarget = aSource->GetTextureTarget();
846 aSource->BindTexture(LOCAL_GL_TEXTURE0, gfx::SamplingFilter::LINEAR);
847
848 GLuint texID = 0;
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);
857 }
858
859 return texID;
860 }
861
SendTextureSource(GLContext * aGLContext,void * aLayerRef,TextureSourceOGL * aSource,bool aFlipY,bool aIsMask,UniquePtr<Packet> aPacket)862 void SenderHelper::SendTextureSource(GLContext* aGLContext, void* aLayerRef,
863 TextureSourceOGL* aSource, bool aFlipY,
864 bool aIsMask, UniquePtr<Packet> aPacket) {
865 MOZ_ASSERT(aGLContext);
866 if (!aGLContext) {
867 return;
868 }
869 GLuint texID = GetTextureID(aGLContext, aSource);
870 if (HasTextureIdBeenSent(texID)) {
871 return;
872 }
873
874 GLenum textureTarget = aSource->GetTextureTarget();
875 ShaderConfigOGL config =
876 ShaderConfigFromTargetAndFormat(textureTarget, aSource->GetFormat());
877 int shaderConfig = config.mFeatures;
878
879 gfx::IntSize size = aSource->GetSize();
880
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)));
889
890 sSentTextureIds.push_back(texID);
891 gLayerScopeManager.CurrentSession().mTexIDs.push_back(texID);
892 }
893
SetAndSendTexture(GLContext * aGLContext,void * aLayerRef,TextureSourceOGL * aSource,const TexturedEffect * aEffect)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
898 // attributes.
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,
905 std::move(packet));
906 }
907
SendTexturedEffect(GLContext * aGLContext,void * aLayerRef,const TexturedEffect * aEffect)908 void SenderHelper::SendTexturedEffect(GLContext* aGLContext, void* aLayerRef,
909 const TexturedEffect* aEffect) {
910 TextureSourceOGL* source = aEffect->mTexture->AsSourceOGL();
911 if (!source) {
912 return;
913 }
914
915 // Fallback texture sending path.
916 SetAndSendTexture(aGLContext, aLayerRef, source, aEffect);
917 }
918
SendMaskEffect(GLContext * aGLContext,void * aLayerRef,const EffectMask * aEffect)919 void SenderHelper::SendMaskEffect(GLContext* aGLContext, void* aLayerRef,
920 const EffectMask* aEffect) {
921 TextureSourceOGL* source = aEffect->mMaskTexture->AsSourceOGL();
922 if (!source) {
923 return;
924 }
925
926 // Expose packet creation here, so we could dump secondary mask effect
927 // attributes.
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++);
935 }
936
937 SendTextureSource(aGLContext, aLayerRef, source, false, true,
938 std::move(packet));
939 }
940
SendYCbCrEffect(GLContext * aGLContext,void * aLayerRef,const EffectYCbCr * aEffect)941 void SenderHelper::SendYCbCrEffect(GLContext* aGLContext, void* aLayerRef,
942 const EffectYCbCr* aEffect) {
943 TextureSource* sourceYCbCr = aEffect->mTexture;
944 if (!sourceYCbCr) return;
945
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()};
950
951 for (auto source : sources) {
952 SetAndSendTexture(aGLContext, aLayerRef, source, aEffect);
953 }
954 }
955
SendEffectChain(GLContext * aGLContext,const EffectChain & aEffectChain,int aWidth,int aHeight)956 void SenderHelper::SendEffectChain(GLContext* aGLContext,
957 const EffectChain& aEffectChain, int aWidth,
958 int aHeight) {
959 if (!sLayersBufferSendable) return;
960
961 const Effect* primaryEffect = aEffectChain.mPrimaryEffect;
962 MOZ_ASSERT(primaryEffect);
963
964 if (!primaryEffect) {
965 return;
966 }
967
968 switch (primaryEffect->mType) {
969 case EffectTypes::RGB: {
970 const TexturedEffect* texturedEffect =
971 static_cast<const TexturedEffect*>(primaryEffect);
972 SendTexturedEffect(aGLContext, aEffectChain.mLayerRef, texturedEffect);
973 break;
974 }
975 case EffectTypes::YCBCR: {
976 const EffectYCbCr* yCbCrEffect =
977 static_cast<const EffectYCbCr*>(primaryEffect);
978 SendYCbCrEffect(aGLContext, aEffectChain.mLayerRef, yCbCrEffect);
979 break;
980 }
981 case EffectTypes::SOLID_COLOR: {
982 const EffectSolidColor* solidColorEffect =
983 static_cast<const EffectSolidColor*>(primaryEffect);
984 SendColor(aEffectChain.mLayerRef, solidColorEffect->mColor, aWidth,
985 aHeight);
986 break;
987 }
988 case EffectTypes::COMPONENT_ALPHA:
989 case EffectTypes::RENDER_TARGET:
990 default:
991 break;
992 }
993
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);
998 }
999 }
1000
ContentChanged(TextureHost * host)1001 void LayerScope::ContentChanged(TextureHost* host) {
1002 if (!CheckSendable()) {
1003 return;
1004 }
1005
1006 gLayerScopeManager.GetContentMonitor()->SetChangedHost(host);
1007 }
1008
1009 // ----------------------------------------------
1010 // SocketHandler implementation
1011 // ----------------------------------------------
OpenStream(nsISocketTransport * aTransport)1012 void LayerScopeWebSocketManager::SocketHandler::OpenStream(
1013 nsISocketTransport* aTransport) {
1014 MOZ_ASSERT(aTransport);
1015
1016 mTransport = aTransport;
1017 mTransport->OpenOutputStream(nsITransport::OPEN_BLOCKING, 0, 0,
1018 getter_AddRefs(mOutputStream));
1019
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());
1024 }
1025
WriteToStream(void * aPtr,uint32_t aSize)1026 bool LayerScopeWebSocketManager::SocketHandler::WriteToStream(void* aPtr,
1027 uint32_t aSize) {
1028 if (mState == NoHandshake) {
1029 // Not yet handshake, just return true in case of
1030 // LayerScope remove this handle
1031 return true;
1032 } else if (mState == HandshakeFailed) {
1033 return false;
1034 }
1035
1036 if (!mOutputStream) {
1037 return false;
1038 }
1039
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;
1045 if (aSize <= 125) {
1046 wsHeaderSize = 2;
1047 wsHeader[1] = aSize;
1048 } else if (aSize < 65536) {
1049 wsHeaderSize = 4;
1050 wsHeader[1] = 0x7E;
1051 NetworkEndian::writeUint16(wsHeader + 2, aSize);
1052 } else {
1053 wsHeaderSize = 10;
1054 wsHeader[1] = 0x7F;
1055 NetworkEndian::writeUint64(wsHeader + 2, aSize);
1056 }
1057
1058 // Send WebSocket header
1059 nsresult rv;
1060 uint32_t cnt;
1061 rv = mOutputStream->Write(reinterpret_cast<char*>(wsHeader), wsHeaderSize,
1062 &cnt);
1063 if (NS_FAILED(rv)) return false;
1064
1065 uint32_t written = 0;
1066 while (written < aSize) {
1067 uint32_t cnt;
1068 rv = mOutputStream->Write(reinterpret_cast<char*>(aPtr) + written,
1069 aSize - written, &cnt);
1070 if (NS_FAILED(rv)) return false;
1071
1072 written += cnt;
1073 }
1074
1075 return true;
1076 }
1077
1078 NS_IMETHODIMP
OnInputStreamReady(nsIAsyncInputStream * aStream)1079 LayerScopeWebSocketManager::SocketHandler::OnInputStreamReady(
1080 nsIAsyncInputStream* aStream) {
1081 MOZ_ASSERT(mInputStream);
1082
1083 if (!mInputStream) {
1084 return NS_OK;
1085 }
1086
1087 if (!mConnected) {
1088 nsTArray<nsCString> protocolString;
1089 ReadInputStreamData(protocolString);
1090
1091 if (WebSocketHandshake(protocolString)) {
1092 mState = HandshakeSuccess;
1093 mConnected = true;
1094 mInputStream->AsyncWait(this, 0, 0, GetCurrentThreadEventTarget());
1095 } else {
1096 mState = HandshakeFailed;
1097 }
1098 return NS_OK;
1099 } else {
1100 return HandleSocketMessage(aStream);
1101 }
1102 }
1103
ReadInputStreamData(nsTArray<nsCString> & aProtocolString)1104 void LayerScopeWebSocketManager::SocketHandler::ReadInputStreamData(
1105 nsTArray<nsCString>& aProtocolString) {
1106 nsLineBuffer<char> lineBuffer;
1107 nsCString line;
1108 bool more = true;
1109 do {
1110 NS_ReadLine(mInputStream.get(), &lineBuffer, line, &more);
1111
1112 if (line.Length() > 0) {
1113 aProtocolString.AppendElement(line);
1114 }
1115 } while (more && line.Length() > 0);
1116 }
1117
WebSocketHandshake(nsTArray<nsCString> & aProtocolString)1118 bool LayerScopeWebSocketManager::SocketHandler::WebSocketHandshake(
1119 nsTArray<nsCString>& aProtocolString) {
1120 nsresult rv;
1121 bool isWebSocket = false;
1122 nsCString version;
1123 nsCString wsKey;
1124 nsCString protocol;
1125
1126 // Validate WebSocket client request.
1127 if (aProtocolString.Length() == 0) return false;
1128
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)) !=
1132 0) {
1133 return false;
1134 }
1135
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")) {
1144 isWebSocket = true;
1145 } else if (key.EqualsIgnoreCase("sec-websocket-version")) {
1146 version = value;
1147 } else if (key.EqualsIgnoreCase("sec-websocket-key")) {
1148 wsKey = value;
1149 } else if (key.EqualsIgnoreCase("sec-websocket-protocol")) {
1150 protocol = value;
1151 }
1152 }
1153 }
1154
1155 if (!isWebSocket) {
1156 return false;
1157 }
1158
1159 if (!(version.EqualsLiteral("7") || version.EqualsLiteral("8") ||
1160 version.EqualsLiteral("13"))) {
1161 return false;
1162 }
1163
1164 if (!(protocol.EqualsIgnoreCase("binary"))) {
1165 return false;
1166 }
1167
1168 if (!mOutputStream) {
1169 return false;
1170 }
1171
1172 // Client request is valid. Start to generate and send server response.
1173 nsAutoCString guid("258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
1174 nsAutoCString res;
1175 SHA1Sum sha1;
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)) {
1183 return false;
1184 }
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 +
1189 nsCString("\r\n"));
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) {
1194 uint32_t cnt;
1195 rv = mOutputStream->Write(const_cast<char*>(response.get()) + written,
1196 size - written, &cnt);
1197 if (NS_FAILED(rv)) return false;
1198
1199 written += cnt;
1200 }
1201 mOutputStream->Flush();
1202
1203 return true;
1204 }
1205
HandleSocketMessage(nsIAsyncInputStream * aStream)1206 nsresult LayerScopeWebSocketManager::SocketHandler::HandleSocketMessage(
1207 nsIAsyncInputStream* aStream) {
1208 // The reading and parsing of this input stream is customized for layer
1209 // viewer.
1210 const uint32_t cPacketSize = 1024;
1211 char buffer[cPacketSize];
1212 uint32_t count = 0;
1213 nsresult rv = NS_OK;
1214
1215 do {
1216 rv = mInputStream->Read((char*)buffer, cPacketSize, &count);
1217
1218 // TODO: combine packets if we have to read more than once
1219
1220 if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
1221 mInputStream->AsyncWait(this, 0, 0, GetCurrentThreadEventTarget());
1222 return NS_OK;
1223 }
1224
1225 if (NS_FAILED(rv)) {
1226 break;
1227 }
1228
1229 if (count == 0) {
1230 // NS_BASE_STREAM_CLOSED
1231 CloseConnection();
1232 break;
1233 }
1234
1235 rv = ProcessInput(reinterpret_cast<uint8_t*>(buffer), count);
1236 } while (NS_SUCCEEDED(rv) && mInputStream);
1237 return rv;
1238 }
1239
ProcessInput(uint8_t * aBuffer,uint32_t aCount)1240 nsresult LayerScopeWebSocketManager::SocketHandler::ProcessInput(
1241 uint8_t* aBuffer, uint32_t aCount) {
1242 uint32_t avail = aCount;
1243
1244 // Decode Websocket data frame
1245 if (avail <= 2) {
1246 NS_WARNING("Packet size is less than 2 bytes");
1247 return NS_OK;
1248 }
1249
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
1254
1255 if (!finBit) {
1256 NS_WARNING(
1257 "We cannot handle multi-fragments messages in Layerscope websocket "
1258 "parser.");
1259 return NS_OK;
1260 }
1261
1262 // Second byte, data length
1263 uint8_t maskBit = aBuffer[1] & 0x80; // 1000 0000
1264 int64_t payloadLength64 = aBuffer[1] & 0x7F; // 0111 1111
1265
1266 if (!maskBit) {
1267 NS_WARNING("Client to Server should set the mask bit");
1268 return NS_OK;
1269 }
1270
1271 uint32_t framingLength = 2 + 4; // 4 for masks
1272
1273 if (payloadLength64 < 126) {
1274 if (avail < framingLength) return NS_OK;
1275 } else if (payloadLength64 == 126) {
1276 // 16 bit length field
1277 framingLength += 2;
1278 if (avail < framingLength) {
1279 return NS_OK;
1280 }
1281
1282 payloadLength64 = aBuffer[2] << 8 | aBuffer[3];
1283 } else {
1284 // 64 bit length
1285 framingLength += 8;
1286 if (avail < framingLength) {
1287 return NS_OK;
1288 }
1289
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;
1295 }
1296
1297 // copy this in case it is unaligned
1298 payloadLength64 = NetworkEndian::readInt64(aBuffer + 2);
1299 }
1300
1301 uint8_t* payload = aBuffer + framingLength;
1302 avail -= framingLength;
1303
1304 uint32_t payloadLength = static_cast<uint32_t>(payloadLength64);
1305 if (avail < payloadLength) {
1306 NS_WARNING("Packet size mismatch the payload length");
1307 return NS_OK;
1308 }
1309
1310 // Apply mask
1311 uint32_t mask = NetworkEndian::readUint32(payload - 4);
1312 ApplyMask(mask, payload, payloadLength);
1313
1314 if (opcode == 0x8) {
1315 // opcode == 0x8 means connection close
1316 CloseConnection();
1317 return NS_BASE_STREAM_CLOSED;
1318 }
1319
1320 if (!HandleDataFrame(payload, payloadLength)) {
1321 NS_WARNING("Cannot decode payload data by the protocol buffer");
1322 }
1323
1324 return NS_OK;
1325 }
1326
ApplyMask(uint32_t aMask,uint8_t * aData,uint64_t aLen)1327 void LayerScopeWebSocketManager::SocketHandler::ApplyMask(uint32_t aMask,
1328 uint8_t* aData,
1329 uint64_t aLen) {
1330 if (!aData || aLen == 0) {
1331 return;
1332 }
1333
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);
1340 aData++;
1341 aLen--;
1342 }
1343
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++) {
1349 *iData ^= aMask;
1350 }
1351 aMask = NetworkEndian::readUint32(&aMask);
1352 aData = (uint8_t*)iData;
1353 aLen = aLen % 4;
1354
1355 // There maybe up to 3 trailing bytes that need to be dealt with
1356 // individually
1357 while (aLen) {
1358 *aData ^= aMask >> 24;
1359 aMask = RotateLeft(aMask, 8);
1360 aData++;
1361 aLen--;
1362 }
1363 }
1364
HandleDataFrame(uint8_t * aData,uint32_t aSize)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);
1370
1371 if (!p->has_type()) {
1372 MOZ_ASSERT(false, "Protocol buffer decoding failed or cannot recongize it");
1373 return false;
1374 }
1375
1376 switch (p->type()) {
1377 case CommandPacket::LAYERS_TREE:
1378 if (p->has_value()) {
1379 SenderHelper::SetLayersTreeSendable(p->value());
1380 }
1381 break;
1382
1383 case CommandPacket::LAYERS_BUFFER:
1384 if (p->has_value()) {
1385 SenderHelper::SetLayersBufferSendable(p->value());
1386 }
1387 break;
1388
1389 case CommandPacket::NO_OP:
1390 default:
1391 NS_WARNING("Invalid message type");
1392 break;
1393 }
1394 return true;
1395 }
1396
CloseConnection()1397 void LayerScopeWebSocketManager::SocketHandler::CloseConnection() {
1398 gLayerScopeManager.GetSocketManager()->CleanDebugData();
1399 if (mInputStream) {
1400 mInputStream->AsyncWait(nullptr, 0, 0, nullptr);
1401 mInputStream = nullptr;
1402 }
1403 if (mOutputStream) {
1404 mOutputStream = nullptr;
1405 }
1406 if (mTransport) {
1407 mTransport->Close(NS_BASE_STREAM_CLOSED);
1408 mTransport = nullptr;
1409 }
1410 mConnected = false;
1411 }
1412
1413 // ----------------------------------------------
1414 // LayerScopeWebSocketManager implementation
1415 // ----------------------------------------------
LayerScopeWebSocketManager()1416 LayerScopeWebSocketManager::LayerScopeWebSocketManager()
1417 : mHandlerMutex("LayerScopeWebSocketManager::mHandlerMutex") {
1418 NS_NewNamedThread("LayerScope", getter_AddRefs(mDebugSenderThread));
1419
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);
1424 }
1425
~LayerScopeWebSocketManager()1426 LayerScopeWebSocketManager::~LayerScopeWebSocketManager() {
1427 mServerSocket->Close();
1428 }
1429
AppendDebugData(DebugGLData * aDebugData)1430 void LayerScopeWebSocketManager::AppendDebugData(DebugGLData* aDebugData) {
1431 if (!mCurrentSender) {
1432 mCurrentSender = new DebugDataSender(mDebugSenderThread);
1433 }
1434
1435 mCurrentSender->Append(aDebugData);
1436 }
1437
CleanDebugData()1438 void LayerScopeWebSocketManager::CleanDebugData() {
1439 if (mCurrentSender) {
1440 mCurrentSender->Cleanup();
1441 }
1442 }
1443
DispatchDebugData()1444 void LayerScopeWebSocketManager::DispatchDebugData() {
1445 MOZ_ASSERT(mCurrentSender.get() != nullptr);
1446
1447 mCurrentSender->Send();
1448 mCurrentSender = nullptr;
1449 }
1450
OnSocketAccepted(nsIServerSocket * aServ,nsISocketTransport * aTransport)1451 NS_IMETHODIMP LayerScopeWebSocketManager::SocketListener::OnSocketAccepted(
1452 nsIServerSocket* aServ, nsISocketTransport* aTransport) {
1453 if (!gLayerScopeManager.GetSocketManager()) return NS_OK;
1454
1455 printf_stderr("*** LayerScope: Accepted connection\n");
1456 gLayerScopeManager.GetSocketManager()->AddConnection(aTransport);
1457 gLayerScopeManager.GetContentMonitor()->Empty();
1458 return NS_OK;
1459 }
1460
1461 // ----------------------------------------------
1462 // LayerScope implementation
1463 // ----------------------------------------------
1464 /*static*/
Init()1465 void LayerScope::Init() {
1466 if (!StaticPrefs::gfx_layerscope_enabled() || XRE_IsGPUProcess()) {
1467 return;
1468 }
1469
1470 gLayerScopeManager.CreateServerSocket();
1471 }
1472
1473 /*static*/
DrawBegin()1474 void LayerScope::DrawBegin() {
1475 if (!CheckSendable()) {
1476 return;
1477 }
1478
1479 gLayerScopeManager.NewDrawSession();
1480 }
1481
1482 /*static*/
SetRenderOffset(float aX,float aY)1483 void LayerScope::SetRenderOffset(float aX, float aY) {
1484 if (!CheckSendable()) {
1485 return;
1486 }
1487
1488 gLayerScopeManager.CurrentSession().mOffsetX = aX;
1489 gLayerScopeManager.CurrentSession().mOffsetY = aY;
1490 }
1491
1492 /*static*/
SetLayerTransform(const gfx::Matrix4x4 & aMatrix)1493 void LayerScope::SetLayerTransform(const gfx::Matrix4x4& aMatrix) {
1494 if (!CheckSendable()) {
1495 return;
1496 }
1497
1498 gLayerScopeManager.CurrentSession().mMVMatrix = aMatrix;
1499 }
1500
1501 /*static*/
SetDrawRects(size_t aRects,const gfx::Rect * aLayerRects,const gfx::Rect * aTextureRects)1502 void LayerScope::SetDrawRects(size_t aRects, const gfx::Rect* aLayerRects,
1503 const gfx::Rect* aTextureRects) {
1504 if (!CheckSendable()) {
1505 return;
1506 }
1507
1508 MOZ_ASSERT(aRects > 0 && aRects <= 4);
1509 MOZ_ASSERT(aLayerRects);
1510
1511 gLayerScopeManager.CurrentSession().mRects = aRects;
1512
1513 for (size_t i = 0; i < aRects; i++) {
1514 gLayerScopeManager.CurrentSession().mLayerRects[i] = aLayerRects[i];
1515 gLayerScopeManager.CurrentSession().mTextureRects[i] = aTextureRects[i];
1516 }
1517 }
1518
1519 /*static*/
DrawEnd(gl::GLContext * aGLContext,const EffectChain & aEffectChain,int aWidth,int aHeight)1520 void LayerScope::DrawEnd(gl::GLContext* aGLContext,
1521 const EffectChain& aEffectChain, int aWidth,
1522 int aHeight) {
1523 // Protect this public function
1524 if (!CheckSendable()) {
1525 return;
1526 }
1527
1528 // 1. Send textures.
1529 SenderHelper::SendEffectChain(aGLContext, aEffectChain, aWidth, aHeight);
1530
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));
1538 }
1539
1540 /*static*/
SendLayer(LayerComposite * aLayer,int aWidth,int aHeight)1541 void LayerScope::SendLayer(LayerComposite* aLayer, int aWidth, int aHeight) {
1542 // Protect this public function
1543 if (!CheckSendable()) {
1544 return;
1545 }
1546 SenderHelper::SendLayer(aLayer, aWidth, aHeight);
1547 }
1548
1549 /*static*/
SendLayerDump(UniquePtr<Packet> aPacket)1550 void LayerScope::SendLayerDump(UniquePtr<Packet> aPacket) {
1551 // Protect this public function
1552 if (!CheckSendable() || !SenderHelper::GetLayersTreeSendable()) {
1553 return;
1554 }
1555 gLayerScopeManager.GetSocketManager()->AppendDebugData(
1556 new DebugGLLayersData(std::move(aPacket)));
1557 }
1558
1559 /*static*/
CheckSendable()1560 bool LayerScope::CheckSendable() {
1561 // Only compositor threads check LayerScope status
1562 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread() || gIsGtest);
1563
1564 if (!StaticPrefs::gfx_layerscope_enabled()) {
1565 return false;
1566 }
1567 if (!gLayerScopeManager.GetSocketManager()) {
1568 Init();
1569 return false;
1570 }
1571 if (!gLayerScopeManager.GetSocketManager()->IsConnected()) {
1572 return false;
1573 }
1574 return true;
1575 }
1576
1577 /*static*/
CleanLayer()1578 void LayerScope::CleanLayer() {
1579 if (CheckSendable()) {
1580 gLayerScopeManager.GetSocketManager()->CleanDebugData();
1581 }
1582 }
1583
1584 /*static*/
SetHWComposed()1585 void LayerScope::SetHWComposed() {
1586 if (CheckSendable()) {
1587 gLayerScopeManager.GetSocketManager()->AppendDebugData(
1588 new DebugGLMetaData(Packet::META, true));
1589 }
1590 }
1591
1592 /*static*/
SetPixelScale(double devPixelsPerCSSPixel)1593 void LayerScope::SetPixelScale(double devPixelsPerCSSPixel) {
1594 gLayerScopeManager.SetPixelScale(devPixelsPerCSSPixel);
1595 }
1596
1597 // ----------------------------------------------
1598 // LayerScopeAutoFrame implementation
1599 // ----------------------------------------------
LayerScopeAutoFrame(int64_t aFrameStamp)1600 LayerScopeAutoFrame::LayerScopeAutoFrame(int64_t aFrameStamp) {
1601 // Do Begin Frame
1602 BeginFrame(aFrameStamp);
1603 }
1604
~LayerScopeAutoFrame()1605 LayerScopeAutoFrame::~LayerScopeAutoFrame() {
1606 // Do End Frame
1607 EndFrame();
1608 }
1609
BeginFrame(int64_t aFrameStamp)1610 void LayerScopeAutoFrame::BeginFrame(int64_t aFrameStamp) {
1611 if (!LayerScope::CheckSendable()) {
1612 return;
1613 }
1614 SenderHelper::ClearSentTextureIds();
1615
1616 gLayerScopeManager.GetSocketManager()->AppendDebugData(
1617 new DebugGLFrameStatusData(Packet::FRAMESTART, aFrameStamp));
1618 }
1619
EndFrame()1620 void LayerScopeAutoFrame::EndFrame() {
1621 if (!LayerScope::CheckSendable()) {
1622 return;
1623 }
1624
1625 gLayerScopeManager.GetSocketManager()->AppendDebugData(
1626 new DebugGLFrameStatusData(Packet::FRAMEEND));
1627 gLayerScopeManager.GetSocketManager()->DispatchDebugData();
1628 }
1629
1630 } // namespace layers
1631 } // namespace mozilla
1632