emulator: opengl: Add custom_write optimization to encoder.

This patch allows an auto-generated GLES encoder function to write
'isLarge' buffers with a custom writer, instead of calling stream->readFully()
directly.

This is intended to allow writing pixel or vertex data that is stored
with a specific stride.

Another patch will introduce the corresponding changes to the .attrib files

Change-Id: I6ca86b968cd3f4db91676bc485ee1e84419e50e0
diff --git a/tools/emulator/opengl/host/tools/emugen/ApiGen.cpp b/tools/emulator/opengl/host/tools/emugen/ApiGen.cpp
index 72b7bb3..4265301 100644
--- a/tools/emulator/opengl/host/tools/emugen/ApiGen.cpp
+++ b/tools/emulator/opengl/host/tools/emugen/ApiGen.cpp
@@ -436,7 +436,12 @@
     } else {
         fprintf(fp, "\t");
     }
-    fprintf(fp, "stream->writeFully(%s, __size_%s);\n", varname, varname);
+    if (var.writeExpression() != "") {
+        fprintf(fp, "%s", var.writeExpression().c_str());
+    } else {
+        fprintf(fp, "stream->writeFully(%s, __size_%s)", varname, varname);
+    }
+    fprintf(fp, ";\n");
 }
 #endif /* WITH_LARGE_SUPPORT */
 
diff --git a/tools/emulator/opengl/host/tools/emugen/EntryPoint.cpp b/tools/emulator/opengl/host/tools/emugen/EntryPoint.cpp
index 044433d..43b904b 100644
--- a/tools/emulator/opengl/host/tools/emugen/EntryPoint.cpp
+++ b/tools/emulator/opengl/host/tools/emugen/EntryPoint.cpp
@@ -119,7 +119,7 @@
         fprintf(stderr, "UNKNOWN retval: %s\n", linestr.c_str());
     }
 
-    m_retval.init(std::string(""), theType, std::string(""), Var::POINTER_OUT, std::string(""));
+    m_retval.init(std::string(""), theType, std::string(""), Var::POINTER_OUT, std::string(""), std::string(""));
 
     // function name
     m_name = getNextToken(linestr, pos, &last, ",)");
@@ -146,7 +146,7 @@
                 varname = oss.str();
             }
 
-            m_vars.push_back(Var(varname, v, std::string(""), Var::POINTER_IN, ""));
+            m_vars.push_back(Var(varname, v, std::string(""), Var::POINTER_IN, "", ""));
         }
         pos = last + 1;
     }
@@ -334,6 +334,23 @@
         // set the size expression into var
         pos = last;
         v->setPackExpression(line.substr(pos));
+    } else if (token == "custom_write") {
+        pos = last;
+        std::string varname = getNextToken(line, pos, &last, WHITESPACE);
+
+        if (varname.size() == 0) {
+            fprintf(stderr, "ERROR: %u: Missing variable name in 'custom_write' attribute\n", (unsigned int)lc);
+            return -1;
+        }
+        Var * v = var(varname);
+        if (v == NULL) {
+            fprintf(stderr, "ERROR: %u: variable %s is not a parameter of %s\n",
+                    (unsigned int)lc, varname.c_str(), name().c_str());
+            return -2;
+        }
+        // set the size expression into var
+        pos = last;
+        v->setWriteExpression(line.substr(pos));
     } else if (token == "flag") {
         pos = last;
         std::string flag = getNextToken(line, pos, &last, WHITESPACE);
diff --git a/tools/emulator/opengl/host/tools/emugen/Var.h b/tools/emulator/opengl/host/tools/emugen/Var.h
index 658b805..322c66a 100644
--- a/tools/emulator/opengl/host/tools/emugen/Var.h
+++ b/tools/emulator/opengl/host/tools/emugen/Var.h
@@ -32,6 +32,7 @@
         m_nullAllowed(false),
         m_isLarge(false),
         m_packExpression(""),
+        m_writeExpression(""),
         m_paramCheckExpression("")
 
     {
@@ -41,7 +42,8 @@
         const VarType * vartype,
         const std::string & lenExpression,
         PointerDir dir,
-        const std::string &packExpression) :
+        const std::string &packExpression,
+        const std::string &writeExpression) :
         m_name(name),
         m_type(const_cast<VarType *>(vartype)),
         m_lenExpression(lenExpression),
