gfx/layers/LayerScope.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 /* This must occur *after* layers/PLayers.h to avoid typedefs conflicts. */
michael@0 7 #include "LayerScope.h"
michael@0 8
michael@0 9 #include "Composer2D.h"
michael@0 10 #include "Effects.h"
michael@0 11 #include "mozilla/TimeStamp.h"
michael@0 12 #include "mozilla/Preferences.h"
michael@0 13 #include "mozilla/Endian.h"
michael@0 14 #include "TexturePoolOGL.h"
michael@0 15 #include "mozilla/layers/TextureHostOGL.h"
michael@0 16
michael@0 17 #include "gfxColor.h"
michael@0 18 #include "gfxContext.h"
michael@0 19 #include "gfxUtils.h"
michael@0 20 #include "gfxPrefs.h"
michael@0 21 #include "nsIWidget.h"
michael@0 22
michael@0 23 #include "GLContext.h"
michael@0 24 #include "GLContextProvider.h"
michael@0 25 #include "GLReadTexImageHelper.h"
michael@0 26
michael@0 27 #include "nsIServiceManager.h"
michael@0 28 #include "nsIConsoleService.h"
michael@0 29
michael@0 30 #include <memory>
michael@0 31 #include "mozilla/LinkedList.h"
michael@0 32 #include "mozilla/Base64.h"
michael@0 33 #include "mozilla/SHA1.h"
michael@0 34 #include "mozilla/StaticPtr.h"
michael@0 35 #include "nsThreadUtils.h"
michael@0 36 #include "nsISocketTransport.h"
michael@0 37 #include "nsIServerSocket.h"
michael@0 38 #include "nsReadLine.h"
michael@0 39 #include "nsNetCID.h"
michael@0 40 #include "nsIOutputStream.h"
michael@0 41 #include "nsIAsyncInputStream.h"
michael@0 42 #include "nsIEventTarget.h"
michael@0 43 #include "nsProxyRelease.h"
michael@0 44
michael@0 45 // Undo the damage done by mozzconf.h
michael@0 46 #undef compress
michael@0 47 #include "mozilla/Compression.h"
michael@0 48
michael@0 49 #ifdef __GNUC__
michael@0 50 #define PACKED_STRUCT __attribute__((packed))
michael@0 51 #else
michael@0 52 #define PACKED_STRUCT
michael@0 53 #endif
michael@0 54
michael@0 55 namespace mozilla {
michael@0 56 namespace layers {
michael@0 57
michael@0 58 using namespace mozilla::Compression;
michael@0 59 using namespace mozilla::gfx;
michael@0 60 using namespace mozilla::gl;
michael@0 61 using namespace mozilla;
michael@0 62
michael@0 63 class DebugDataSender;
michael@0 64 class DebugGLData;
michael@0 65
michael@0 66 /* This class handle websocket protocol which included
michael@0 67 * handshake and data frame's header
michael@0 68 */
michael@0 69 class LayerScopeWebSocketHandler : public nsIInputStreamCallback {
michael@0 70 public:
michael@0 71 NS_DECL_THREADSAFE_ISUPPORTS
michael@0 72
michael@0 73 enum SocketStateType {
michael@0 74 NoHandshake,
michael@0 75 HandshakeSuccess,
michael@0 76 HandshakeFailed
michael@0 77 };
michael@0 78
michael@0 79 LayerScopeWebSocketHandler()
michael@0 80 : mState(NoHandshake)
michael@0 81 { }
michael@0 82
michael@0 83 virtual ~LayerScopeWebSocketHandler()
michael@0 84 {
michael@0 85 if (mTransport) {
michael@0 86 mTransport->Close(NS_OK);
michael@0 87 }
michael@0 88 }
michael@0 89
michael@0 90 void OpenStream(nsISocketTransport* aTransport) {
michael@0 91 MOZ_ASSERT(aTransport);
michael@0 92
michael@0 93 mTransport = aTransport;
michael@0 94 mTransport->OpenOutputStream(nsITransport::OPEN_BLOCKING,
michael@0 95 0,
michael@0 96 0,
michael@0 97 getter_AddRefs(mOutputStream));
michael@0 98
michael@0 99 nsCOMPtr<nsIInputStream> debugInputStream;
michael@0 100 mTransport->OpenInputStream(0,
michael@0 101 0,
michael@0 102 0,
michael@0 103 getter_AddRefs(debugInputStream));
michael@0 104 mInputStream = do_QueryInterface(debugInputStream);
michael@0 105 mInputStream->AsyncWait(this, 0, 0, NS_GetCurrentThread());
michael@0 106 }
michael@0 107
michael@0 108 bool WriteToStream(void *ptr, uint32_t size) {
michael@0 109 if (mState == NoHandshake) {
michael@0 110 // Not yet handshake, just return true in case of
michael@0 111 // LayerScope remove this handle
michael@0 112 return true;
michael@0 113 } else if (mState == HandshakeFailed) {
michael@0 114 return false;
michael@0 115 }
michael@0 116
michael@0 117 // Generate WebSocket header
michael@0 118 uint8_t wsHeader[10];
michael@0 119 int wsHeaderSize = 0;
michael@0 120 const uint8_t opcode = 0x2;
michael@0 121 wsHeader[0] = 0x80 | (opcode & 0x0f); // FIN + opcode;
michael@0 122 if (size <= 125) {
michael@0 123 wsHeaderSize = 2;
michael@0 124 wsHeader[1] = size;
michael@0 125 } else if (size < 65536) {
michael@0 126 wsHeaderSize = 4;
michael@0 127 wsHeader[1] = 0x7E;
michael@0 128 NetworkEndian::writeUint16(wsHeader + 2, size);
michael@0 129 } else {
michael@0 130 wsHeaderSize = 10;
michael@0 131 wsHeader[1] = 0x7F;
michael@0 132 NetworkEndian::writeUint64(wsHeader + 2, size);
michael@0 133 }
michael@0 134
michael@0 135 // Send WebSocket header
michael@0 136 nsresult rv;
michael@0 137 uint32_t cnt;
michael@0 138 rv = mOutputStream->Write(reinterpret_cast<char*>(wsHeader),
michael@0 139 wsHeaderSize, &cnt);
michael@0 140 if (NS_FAILED(rv))
michael@0 141 return false;
michael@0 142
michael@0 143 uint32_t written = 0;
michael@0 144 while (written < size) {
michael@0 145 uint32_t cnt;
michael@0 146 rv = mOutputStream->Write(reinterpret_cast<char*>(ptr) + written,
michael@0 147 size - written, &cnt);
michael@0 148 if (NS_FAILED(rv))
michael@0 149 return false;
michael@0 150
michael@0 151 written += cnt;
michael@0 152 }
michael@0 153
michael@0 154 return true;
michael@0 155 }
michael@0 156
michael@0 157 // nsIInputStreamCallback
michael@0 158 NS_IMETHODIMP OnInputStreamReady(nsIAsyncInputStream *stream) MOZ_OVERRIDE
michael@0 159 {
michael@0 160 nsTArray<nsCString> protocolString;
michael@0 161 ReadInputStreamData(protocolString);
michael@0 162
michael@0 163 if (WebSocketHandshake(protocolString)) {
michael@0 164 mState = HandshakeSuccess;
michael@0 165 } else {
michael@0 166 mState = HandshakeFailed;
michael@0 167 }
michael@0 168 return NS_OK;
michael@0 169 }
michael@0 170 private:
michael@0 171 void ReadInputStreamData(nsTArray<nsCString>& aProtocolString)
michael@0 172 {
michael@0 173 nsLineBuffer<char> lineBuffer;
michael@0 174 nsCString line;
michael@0 175 bool more = true;
michael@0 176 do {
michael@0 177 NS_ReadLine(mInputStream.get(), &lineBuffer, line, &more);
michael@0 178
michael@0 179 if (line.Length() > 0) {
michael@0 180 aProtocolString.AppendElement(line);
michael@0 181 }
michael@0 182 } while (more && line.Length() > 0);
michael@0 183 }
michael@0 184
michael@0 185 bool WebSocketHandshake(nsTArray<nsCString>& aProtocolString)
michael@0 186 {
michael@0 187 nsresult rv;
michael@0 188 bool isWebSocket = false;
michael@0 189 nsCString version;
michael@0 190 nsCString wsKey;
michael@0 191 nsCString protocol;
michael@0 192
michael@0 193 // Validate WebSocket client request.
michael@0 194 if (aProtocolString.Length() == 0)
michael@0 195 return false;
michael@0 196
michael@0 197 // Check that the HTTP method is GET
michael@0 198 const char* HTTP_METHOD = "GET ";
michael@0 199 if (strncmp(aProtocolString[0].get(), HTTP_METHOD, strlen(HTTP_METHOD)) != 0) {
michael@0 200 return false;
michael@0 201 }
michael@0 202
michael@0 203 for (uint32_t i = 1; i < aProtocolString.Length(); ++i) {
michael@0 204 const char* line = aProtocolString[i].get();
michael@0 205 const char* prop_pos = strchr(line, ':');
michael@0 206 if (prop_pos != nullptr) {
michael@0 207 nsCString key(line, prop_pos - line);
michael@0 208 nsCString value(prop_pos + 2);
michael@0 209 if (key.EqualsIgnoreCase("upgrade") &&
michael@0 210 value.EqualsIgnoreCase("websocket")) {
michael@0 211 isWebSocket = true;
michael@0 212 } else if (key.EqualsIgnoreCase("sec-websocket-version")) {
michael@0 213 version = value;
michael@0 214 } else if (key.EqualsIgnoreCase("sec-websocket-key")) {
michael@0 215 wsKey = value;
michael@0 216 } else if (key.EqualsIgnoreCase("sec-websocket-protocol")) {
michael@0 217 protocol = value;
michael@0 218 }
michael@0 219 }
michael@0 220 }
michael@0 221
michael@0 222 if (!isWebSocket) {
michael@0 223 return false;
michael@0 224 }
michael@0 225
michael@0 226 if (!(version.Equals("7") || version.Equals("8") || version.Equals("13"))) {
michael@0 227 return false;
michael@0 228 }
michael@0 229
michael@0 230 if (!(protocol.EqualsIgnoreCase("binary"))) {
michael@0 231 return false;
michael@0 232 }
michael@0 233
michael@0 234 // Client request is valid. Start to generate and send server response.
michael@0 235 nsAutoCString guid("258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
michael@0 236 nsAutoCString res;
michael@0 237 SHA1Sum sha1;
michael@0 238 nsCString combined(wsKey + guid);
michael@0 239 sha1.update(combined.get(), combined.Length());
michael@0 240 uint8_t digest[SHA1Sum::HashSize]; // SHA1 digests are 20 bytes long.
michael@0 241 sha1.finish(digest);
michael@0 242 nsCString newString(reinterpret_cast<char*>(digest), SHA1Sum::HashSize);
michael@0 243 Base64Encode(newString, res);
michael@0 244
michael@0 245 nsCString response("HTTP/1.1 101 Switching Protocols\r\n");
michael@0 246 response.Append("Upgrade: websocket\r\n");
michael@0 247 response.Append("Connection: Upgrade\r\n");
michael@0 248 response.Append(nsCString("Sec-WebSocket-Accept: ") + res + nsCString("\r\n"));
michael@0 249 response.Append("Sec-WebSocket-Protocol: binary\r\n\r\n");
michael@0 250 uint32_t written = 0;
michael@0 251 uint32_t size = response.Length();
michael@0 252 while (written < size) {
michael@0 253 uint32_t cnt;
michael@0 254 rv = mOutputStream->Write(const_cast<char*>(response.get()) + written,
michael@0 255 size - written, &cnt);
michael@0 256 if (NS_FAILED(rv))
michael@0 257 return false;
michael@0 258
michael@0 259 written += cnt;
michael@0 260 }
michael@0 261 mOutputStream->Flush();
michael@0 262
michael@0 263 return true;
michael@0 264 }
michael@0 265
michael@0 266 nsCOMPtr<nsIOutputStream> mOutputStream;
michael@0 267 nsCOMPtr<nsIAsyncInputStream> mInputStream;
michael@0 268 nsCOMPtr<nsISocketTransport> mTransport;
michael@0 269 SocketStateType mState;
michael@0 270 };
michael@0 271
michael@0 272 NS_IMPL_ISUPPORTS(LayerScopeWebSocketHandler, nsIInputStreamCallback);
michael@0 273
michael@0 274 class LayerScopeWebSocketManager {
michael@0 275 public:
michael@0 276 LayerScopeWebSocketManager();
michael@0 277 ~LayerScopeWebSocketManager();
michael@0 278
michael@0 279 void AddConnection(nsISocketTransport *aTransport)
michael@0 280 {
michael@0 281 MOZ_ASSERT(aTransport);
michael@0 282 nsRefPtr<LayerScopeWebSocketHandler> temp = new LayerScopeWebSocketHandler();
michael@0 283 temp->OpenStream(aTransport);
michael@0 284 mHandlers.AppendElement(temp.get());
michael@0 285 }
michael@0 286
michael@0 287 void RemoveConnection(uint32_t aIndex)
michael@0 288 {
michael@0 289 MOZ_ASSERT(aIndex < mHandlers.Length());
michael@0 290 mHandlers.RemoveElementAt(aIndex);
michael@0 291 }
michael@0 292
michael@0 293 void RemoveAllConnections()
michael@0 294 {
michael@0 295 mHandlers.Clear();
michael@0 296 }
michael@0 297
michael@0 298 bool WriteAll(void *ptr, uint32_t size)
michael@0 299 {
michael@0 300 for (int32_t i = mHandlers.Length() - 1; i >= 0; --i) {
michael@0 301 if (!mHandlers[i]->WriteToStream(ptr, size)) {
michael@0 302 // Send failed, remove this handler
michael@0 303 RemoveConnection(i);
michael@0 304 }
michael@0 305 }
michael@0 306
michael@0 307 return true;
michael@0 308 }
michael@0 309
michael@0 310 bool IsConnected()
michael@0 311 {
michael@0 312 return (mHandlers.Length() != 0) ? true : false;
michael@0 313 }
michael@0 314
michael@0 315 void AppendDebugData(DebugGLData *aDebugData);
michael@0 316 void DispatchDebugData();
michael@0 317 private:
michael@0 318 nsTArray<nsRefPtr<LayerScopeWebSocketHandler> > mHandlers;
michael@0 319 nsCOMPtr<nsIThread> mDebugSenderThread;
michael@0 320 nsRefPtr<DebugDataSender> mCurrentSender;
michael@0 321 nsCOMPtr<nsIServerSocket> mServerSocket;
michael@0 322 };
michael@0 323
michael@0 324 static StaticAutoPtr<LayerScopeWebSocketManager> gLayerScopeWebSocketManager;
michael@0 325
michael@0 326 class DebugGLData : public LinkedListElement<DebugGLData> {
michael@0 327 public:
michael@0 328 typedef enum {
michael@0 329 FrameStart,
michael@0 330 FrameEnd,
michael@0 331 TextureData,
michael@0 332 ColorData
michael@0 333 } DataType;
michael@0 334
michael@0 335 virtual ~DebugGLData() { }
michael@0 336
michael@0 337 DataType GetDataType() const { return mDataType; }
michael@0 338 intptr_t GetContextAddress() const { return mContextAddress; }
michael@0 339 int64_t GetValue() const { return mValue; }
michael@0 340
michael@0 341 DebugGLData(DataType dataType)
michael@0 342 : mDataType(dataType),
michael@0 343 mContextAddress(0),
michael@0 344 mValue(0)
michael@0 345 { }
michael@0 346
michael@0 347 DebugGLData(DataType dataType, GLContext* cx)
michael@0 348 : mDataType(dataType),
michael@0 349 mContextAddress(reinterpret_cast<intptr_t>(cx)),
michael@0 350 mValue(0)
michael@0 351 { }
michael@0 352
michael@0 353 DebugGLData(DataType dataType, GLContext* cx, int64_t value)
michael@0 354 : mDataType(dataType),
michael@0 355 mContextAddress(reinterpret_cast<intptr_t>(cx)),
michael@0 356 mValue(value)
michael@0 357 { }
michael@0 358
michael@0 359 virtual bool Write() {
michael@0 360 if (mDataType != FrameStart &&
michael@0 361 mDataType != FrameEnd)
michael@0 362 {
michael@0 363 NS_WARNING("Unimplemented data type!");
michael@0 364 return false;
michael@0 365 }
michael@0 366
michael@0 367 DebugGLData::BasicPacket packet;
michael@0 368
michael@0 369 packet.type = mDataType;
michael@0 370 packet.ptr = static_cast<uint64_t>(mContextAddress);
michael@0 371 packet.value = mValue;
michael@0 372
michael@0 373 return WriteToStream(&packet, sizeof(packet));
michael@0 374 }
michael@0 375
michael@0 376 static bool WriteToStream(void *ptr, uint32_t size) {
michael@0 377 if (!gLayerScopeWebSocketManager)
michael@0 378 return true;
michael@0 379 return gLayerScopeWebSocketManager->WriteAll(ptr, size);
michael@0 380 }
michael@0 381
michael@0 382 protected:
michael@0 383 DataType mDataType;
michael@0 384 intptr_t mContextAddress;
michael@0 385 int64_t mValue;
michael@0 386
michael@0 387 public:
michael@0 388 // the data packet formats; all packed
michael@0 389 #ifdef _MSC_VER
michael@0 390 #pragma pack(push, 1)
michael@0 391 #endif
michael@0 392 typedef struct {
michael@0 393 uint32_t type;
michael@0 394 uint64_t ptr;
michael@0 395 uint64_t value;
michael@0 396 } PACKED_STRUCT BasicPacket;
michael@0 397
michael@0 398 typedef struct {
michael@0 399 uint32_t type;
michael@0 400 uint64_t ptr;
michael@0 401 uint64_t layerref;
michael@0 402 uint32_t color;
michael@0 403 uint32_t width;
michael@0 404 uint32_t height;
michael@0 405 } PACKED_STRUCT ColorPacket;
michael@0 406
michael@0 407 typedef struct {
michael@0 408 uint32_t type;
michael@0 409 uint64_t ptr;
michael@0 410 uint64_t layerref;
michael@0 411 uint32_t name;
michael@0 412 uint32_t width;
michael@0 413 uint32_t height;
michael@0 414 uint32_t stride;
michael@0 415 uint32_t format;
michael@0 416 uint32_t target;
michael@0 417 uint32_t dataFormat;
michael@0 418 uint32_t dataSize;
michael@0 419 } PACKED_STRUCT TexturePacket;
michael@0 420 #ifdef _MSC_VER
michael@0 421 #pragma pack(pop)
michael@0 422 #endif
michael@0 423 };
michael@0 424
michael@0 425 class DebugGLTextureData : public DebugGLData {
michael@0 426 public:
michael@0 427 DebugGLTextureData(GLContext* cx, void* layerRef, GLuint target, GLenum name, DataSourceSurface* img)
michael@0 428 : DebugGLData(DebugGLData::TextureData, cx),
michael@0 429 mLayerRef(layerRef),
michael@0 430 mTarget(target),
michael@0 431 mName(name),
michael@0 432 mImage(img)
michael@0 433 { }
michael@0 434
michael@0 435 void *GetLayerRef() const { return mLayerRef; }
michael@0 436 GLuint GetName() const { return mName; }
michael@0 437 DataSourceSurface* GetImage() const { return mImage; }
michael@0 438 GLenum GetTextureTarget() const { return mTarget; }
michael@0 439
michael@0 440 virtual bool Write() {
michael@0 441 DebugGLData::TexturePacket packet;
michael@0 442 char* dataptr = nullptr;
michael@0 443 uint32_t datasize = 0;
michael@0 444 std::auto_ptr<char> compresseddata;
michael@0 445
michael@0 446 packet.type = mDataType;
michael@0 447 packet.ptr = static_cast<uint64_t>(mContextAddress);
michael@0 448 packet.layerref = reinterpret_cast<uint64_t>(mLayerRef);
michael@0 449 packet.name = mName;
michael@0 450 packet.format = 0;
michael@0 451 packet.target = mTarget;
michael@0 452 packet.dataFormat = LOCAL_GL_RGBA;
michael@0 453
michael@0 454 if (mImage) {
michael@0 455 packet.width = mImage->GetSize().width;
michael@0 456 packet.height = mImage->GetSize().height;
michael@0 457 packet.stride = mImage->Stride();
michael@0 458 packet.dataSize = mImage->GetSize().height * mImage->Stride();
michael@0 459
michael@0 460 dataptr = (char*) mImage->GetData();
michael@0 461 datasize = packet.dataSize;
michael@0 462
michael@0 463 compresseddata = std::auto_ptr<char>((char*) moz_malloc(LZ4::maxCompressedSize(datasize)));
michael@0 464 if (compresseddata.get()) {
michael@0 465 int ndatasize = LZ4::compress(dataptr, datasize, compresseddata.get());
michael@0 466 if (ndatasize > 0) {
michael@0 467 datasize = ndatasize;
michael@0 468 dataptr = compresseddata.get();
michael@0 469
michael@0 470 packet.dataFormat = (1 << 16) | packet.dataFormat;
michael@0 471 packet.dataSize = datasize;
michael@0 472 }
michael@0 473 }
michael@0 474 } else {
michael@0 475 packet.width = 0;
michael@0 476 packet.height = 0;
michael@0 477 packet.stride = 0;
michael@0 478 packet.dataSize = 0;
michael@0 479 }
michael@0 480
michael@0 481 // write the packet header data
michael@0 482 if (!WriteToStream(&packet, sizeof(packet)))
michael@0 483 return false;
michael@0 484
michael@0 485 // then the image data
michael@0 486 if (!WriteToStream(dataptr, datasize))
michael@0 487 return false;
michael@0 488
michael@0 489 // then pad out to 4 bytes
michael@0 490 if (datasize % 4 != 0) {
michael@0 491 static char buf[] = { 0, 0, 0, 0 };
michael@0 492 if (!WriteToStream(buf, 4 - (datasize % 4)))
michael@0 493 return false;
michael@0 494 }
michael@0 495
michael@0 496 return true;
michael@0 497 }
michael@0 498
michael@0 499 protected:
michael@0 500 void* mLayerRef;
michael@0 501 GLenum mTarget;
michael@0 502 GLuint mName;
michael@0 503 RefPtr<DataSourceSurface> mImage;
michael@0 504 };
michael@0 505
michael@0 506 class DebugGLColorData : public DebugGLData {
michael@0 507 public:
michael@0 508 DebugGLColorData(void* layerRef, const gfxRGBA& color, int width, int height)
michael@0 509 : DebugGLData(DebugGLData::ColorData),
michael@0 510 mColor(color.Packed()),
michael@0 511 mSize(width, height)
michael@0 512 { }
michael@0 513
michael@0 514 void *GetLayerRef() const { return mLayerRef; }
michael@0 515 uint32_t GetColor() const { return mColor; }
michael@0 516 const nsIntSize& GetSize() const { return mSize; }
michael@0 517
michael@0 518 virtual bool Write() {
michael@0 519 DebugGLData::ColorPacket packet;
michael@0 520
michael@0 521 packet.type = mDataType;
michael@0 522 packet.ptr = static_cast<uint64_t>(mContextAddress);
michael@0 523 packet.layerref = reinterpret_cast<uintptr_t>(mLayerRef);
michael@0 524 packet.color = mColor;
michael@0 525 packet.width = mSize.width;
michael@0 526 packet.height = mSize.height;
michael@0 527
michael@0 528 return WriteToStream(&packet, sizeof(packet));
michael@0 529 }
michael@0 530
michael@0 531 protected:
michael@0 532 void *mLayerRef;
michael@0 533 uint32_t mColor;
michael@0 534 nsIntSize mSize;
michael@0 535 };
michael@0 536
michael@0 537 static bool
michael@0 538 CheckSender()
michael@0 539 {
michael@0 540 if (!gLayerScopeWebSocketManager)
michael@0 541 return false;
michael@0 542
michael@0 543 if (!gLayerScopeWebSocketManager->IsConnected())
michael@0 544 return false;
michael@0 545
michael@0 546 return true;
michael@0 547 }
michael@0 548
michael@0 549 class DebugListener : public nsIServerSocketListener
michael@0 550 {
michael@0 551 public:
michael@0 552
michael@0 553 NS_DECL_THREADSAFE_ISUPPORTS
michael@0 554
michael@0 555 DebugListener() { }
michael@0 556 virtual ~DebugListener() { }
michael@0 557
michael@0 558 /* nsIServerSocketListener */
michael@0 559
michael@0 560 NS_IMETHODIMP OnSocketAccepted(nsIServerSocket *aServ,
michael@0 561 nsISocketTransport *aTransport)
michael@0 562 {
michael@0 563 if (!gLayerScopeWebSocketManager)
michael@0 564 return NS_OK;
michael@0 565
michael@0 566 printf_stderr("*** LayerScope: Accepted connection\n");
michael@0 567 gLayerScopeWebSocketManager->AddConnection(aTransport);
michael@0 568 return NS_OK;
michael@0 569 }
michael@0 570
michael@0 571 NS_IMETHODIMP OnStopListening(nsIServerSocket *aServ,
michael@0 572 nsresult aStatus)
michael@0 573 {
michael@0 574 return NS_OK;
michael@0 575 }
michael@0 576 };
michael@0 577
michael@0 578 NS_IMPL_ISUPPORTS(DebugListener, nsIServerSocketListener);
michael@0 579
michael@0 580
michael@0 581 class DebugDataSender : public nsIRunnable
michael@0 582 {
michael@0 583 public:
michael@0 584
michael@0 585 NS_DECL_THREADSAFE_ISUPPORTS
michael@0 586
michael@0 587 DebugDataSender() {
michael@0 588 mList = new LinkedList<DebugGLData>();
michael@0 589 }
michael@0 590
michael@0 591 virtual ~DebugDataSender() {
michael@0 592 Cleanup();
michael@0 593 }
michael@0 594
michael@0 595 void Append(DebugGLData *d) {
michael@0 596 mList->insertBack(d);
michael@0 597 }
michael@0 598
michael@0 599 void Cleanup() {
michael@0 600 if (!mList)
michael@0 601 return;
michael@0 602
michael@0 603 DebugGLData *d;
michael@0 604 while ((d = mList->popFirst()) != nullptr)
michael@0 605 delete d;
michael@0 606 delete mList;
michael@0 607
michael@0 608 mList = nullptr;
michael@0 609 }
michael@0 610
michael@0 611 /* nsIRunnable impl; send the data */
michael@0 612
michael@0 613 NS_IMETHODIMP Run() {
michael@0 614 DebugGLData *d;
michael@0 615 nsresult rv = NS_OK;
michael@0 616
michael@0 617 while ((d = mList->popFirst()) != nullptr) {
michael@0 618 std::auto_ptr<DebugGLData> cleaner(d);
michael@0 619 if (!d->Write()) {
michael@0 620 rv = NS_ERROR_FAILURE;
michael@0 621 break;
michael@0 622 }
michael@0 623 }
michael@0 624
michael@0 625 Cleanup();
michael@0 626
michael@0 627 if (NS_FAILED(rv)) {
michael@0 628 LayerScope::DestroyServerSocket();
michael@0 629 }
michael@0 630
michael@0 631 return NS_OK;
michael@0 632 }
michael@0 633
michael@0 634 protected:
michael@0 635 LinkedList<DebugGLData> *mList;
michael@0 636 };
michael@0 637
michael@0 638 NS_IMPL_ISUPPORTS(DebugDataSender, nsIRunnable);
michael@0 639
michael@0 640 void
michael@0 641 LayerScope::CreateServerSocket()
michael@0 642 {
michael@0 643 if (!gfxPrefs::LayerScopeEnabled()) {
michael@0 644 return;
michael@0 645 }
michael@0 646
michael@0 647 if (!gLayerScopeWebSocketManager) {
michael@0 648 gLayerScopeWebSocketManager = new LayerScopeWebSocketManager();
michael@0 649 }
michael@0 650 }
michael@0 651
michael@0 652 void
michael@0 653 LayerScope::DestroyServerSocket()
michael@0 654 {
michael@0 655 if (gLayerScopeWebSocketManager) {
michael@0 656 gLayerScopeWebSocketManager->RemoveAllConnections();
michael@0 657 }
michael@0 658 }
michael@0 659
michael@0 660 void
michael@0 661 LayerScope::BeginFrame(GLContext* aGLContext, int64_t aFrameStamp)
michael@0 662 {
michael@0 663 if (!gLayerScopeWebSocketManager)
michael@0 664 return;
michael@0 665
michael@0 666 if (!gLayerScopeWebSocketManager->IsConnected())
michael@0 667 return;
michael@0 668
michael@0 669 #if 0
michael@0 670 // if we're sending data in between frames, flush the list down the socket,
michael@0 671 // and start a new one
michael@0 672 if (gCurrentSender) {
michael@0 673 gDebugSenderThread->Dispatch(gCurrentSender, NS_DISPATCH_NORMAL);
michael@0 674 }
michael@0 675 #endif
michael@0 676
michael@0 677 gLayerScopeWebSocketManager->AppendDebugData(new DebugGLData(DebugGLData::FrameStart, aGLContext, aFrameStamp));
michael@0 678 }
michael@0 679
michael@0 680 void
michael@0 681 LayerScope::EndFrame(GLContext* aGLContext)
michael@0 682 {
michael@0 683 if (!CheckSender())
michael@0 684 return;
michael@0 685
michael@0 686 gLayerScopeWebSocketManager->AppendDebugData(new DebugGLData(DebugGLData::FrameEnd, aGLContext));
michael@0 687 gLayerScopeWebSocketManager->DispatchDebugData();
michael@0 688 }
michael@0 689
michael@0 690 static void
michael@0 691 SendColor(void* aLayerRef, const gfxRGBA& aColor, int aWidth, int aHeight)
michael@0 692 {
michael@0 693 if (!CheckSender())
michael@0 694 return;
michael@0 695
michael@0 696 gLayerScopeWebSocketManager->AppendDebugData(
michael@0 697 new DebugGLColorData(aLayerRef, aColor, aWidth, aHeight));
michael@0 698 }
michael@0 699
michael@0 700 static void
michael@0 701 SendTextureSource(GLContext* aGLContext,
michael@0 702 void* aLayerRef,
michael@0 703 TextureSourceOGL* aSource,
michael@0 704 bool aFlipY)
michael@0 705 {
michael@0 706 GLenum textureTarget = aSource->GetTextureTarget();
michael@0 707 ShaderConfigOGL config = ShaderConfigFromTargetAndFormat(textureTarget,
michael@0 708 aSource->GetFormat());
michael@0 709 int shaderConfig = config.mFeatures;
michael@0 710
michael@0 711 aSource->BindTexture(LOCAL_GL_TEXTURE0, gfx::Filter::LINEAR);
michael@0 712
michael@0 713 GLuint textureId = 0;
michael@0 714 // This is horrid hack. It assumes that aGLContext matches the context
michael@0 715 // aSource has bound to.
michael@0 716 if (textureTarget == LOCAL_GL_TEXTURE_2D) {
michael@0 717 aGLContext->GetUIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, &textureId);
michael@0 718 } else if (textureTarget == LOCAL_GL_TEXTURE_EXTERNAL) {
michael@0 719 aGLContext->GetUIntegerv(LOCAL_GL_TEXTURE_BINDING_EXTERNAL, &textureId);
michael@0 720 } else if (textureTarget == LOCAL_GL_TEXTURE_RECTANGLE) {
michael@0 721 aGLContext->GetUIntegerv(LOCAL_GL_TEXTURE_BINDING_RECTANGLE, &textureId);
michael@0 722 }
michael@0 723
michael@0 724 gfx::IntSize size = aSource->GetSize();
michael@0 725
michael@0 726 // By sending 0 to ReadTextureImage rely upon aSource->BindTexture binding
michael@0 727 // texture correctly. textureId is used for tracking in DebugGLTextureData.
michael@0 728 RefPtr<DataSourceSurface> img =
michael@0 729 aGLContext->ReadTexImageHelper()->ReadTexImage(0, textureTarget,
michael@0 730 size,
michael@0 731 shaderConfig, aFlipY);
michael@0 732
michael@0 733 gLayerScopeWebSocketManager->AppendDebugData(
michael@0 734 new DebugGLTextureData(aGLContext, aLayerRef, textureTarget,
michael@0 735 textureId, img));
michael@0 736 }
michael@0 737
michael@0 738 static void
michael@0 739 SendTexturedEffect(GLContext* aGLContext,
michael@0 740 void* aLayerRef,
michael@0 741 const TexturedEffect* aEffect)
michael@0 742 {
michael@0 743 TextureSourceOGL* source = aEffect->mTexture->AsSourceOGL();
michael@0 744 if (!source)
michael@0 745 return;
michael@0 746
michael@0 747 bool flipY = false;
michael@0 748 SendTextureSource(aGLContext, aLayerRef, source, flipY);
michael@0 749 }
michael@0 750
michael@0 751 static void
michael@0 752 SendYCbCrEffect(GLContext* aGLContext,
michael@0 753 void* aLayerRef,
michael@0 754 const EffectYCbCr* aEffect)
michael@0 755 {
michael@0 756 TextureSource* sourceYCbCr = aEffect->mTexture;
michael@0 757 if (!sourceYCbCr)
michael@0 758 return;
michael@0 759
michael@0 760 const int Y = 0, Cb = 1, Cr = 2;
michael@0 761 TextureSourceOGL* sourceY = sourceYCbCr->GetSubSource(Y)->AsSourceOGL();
michael@0 762 TextureSourceOGL* sourceCb = sourceYCbCr->GetSubSource(Cb)->AsSourceOGL();
michael@0 763 TextureSourceOGL* sourceCr = sourceYCbCr->GetSubSource(Cr)->AsSourceOGL();
michael@0 764
michael@0 765 bool flipY = false;
michael@0 766 SendTextureSource(aGLContext, aLayerRef, sourceY, flipY);
michael@0 767 SendTextureSource(aGLContext, aLayerRef, sourceCb, flipY);
michael@0 768 SendTextureSource(aGLContext, aLayerRef, sourceCr, flipY);
michael@0 769 }
michael@0 770
michael@0 771 void
michael@0 772 LayerScope::SendEffectChain(GLContext* aGLContext,
michael@0 773 const EffectChain& aEffectChain,
michael@0 774 int aWidth, int aHeight)
michael@0 775 {
michael@0 776 if (!CheckSender())
michael@0 777 return;
michael@0 778
michael@0 779 const Effect* primaryEffect = aEffectChain.mPrimaryEffect;
michael@0 780 switch (primaryEffect->mType) {
michael@0 781 case EFFECT_RGB:
michael@0 782 {
michael@0 783 const TexturedEffect* texturedEffect =
michael@0 784 static_cast<const TexturedEffect*>(primaryEffect);
michael@0 785 SendTexturedEffect(aGLContext, aEffectChain.mLayerRef, texturedEffect);
michael@0 786 }
michael@0 787 break;
michael@0 788 case EFFECT_YCBCR:
michael@0 789 {
michael@0 790 const EffectYCbCr* yCbCrEffect =
michael@0 791 static_cast<const EffectYCbCr*>(primaryEffect);
michael@0 792 SendYCbCrEffect(aGLContext, aEffectChain.mLayerRef, yCbCrEffect);
michael@0 793 }
michael@0 794 case EFFECT_SOLID_COLOR:
michael@0 795 {
michael@0 796 const EffectSolidColor* solidColorEffect =
michael@0 797 static_cast<const EffectSolidColor*>(primaryEffect);
michael@0 798 gfxRGBA color(solidColorEffect->mColor.r,
michael@0 799 solidColorEffect->mColor.g,
michael@0 800 solidColorEffect->mColor.b,
michael@0 801 solidColorEffect->mColor.a);
michael@0 802 SendColor(aEffectChain.mLayerRef, color, aWidth, aHeight);
michael@0 803 }
michael@0 804 break;
michael@0 805 case EFFECT_COMPONENT_ALPHA:
michael@0 806 case EFFECT_RENDER_TARGET:
michael@0 807 default:
michael@0 808 break;
michael@0 809 }
michael@0 810
michael@0 811 //const Effect* secondaryEffect = aEffectChain.mSecondaryEffects[EFFECT_MASK];
michael@0 812 // TODO:
michael@0 813 }
michael@0 814
michael@0 815 LayerScopeWebSocketManager::LayerScopeWebSocketManager()
michael@0 816 {
michael@0 817 NS_NewThread(getter_AddRefs(mDebugSenderThread));
michael@0 818
michael@0 819 mServerSocket = do_CreateInstance(NS_SERVERSOCKET_CONTRACTID);
michael@0 820 int port = gfxPrefs::LayerScopePort();
michael@0 821 mServerSocket->Init(port, false, -1);
michael@0 822 mServerSocket->AsyncListen(new DebugListener);
michael@0 823 }
michael@0 824
michael@0 825 LayerScopeWebSocketManager::~LayerScopeWebSocketManager()
michael@0 826 {
michael@0 827 }
michael@0 828
michael@0 829 void LayerScopeWebSocketManager::AppendDebugData(DebugGLData *aDebugData)
michael@0 830 {
michael@0 831 if (!mCurrentSender) {
michael@0 832 mCurrentSender = new DebugDataSender();
michael@0 833 }
michael@0 834
michael@0 835 mCurrentSender->Append(aDebugData);
michael@0 836 }
michael@0 837
michael@0 838 void LayerScopeWebSocketManager::DispatchDebugData()
michael@0 839 {
michael@0 840 mDebugSenderThread->Dispatch(mCurrentSender, NS_DISPATCH_NORMAL);
michael@0 841 mCurrentSender = nullptr;
michael@0 842 }
michael@0 843
michael@0 844 } /* layers */
michael@0 845 } /* mozilla */

mercurial