GLES2Dbg: added reference frame for glReadPixels

Change-Id: I37398d8d835e54a1764dfabd617fdc2c640864c2
diff --git a/opengl/libs/GLES2_dbg/generate_debugger_message_proto.py b/opengl/libs/GLES2_dbg/generate_debugger_message_proto.py
index 48a29da..ed8eae2 100755
--- a/opengl/libs/GLES2_dbg/generate_debugger_message_proto.py
+++ b/opengl/libs/GLES2_dbg/generate_debugger_message_proto.py
@@ -118,7 +118,17 @@
     optional int32 arg6 = 18;
     optional int32 arg7 = 19;
     optional int32 arg8 = 20;
+
     optional bytes data = 10; // variable length data used for GL call
+    enum DataType
+    {
+        ReferencedImage = 0; // for image sourced from ReadPixels
+        NonreferencedImage = 1; // for image sourced from ReadPixels
+    };
+    optional DataType data_type = 23; // most data types can be inferred from function
+    optional int32 pixel_format = 24; // used for image data if format and type 
+    optional int32 pixel_type = 25;   //     cannot be determined from arg 
+    
     optional float time = 11; // duration of previous GL call (ms)
     enum Prop
     {
diff --git a/opengl/libs/GLES2_dbg/src/api.h b/opengl/libs/GLES2_dbg/src/api.h
index 069ac9e..fd6833e 100644
--- a/opengl/libs/GLES2_dbg/src/api.h
+++ b/opengl/libs/GLES2_dbg/src/api.h
@@ -21,7 +21,7 @@
     const unsigned compressed = dbg->Compress(pixels, width * height * 4); \
     msg.set_data(dbg->lzf_buf, compressed); \
     free(pixels);
-    
+
 #define EXTEND_Debug_glCopyTexSubImage2D EXTEND_Debug_glCopyTexImage2D
 
 #define EXTEND_Debug_glShaderSource \
@@ -30,4 +30,4 @@
         if (!length || length[i] < 0) \
             data->append(string[i]); \
         else \
-            data->append(string[i], length[i]);
\ No newline at end of file
+            data->append(string[i], length[i]);
diff --git a/opengl/libs/GLES2_dbg/src/dbgcontext.cpp b/opengl/libs/GLES2_dbg/src/dbgcontext.cpp
index 28439ba..951f255 100644
--- a/opengl/libs/GLES2_dbg/src/dbgcontext.cpp
+++ b/opengl/libs/GLES2_dbg/src/dbgcontext.cpp
@@ -16,7 +16,8 @@
 
 #include "header.h"
 
-extern "C" {
+extern "C"
+{
 #include "liblzf/lzf.h"
 }
 
@@ -26,11 +27,13 @@
 DbgContext::DbgContext(const unsigned version, const gl_hooks_t * const hooks,
                        const unsigned MAX_VERTEX_ATTRIBS)
         : lzf_buf(NULL), lzf_bufSize(0)
+        , lzf_readIndex(0), lzf_refSize(0), lzf_refBufSize(0)
         , version(version), hooks(hooks)
         , MAX_VERTEX_ATTRIBS(MAX_VERTEX_ATTRIBS)
         , vertexAttribs(new VertexAttrib[MAX_VERTEX_ATTRIBS])
         , hasNonVBOAttribs(false), indexBuffers(NULL), indexBuffer(NULL)
 {
+    lzf_ref[0] = lzf_ref[1] = NULL;
     for (unsigned i = 0; i < MAX_VERTEX_ATTRIBS; i++)
         vertexAttribs[i] = VertexAttrib();
 }
@@ -39,6 +42,8 @@
 {
     delete vertexAttribs;
     free(lzf_buf);
+    free(lzf_ref[0]);
+    free(lzf_ref[1]);
 }
 
 DbgContext * CreateDbgContext(const unsigned version, const gl_hooks_t * const hooks)
@@ -76,12 +81,35 @@
         lzf_buf = (char *)realloc(lzf_buf, lzf_bufSize);
     }
     unsigned compressedSize = lzf_compress((const char *)in_data,
-                              in_len, lzf_buf, lzf_bufSize);
-    LOGD("DbgContext::lzf_compress in=%u out=%u", in_len, compressedSize);
+                                           in_len, lzf_buf, lzf_bufSize);
     assert (0 < compressedSize);
     return compressedSize;
 }
 