@@ -49,17 +51,21 @@
         m_nullAllowed(false),
         m_isLarge(false),
         m_packExpression(packExpression),
+        m_writeExpression(writeExpression),
 	m_paramCheckExpression("")
     {
     }
 
     void init(const std::string name, const VarType * vartype,
               std::string lenExpression,
-              PointerDir dir, std::string packExpression) {
+              PointerDir dir,
+              std::string packExpression,
+              std::string writeExpression) {
         m_name = name;
         m_type = vartype;
         m_lenExpression = lenExpression;
         m_packExpression = packExpression;
+        m_writeExpression = writeExpression;
         m_pointerDir = dir;
         m_nullAllowed = false;
         m_isLarge = false;
@@ -72,9 +78,11 @@
     bool isVoid() const { return ((m_type->bytes() == 0) && (!m_type->isPointer())); }
     const std::string & lenExpression() const { return m_lenExpression; }
     const std::string & packExpression() const { return(m_packExpression); }
+    const std::string & writeExpression() const { return(m_writeExpression); }
     const std::string & paramCheckExpression() const { return m_paramCheckExpression; }
     void setLenExpression(const std::string & lenExpression) { m_lenExpression = lenExpression; }
     void setPackExpression(const std::string & packExpression) { m_packExpression = packExpression; }
+    void setWriteExpression(const std::string & writeExpression) { m_writeExpression = writeExpression; }
     void setParamCheckExpression(const std::string & paramCheckExpression) { m_paramCheckExpression = paramCheckExpression; }
     void setPointerDir(PointerDir dir) { m_pointerDir = dir; }
     PointerDir pointerDir() { return m_pointerDir; }
@@ -94,6 +102,7 @@
     bool m_nullAllowed;
     bool m_isLarge;
     std::string m_packExpression; // an expression to pack data into the stream
+    std::string m_writeExpression; // an expression to write data into the stream
     std::string m_paramCheckExpression; //an expression to check parameter value
 
 };
diff --git a/tools/emulator/opengl/shared/OpenglCodecCommon/glUtils.cpp b/tools/emulator/opengl/shared/OpenglCodecCommon/glUtils.cpp
index b0702a7..ae70598 100644
--- a/tools/emulator/opengl/shared/OpenglCodecCommon/glUtils.cpp
+++ b/tools/emulator/opengl/shared/OpenglCodecCommon/glUtils.cpp
@@ -16,6 +16,7 @@
 #include "glUtils.h"
 #include <string.h>
 #include "ErrorLog.h"
+#include <IOStream.h>
 
 size_t glSizeof(GLenum type)
 {
@@ -344,6 +345,25 @@
     }
 }
 
+void glUtilsWritePackPointerData(void* _stream, unsigned char *src,
+                                 int size, GLenum type, unsigned int stride,
+                                 unsigned int datalen)
+{
+    IOStream* stream = reinterpret_cast<IOStream*>(_stream);
+
+    unsigned int  vsize = size * glSizeof(type);
+    if (stride == 0) stride = vsize;
+
+    if (stride == vsize) {
+        stream->writeFully(src, datalen);
+    } else {
+        for (unsigned int i = 0; i < datalen; i += vsize) {
+            stream->writeFully(src, (size_t)vsize);
+            src += stride;
+        }
+    }
+}
+
 int glUtilsPixelBitSize(GLenum format, GLenum type)
 {
     int components = 0;
diff --git a/tools/emulator/opengl/shared/OpenglCodecCommon/glUtils.h b/tools/emulator/opengl/shared/OpenglCodecCommon/glUtils.h
index c66c568..f8857f1 100644
--- a/tools/emulator/opengl/shared/OpenglCodecCommon/glUtils.h
+++ b/tools/emulator/opengl/shared/OpenglCodecCommon/glUtils.h
@@ -51,6 +51,9 @@
     void   glUtilsPackPointerData(unsigned char *dst, unsigned char *str,
                            int size, GLenum type, unsigned int stride,
                            unsigned int datalen);
+    void glUtilsWritePackPointerData(void* stream, unsigned char *src,
+                                    int size, GLenum type, unsigned int stride,
+                                    unsigned int datalen);
     int glUtilsPixelBitSize(GLenum format, GLenum type);
     void   glUtilsPackStrings(char *ptr, char **strings, GLint *length, GLsizei count);
     int glUtilsCalcShaderSourceLen(char **strings, GLint *length, GLsizei count);