1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/layers/LayerScope.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,845 @@ 1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/* This must occur *after* layers/PLayers.h to avoid typedefs conflicts. */ 1.10 +#include "LayerScope.h" 1.11 + 1.12 +#include "Composer2D.h" 1.13 +#include "Effects.h" 1.14 +#include "mozilla/TimeStamp.h" 1.15 +#include "mozilla/Preferences.h" 1.16 +#include "mozilla/Endian.h" 1.17 +#include "TexturePoolOGL.h" 1.18 +#include "mozilla/layers/TextureHostOGL.h" 1.19 + 1.20 +#include "gfxColor.h" 1.21 +#include "gfxContext.h" 1.22 +#include "gfxUtils.h" 1.23 +#include "gfxPrefs.h" 1.24 +#include "nsIWidget.h" 1.25 + 1.26 +#include "GLContext.h" 1.27 +#include "GLContextProvider.h" 1.28 +#include "GLReadTexImageHelper.h" 1.29 + 1.30 +#include "nsIServiceManager.h" 1.31 +#include "nsIConsoleService.h" 1.32 + 1.33 +#include <memory> 1.34 +#include "mozilla/LinkedList.h" 1.35 +#include "mozilla/Base64.h" 1.36 +#include "mozilla/SHA1.h" 1.37 +#include "mozilla/StaticPtr.h" 1.38 +#include "nsThreadUtils.h" 1.39 +#include "nsISocketTransport.h" 1.40 +#include "nsIServerSocket.h" 1.41 +#include "nsReadLine.h" 1.42 +#include "nsNetCID.h" 1.43 +#include "nsIOutputStream.h" 1.44 +#include "nsIAsyncInputStream.h" 1.45 +#include "nsIEventTarget.h" 1.46 +#include "nsProxyRelease.h" 1.47 + 1.48 +// Undo the damage done by mozzconf.h 1.49 +#undef compress 1.50 +#include "mozilla/Compression.h" 1.51 + 1.52 +#ifdef __GNUC__ 1.53 +#define PACKED_STRUCT __attribute__((packed)) 1.54 +#else 1.55 +#define PACKED_STRUCT 1.56 +#endif 1.57 + 1.58 +namespace mozilla { 1.59 +namespace layers { 1.60 + 1.61 +using namespace mozilla::Compression; 1.62 +using namespace mozilla::gfx; 1.63 +using namespace mozilla::gl; 1.64 +using namespace mozilla; 1.65 + 1.66 +class DebugDataSender; 1.67 +class DebugGLData; 1.68 + 1.69 +/* This class handle websocket protocol which included 1.70 + * handshake and data frame's header 1.71 + */ 1.72 +class LayerScopeWebSocketHandler : public nsIInputStreamCallback { 1.73 +public: 1.74 + NS_DECL_THREADSAFE_ISUPPORTS 1.75 + 1.76 + enum SocketStateType { 1.77 + NoHandshake, 1.78 + HandshakeSuccess, 1.79 + HandshakeFailed 1.80 + }; 1.81 + 1.82 + LayerScopeWebSocketHandler() 1.83 + : mState(NoHandshake) 1.84 + { } 1.85 + 1.86 + virtual ~LayerScopeWebSocketHandler() 1.87 + { 1.88 + if (mTransport) { 1.89 + mTransport->Close(NS_OK); 1.90 + } 1.91 + } 1.92 + 1.93 + void OpenStream(nsISocketTransport* aTransport) { 1.94 + MOZ_ASSERT(aTransport); 1.95 + 1.96 + mTransport = aTransport; 1.97 + mTransport->OpenOutputStream(nsITransport::OPEN_BLOCKING, 1.98 + 0, 1.99 + 0, 1.100 + getter_AddRefs(mOutputStream)); 1.101 + 1.102 + nsCOMPtr<nsIInputStream> debugInputStream; 1.103 + mTransport->OpenInputStream(0, 1.104 + 0, 1.105 + 0, 1.106 + getter_AddRefs(debugInputStream)); 1.107 + mInputStream = do_QueryInterface(debugInputStream); 1.108 + mInputStream->AsyncWait(this, 0, 0, NS_GetCurrentThread()); 1.109 + } 1.110 + 1.111 + bool WriteToStream(void *ptr, uint32_t size) { 1.112 + if (mState == NoHandshake) { 1.113 + // Not yet handshake, just return true in case of 1.114 + // LayerScope remove this handle 1.115 + return true; 1.116 + } else if (mState == HandshakeFailed) { 1.117 + return false; 1.118 + } 1.119 + 1.120 + // Generate WebSocket header 1.121 + uint8_t wsHeader[10]; 1.122 + int wsHeaderSize = 0; 1.123 + const uint8_t opcode = 0x2; 1.124 + wsHeader[0] = 0x80 | (opcode & 0x0f); // FIN + opcode; 1.125 + if (size <= 125) { 1.126 + wsHeaderSize = 2; 1.127 + wsHeader[1] = size; 1.128 + } else if (size < 65536) { 1.129 + wsHeaderSize = 4; 1.130 + wsHeader[1] = 0x7E; 1.131 + NetworkEndian::writeUint16(wsHeader + 2, size); 1.132 + } else { 1.133 + wsHeaderSize = 10; 1.134 + wsHeader[1] = 0x7F; 1.135 + NetworkEndian::writeUint64(wsHeader + 2, size); 1.136 + } 1.137 + 1.138 + // Send WebSocket header 1.139 + nsresult rv; 1.140 + uint32_t cnt; 1.141 + rv = mOutputStream->Write(reinterpret_cast<char*>(wsHeader), 1.142 + wsHeaderSize, &cnt); 1.143 + if (NS_FAILED(rv)) 1.144 + return false; 1.145 + 1.146 + uint32_t written = 0; 1.147 + while (written < size) { 1.148 + uint32_t cnt; 1.149 + rv = mOutputStream->Write(reinterpret_cast<char*>(ptr) + written, 1.150 + size - written, &cnt); 1.151 + if (NS_FAILED(rv)) 1.152 + return false; 1.153 + 1.154 + written += cnt; 1.155 + } 1.156 + 1.157 + return true; 1.158 + } 1.159 + 1.160 + // nsIInputStreamCallback 1.161 + NS_IMETHODIMP OnInputStreamReady(nsIAsyncInputStream *stream) MOZ_OVERRIDE 1.162 + { 1.163 + nsTArray<nsCString> protocolString; 1.164 + ReadInputStreamData(protocolString); 1.165 + 1.166 + if (WebSocketHandshake(protocolString)) { 1.167 + mState = HandshakeSuccess; 1.168 + } else { 1.169 + mState = HandshakeFailed; 1.170 + } 1.171 + return NS_OK; 1.172 + } 1.173 +private: 1.174 + void ReadInputStreamData(nsTArray<nsCString>& aProtocolString) 1.175 + { 1.176 + nsLineBuffer<char> lineBuffer; 1.177 + nsCString line; 1.178 + bool more = true; 1.179 + do { 1.180 + NS_ReadLine(mInputStream.get(), &lineBuffer, line, &more); 1.181 + 1.182 + if (line.Length() > 0) { 1.183 + aProtocolString.AppendElement(line); 1.184 + } 1.185 + } while (more && line.Length() > 0); 1.186 + } 1.187 + 1.188 + bool WebSocketHandshake(nsTArray<nsCString>& aProtocolString) 1.189 + { 1.190 + nsresult rv; 1.191 + bool isWebSocket = false; 1.192 + nsCString version; 1.193 + nsCString wsKey; 1.194 + nsCString protocol; 1.195 + 1.196 + // Validate WebSocket client request. 1.197 + if (aProtocolString.Length() == 0) 1.198 + return false; 1.199 + 1.200 + // Check that the HTTP method is GET 1.201 + const char* HTTP_METHOD = "GET "; 1.202 + if (strncmp(aProtocolString[0].get(), HTTP_METHOD, strlen(HTTP_METHOD)) != 0) { 1.203 + return false; 1.204 + } 1.205 + 1.206 + for (uint32_t i = 1; i < aProtocolString.Length(); ++i) { 1.207 + const char* line = aProtocolString[i].get(); 1.208 + const char* prop_pos = strchr(line, ':'); 1.209 + if (prop_pos != nullptr) { 1.210 + nsCString key(line, prop_pos - line); 1.211 + nsCString value(prop_pos + 2); 1.212 + if (key.EqualsIgnoreCase("upgrade") && 1.213 + value.EqualsIgnoreCase("websocket")) { 1.214 + isWebSocket = true; 1.215 + } else if (key.EqualsIgnoreCase("sec-websocket-version")) { 1.216 + version = value; 1.217 + } else if (key.EqualsIgnoreCase("sec-websocket-key")) { 1.218 + wsKey = value; 1.219 + } else if (key.EqualsIgnoreCase("sec-websocket-protocol")) { 1.220 + protocol = value; 1.221 + } 1.222 + } 1.223 + } 1.224 + 1.225 + if (!isWebSocket) { 1.226 + return false; 1.227 + } 1.228 + 1.229 + if (!(version.Equals("7") || version.Equals("8") || version.Equals("13"))) { 1.230 + return false; 1.231 + } 1.232 + 1.233 + if (!(protocol.EqualsIgnoreCase("binary"))) { 1.234 + return false; 1.235 + } 1.236 + 1.237 + // Client request is valid. Start to generate and send server response. 1.238 + nsAutoCString guid("258EAFA5-E914-47DA-95CA-C5AB0DC85B11"); 1.239 + nsAutoCString res; 1.240 + SHA1Sum sha1; 1.241 + nsCString combined(wsKey + guid); 1.242 + sha1.update(combined.get(), combined.Length()); 1.243 + uint8_t digest[SHA1Sum::HashSize]; // SHA1 digests are 20 bytes long. 1.244 + sha1.finish(digest); 1.245 + nsCString newString(reinterpret_cast<char*>(digest), SHA1Sum::HashSize); 1.246 + Base64Encode(newString, res); 1.247 + 1.248 + nsCString response("HTTP/1.1 101 Switching Protocols\r\n"); 1.249 + response.Append("Upgrade: websocket\r\n"); 1.250 + response.Append("Connection: Upgrade\r\n"); 1.251 + response.Append(nsCString("Sec-WebSocket-Accept: ") + res + nsCString("\r\n")); 1.252 + response.Append("Sec-WebSocket-Protocol: binary\r\n\r\n"); 1.253 + uint32_t written = 0; 1.254 + uint32_t size = response.Length(); 1.255 + while (written < size) { 1.256 + uint32_t cnt; 1.257 + rv = mOutputStream->Write(const_cast<char*>(response.get()) + written, 1.258 + size - written, &cnt); 1.259 + if (NS_FAILED(rv)) 1.260 + return false; 1.261 + 1.262 + written += cnt; 1.263 + } 1.264 + mOutputStream->Flush(); 1.265 + 1.266 + return true; 1.267 + } 1.268 + 1.269 + nsCOMPtr<nsIOutputStream> mOutputStream; 1.270 + nsCOMPtr<nsIAsyncInputStream> mInputStream; 1.271 + nsCOMPtr<nsISocketTransport> mTransport; 1.272 + SocketStateType mState; 1.273 +}; 1.274 + 1.275 +NS_IMPL_ISUPPORTS(LayerScopeWebSocketHandler, nsIInputStreamCallback); 1.276 + 1.277 +class LayerScopeWebSocketManager { 1.278 +public: 1.279 + LayerScopeWebSocketManager(); 1.280 + ~LayerScopeWebSocketManager(); 1.281 + 1.282 + void AddConnection(nsISocketTransport *aTransport) 1.283 + { 1.284 + MOZ_ASSERT(aTransport); 1.285 + nsRefPtr<LayerScopeWebSocketHandler> temp = new LayerScopeWebSocketHandler(); 1.286 + temp->OpenStream(aTransport); 1.287 + mHandlers.AppendElement(temp.get()); 1.288 + } 1.289 + 1.290 + void RemoveConnection(uint32_t aIndex) 1.291 + { 1.292 + MOZ_ASSERT(aIndex < mHandlers.Length()); 1.293 + mHandlers.RemoveElementAt(aIndex); 1.294 + } 1.295 + 1.296 + void RemoveAllConnections() 1.297 + { 1.298 + mHandlers.Clear(); 1.299 + } 1.300 + 1.301 + bool WriteAll(void *ptr, uint32_t size) 1.302 + { 1.303 + for (int32_t i = mHandlers.Length() - 1; i >= 0; --i) { 1.304 + if (!mHandlers[i]->WriteToStream(ptr, size)) { 1.305 + // Send failed, remove this handler 1.306 + RemoveConnection(i); 1.307 + } 1.308 + } 1.309 + 1.310 + return true; 1.311 + } 1.312 + 1.313 + bool IsConnected() 1.314 + { 1.315 + return (mHandlers.Length() != 0) ? true : false; 1.316 + } 1.317 + 1.318 + void AppendDebugData(DebugGLData *aDebugData); 1.319 + void DispatchDebugData(); 1.320 +private: 1.321 + nsTArray<nsRefPtr<LayerScopeWebSocketHandler> > mHandlers; 1.322 + nsCOMPtr<nsIThread> mDebugSenderThread; 1.323 + nsRefPtr<DebugDataSender> mCurrentSender; 1.324 + nsCOMPtr<nsIServerSocket> mServerSocket; 1.325 +}; 1.326 + 1.327 +static StaticAutoPtr<LayerScopeWebSocketManager> gLayerScopeWebSocketManager; 1.328 + 1.329 +class DebugGLData : public LinkedListElement<DebugGLData> { 1.330 +public: 1.331 + typedef enum { 1.332 + FrameStart, 1.333 + FrameEnd, 1.334 + TextureData, 1.335 + ColorData 1.336 + } DataType; 1.337 + 1.338 + virtual ~DebugGLData() { } 1.339 + 1.340 + DataType GetDataType() const { return mDataType; } 1.341 + intptr_t GetContextAddress() const { return mContextAddress; } 1.342 + int64_t GetValue() const { return mValue; } 1.343 + 1.344 + DebugGLData(DataType dataType) 1.345 + : mDataType(dataType), 1.346 + mContextAddress(0), 1.347 + mValue(0) 1.348 + { } 1.349 + 1.350 + DebugGLData(DataType dataType, GLContext* cx) 1.351 + : mDataType(dataType), 1.352 + mContextAddress(reinterpret_cast<intptr_t>(cx)), 1.353 + mValue(0) 1.354 + { } 1.355 + 1.356 + DebugGLData(DataType dataType, GLContext* cx, int64_t value) 1.357 + : mDataType(dataType), 1.358 + mContextAddress(reinterpret_cast<intptr_t>(cx)), 1.359 + mValue(value) 1.360 + { } 1.361 + 1.362 + virtual bool Write() { 1.363 + if (mDataType != FrameStart && 1.364 + mDataType != FrameEnd) 1.365 + { 1.366 + NS_WARNING("Unimplemented data type!"); 1.367 + return false; 1.368 + } 1.369 + 1.370 + DebugGLData::BasicPacket packet; 1.371 + 1.372 + packet.type = mDataType; 1.373 + packet.ptr = static_cast<uint64_t>(mContextAddress); 1.374 + packet.value = mValue; 1.375 + 1.376 + return WriteToStream(&packet, sizeof(packet)); 1.377 + } 1.378 + 1.379 + static bool WriteToStream(void *ptr, uint32_t size) { 1.380 + if (!gLayerScopeWebSocketManager) 1.381 + return true; 1.382 + return gLayerScopeWebSocketManager->WriteAll(ptr, size); 1.383 + } 1.384 + 1.385 +protected: 1.386 + DataType mDataType; 1.387 + intptr_t mContextAddress; 1.388 + int64_t mValue; 1.389 + 1.390 +public: 1.391 + // the data packet formats; all packed 1.392 +#ifdef _MSC_VER 1.393 +#pragma pack(push, 1) 1.394 +#endif 1.395 + typedef struct { 1.396 + uint32_t type; 1.397 + uint64_t ptr; 1.398 + uint64_t value; 1.399 + } PACKED_STRUCT BasicPacket; 1.400 + 1.401 + typedef struct { 1.402 + uint32_t type; 1.403 + uint64_t ptr; 1.404 + uint64_t layerref; 1.405 + uint32_t color; 1.406 + uint32_t width; 1.407 + uint32_t height; 1.408 + } PACKED_STRUCT ColorPacket; 1.409 + 1.410 + typedef struct { 1.411 + uint32_t type; 1.412 + uint64_t ptr; 1.413 + uint64_t layerref; 1.414 + uint32_t name; 1.415 + uint32_t width; 1.416 + uint32_t height; 1.417 + uint32_t stride; 1.418 + uint32_t format; 1.419 + uint32_t target; 1.420 + uint32_t dataFormat; 1.421 + uint32_t dataSize; 1.422 + } PACKED_STRUCT TexturePacket; 1.423 +#ifdef _MSC_VER 1.424 +#pragma pack(pop) 1.425 +#endif 1.426 +}; 1.427 + 1.428 +class DebugGLTextureData : public DebugGLData { 1.429 +public: 1.430 + DebugGLTextureData(GLContext* cx, void* layerRef, GLuint target, GLenum name, DataSourceSurface* img) 1.431 + : DebugGLData(DebugGLData::TextureData, cx), 1.432 + mLayerRef(layerRef), 1.433 + mTarget(target), 1.434 + mName(name), 1.435 + mImage(img) 1.436 + { } 1.437 + 1.438 + void *GetLayerRef() const { return mLayerRef; } 1.439 + GLuint GetName() const { return mName; } 1.440 + DataSourceSurface* GetImage() const { return mImage; } 1.441 + GLenum GetTextureTarget() const { return mTarget; } 1.442 + 1.443 + virtual bool Write() { 1.444 + DebugGLData::TexturePacket packet; 1.445 + char* dataptr = nullptr; 1.446 + uint32_t datasize = 0; 1.447 + std::auto_ptr<char> compresseddata; 1.448 + 1.449 + packet.type = mDataType; 1.450 + packet.ptr = static_cast<uint64_t>(mContextAddress); 1.451 + packet.layerref = reinterpret_cast<uint64_t>(mLayerRef); 1.452 + packet.name = mName; 1.453 + packet.format = 0; 1.454 + packet.target = mTarget; 1.455 + packet.dataFormat = LOCAL_GL_RGBA; 1.456 + 1.457 + if (mImage) { 1.458 + packet.width = mImage->GetSize().width; 1.459 + packet.height = mImage->GetSize().height; 1.460 + packet.stride = mImage->Stride(); 1.461 + packet.dataSize = mImage->GetSize().height * mImage->Stride(); 1.462 + 1.463 + dataptr = (char*) mImage->GetData(); 1.464 + datasize = packet.dataSize; 1.465 + 1.466 + compresseddata = std::auto_ptr<char>((char*) moz_malloc(LZ4::maxCompressedSize(datasize))); 1.467 + if (compresseddata.get()) { 1.468 + int ndatasize = LZ4::compress(dataptr, datasize, compresseddata.get()); 1.469 + if (ndatasize > 0) { 1.470 + datasize = ndatasize; 1.471 + dataptr = compresseddata.get(); 1.472 + 1.473 + packet.dataFormat = (1 << 16) | packet.dataFormat; 1.474 + packet.dataSize = datasize; 1.475 + } 1.476 + } 1.477 + } else { 1.478 + packet.width = 0; 1.479 + packet.height = 0; 1.480 + packet.stride = 0; 1.481 + packet.dataSize = 0; 1.482 + } 1.483 + 1.484 + // write the packet header data 1.485 + if (!WriteToStream(&packet, sizeof(packet))) 1.486 + return false; 1.487 + 1.488 + // then the image data 1.489 + if (!WriteToStream(dataptr, datasize)) 1.490 + return false; 1.491 + 1.492 + // then pad out to 4 bytes 1.493 + if (datasize % 4 != 0) { 1.494 + static char buf[] = { 0, 0, 0, 0 }; 1.495 + if (!WriteToStream(buf, 4 - (datasize % 4))) 1.496 + return false; 1.497 + } 1.498 + 1.499 + return true; 1.500 + } 1.501 + 1.502 +protected: 1.503 + void* mLayerRef; 1.504 + GLenum mTarget; 1.505 + GLuint mName; 1.506 + RefPtr<DataSourceSurface> mImage; 1.507 +}; 1.508 + 1.509 +class DebugGLColorData : public DebugGLData { 1.510 +public: 1.511 + DebugGLColorData(void* layerRef, const gfxRGBA& color, int width, int height) 1.512 + : DebugGLData(DebugGLData::ColorData), 1.513 + mColor(color.Packed()), 1.514 + mSize(width, height) 1.515 + { } 1.516 + 1.517 + void *GetLayerRef() const { return mLayerRef; } 1.518 + uint32_t GetColor() const { return mColor; } 1.519 + const nsIntSize& GetSize() const { return mSize; } 1.520 + 1.521 + virtual bool Write() { 1.522 + DebugGLData::ColorPacket packet; 1.523 + 1.524 + packet.type = mDataType; 1.525 + packet.ptr = static_cast<uint64_t>(mContextAddress); 1.526 + packet.layerref = reinterpret_cast<uintptr_t>(mLayerRef); 1.527 + packet.color = mColor; 1.528 + packet.width = mSize.width; 1.529 + packet.height = mSize.height; 1.530 + 1.531 + return WriteToStream(&packet, sizeof(packet)); 1.532 + } 1.533 + 1.534 +protected: 1.535 + void *mLayerRef; 1.536 + uint32_t mColor; 1.537 + nsIntSize mSize; 1.538 +}; 1.539 + 1.540 +static bool 1.541 +CheckSender() 1.542 +{ 1.543 + if (!gLayerScopeWebSocketManager) 1.544 + return false; 1.545 + 1.546 + if (!gLayerScopeWebSocketManager->IsConnected()) 1.547 + return false; 1.548 + 1.549 + return true; 1.550 +} 1.551 + 1.552 +class DebugListener : public nsIServerSocketListener 1.553 +{ 1.554 +public: 1.555 + 1.556 + NS_DECL_THREADSAFE_ISUPPORTS 1.557 + 1.558 + DebugListener() { } 1.559 + virtual ~DebugListener() { } 1.560 + 1.561 + /* nsIServerSocketListener */ 1.562 + 1.563 + NS_IMETHODIMP OnSocketAccepted(nsIServerSocket *aServ, 1.564 + nsISocketTransport *aTransport) 1.565 + { 1.566 + if (!gLayerScopeWebSocketManager) 1.567 + return NS_OK; 1.568 + 1.569 + printf_stderr("*** LayerScope: Accepted connection\n"); 1.570 + gLayerScopeWebSocketManager->AddConnection(aTransport); 1.571 + return NS_OK; 1.572 + } 1.573 + 1.574 + NS_IMETHODIMP OnStopListening(nsIServerSocket *aServ, 1.575 + nsresult aStatus) 1.576 + { 1.577 + return NS_OK; 1.578 + } 1.579 +}; 1.580 + 1.581 +NS_IMPL_ISUPPORTS(DebugListener, nsIServerSocketListener); 1.582 + 1.583 + 1.584 +class DebugDataSender : public nsIRunnable 1.585 +{ 1.586 +public: 1.587 + 1.588 + NS_DECL_THREADSAFE_ISUPPORTS 1.589 + 1.590 + DebugDataSender() { 1.591 + mList = new LinkedList<DebugGLData>(); 1.592 + } 1.593 + 1.594 + virtual ~DebugDataSender() { 1.595 + Cleanup(); 1.596 + } 1.597 + 1.598 + void Append(DebugGLData *d) { 1.599 + mList->insertBack(d); 1.600 + } 1.601 + 1.602 + void Cleanup() { 1.603 + if (!mList) 1.604 + return; 1.605 + 1.606 + DebugGLData *d; 1.607 + while ((d = mList->popFirst()) != nullptr) 1.608 + delete d; 1.609 + delete mList; 1.610 + 1.611 + mList = nullptr; 1.612 + } 1.613 + 1.614 + /* nsIRunnable impl; send the data */ 1.615 + 1.616 + NS_IMETHODIMP Run() { 1.617 + DebugGLData *d; 1.618 + nsresult rv = NS_OK; 1.619 + 1.620 + while ((d = mList->popFirst()) != nullptr) { 1.621 + std::auto_ptr<DebugGLData> cleaner(d); 1.622 + if (!d->Write()) { 1.623 + rv = NS_ERROR_FAILURE; 1.624 + break; 1.625 + } 1.626 + } 1.627 + 1.628 + Cleanup(); 1.629 + 1.630 + if (NS_FAILED(rv)) { 1.631 + LayerScope::DestroyServerSocket(); 1.632 + } 1.633 + 1.634 + return NS_OK; 1.635 + } 1.636 + 1.637 +protected: 1.638 + LinkedList<DebugGLData> *mList; 1.639 +}; 1.640 + 1.641 +NS_IMPL_ISUPPORTS(DebugDataSender, nsIRunnable); 1.642 + 1.643 +void 1.644 +LayerScope::CreateServerSocket() 1.645 +{ 1.646 + if (!gfxPrefs::LayerScopeEnabled()) { 1.647 + return; 1.648 + } 1.649 + 1.650 + if (!gLayerScopeWebSocketManager) { 1.651 + gLayerScopeWebSocketManager = new LayerScopeWebSocketManager(); 1.652 + } 1.653 +} 1.654 + 1.655 +void 1.656 +LayerScope::DestroyServerSocket() 1.657 +{ 1.658 + if (gLayerScopeWebSocketManager) { 1.659 + gLayerScopeWebSocketManager->RemoveAllConnections(); 1.660 + } 1.661 +} 1.662 + 1.663 +void 1.664 +LayerScope::BeginFrame(GLContext* aGLContext, int64_t aFrameStamp) 1.665 +{ 1.666 + if (!gLayerScopeWebSocketManager) 1.667 + return; 1.668 + 1.669 + if (!gLayerScopeWebSocketManager->IsConnected()) 1.670 + return; 1.671 + 1.672 +#if 0 1.673 + // if we're sending data in between frames, flush the list down the socket, 1.674 + // and start a new one 1.675 + if (gCurrentSender) { 1.676 + gDebugSenderThread->Dispatch(gCurrentSender, NS_DISPATCH_NORMAL); 1.677 + } 1.678 +#endif 1.679 + 1.680 + gLayerScopeWebSocketManager->AppendDebugData(new DebugGLData(DebugGLData::FrameStart, aGLContext, aFrameStamp)); 1.681 +} 1.682 + 1.683 +void 1.684 +LayerScope::EndFrame(GLContext* aGLContext) 1.685 +{ 1.686 + if (!CheckSender()) 1.687 + return; 1.688 + 1.689 + gLayerScopeWebSocketManager->AppendDebugData(new DebugGLData(DebugGLData::FrameEnd, aGLContext)); 1.690 + gLayerScopeWebSocketManager->DispatchDebugData(); 1.691 +} 1.692 + 1.693 +static void 1.694 +SendColor(void* aLayerRef, const gfxRGBA& aColor, int aWidth, int aHeight) 1.695 +{ 1.696 + if (!CheckSender()) 1.697 + return; 1.698 + 1.699 + gLayerScopeWebSocketManager->AppendDebugData( 1.700 + new DebugGLColorData(aLayerRef, aColor, aWidth, aHeight)); 1.701 +} 1.702 + 1.703 +static void 1.704 +SendTextureSource(GLContext* aGLContext, 1.705 + void* aLayerRef, 1.706 + TextureSourceOGL* aSource, 1.707 + bool aFlipY) 1.708 +{ 1.709 + GLenum textureTarget = aSource->GetTextureTarget(); 1.710 + ShaderConfigOGL config = ShaderConfigFromTargetAndFormat(textureTarget, 1.711 + aSource->GetFormat()); 1.712 + int shaderConfig = config.mFeatures; 1.713 + 1.714 + aSource->BindTexture(LOCAL_GL_TEXTURE0, gfx::Filter::LINEAR); 1.715 + 1.716 + GLuint textureId = 0; 1.717 + // This is horrid hack. It assumes that aGLContext matches the context 1.718 + // aSource has bound to. 1.719 + if (textureTarget == LOCAL_GL_TEXTURE_2D) { 1.720 + aGLContext->GetUIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, &textureId); 1.721 + } else if (textureTarget == LOCAL_GL_TEXTURE_EXTERNAL) { 1.722 + aGLContext->GetUIntegerv(LOCAL_GL_TEXTURE_BINDING_EXTERNAL, &textureId); 1.723 + } else if (textureTarget == LOCAL_GL_TEXTURE_RECTANGLE) { 1.724 + aGLContext->GetUIntegerv(LOCAL_GL_TEXTURE_BINDING_RECTANGLE, &textureId); 1.725 + } 1.726 + 1.727 + gfx::IntSize size = aSource->GetSize(); 1.728 + 1.729 + // By sending 0 to ReadTextureImage rely upon aSource->BindTexture binding 1.730 + // texture correctly. textureId is used for tracking in DebugGLTextureData. 1.731 + RefPtr<DataSourceSurface> img = 1.732 + aGLContext->ReadTexImageHelper()->ReadTexImage(0, textureTarget, 1.733 + size, 1.734 + shaderConfig, aFlipY); 1.735 + 1.736 + gLayerScopeWebSocketManager->AppendDebugData( 1.737 + new DebugGLTextureData(aGLContext, aLayerRef, textureTarget, 1.738 + textureId, img)); 1.739 +} 1.740 + 1.741 +static void 1.742 +SendTexturedEffect(GLContext* aGLContext, 1.743 + void* aLayerRef, 1.744 + const TexturedEffect* aEffect) 1.745 +{ 1.746 + TextureSourceOGL* source = aEffect->mTexture->AsSourceOGL(); 1.747 + if (!source) 1.748 + return; 1.749 + 1.750 + bool flipY = false; 1.751 + SendTextureSource(aGLContext, aLayerRef, source, flipY); 1.752 +} 1.753 + 1.754 +static void 1.755 +SendYCbCrEffect(GLContext* aGLContext, 1.756 + void* aLayerRef, 1.757 + const EffectYCbCr* aEffect) 1.758 +{ 1.759 + TextureSource* sourceYCbCr = aEffect->mTexture; 1.760 + if (!sourceYCbCr) 1.761 + return; 1.762 + 1.763 + const int Y = 0, Cb = 1, Cr = 2; 1.764 + TextureSourceOGL* sourceY = sourceYCbCr->GetSubSource(Y)->AsSourceOGL(); 1.765 + TextureSourceOGL* sourceCb = sourceYCbCr->GetSubSource(Cb)->AsSourceOGL(); 1.766 + TextureSourceOGL* sourceCr = sourceYCbCr->GetSubSource(Cr)->AsSourceOGL(); 1.767 + 1.768 + bool flipY = false; 1.769 + SendTextureSource(aGLContext, aLayerRef, sourceY, flipY); 1.770 + SendTextureSource(aGLContext, aLayerRef, sourceCb, flipY); 1.771 + SendTextureSource(aGLContext, aLayerRef, sourceCr, flipY); 1.772 +} 1.773 + 1.774 +void 1.775 +LayerScope::SendEffectChain(GLContext* aGLContext, 1.776 + const EffectChain& aEffectChain, 1.777 + int aWidth, int aHeight) 1.778 +{ 1.779 + if (!CheckSender()) 1.780 + return; 1.781 + 1.782 + const Effect* primaryEffect = aEffectChain.mPrimaryEffect; 1.783 + switch (primaryEffect->mType) { 1.784 + case EFFECT_RGB: 1.785 + { 1.786 + const TexturedEffect* texturedEffect = 1.787 + static_cast<const TexturedEffect*>(primaryEffect); 1.788 + SendTexturedEffect(aGLContext, aEffectChain.mLayerRef, texturedEffect); 1.789 + } 1.790 + break; 1.791 + case EFFECT_YCBCR: 1.792 + { 1.793 + const EffectYCbCr* yCbCrEffect = 1.794 + static_cast<const EffectYCbCr*>(primaryEffect); 1.795 + SendYCbCrEffect(aGLContext, aEffectChain.mLayerRef, yCbCrEffect); 1.796 + } 1.797 + case EFFECT_SOLID_COLOR: 1.798 + { 1.799 + const EffectSolidColor* solidColorEffect = 1.800 + static_cast<const EffectSolidColor*>(primaryEffect); 1.801 + gfxRGBA color(solidColorEffect->mColor.r, 1.802 + solidColorEffect->mColor.g, 1.803 + solidColorEffect->mColor.b, 1.804 + solidColorEffect->mColor.a); 1.805 + SendColor(aEffectChain.mLayerRef, color, aWidth, aHeight); 1.806 + } 1.807 + break; 1.808 + case EFFECT_COMPONENT_ALPHA: 1.809 + case EFFECT_RENDER_TARGET: 1.810 + default: 1.811 + break; 1.812 + } 1.813 + 1.814 + //const Effect* secondaryEffect = aEffectChain.mSecondaryEffects[EFFECT_MASK]; 1.815 + // TODO: 1.816 +} 1.817 + 1.818 +LayerScopeWebSocketManager::LayerScopeWebSocketManager() 1.819 +{ 1.820 + NS_NewThread(getter_AddRefs(mDebugSenderThread)); 1.821 + 1.822 + mServerSocket = do_CreateInstance(NS_SERVERSOCKET_CONTRACTID); 1.823 + int port = gfxPrefs::LayerScopePort(); 1.824 + mServerSocket->Init(port, false, -1); 1.825 + mServerSocket->AsyncListen(new DebugListener); 1.826 +} 1.827 + 1.828 +LayerScopeWebSocketManager::~LayerScopeWebSocketManager() 1.829 +{ 1.830 +} 1.831 + 1.832 +void LayerScopeWebSocketManager::AppendDebugData(DebugGLData *aDebugData) 1.833 +{ 1.834 + if (!mCurrentSender) { 1.835 + mCurrentSender = new DebugDataSender(); 1.836 + } 1.837 + 1.838 + mCurrentSender->Append(aDebugData); 1.839 +} 1.840 + 1.841 +void LayerScopeWebSocketManager::DispatchDebugData() 1.842 +{ 1.843 + mDebugSenderThread->Dispatch(mCurrentSender, NS_DISPATCH_NORMAL); 1.844 + mCurrentSender = nullptr; 1.845 +} 1.846 + 1.847 +} /* layers */ 1.848 +} /* mozilla */