+void * DbgContext::GetReadPixelsBuffer(const unsigned size)
+{
+    if (lzf_refSize < size) {
+        lzf_refSize = size;
+        lzf_refBufSize = lzf_refSize + 64;
+        lzf_ref[0] = (unsigned *)realloc(lzf_ref[0], lzf_refBufSize);
+        memset(lzf_ref[0], 0, lzf_refSize);
+        lzf_ref[1] = (unsigned *)realloc(lzf_ref[1], lzf_refBufSize);
+        memset(lzf_ref[1], 0, lzf_refSize);
+    }
+    lzf_refSize = size;
+    lzf_readIndex ^= 1;
+    return lzf_ref[lzf_readIndex];
+}
+
+unsigned DbgContext::CompressReadPixelBuffer()
+{
+    unsigned * const ref = lzf_ref[lzf_readIndex ^ 1];
+    unsigned * const src = lzf_ref[lzf_readIndex];
+    for (unsigned i = 0; i < lzf_refSize / sizeof(*ref) + 1; i++)
+        ref[i] ^= src[i];
+    return Compress(ref, lzf_refSize);
+}
+
 void DbgContext::glUseProgram(GLuint program)
 {
     while (GLenum error = hooks->gl.glGetError())
diff --git a/opengl/libs/GLES2_dbg/src/debugger_message.pb.cpp b/opengl/libs/GLES2_dbg/src/debugger_message.pb.cpp
index 1f404c2..94bf3ef 100644
--- a/opengl/libs/GLES2_dbg/src/debugger_message.pb.cpp
+++ b/opengl/libs/GLES2_dbg/src/debugger_message.pb.cpp
@@ -450,6 +450,23 @@
 const Message_Type Message::Type_MAX;
 const int Message::Type_ARRAYSIZE;
 #endif  // _MSC_VER
+bool Message_DataType_IsValid(int value) {
+  switch(value) {
+    case 0:
+    case 1:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#ifndef _MSC_VER
+const Message_DataType Message::ReferencedImage;
+const Message_DataType Message::NonreferencedImage;
+const Message_DataType Message::DataType_MIN;
+const Message_DataType Message::DataType_MAX;
+const int Message::DataType_ARRAYSIZE;
+#endif  // _MSC_VER
 bool Message_Prop_IsValid(int value) {
   switch(value) {
     case 0:
@@ -484,6 +501,9 @@
 const int Message::kArg7FieldNumber;
 const int Message::kArg8FieldNumber;
 const int Message::kDataFieldNumber;
+const int Message::kDataTypeFieldNumber;
+const int Message::kPixelFormatFieldNumber;
+const int Message::kPixelTypeFieldNumber;
 const int Message::kTimeFieldNumber;
 const int Message::kPropFieldNumber;
 const int Message::kClockFieldNumber;
@@ -520,6 +540,9 @@
   arg7_ = 0;
   arg8_ = 0;
   data_ = const_cast< ::std::string*>(&_default_data_);
+  data_type_ = 0;
+  pixel_format_ = 0;
+  pixel_type_ = 0;
   time_ = 0;
   prop_ = 0;
   clock_ = 0;
@@ -576,9 +599,12 @@
         data_->clear();
       }
     }
-    time_ = 0;
+    data_type_ = 0;
   }
   if (_has_bits_[16 / 32] & (0xffu << (16 % 32))) {
+    pixel_format_ = 0;
+    pixel_type_ = 0;
+    time_ = 0;
     prop_ = 0;
     clock_ = 0;
   }
@@ -762,7 +788,7 @@
           DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
                    float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
                  input, &time_)));
-          _set_bit(15);
+          _set_bit(18);
         } else {
           goto handle_uninterpreted;
         }
