GLES2Dbg: use libLZF for compressing images

liblzf is in external/liblzf, it's BSD-type licence (optionally GPL2)

Change-Id: Idc7883fe2155f366cda384e64796a1493335ae4f
Signed-off-by: David Li <davidxli@google.com>
diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
index 123306b6..7d72729 100644
--- a/opengl/libs/Android.mk
+++ b/opengl/libs/Android.mk
@@ -13,7 +13,7 @@
 	EGL/hooks.cpp 	       \
 	EGL/Loader.cpp 	       \
 #
-LOCAL_STATIC_LIBRARIES += libGLESv2_dbg libprotobuf-cpp-2.3.0-lite
+LOCAL_STATIC_LIBRARIES += libGLESv2_dbg libprotobuf-cpp-2.3.0-lite liblzf
 LOCAL_SHARED_LIBRARIES += libcutils libutils libstlport
 LOCAL_LDLIBS := -lpthread -ldl
 LOCAL_MODULE:= libEGL
diff --git a/opengl/libs/GLES2_dbg/Android.mk b/opengl/libs/GLES2_dbg/Android.mk
index e593c32..943d59d 100644
--- a/opengl/libs/GLES2_dbg/Android.mk
+++ b/opengl/libs/GLES2_dbg/Android.mk
@@ -16,6 +16,7 @@
     $(LOCAL_PATH)/../ \
     external/stlport/stlport \
     external/protobuf/src \
+    external \
     bionic
 
 #LOCAL_CFLAGS += -O0 -g -DDEBUG -UNDEBUG
diff --git a/opengl/libs/GLES2_dbg/src/api.h b/opengl/libs/GLES2_dbg/src/api.h
index be94dfc..069ac9e 100644
--- a/opengl/libs/GLES2_dbg/src/api.h
+++ b/opengl/libs/GLES2_dbg/src/api.h
@@ -17,7 +17,9 @@
 #define EXTEND_Debug_glCopyTexImage2D \
     void * pixels = malloc(width * height * 4); \
     getGLTraceThreadSpecific()->gl.glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); \
-    msg.set_data(pixels, width * height * 4); \
+    DbgContext * const dbg = getDbgContextThreadSpecific(); \
+    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
diff --git a/opengl/libs/GLES2_dbg/src/dbgcontext.cpp b/opengl/libs/GLES2_dbg/src/dbgcontext.cpp
index 5c418258..28439ba 100644
--- a/opengl/libs/GLES2_dbg/src/dbgcontext.cpp
+++ b/opengl/libs/GLES2_dbg/src/dbgcontext.cpp
@@ -13,15 +13,20 @@
  ** See the License for the specific language governing permissions and
  ** limitations under the License.
  */
- 
+
 #include "header.h"
 
+extern "C" {
+#include "liblzf/lzf.h"
+}
+
 namespace android
 {
 
 DbgContext::DbgContext(const unsigned version, const gl_hooks_t * const hooks,
                        const unsigned MAX_VERTEX_ATTRIBS)
-        : version(version), hooks(hooks)
+        : lzf_buf(NULL), lzf_bufSize(0)
+        , version(version), hooks(hooks)
         , MAX_VERTEX_ATTRIBS(MAX_VERTEX_ATTRIBS)
         , vertexAttribs(new VertexAttrib[MAX_VERTEX_ATTRIBS])
         , hasNonVBOAttribs(false), indexBuffers(NULL), indexBuffer(NULL)
@@ -33,6 +38,7 @@
 DbgContext::~DbgContext()
 {
     delete vertexAttribs;
+    free(lzf_buf);
 }
 
 DbgContext * CreateDbgContext(const unsigned version, const gl_hooks_t * const hooks)
@@ -63,11 +69,24 @@
     }
 }
 
+unsigned DbgContext::Compress(const void * in_data, unsigned in_len)
+{
+    if (lzf_bufSize < in_len + 256) {
+        lzf_bufSize = in_len + 256;
+        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);
+    assert (0 < compressedSize);
+    return compressedSize;
+}
+
 void DbgContext::glUseProgram(GLuint program)
 {
     while (GLenum error = hooks->gl.glGetError())
         LOGD("DbgContext::glUseProgram: before glGetError() = 0x%.4X", error);
-        
+
     this->program = program;
 
     GLint activeAttributes = 0;
@@ -107,7 +126,7 @@
             maxAttrib = slot;
     }
     delete name;
-    
+
     while (GLenum error = hooks->gl.glGetError())
         LOGD("DbgContext::glUseProgram: after glGetError() = 0x%.4X", error);
 }
