GLES2Debugger: Make command exchange async to improve performance.

In message loop, use select to check for available commands from client,
 rather than always expecting commands in eglSwapBuffers.

Change-Id: Ifc34dd77c2528c8b9c71f594e3eda4f93400cd2b
Signed-off-by: David Li <davidxli@google.com>
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 861d7ac..4d80075 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -340,7 +340,10 @@
     }
     
     if (gEGLDebugLevel > 0)
-        StartDebugServer();
+    {
+        property_get("debug.egl.debug_port", value, "5039");
+        StartDebugServer(atoi(value));
+    }
 }
 
 static void setGLHooksThreadSpecific(gl_hooks_t const *value) {
@@ -350,7 +353,6 @@
     } else if (gEGLDebugLevel > 0 && value != &gHooksNoContext) {
         setGlTraceThreadSpecific(value);
         setGlThreadSpecific(&gHooksDebug);
-        LOGD("\n* setGLHooksThreadSpecific gHooksDebug");
     } else {
         setGlThreadSpecific(value);
     }
diff --git a/opengl/libs/GLES2_dbg/generate_debugger_message_proto.py b/opengl/libs/GLES2_dbg/generate_debugger_message_proto.py
index b14885b..48a29da 100755
--- a/opengl/libs/GLES2_dbg/generate_debugger_message_proto.py
+++ b/opengl/libs/GLES2_dbg/generate_debugger_message_proto.py
@@ -98,9 +98,6 @@
     output.write("        SETPROP = %d;\n" % (i))
     i += 1
     