@@ -877,6 +903,57 @@
           DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
                    float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
                  input, &clock_)));
+          _set_bit(20);
+        } else {
+          goto handle_uninterpreted;
+        }
+        if (input->ExpectTag(184)) goto parse_data_type;
+        break;
+      }
+      
+      // optional .com.android.glesv2debugger.Message.DataType data_type = 23;
+      case 23: {
+        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+         parse_data_type:
+          int value;
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+                 input, &value)));
+          if (::com::android::glesv2debugger::Message_DataType_IsValid(value)) {
+            set_data_type(static_cast< ::com::android::glesv2debugger::Message_DataType >(value));
+          }
+        } else {
+          goto handle_uninterpreted;
+        }
+        if (input->ExpectTag(192)) goto parse_pixel_format;
+        break;
+      }
+      
+      // optional int32 pixel_format = 24;
+      case 24: {
+        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+         parse_pixel_format:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &pixel_format_)));
+          _set_bit(16);
+        } else {
+          goto handle_uninterpreted;
+        }
+        if (input->ExpectTag(200)) goto parse_pixel_type;
+        break;
+      }
+      
+      // optional int32 pixel_type = 25;
+      case 25: {
+        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+         parse_pixel_type:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &pixel_type_)));
           _set_bit(17);
         } else {
           goto handle_uninterpreted;
@@ -956,7 +1033,7 @@
   }
   
   // optional float time = 11;
-  if (_has_bit(15)) {
+  if (_has_bit(18)) {
     ::google::protobuf::internal::WireFormatLite::WriteFloat(11, this->time(), output);
   }
   
@@ -986,16 +1063,32 @@
   }
   
   // optional .com.android.glesv2debugger.Message.Prop prop = 21;
-  if (_has_bit(16)) {
+  if (_has_bit(19)) {
     ::google::protobuf::internal::WireFormatLite::WriteEnum(
       21, this->prop(), output);
   }
   
   // optional float clock = 22;
-  if (_has_bit(17)) {
+  if (_has_bit(20)) {
     ::google::protobuf::internal::WireFormatLite::WriteFloat(22, this->clock(), output);
   }
   
+  // optional .com.android.glesv2debugger.Message.DataType data_type = 23;
+  if (_has_bit(15)) {
+    ::google::protobuf::internal::WireFormatLite::WriteEnum(
+      23, this->data_type(), output);
+  }
+  
+  // optional int32 pixel_format = 24;
+  if (_has_bit(16)) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(24, this->pixel_format(), output);
+  }
+  
+  // optional int32 pixel_type = 25;
+  if (_has_bit(17)) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(25, this->pixel_type(), output);
+  }
+  
 }
 
 int Message::ByteSize() const {
@@ -1105,13 +1198,33 @@
           this->data());
     }
     
+    // optional .com.android.glesv2debugger.Message.DataType data_type = 23;
+    if (has_data_type()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::EnumSize(this->data_type());
+    }
+    
+  }
+  if (_has_bits_[16 / 32] & (0xffu << (16 % 32))) {
+    // optional int32 pixel_format = 24;
+    if (has_pixel_format()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->pixel_format());
+    }
+    
+    // optional int32 pixel_type = 25;
+    if (has_pixel_type()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->pixel_type());
+    }
+    
     // optional float time = 11;
     if (has_time()) {
       total_size += 1 + 4;
     }
     
-  }
-  if (_has_bits_[16 / 32] & (0xffu << (16 % 32))) {
     // optional .com.android.glesv2debugger.Message.Prop prop = 21;
     if (has_prop()) {
       total_size += 2 +
@@ -1186,14 +1299,23 @@
       set_data(from.data());
     }
     if (from._has_bit(15)) {
-      set_time(from.time());
+      set_data_type(from.data_type());
     }
   }
   if (from._has_bits_[16 / 32] & (0xffu << (16 % 32))) {
     if (from._has_bit(16)) {
-      set_prop(from.prop());
+      set_pixel_format(from.pixel_format());
     }
     if (from._has_bit(17)) {
+      set_pixel_type(from.pixel_type());
+    }
+    if (from._has_bit(18)) {
+      set_time(from.time());
+    }
+    if (from._has_bit(19)) {
+      set_prop(from.prop());
+    }
+    if (from._has_bit(20)) {
       set_clock(from.clock());
     }
   }
