Source code

Revision control

Other Tools

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
78
void RemoveAllConnections() {
79
MOZ_ASSERT(NS_IsMainThread());
80
81
MutexAutoLock lock(mHandlerMutex);
82
mHandlers.Clear();
83
}
84
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
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:
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
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;
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
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:
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:
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.
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.
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.
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
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:
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
282
void DestroyServerSocket() {
283
// Destroy Web Server Socket
284
if (mWebSocketManager) {
285
mWebSocketManager->RemoveAllConnections();
286
}
287
}
288
289
LayerScopeWebSocketManager* GetSocketManager() {
290
return mWebSocketManager.get();
291
}
292
293
ContentMonitor* GetContentMonitor() {
294
if (!mContentMonitor.get()) {
295
mContentMonitor = mozilla::MakeUnique<ContentMonitor>();
296
}
297
298
return mContentMonitor.get();
299
}
300
301
void NewDrawSession() { mSession = mozilla::MakeUnique<DrawSession>(); }
302
303
DrawSession& CurrentSession() { return *mSession; }
304
305
void SetPixelScale(double scale) { mScale = scale; }
306
307
double GetPixelScale() const { return mScale; }
308
309
LayerScopeManager() : mScale(1.0) {}
310
311
private:
312
friend class CreateServerSocketRunnable;
313
class CreateServerSocketRunnable : public Runnable {
314
public:
315
explicit CreateServerSocketRunnable(LayerScopeManager* aLayerScopeManager)
316
: Runnable("layers::LayerScopeManager::CreateServerSocketRunnable"),
317
mLayerScopeManager(aLayerScopeManager) {}
318
NS_IMETHOD Run() override {
319
mLayerScopeManager->mWebSocketManager =
320
mozilla::MakeUnique<LayerScopeWebSocketManager>();
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>
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
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:
378
explicit DebugGLData(Packet::DataType aDataType) : mDataType(aDataType) {}
379
380
virtual ~DebugGLData() = default;
381
382
virtual bool Write() = 0;
383
384
protected:
385
static bool WriteToStream(Packet& aPacket) {
386
if (!gLayerScopeManager.GetSocketManager()) return true;
387
388
uint32_t size = aPacket.ByteSize();
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:
399
DebugGLFrameStatusData(Packet::DataType aDataType, int64_t aValue)
400
: DebugGLData(aDataType), mFrameStamp(aValue) {}
401
402
explicit DebugGLFrameStatusData(Packet::DataType aDataType)
403
: DebugGLData(aDataType), mFrameStamp(0) {}
404
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:
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
441
bool Write() override { return WriteToStream(*mPacket); }
442
443
private:
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:
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
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:
529
explicit DebugGLLayersData(UniquePtr<Packet> aPacket)
530
: DebugGLData(Packet::LAYERS), mPacket(std::move(aPacket)) {}
531
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:
543
DebugGLMetaData(Packet::DataType aDataType, bool aValue)
544
: DebugGLData(aDataType), mComposedByHwc(aValue) {}
545
546
explicit DebugGLMetaData(Packet::DataType aDataType)
547
: DebugGLData(aDataType), mComposedByHwc(false) {}
548
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:
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
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
633
AppendTask(DebugDataSender* host, DebugGLData* d) : mData(d), mHost(host) {}
634
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
654
explicit ClearTask(DebugDataSender* host) : mHost(host) {}
655
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
673
explicit SendTask(DebugDataSender* host) : mHost(host) {}
674
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
697
explicit DebugDataSender(nsIThread* thread) : mThread(thread) {}
698
699
void Append(DebugGLData* d) {
700
mThread->Dispatch(new AppendTask(this, d), NS_DISPATCH_NORMAL);
701
}
702
703
void Cleanup() { mThread->Dispatch(new ClearTask(this), NS_DISPATCH_NORMAL); }
704
705
void Send() { mThread->Dispatch(new SendTask(this), NS_DISPATCH_NORMAL); }
706
707
protected:
708
virtual ~DebugDataSender() = default;
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
747
static void SetLayersTreeSendable(bool aSet) { sLayersTreeSendable = aSet; }
748
749
static void SetLayersBufferSendable(bool aSet) {
750
sLayersBufferSendable = aSet;
751
}
752
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
// ----------------------------------------------
789
void SenderHelper::ClearSentTextureIds() { sSentTextureIds.clear(); }
790
791
bool SenderHelper::HasTextureIdBeenSent(GLuint aTextureId) {
792
return std::find(sSentTextureIds.begin(), sSentTextureIds.end(),
793
aTextureId) != sSentTextureIds.end();
794
}
795
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
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
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
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
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
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
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
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
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
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
// ----------------------------------------------
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
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
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
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
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
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
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
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
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
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
// ----------------------------------------------
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
1426
LayerScopeWebSocketManager::~LayerScopeWebSocketManager() {
1427
mServerSocket->Close();
1428
}
1429
1430
void LayerScopeWebSocketManager::AppendDebugData(DebugGLData* aDebugData) {
1431
if (!mCurrentSender) {
1432
mCurrentSender = new DebugDataSender(mDebugSenderThread);
1433
}
1434
1435
mCurrentSender->Append(aDebugData);
1436
}
1437
1438
void LayerScopeWebSocketManager::CleanDebugData() {
1439
if (mCurrentSender) {
1440
mCurrentSender->Cleanup();
1441
}
1442
}
1443
1444
void LayerScopeWebSocketManager::DispatchDebugData() {
1445
MOZ_ASSERT(mCurrentSender.get() != nullptr);
1446
1447
mCurrentSender->Send();
1448
mCurrentSender = nullptr;
1449
}
1450
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*/
1465
void LayerScope::Init() {
1466
if (!StaticPrefs::gfx_layerscope_enabled() || XRE_IsGPUProcess()) {
1467
return;
1468
}
1469
1470
gLayerScopeManager.CreateServerSocket();
1471
}
1472
1473
/*static*/
1474
void LayerScope::DrawBegin() {
1475
if (!CheckSendable()) {
1476
return;
1477
}
1478
1479
gLayerScopeManager.NewDrawSession();
1480
}
1481
1482
/*static*/
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*/
1493
void LayerScope::SetLayerTransform(const gfx::Matrix4x4& aMatrix) {
1494
if (!CheckSendable()) {
1495
return;
1496
}
1497
1498
gLayerScopeManager.CurrentSession().mMVMatrix = aMatrix;
1499
}
1500
1501
/*static*/
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*/
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*/
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*/
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*/
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*/
1578
void LayerScope::CleanLayer() {
1579
if (CheckSendable()) {
1580
gLayerScopeManager.GetSocketManager()->CleanDebugData();
1581
}
1582
}
1583
1584
/*static*/
1585
void LayerScope::SetHWComposed() {
1586
if (CheckSendable()) {
1587
gLayerScopeManager.GetSocketManager()->AppendDebugData(
1588
new DebugGLMetaData(Packet::META, true));
1589
}
1590
}
1591
1592
/*static*/
1593
void LayerScope::SetPixelScale(double devPixelsPerCSSPixel) {
1594
gLayerScopeManager.SetPixelScale(devPixelsPerCSSPixel);
1595
}
1596
1597
// ----------------------------------------------
1598
// LayerScopeAutoFrame implementation
1599
// ----------------------------------------------
1600
LayerScopeAutoFrame::LayerScopeAutoFrame(int64_t aFrameStamp) {
1601
// Do Begin Frame
1602
BeginFrame(aFrameStamp);
1603
}
1604
1605
LayerScopeAutoFrame::~LayerScopeAutoFrame() {
1606
// Do End Frame
1607
EndFrame();
1608
}
1609
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
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