-    output.write("        CAPTURE = %d;\n" % (i))
-    i += 1
-
     output.write("""    }
     required Function function = 2 [default = NEG]; // type/function of message
     enum Type
diff --git a/opengl/libs/GLES2_dbg/src/dbgcontext.cpp b/opengl/libs/GLES2_dbg/src/dbgcontext.cpp
index 68514df..5c418258 100644
--- a/opengl/libs/GLES2_dbg/src/dbgcontext.cpp
+++ b/opengl/libs/GLES2_dbg/src/dbgcontext.cpp
@@ -65,8 +65,9 @@
 
 void DbgContext::glUseProgram(GLuint program)
 {
-    assert(GL_NO_ERROR == hooks->gl.glGetError());
-
+    while (GLenum error = hooks->gl.glGetError())
+        LOGD("DbgContext::glUseProgram: before glGetError() = 0x%.4X", error);
+        
     this->program = program;
 
     GLint activeAttributes = 0;
@@ -106,6 +107,9 @@
             maxAttrib = slot;
     }
     delete name;
+    
+    while (GLenum error = hooks->gl.glGetError())
+        LOGD("DbgContext::glUseProgram: after glGetError() = 0x%.4X", error);
 }
 
 static bool HasNonVBOAttribs(const DbgContext * const ctx)
diff --git a/opengl/libs/GLES2_dbg/src/debugger_message.pb.cpp b/opengl/libs/GLES2_dbg/src/debugger_message.pb.cpp
index 4083c44..1f404c2 100644
--- a/opengl/libs/GLES2_dbg/src/debugger_message.pb.cpp
+++ b/opengl/libs/GLES2_dbg/src/debugger_message.pb.cpp
@@ -229,7 +229,6 @@
     case 188:
     case 189:
     case 190:
-    case 191:
       return true;
     default:
       return false;
@@ -428,7 +427,6 @@
 const Message_Function Message::CONTINUE;
 const Message_Function Message::SKIP;
 const Message_Function Message::SETPROP;
-const Message_Function Message::CAPTURE;
 const Message_Function Message::Function_MIN;
 const Message_Function Message::Function_MAX;
 const int Message::Function_ARRAYSIZE;
diff --git a/opengl/libs/GLES2_dbg/src/debugger_message.pb.h b/opengl/libs/GLES2_dbg/src/debugger_message.pb.h
index 3f2b842..59e7bab 100644
--- a/opengl/libs/GLES2_dbg/src/debugger_message.pb.h
+++ b/opengl/libs/GLES2_dbg/src/debugger_message.pb.h
@@ -226,12 +226,11 @@
   Message_Function_NEG = 187,
   Message_Function_CONTINUE = 188,
   Message_Function_SKIP = 189,
-  Message_Function_SETPROP = 190,
-  Message_Function_CAPTURE = 191
+  Message_Function_SETPROP = 190
 };
 bool Message_Function_IsValid(int value);
 const Message_Function Message_Function_Function_MIN = Message_Function_glActiveTexture;
-const Message_Function Message_Function_Function_MAX = Message_Function_CAPTURE;
+const Message_Function Message_Function_Function_MAX = Message_Function_SETPROP;
 const int Message_Function_Function_ARRAYSIZE = Message_Function_Function_MAX + 1;
 
 enum Message_Type {
@@ -488,7 +487,6 @@
   static const Function CONTINUE = Message_Function_CONTINUE;
   static const Function SKIP = Message_Function_SKIP;
   static const Function SETPROP = Message_Function_SETPROP;
-  static const Function CAPTURE = Message_Function_CAPTURE;
   static inline bool Function_IsValid(int value) {
     return Message_Function_IsValid(value);
   }
diff --git a/opengl/libs/GLES2_dbg/src/egl.cpp b/opengl/libs/GLES2_dbg/src/egl.cpp
index b3979a3..27c7f7e 100644
--- a/opengl/libs/GLES2_dbg/src/egl.cpp
+++ b/opengl/libs/GLES2_dbg/src/egl.cpp
@@ -19,7 +19,7 @@
 EGLBoolean Debug_eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
 {
     glesv2debugger::Message msg;
-    const bool expectResponse = true;
+    const bool expectResponse = false;
     struct : public FunctionCall {
         EGLDisplay dpy;
         EGLSurface draw;
diff --git a/opengl/libs/GLES2_dbg/src/header.h b/opengl/libs/GLES2_dbg/src/header.h
index cbd448a..b79cc0f 100644
--- a/opengl/libs/GLES2_dbg/src/header.h
+++ b/opengl/libs/GLES2_dbg/src/header.h
@@ -113,7 +113,7 @@
     virtual ~FunctionCall() {}
 };
 
-// move these into DbgContext
+// move these into DbgContext as static
 extern bool capture;
 extern int timeMode; // SYSTEM_TIME_
 
@@ -121,8 +121,10 @@
 
 unsigned GetBytesPerPixel(const GLenum format, const GLenum type);
 
+// every Debug_gl* function calls this to send message to client and possibly receive commands
 int * MessageLoop(FunctionCall & functionCall, glesv2debugger::Message & msg,
                   const bool expectResponse, const glesv2debugger::Message_Function function);
+
 void Receive(glesv2debugger::Message & cmd);
 float Send(const glesv2debugger::Message & msg, glesv2debugger::Message & cmd);
 void SetProp(const glesv2debugger::Message & cmd);
diff --git a/opengl/libs/GLES2_dbg/src/server.cpp b/opengl/libs/GLES2_dbg/src/server.cpp
index 820e9de..03c3dae 100644
--- a/opengl/libs/GLES2_dbg/src/server.cpp
+++ b/opengl/libs/GLES2_dbg/src/server.cpp
@@ -38,7 +38,7 @@
     exit(1);
 }
 
-void StartDebugServer()
+void StartDebugServer(unsigned short port)
 {
     LOGD("GLESv2_dbg: StartDebugServer");
     if (serverSock >= 0)
@@ -53,8 +53,8 @@
     }
     /* Construct the server sockaddr_in structure */
     server.sin_family = AF_INET;                  /* Internet/IP */
-    server.sin_addr.s_addr = htonl(INADDR_ANY);   /* Incoming addr */
-    server.sin_port = htons(5039);       /* server port */
+    server.sin_addr.s_addr = htonl(INADDR_LOOPBACK);   /* Incoming addr */
+    server.sin_port = htons(port);       /* server port */
 
     /* Bind the server socket */
     socklen_t sizeofSockaddr_in = sizeof(sockaddr_in);
@@ -79,13 +79,6 @@
 
     LOGD("Client connected: %s\n", inet_ntoa(client.sin_addr));
 //    fcntl(clientSock, F_SETFL, O_NONBLOCK);
-
-    glesv2debugger::Message msg, cmd;
-    msg.set_context_id(0);
-    msg.set_function(glesv2debugger::Message_Function_ACK);
-    msg.set_type(glesv2debugger::Message_Type_Response);
-    msg.set_expect_response(false);
-    Send(msg, cmd);
 }
 
 void StopDebugServer()
@@ -130,6 +123,27 @@
     cmd.ParseFromArray(buffer, len);
 }
 
+bool TryReceive(glesv2debugger::Message & cmd)
+{
+    fd_set readSet;
+    FD_ZERO(&readSet);
+    FD_SET(clientSock, &readSet);
+    timeval timeout;
+    timeout.tv_sec = timeout.tv_usec = 0;
+
+    int rc = select(clientSock + 1, &readSet, NULL, NULL, &timeout);
+    if (rc < 0)
+        Die("failed to select clientSock");
+
+    bool received = false;
+    if (FD_ISSET(clientSock, &readSet)) {
+        LOGD("TryReceive: avaiable for read");
+        Receive(cmd);
+        return true;
+    }
+    return false;
+}
+
 float Send(const glesv2debugger::Message & msg, glesv2debugger::Message & cmd)
 {
     static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
@@ -155,12 +169,18 @@
         Die("Failed to send message");
     }
 
+    // try to receive commands even though not expecting response,
+    // since client can send SETPROP commands anytime
     if (!msg.expect_response()) {
-        pthread_mutex_unlock(&mutex);
-        return t;
-    }
-
-    Receive(cmd);
+        if (TryReceive(cmd)) {
+            LOGD("Send: TryReceived");
+            if (glesv2debugger::Message_Function_SETPROP == cmd.function())
+                LOGD("Send: received SETPROP");
+            else
+                LOGD("Send: received something else");
+        }
+    } else
+        Receive(cmd);
 
     //LOGD("Message sent tid=%lu len=%d", pthread_self(), str.length());
     pthread_mutex_unlock(&mutex);
@@ -193,24 +213,26 @@
     msg.set_type(glesv2debugger::Message_Type_BeforeCall);
     msg.set_expect_response(expectResponse);
     msg.set_function(function);
-    Send(msg, cmd);
     if (!expectResponse)
         cmd.set_function(glesv2debugger::Message_Function_CONTINUE);
+    Send(msg, cmd);
     while (true) {
         msg.Clear();
         nsecs_t c0 = systemTime(timeMode);
         switch (cmd.function()) {
         case glesv2debugger::Message_Function_CONTINUE:
             ret = functionCall(&dbg->hooks->gl, msg);
+            while (GLenum error = dbg->hooks->gl.glGetError())
+                LOGD("Function=%u glGetError() = 0x%.4X", function, error);
             if (!msg.has_time()) // some has output data copy, so time inside call
                 msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
             msg.set_context_id(reinterpret_cast<int>(dbg));
             msg.set_function(function);
             msg.set_type(glesv2debugger::Message_Type_AfterCall);
             msg.set_expect_response(expectResponse);
-            Send(msg, cmd);
             if (!expectResponse)
                 cmd.set_function(glesv2debugger::Message_Function_SKIP);
+            Send(msg, cmd);
             break;
         case glesv2debugger::Message_Function_SKIP:
             return const_cast<int *>(ret);
diff --git a/opengl/libs/GLES2_dbg/src/vertex.cpp b/opengl/libs/GLES2_dbg/src/vertex.cpp
index 52ce907..a73967f 100644
--- a/opengl/libs/GLES2_dbg/src/vertex.cpp
+++ b/opengl/libs/GLES2_dbg/src/vertex.cpp
@@ -41,10 +41,10 @@
     msg.set_arg6(reinterpret_cast<int>(pixels));
     //void * data = NULL;
     //unsigned encodedSize = 0;
-    Send(msg, cmd);
-    float t = 0;
     if (!expectResponse)
         cmd.set_function(glesv2debugger::Message_Function_CONTINUE);
+    Send(msg, cmd);
+    float t = 0;
     while (true) {
         msg.Clear();
         nsecs_t c0 = systemTime(timeMode);
@@ -61,6 +61,8 @@
             //msg.set_data(data, encodedSize);
             //free(data);
             c0 = systemTime(timeMode);
+            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);
@@ -69,11 +71,13 @@
             msg.set_expect_response(false);
             msg.set_type(glesv2debugger::Message_Type_AfterCall);
             //Send(msg, cmd);
-            if (!expectResponse)
-                cmd.set_function(glesv2debugger::Message_Function_SKIP);
             break;
         case glesv2debugger::Message_Function_SKIP:
             return;
+        case glesv2debugger::Message_Function_SETPROP:
+            SetProp(cmd);
+            Receive(cmd);
+            break;
         default:
             assert(0); //GenerateCall(msg, cmd);
             break;
@@ -104,9 +108,9 @@
     void * pixels = NULL;
     GLint readFormat = 0, readType = 0;
     int viewport[4] = {};
-    Send(msg, cmd);
     if (!expectResponse)
         cmd.set_function(glesv2debugger::Message_Function_CONTINUE);
+    Send(msg, cmd);
     while (true) {
         msg.Clear();
         nsecs_t c0 = systemTime(timeMode);
@@ -118,25 +122,26 @@
             msg.set_function(glesv2debugger::Message_Function_glDrawArrays);
             msg.set_type(glesv2debugger::Message_Type_AfterCall);
             msg.set_expect_response(expectResponse);
-            Send(msg, cmd);
-            if (capture)
-                cmd.set_function(glesv2debugger::Message_Function_CAPTURE);
-            else if (!expectResponse)
+            if (!expectResponse)
                 cmd.set_function(glesv2debugger::Message_Function_SKIP);
+            Send(msg, cmd);
+            if (capture) {
+                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);
+                pixels = malloc(viewport[2] * viewport[3] * 4);
+                Debug_glReadPixels(viewport[0], viewport[1], viewport[2], viewport[3],
+                                   readFormat, readType, pixels);
+                free(pixels);
+            }
             break;
         case glesv2debugger::Message_Function_SKIP:
             return;
-        case glesv2debugger::Message_Function_CAPTURE:
-            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);
-            pixels = malloc(viewport[2] * viewport[3] * 4);
-            Debug_glReadPixels(viewport[0], viewport[1], viewport[2], viewport[3],
-                               readFormat, readType, pixels);
-            free(pixels);
-            cmd.set_function(glesv2debugger::Message_Function_SKIP);
+        case glesv2debugger::Message_Function_SETPROP:
+            SetProp(cmd);
+            Receive(cmd);
             break;
         default:
             assert(0); //GenerateCall(msg, cmd);
@@ -189,9 +194,9 @@
     void * pixels = NULL;
     GLint readFormat = 0, readType = 0;
     int viewport[4] = {};
-    Send(msg, cmd);
     if (!expectResponse)
         cmd.set_function(glesv2debugger::Message_Function_CONTINUE);
+    Send(msg, cmd);
     while (true) {
         msg.Clear();
         nsecs_t c0 = systemTime(timeMode);
@@ -203,25 +208,26 @@
             msg.set_function(glesv2debugger::Message_Function_glDrawElements);
             msg.set_type(glesv2debugger::Message_Type_AfterCall);
             msg.set_expect_response(expectResponse);
-            Send(msg, cmd);
-            if (capture)
-                cmd.set_function(glesv2debugger::Message_Function_CAPTURE);
-            else if (!expectResponse)
+            if (!expectResponse)
                 cmd.set_function(glesv2debugger::Message_Function_SKIP);
+            Send(msg, cmd);
+            if (capture) {
+                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);
+                pixels = malloc(viewport[2] * viewport[3] * 4);
+                Debug_glReadPixels(viewport[0], viewport[1], viewport[2], viewport[3],
+                                   readFormat, readType, pixels);
+                free(pixels);
+            }
             break;
         case glesv2debugger::Message_Function_SKIP:
             return;
-        case glesv2debugger::Message_Function_CAPTURE:
-            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);
-            pixels = malloc(viewport[2] * viewport[3] * 4);
-            Debug_glReadPixels(viewport[0], viewport[1], viewport[2], viewport[3],
-                               readFormat, readType, pixels);
-            free(pixels);
-            cmd.set_function(glesv2debugger::Message_Function_SKIP);
+        case glesv2debugger::Message_Function_SETPROP:
+            SetProp(cmd);
+            Receive(cmd);
             break;
         default:
             assert(0); //GenerateCall(msg, cmd);
diff --git a/opengl/libs/glesv2dbg.h b/opengl/libs/glesv2dbg.h
index b988eb7..8029dce 100644
--- a/opengl/libs/glesv2dbg.h
+++ b/opengl/libs/glesv2dbg.h
@@ -24,7 +24,7 @@
     DbgContext * CreateDbgContext(const unsigned version, const gl_hooks_t * const hooks);
     void DestroyDbgContext(DbgContext * const dbg);
     
-    void StartDebugServer(); // create and bind socket if haven't already
+    void StartDebugServer(unsigned short port); // create and bind socket if haven't already
     void StopDebugServer(); // close socket if open
     
 }; // namespace android