diff --git a/opengl/libs/GLES2_dbg/src/header.h b/opengl/libs/GLES2_dbg/src/header.h
index b79cc0f..21b1dfb 100644
--- a/opengl/libs/GLES2_dbg/src/header.h
+++ b/opengl/libs/GLES2_dbg/src/header.h
@@ -57,6 +57,12 @@
 {
 
 struct DbgContext {
+private:
+    unsigned lzf_bufSize;
+    
+public:
+    char * lzf_buf;
+    
     const unsigned version; // 0 is GLES1, 1 is GLES2
     const gl_hooks_t * const hooks;
     const unsigned MAX_VERTEX_ATTRIBS;
@@ -93,7 +99,8 @@
     ~DbgContext();
 
     void Fetch(const unsigned index, std::string * const data) const;
-
+    unsigned Compress(const void * in_data, unsigned in_len); // compressed to lzf_buf
+    
     void glUseProgram(GLuint program);
     void glEnableVertexAttribArray(GLuint index);
     void glDisableVertexAttribArray(GLuint index);
diff --git a/opengl/libs/GLES2_dbg/src/texture.cpp b/opengl/libs/GLES2_dbg/src/texture.cpp
index 3aa0aab..5ef99f60 100644
--- a/opengl/libs/GLES2_dbg/src/texture.cpp
+++ b/opengl/libs/GLES2_dbg/src/texture.cpp
@@ -50,89 +50,11 @@
         return 0;
     }
 }
-
-#define USE_RLE 0
-#if USE_RLE
-export template<typename T>
-void * RLEEncode(const void * pixels, unsigned count, unsigned * encodedSize)
-{
-    // first is a byte indicating data size [1,2,4] bytes
-    // then an unsigned indicating decompressed size
-    // then a byte of header: MSB == 1 indicates run, else literal
-    // LSB7 is run or literal length (actual length - 1)
-
-    const T * data = (T *)pixels;
-    unsigned bufferSize = sizeof(T) * count / 2 + 8;
-    unsigned char * buffer = (unsigned char *)malloc(bufferSize);
-    buffer[0] = sizeof(T);
-    unsigned bufferWritten = 1; // number of bytes written
-    *(unsigned *)(buffer + bufferWritten) = count;
-    bufferWritten += sizeof(count);
-    while (count) {
-        unsigned char run = 1;
-        bool repeat = true;
-        for (run = 1; run < count; run++)
-            if (data[0] != data[run]) {
-                repeat = false;
-                break;
-            } else if (run > 126)
-                break;
-        if (!repeat) {
-            // find literal length
-            for (run = 1; run < count; run++)
-                if (data[run - 1] == data[run])
-                    break;
-                else if (run > 126)
-                    break;
-            unsigned bytesToWrite = 1 + sizeof(T) * run;
-            if (bufferWritten + bytesToWrite > bufferSize) {
-                bufferSize += sizeof(T) * run + 256;
-                buffer = (unsigned char *)realloc(buffer, bufferSize);
-            }
-            buffer[bufferWritten++] = run - 1;
-            for (unsigned i = 0; i < run; i++) {
-                *(T *)(buffer + bufferWritten) = *data;
-                bufferWritten += sizeof(T);
-                data++;
-            }
-            count -= run;
-        } else {
-            unsigned bytesToWrite = 1 + sizeof(T);
-            if (bufferWritten + bytesToWrite > bufferSize) {
-                bufferSize += 256;
-                buffer = (unsigned char *)realloc(buffer, bufferSize);
-            }
-            buffer[bufferWritten++] = (run - 1) | 0x80;
-            *(T *)(buffer + bufferWritten) = data[0];
-            bufferWritten += sizeof(T);
-            data += run;
-            count -= run;
-        }
-    }
-    if (encodedSize)
-        *encodedSize = bufferWritten;
-    return buffer;
-}
-
-void * RLEEncode(const void * pixels, const unsigned bytesPerPixel, const unsigned count, unsigned * encodedSize)
-{
-    switch (bytesPerPixel) {
-    case 4:
-        return RLEEncode<int>(pixels, count, encodedSize);
-    case 2:
-        return RLEEncode<short>(pixels, count, encodedSize);
-    case 1:
-        return RLEEncode<char>(pixels, count, encodedSize);
-    default:
-        assert(0);
-        return NULL;
-    }
-}
-#endif
 }; // namespace android
 
 void Debug_glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels)
 {
+    DbgContext * const dbg = getDbgContextThreadSpecific();
     glesv2debugger::Message msg;
     const bool expectResponse = false;
     struct : public FunctionCall {
@@ -179,27 +101,19 @@
 
         unsigned bytesPerPixel = GetBytesPerPixel(format, type);
         assert(0 < bytesPerPixel);
-
 //        LOGD("GLESv2_dbg: glTexImage2D width=%d height=%d level=%d bytesPerPixel=%d",
 //             width, height, level, bytesPerPixel);
-#if USE_RLE
-        unsigned encodedSize = 0;
-        void * data = RLEEncode(pixels, bytesPerPixel, width * height, &encodedSize);
-        msg.set_data(data, encodedSize);
-        free(data);
-        if (encodedSize > bytesPerPixel * width * height)
-            LOGD("GLESv2_dbg: glTexImage2D sending data encodedSize=%d size=%d", encodedSize, bytesPerPixel * width * height);
-#else
-        msg.set_data(pixels, bytesPerPixel * width * height);
-#endif
+        unsigned compressedSize = dbg->Compress(pixels, bytesPerPixel * width * height);
+        msg.set_data(dbg->lzf_buf, compressedSize);
     }
-    
+
     int * ret = MessageLoop(caller, msg, expectResponse,
                             glesv2debugger::Message_Function_glTexImage2D);
 }
 
 void Debug_glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels)
 {
+    DbgContext * const dbg = getDbgContextThreadSpecific();
     glesv2debugger::Message msg;
     const bool expectResponse = false;
     struct : public FunctionCall {
@@ -244,22 +158,12 @@
     if (pixels) {
         unsigned bytesPerPixel = GetBytesPerPixel(format, type);
         assert(0 < bytesPerPixel);
-
 //        LOGD("GLESv2_dbg: glTexSubImage2D width=%d height=%d level=%d bytesPerPixel=%d",
 //             width, height, level, bytesPerPixel);
-
-#if USE_RLE
-        unsigned encodedSize = 0;
-        void * data = RLEEncode(pixels, bytesPerPixel, width * height, &encodedSize);
-        msg.set_data(data, encodedSize);
-        free(data);
-        if (encodedSize > bytesPerPixel * width * height)
-            LOGD("GLESv2_dbg: glTexImage2D sending data encodedSize=%d size=%d", encodedSize, bytesPerPixel * width * height);
-#else
-        msg.set_data(pixels, bytesPerPixel * width * height);
-#endif
+        unsigned compressedSize = dbg->Compress(pixels, bytesPerPixel * width * height);
+        msg.set_data(dbg->lzf_buf, compressedSize);
     }
-    
+
     int * ret = MessageLoop(caller, msg, expectResponse,
                             glesv2debugger::Message_Function_glTexSubImage2D);
-}
\ No newline at end of file
+}
diff --git a/opengl/libs/GLES2_dbg/src/vertex.cpp b/opengl/libs/GLES2_dbg/src/vertex.cpp
index a73967f..c4598f5 100644
--- a/opengl/libs/GLES2_dbg/src/vertex.cpp
+++ b/opengl/libs/GLES2_dbg/src/vertex.cpp
@@ -19,8 +19,6 @@
 namespace android
 {
 bool capture; // capture after each glDraw*
-
-void * RLEEncode(const void * pixels, const unsigned bytesPerPixel, const unsigned count, unsigned * encodedSize);
 }
 
 void Debug_glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels)
@@ -39,8 +37,9 @@
     msg.set_arg4(format);
     msg.set_arg5(type);
     msg.set_arg6(reinterpret_cast<int>(pixels));
-    //void * data = NULL;
-    //unsigned encodedSize = 0;
+    
+    const unsigned size = width * height * GetBytesPerPixel(format, type);
+    unsigned compressed = 0;
     if (!expectResponse)
         cmd.set_function(glesv2debugger::Message_Function_CONTINUE);
     Send(msg, cmd);
@@ -56,21 +55,11 @@
             msg.set_function(glesv2debugger::Message_Function_glReadPixels);
             msg.set_type(glesv2debugger::Message_Type_AfterCall);
             msg.set_expect_response(expectResponse);
-            //data = RLEEncode(pixels, GetBytesPerPixel(format, type), width * height, &encodedSize);
-            msg.set_data(pixels, width * height * GetBytesPerPixel(format, type));
-            //msg.set_data(data, encodedSize);
-            //free(data);
-            c0 = systemTime(timeMode);
+            compressed = dbg->Compress(pixels, size);
+            msg.set_data(dbg->lzf_buf, compressed);
             if (!expectResponse)
                 cmd.set_function(glesv2debugger::Message_Function_SKIP);
-            t = Send(msg, cmd);
-            msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
-            msg.set_clock(t);
-            // time is total send time in seconds, clock is msg serialization time in seconds
-            msg.clear_data();
-            msg.set_expect_response(false);
-            msg.set_type(glesv2debugger::Message_Type_AfterCall);
-            //Send(msg, cmd);
+            Send(msg, cmd);
             break;
         case glesv2debugger::Message_Function_SKIP:
             return;
@@ -129,8 +118,8 @@
                 dbg->hooks->gl.glGetIntegerv(GL_VIEWPORT, viewport);
                 dbg->hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &readFormat);
                 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);
+//                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);
                 Debug_glReadPixels(viewport[0], viewport[1], viewport[2], viewport[3],
                                    readFormat, readType, pixels);
@@ -215,8 +204,8 @@
                 dbg->hooks->gl.glGetIntegerv(GL_VIEWPORT, viewport);
                 dbg->hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &readFormat);
                 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);
+//                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);
                 Debug_glReadPixels(viewport[0], viewport[1], viewport[2], viewport[3],
                                    readFormat, readType, pixels);