@@ -1228,6 +1350,9 @@
     std::swap(arg7_, other->arg7_);
     std::swap(arg8_, other->arg8_);
     std::swap(data_, other->data_);
+    std::swap(data_type_, other->data_type_);
+    std::swap(pixel_format_, other->pixel_format_);
+    std::swap(pixel_type_, other->pixel_type_);
     std::swap(time_, other->time_);
     std::swap(prop_, other->prop_);
     std::swap(clock_, other->clock_);
diff --git a/opengl/libs/GLES2_dbg/src/debugger_message.pb.h b/opengl/libs/GLES2_dbg/src/debugger_message.pb.h
index 59e7bab..12ef781 100644
--- a/opengl/libs/GLES2_dbg/src/debugger_message.pb.h
+++ b/opengl/libs/GLES2_dbg/src/debugger_message.pb.h
@@ -243,6 +243,15 @@
 const Message_Type Message_Type_Type_MAX = Message_Type_Response;
 const int Message_Type_Type_ARRAYSIZE = Message_Type_Type_MAX + 1;
 
+enum Message_DataType {
+  Message_DataType_ReferencedImage = 0,
+  Message_DataType_NonreferencedImage = 1
+};
+bool Message_DataType_IsValid(int value);
+const Message_DataType Message_DataType_DataType_MIN = Message_DataType_ReferencedImage;
+const Message_DataType Message_DataType_DataType_MAX = Message_DataType_NonreferencedImage;
+const int Message_DataType_DataType_ARRAYSIZE = Message_DataType_DataType_MAX + 1;
+
 enum Message_Prop {
   Message_Prop_Capture = 0,
   Message_Prop_TimeMode = 1
@@ -511,6 +520,19 @@
   static const int Type_ARRAYSIZE =
     Message_Type_Type_ARRAYSIZE;
   
+  typedef Message_DataType DataType;
+  static const DataType ReferencedImage = Message_DataType_ReferencedImage;
+  static const DataType NonreferencedImage = Message_DataType_NonreferencedImage;
+  static inline bool DataType_IsValid(int value) {
+    return Message_DataType_IsValid(value);
+  }
+  static const DataType DataType_MIN =
+    Message_DataType_DataType_MIN;
+  static const DataType DataType_MAX =
+    Message_DataType_DataType_MAX;
+  static const int DataType_ARRAYSIZE =
+    Message_DataType_DataType_ARRAYSIZE;
+  
   typedef Message_Prop Prop;
   static const Prop Capture = Message_Prop_Capture;
   static const Prop TimeMode = Message_Prop_TimeMode;
@@ -634,6 +656,27 @@
   inline void set_data(const void* value, size_t size);
   inline ::std::string* mutable_data();
   
+  // optional .com.android.glesv2debugger.Message.DataType data_type = 23;
+  inline bool has_data_type() const;
+  inline void clear_data_type();
+  static const int kDataTypeFieldNumber = 23;
+  inline ::com::android::glesv2debugger::Message_DataType data_type() const;
+  inline void set_data_type(::com::android::glesv2debugger::Message_DataType value);
+  
+  // optional int32 pixel_format = 24;
+  inline bool has_pixel_format() const;
+  inline void clear_pixel_format();
+  static const int kPixelFormatFieldNumber = 24;
+  inline ::google::protobuf::int32 pixel_format() const;
+  inline void set_pixel_format(::google::protobuf::int32 value);
+  
+  // optional int32 pixel_type = 25;
+  inline bool has_pixel_type() const;
+  inline void clear_pixel_type();
+  static const int kPixelTypeFieldNumber = 25;
+  inline ::google::protobuf::int32 pixel_type() const;
+  inline void set_pixel_type(::google::protobuf::int32 value);
+  
   // optional float time = 11;
   inline bool has_time() const;
   inline void clear_time();
@@ -675,6 +718,9 @@
   ::google::protobuf::int32 arg8_;
   ::std::string* data_;
   static const ::std::string _default_data_;
+  int data_type_;
+  ::google::protobuf::int32 pixel_format_;
+  ::google::protobuf::int32 pixel_type_;
   float time_;
   int prop_;
   float clock_;
@@ -682,7 +728,7 @@
   friend void protobuf_AssignDesc_debugger_5fmessage_2eproto();
   friend void protobuf_ShutdownFile_debugger_5fmessage_2eproto();
   
-  ::google::protobuf::uint32 _has_bits_[(18 + 31) / 32];
+  ::google::protobuf::uint32 _has_bits_[(21 + 31) / 32];
   
   // WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
   inline bool _has_bit(int index) const {
@@ -973,52 +1019,101 @@
   return data_;
 }
 
+// optional .com.android.glesv2debugger.Message.DataType data_type = 23;
+inline bool Message::has_data_type() const {
+  return _has_bit(15);
+}
+inline void Message::clear_data_type() {
+  data_type_ = 0;
+  _clear_bit(15);
+}
+inline ::com::android::glesv2debugger::Message_DataType Message::data_type() const {
+  return static_cast< ::com::android::glesv2debugger::Message_DataType >(data_type_);
+}
+inline void Message::set_data_type(::com::android::glesv2debugger::Message_DataType value) {
+  GOOGLE_DCHECK(::com::android::glesv2debugger::Message_DataType_IsValid(value));
+  _set_bit(15);
+  data_type_ = value;
+}
+
+// optional int32 pixel_format = 24;
+inline bool Message::has_pixel_format() const {
+  return _has_bit(16);
+}
+inline void Message::clear_pixel_format() {
+  pixel_format_ = 0;
+  _clear_bit(16);
+}
+inline ::google::protobuf::int32 Message::pixel_format() const {
+  return pixel_format_;
+}
+inline void Message::set_pixel_format(::google::protobuf::int32 value) {
+  _set_bit(16);
+  pixel_format_ = value;
+}
+
+// optional int32 pixel_type = 25;
+inline bool Message::has_pixel_type() const {
+  return _has_bit(17);
+}
+inline void Message::clear_pixel_type() {
+  pixel_type_ = 0;
+  _clear_bit(17);
+}
+inline ::google::protobuf::int32 Message::pixel_type() const {
+  return pixel_type_;
+}
+inline void Message::set_pixel_type(::google::protobuf::int32 value) {
+  _set_bit(17);
+  pixel_type_ = value;
+}
+
 // optional float time = 11;
 inline bool Message::has_time() const {
-  return _has_bit(15);
+  return _has_bit(18);
 }
 inline void Message::clear_time() {
   time_ = 0;
-  _clear_bit(15);
+  _clear_bit(18);
 }
 inline float Message::time() const {
   return time_;
 }
 inline void Message::set_time(float value) {
-  _set_bit(15);
+  _set_bit(18);
   time_ = value;
 }
 
 // optional .com.android.glesv2debugger.Message.Prop prop = 21;
 inline bool Message::has_prop() const {
-  return _has_bit(16);
+  return _has_bit(19);
 }
 inline void Message::clear_prop() {
   prop_ = 0;
-  _clear_bit(16);
+  _clear_bit(19);
 }
 inline ::com::android::glesv2debugger::Message_Prop Message::prop() const {
   return static_cast< ::com::android::glesv2debugger::Message_Prop >(prop_);
 }
 inline void Message::set_prop(::com::android::glesv2debugger::Message_Prop value) {
   GOOGLE_DCHECK(::com::android::glesv2debugger::Message_Prop_IsValid(value));
-  _set_bit(16);
+  _set_bit(19);
   prop_ = value;
 }
 
 // optional float clock = 22;
 inline bool Message::has_clock() const {
-  return _has_bit(17);
+  return _has_bit(20);
 }
 inline void Message::clear_clock() {
   clock_ = 0;
-  _clear_bit(17);
+  _clear_bit(20);
 }
 inline float Message::clock() const {
   return clock_;
 }
 inline void Message::set_clock(float value) {
-  _set_bit(17);
+  _set_bit(20);
   clock_ = value;
 }
 
diff --git a/opengl/libs/GLES2_dbg/src/egl.cpp b/opengl/libs/GLES2_dbg/src/egl.cpp
index 27c7f7e..3e78e16 100644
--- a/opengl/libs/GLES2_dbg/src/egl.cpp
+++ b/opengl/libs/GLES2_dbg/src/egl.cpp
@@ -23,7 +23,7 @@
     struct : public FunctionCall {
         EGLDisplay dpy;
         EGLSurface draw;
-        
+
         const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
             msg.set_time(-1);
             return reinterpret_cast<const int *>(true);
@@ -31,10 +31,10 @@
     } caller;
     caller.dpy = dpy;
     caller.draw = draw;
-    
+
     msg.set_arg0(reinterpret_cast<int>(dpy));
     msg.set_arg1(reinterpret_cast<int>(draw));
-    
+
     int * ret = MessageLoop(caller, msg, expectResponse,
                             glesv2debugger::Message_Function_eglSwapBuffers);
     return static_cast<EGLBoolean>(reinterpret_cast<int>(ret));
diff --git a/opengl/libs/GLES2_dbg/src/header.h b/opengl/libs/GLES2_dbg/src/header.h
index 21b1dfb..0623a5d 100644
--- a/opengl/libs/GLES2_dbg/src/header.h
+++ b/opengl/libs/GLES2_dbg/src/header.h
@@ -59,14 +59,19 @@
 struct DbgContext {
 private:
     unsigned lzf_bufSize;
-    
+
+    // used as buffer and reference frame for ReadPixels; malloc/free
+    unsigned * lzf_ref [2];
+    unsigned lzf_readIndex; // 0 or 1
+    unsigned lzf_refSize, lzf_refBufSize; // bytes
+
 public:
-    char * lzf_buf;
-    
+    char * lzf_buf; // auto malloc/free; output of lzf_compress
+
     const unsigned version; // 0 is GLES1, 1 is GLES2
     const gl_hooks_t * const hooks;
     const unsigned MAX_VERTEX_ATTRIBS;
-    
+
     struct VertexAttrib {
         GLenum type; // element data type
         unsigned size; // number of data per element
@@ -100,7 +105,12 @@
 
     void Fetch(const unsigned index, std::string * const data) const;
     unsigned Compress(const void * in_data, unsigned in_len); // compressed to lzf_buf
-    
+    void * GetReadPixelsBuffer(const unsigned size);
+    bool IsReadPixelBuffer(const void * const ptr)  {
+        return ptr == lzf_ref[lzf_readIndex];
+    }
+    unsigned CompressReadPixelBuffer();
+
     void glUseProgram(GLuint program);
     void glEnableVertexAttribArray(GLuint index);
     void glDisableVertexAttribArray(GLuint index);
diff --git a/opengl/libs/GLES2_dbg/src/server.cpp b/opengl/libs/GLES2_dbg/src/server.cpp
index 03c3dae..b3a9d69 100644
--- a/opengl/libs/GLES2_dbg/src/server.cpp
+++ b/opengl/libs/GLES2_dbg/src/server.cpp
@@ -153,10 +153,9 @@
         assert(msg.has_context_id() && msg.context_id() != 0);
     static std::string str;
     msg.SerializeToString(&str);
-    unsigned len = str.length();
-    len = htonl(len);
+    uint32_t len = htonl(str.length());
     int sent = -1;
-    sent = send(clientSock, (const char *)&len, sizeof(len), 0);
+    sent = send(clientSock, &len, sizeof(len), 0);
     if (sent != sizeof(len)) {
         LOGD("actual sent=%d expected=%d clientSock=%d", sent, sizeof(len), clientSock);
         Die("Failed to send message length");
@@ -182,7 +181,6 @@
     } else
         Receive(cmd);
 
-    //LOGD("Message sent tid=%lu len=%d", pthread_self(), str.length());
     pthread_mutex_unlock(&mutex);
     return t;
 }
diff --git a/opengl/libs/GLES2_dbg/src/vertex.cpp b/opengl/libs/GLES2_dbg/src/vertex.cpp
index c4598f5..71ebe363 100644
--- a/opengl/libs/GLES2_dbg/src/vertex.cpp
+++ b/opengl/libs/GLES2_dbg/src/vertex.cpp
@@ -37,7 +37,7 @@
     msg.set_arg4(format);
     msg.set_arg5(type);
     msg.set_arg6(reinterpret_cast<int>(pixels));
-    
+
     const unsigned size = width * height * GetBytesPerPixel(format, type);
     unsigned compressed = 0;
     if (!expectResponse)
@@ -55,7 +55,13 @@
             msg.set_function(glesv2debugger::Message_Function_glReadPixels);
             msg.set_type(glesv2debugger::Message_Type_AfterCall);
             msg.set_expect_response(expectResponse);
-            compressed = dbg->Compress(pixels, size);
+            if (dbg->IsReadPixelBuffer(pixels)) {
+                compressed = dbg->CompressReadPixelBuffer();
+                msg.set_data_type(msg.ReferencedImage);
+            } else {
+                compressed = dbg->Compress(pixels, size);
+                msg.set_data_type(msg.NonreferencedImage);
+            }
             msg.set_data(dbg->lzf_buf, compressed);
             if (!expectResponse)
                 cmd.set_function(glesv2debugger::Message_Function_SKIP);
@@ -120,10 +126,10 @@
                 dbg->hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &readType);
 //                LOGD("glDrawArrays CAPTURE: x=%d y=%d width=%d height=%d format=0x%.4X type=0x%.4X",
 //                     viewport[0], viewport[1], viewport[2], viewport[3], readFormat, readType);
-                pixels = malloc(viewport[2] * viewport[3] * 4);
+                pixels = dbg->GetReadPixelsBuffer(viewport[2] * viewport[3] *
+                                                  GetBytesPerPixel(readFormat, readType));
                 Debug_glReadPixels(viewport[0], viewport[1], viewport[2], viewport[3],
                                    readFormat, readType, pixels);
-                free(pixels);
             }
             break;
         case glesv2debugger::Message_Function_SKIP:
@@ -169,12 +175,14 @@
     std::string * const data = msg.mutable_data();
     if (GL_UNSIGNED_BYTE == type) {
         if (dbg->indexBuffer)
-            FetchIndexed(count, (unsigned char *)dbg->indexBuffer->data + (unsigned long)indices, data, dbg);
+            FetchIndexed(count, (unsigned char *)dbg->indexBuffer->data +
+                         (unsigned long)indices, data, dbg);
         else
             FetchIndexed(count, (unsigned char *)indices, data, dbg);
     } else if (GL_UNSIGNED_SHORT == type) {
         if (dbg->indexBuffer)
-            FetchIndexed(count, (unsigned short *)((char *)dbg->indexBuffer->data + (unsigned long)indices), data, dbg);
+            FetchIndexed(count, (unsigned short *)((char *)dbg->indexBuffer->data +
+                                                   (unsigned long)indices), data, dbg);
         else
             FetchIndexed(count, (unsigned short *)indices, data, dbg);
     } else
@@ -206,10 +214,10 @@
                 dbg->hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &readType);
 //                LOGD("glDrawArrays CAPTURE: x=%d y=%d width=%d height=%d format=0x%.4X type=0x%.4X",
 //                     viewport[0], viewport[1], viewport[2], viewport[3], readFormat, readType);
-                pixels = malloc(viewport[2] * viewport[3] * 4);
+                pixels = dbg->GetReadPixelsBuffer(viewport[2] * viewport[3] *
+                                                  GetBytesPerPixel(readFormat, readType));
                 Debug_glReadPixels(viewport[0], viewport[1], viewport[2], viewport[3],
                                    readFormat, readType, pixels);
-                free(pixels);
             }
             break;
         case glesv2debugger::Message_Function_SKIP: