diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..0ab2568d9687090645b14491436ae5eca2863ea0
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,22 @@
+*~
+*.bak
+*.pyc
+Thumbs.db
+*.class
+*.DS_Store
+testapps/testSensors/proguard.cfg
+.gradle
+/build/ivy.xml
+
+# Hide temporary files created by the build_server script
+eclipse/assemble.com.android.ide.eclipse.*.xml
+eclipse/package.com.android.ide.eclipse.*.xml
+eclipse/final*Versions*.properties
+eclipse/plugins/com.android.ide.eclipse.*/@dot*
+eclipse/plugins/com.android.*/javaCompiler...args
+eclipse/plugins/com.android.ide.eclipse.*/build.xml
+eclipse/features/com.android.ide.eclipse.*/build.xml
+eclipse/features/com.android.ide.eclipse.*/*.zip
+/eclipse/v[0-9-]*-[0-9]*
+/eclipse/v[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]
+/status-output
diff --git a/host/Android.bp b/host/Android.bp
new file mode 100644
index 0000000000000000000000000000000000000000..5464fac40f76977f96c0362825adead503e83f9c
--- /dev/null
+++ b/host/Android.bp
@@ -0,0 +1,5 @@
+cc_library_headers {
+  name: "virtio_gpu_uapi_headers",
+  host_supported: true,
+  export_include_dirs: ["linux_uapi"],
+}
diff --git a/host/commands/Android.bp b/host/commands/Android.bp
new file mode 100644
index 0000000000000000000000000000000000000000..485e2ef26e9c6f24a241c2d2feea1bcb3e9c74af
--- /dev/null
+++ b/host/commands/Android.bp
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+subdirs = [
+    "emugen",
+]
+
+python_binary_host {
+  name: "gen_entries_cuttlefish",
+  srcs: ["gen_entries.py"],
+  main: "gen_entries.py",
+  version: {
+    py2: {
+      enabled: true,
+    },
+    py3: {
+      enabled: false,
+    },
+  },
+}
diff --git a/host/commands/emugen/Android.bp b/host/commands/emugen/Android.bp
new file mode 100644
index 0000000000000000000000000000000000000000..516d116a04307ccb8bfa3311fb1c6f34af88130a
--- /dev/null
+++ b/host/commands/emugen/Android.bp
@@ -0,0 +1,12 @@
+cc_binary_host {
+    name: "emugen_cuttlefish",
+    srcs: [
+        "ApiGen.cpp",
+        "EntryPoint.cpp",
+        "main.cpp",
+        "Parser.cpp",
+        "strUtils.cpp",
+        "TypeFactory.cpp",
+    ],
+    cflags: ["-Wno-unused-parameter"],
+}
diff --git a/host/commands/emugen/ApiGen.cpp b/host/commands/emugen/ApiGen.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4b40dc67740813d5fb126e693401aeb6e7b2aa25
--- /dev/null
+++ b/host/commands/emugen/ApiGen.cpp
@@ -0,0 +1,1584 @@
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#include "ApiGen.h"
+#include "android/base/EnumFlags.h"
+#include "EntryPoint.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include "strUtils.h"
+#include <errno.h>
+#include <sys/types.h>
+
+/* Define this to 1 to enable support for the 'isLarge' variable flag
+ * that instructs the encoder to send large data buffers by a direct
+ * write through the pipe (i.e. without copying it into a temporary
+ * buffer. This has definite performance benefits when using a QEMU Pipe.
+ *
+ * Set to 0 otherwise.
+ */
+#define WITH_LARGE_SUPPORT  1
+
+// Set to 1 to ensure buffers passed to/from EGL/GL are properly aligned.
+// This prevents crashes with certain backends (e.g. OSMesa).
+#define USE_ALIGNED_BUFFERS 1
+
+// Set these to 1 if you want to instrument either guest's or host's code for
+// time-per-call printing.
+#define INSTRUMENT_TIMING_GUEST 0
+#define INSTRUMENT_TIMING_HOST 0
+
+// Set to 1 to print to logcat for every GL call encoded.
+#define DLOG_ALL_ENCODES 0
+
+// Set to 1 to check GL errors before and after every decoder call.
+#define DECODER_CHECK_GL_ERRORS 0
+
+EntryPoint * ApiGen::findEntryByName(const std::string & name)
+{
+    EntryPoint * entry = NULL;
+
+    size_t n = this->size();
+    for (size_t i = 0; i < n; i++) {
+        if (at(i).name() == name) {
+            entry = &(at(i));
+            break;
+        }
+    }
+    return entry;
+}
+
+void ApiGen::printHeader(FILE *fp) const
+{
+    fprintf(fp, "// Generated Code - DO NOT EDIT !!\n");
+    fprintf(fp, "// generated by 'emugen'\n");
+}
+
+int ApiGen::genProcTypes(const std::string &filename, SideType side)
+{
+    FILE *fp = fopen(filename.c_str(), "wt");
+    if (fp == NULL) {
+        perror(filename.c_str());
+        return -1;
+    }
+    printHeader(fp);
+
+    const char* basename = m_basename.c_str();
+
+    fprintf(fp, "#ifndef __%s_%s_proc_t_h\n", basename, sideString(side));
+    fprintf(fp, "#define __%s_%s_proc_t_h\n", basename, sideString(side));
+    fprintf(fp, "\n\n");
+    fprintf(fp, "\n#include \"%s_types.h\"\n",basename);
+    fprintf(fp, "#ifndef %s_APIENTRY\n",basename);
+    fprintf(fp, "#define %s_APIENTRY \n",basename);
+    fprintf(fp, "#endif\n");
+
+
+    for (size_t i = 0; i < size(); i++) {
+        EntryPoint *e = &at(i);
+
+        fprintf(fp, "typedef ");
+        e->retval().printType(fp);
+        fprintf(fp, " (%s_APIENTRY *%s_%s_proc_t) (", basename, e->name().c_str(), sideString(side));
+        if (side == CLIENT_SIDE) { fprintf(fp, "void * ctx"); }
+        if (e->customDecoder() && side == SERVER_SIDE) { fprintf(fp, "void *ctx"); }
+
+        VarsArray & evars = e->vars();
+        size_t n = evars.size();
+
+        for (size_t j = 0; j < n; j++) {
+            if (!evars[j].isVoid()) {
+                if (j != 0 || side == CLIENT_SIDE || (side == SERVER_SIDE && e->customDecoder())) fprintf(fp, ", ");
+                evars[j].printType(fp);
+            }
+        }
+        fprintf(fp, ");\n");
+
+        if (side == SERVER_SIDE && e->customDecoder() && !e->notApi()) {
+            fprintf(fp, "typedef ");
+            e->retval().printType(fp);
+            fprintf(fp, " (%s_APIENTRY *%s_dec_%s_proc_t) (", basename, e->name().c_str(), sideString(side));
+
+            VarsArray & evars = e->vars();
+            size_t n = evars.size();
+
+            for (size_t j = 0; j < n; j++) {
+                if (!evars[j].isVoid()) {
+                    if (j != 0) fprintf(fp, ", ");
+                    evars[j].printType(fp);
+                }
+            }
+            fprintf(fp, ");\n");
+        }
+    }
+    fprintf(fp, "\n\n#endif\n");
+    return 0;
+}
+
+int ApiGen::genFuncTable(const std::string &filename, SideType side)
+{
+    FILE *fp = fopen(filename.c_str(), "wt");
+    if (fp == NULL) {
+        perror(filename.c_str());
+        return -1;
+    }
+    printHeader(fp);
+
+    fprintf(fp, "#ifndef __%s_%s_ftable_t_h\n", m_basename.c_str(), sideString(side));
+    fprintf(fp, "#define __%s_%s_ftable_t_h\n", m_basename.c_str(), sideString(side));
+    fprintf(fp, "\n\n");
+    fprintf(fp, "static const struct _%s_funcs_by_name {\n", m_basename.c_str());
+    fprintf(fp,
+            "\tconst char *name;\n" \
+            "\tvoid *proc;\n" \
+            "} %s_funcs_by_name[] = {\n", m_basename.c_str());
+
+
+    for (size_t i = 0; i < size(); i++) {
+        EntryPoint *e = &at(i);
+        if (e->notApi()) continue;
+        fprintf(fp, "\t{\"%s\", (void*)%s},\n", e->name().c_str(), e->name().c_str());
+    }
+    fprintf(fp, "};\n");
+    fprintf(fp, "static const int %s_num_funcs = sizeof(%s_funcs_by_name) / sizeof(struct _%s_funcs_by_name);\n",
+            m_basename.c_str(), m_basename.c_str(), m_basename.c_str());
+    fprintf(fp, "\n\n#endif\n");
+    return 0;
+}
+
+int ApiGen::genContext(const std::string & filename, SideType side)
+{
+    FILE *fp = fopen(filename.c_str(), "wt");
+    if (fp == NULL) {
+        perror(filename.c_str());
+        return -1;
+    }
+    printHeader(fp);
+
+    fprintf(fp, "#ifndef __%s_%s_context_t_h\n", m_basename.c_str(), sideString(side));
+    fprintf(fp, "#define __%s_%s_context_t_h\n", m_basename.c_str(), sideString(side));
+
+    fprintf(fp, "\n#include \"%s_%s_proc.h\"\n",
+            m_basename.c_str(),
+            side == CLIENT_SIDE ? "client" : "server");
+    fprintf(fp, "\n#include \"%s_types.h\"\n", m_basename.c_str());
+
+    StringVec & contextHeaders = side == CLIENT_SIDE ? m_clientContextHeaders : m_serverContextHeaders;
+    for (size_t i = 0; i < contextHeaders.size(); i++) {
+        fprintf(fp, "#include %s\n", contextHeaders[i].c_str());
+    }
+    fprintf(fp, "\n");
+
+    fprintf(fp, "\nstruct %s_%s_context_t {\n\n",
+            m_basename.c_str(), sideString(side));
+
+    // API entry points
+    for (size_t i = 0; i < size(); i++) {
+        EntryPoint *e = &at(i);
+        if (side == SERVER_SIDE && e->customDecoder() && !e->notApi()) {
+            fprintf(fp, "\t%s_dec_%s_proc_t %s;\n", e->name().c_str(), sideString(side), e->name().c_str());
+            fprintf(fp, "\t%s_%s_proc_t %s_dec;\n", e->name().c_str(), sideString(side), e->name().c_str());
+        } else {
+            fprintf(fp, "\t%s_%s_proc_t %s;\n", e->name().c_str(), sideString(side), e->name().c_str());
+        }
+    }
+
+    // virtual destructor
+    fprintf(fp, "\tvirtual ~%s_%s_context_t() {}\n", m_basename.c_str(), sideString(side));
+    // accessor
+    if (side == CLIENT_SIDE || side == WRAPPER_SIDE) {
+        fprintf(fp, "\n\ttypedef %s_%s_context_t *CONTEXT_ACCESSOR_TYPE(void);\n",
+                m_basename.c_str(), sideString(side));
+        fprintf(fp, "\tstatic void setContextAccessor(CONTEXT_ACCESSOR_TYPE *f);\n");
+    }
+
+    // init function
+    fprintf(fp, "\tint initDispatchByName( void *(*getProc)(const char *name, void *userData), void *userData);\n");
+
+    //client site set error virtual func
+    if (side == CLIENT_SIDE) {
+        fprintf(fp, "\tvirtual void setError(unsigned int  error){ (void)error; };\n");
+        fprintf(fp, "\tvirtual unsigned int getError(){ return 0; };\n");
+    }
+
+    fprintf(fp, "};\n");
+
+    fprintf(fp, "\n#endif\n");
+    fclose(fp);
+    return 0;
+}
+
+int ApiGen::genEntryPoints(const std::string & filename, SideType side)
+{
+
+    if (side != CLIENT_SIDE && side != WRAPPER_SIDE) {
+        fprintf(stderr, "Entry points are only defined for Client and Wrapper components\n");
+        return -999;
+    }
+
+
+    FILE *fp = fopen(filename.c_str(), "wt");
+    if (fp == NULL) {
+        perror(filename.c_str());
+        return errno;
+    }
+
+    printHeader(fp);
+    fprintf(fp, "#include <stdio.h>\n");
+    fprintf(fp, "#include <stdlib.h>\n");
+    fprintf(fp, "#include \"%s_%s_context.h\"\n", m_basename.c_str(), sideString(side));
+    fprintf(fp, "\n");
+
+    fprintf(fp, "extern \"C\" {\n");
+
+    for (size_t i = 0; i < size(); i++) {
+        fprintf(fp, "\t"); at(i).print(fp, false); fprintf(fp, ";\n");
+    }
+    fprintf(fp, "};\n\n");
+
+    fprintf(fp, "#ifndef GET_CONTEXT\n");
+    fprintf(fp, "static %s_%s_context_t::CONTEXT_ACCESSOR_TYPE *getCurrentContext = NULL;\n",
+            m_basename.c_str(), sideString(side));
+
+    fprintf(fp,
+            "void %s_%s_context_t::setContextAccessor(CONTEXT_ACCESSOR_TYPE *f) { getCurrentContext = f; }\n",
+            m_basename.c_str(), sideString(side));
+    fprintf(fp, "#define GET_CONTEXT %s_%s_context_t * ctx = getCurrentContext()\n",
+                m_basename.c_str(), sideString(side));
+    fprintf(fp, "#endif\n\n");
+
+
+    for (size_t i = 0; i < size(); i++) {
+        EntryPoint *e = &at(i);
+        e->print(fp);
+        fprintf(fp, "{\n");
+        fprintf(fp, "\tGET_CONTEXT;\n");
+
+        bool shouldReturn = !e->retval().isVoid();
+        bool shouldCallWithContext = (side == CLIENT_SIDE);
+        //param check
+        if (shouldCallWithContext) {
+            for (size_t j=0; j<e->vars().size(); j++) {
+                if (e->vars()[j].paramCheckExpression() != "")
+                    fprintf(fp, "\t%s\n", e->vars()[j].paramCheckExpression().c_str());
+            }
+        }
+        fprintf(fp, "\t%sctx->%s(%s",
+                shouldReturn ? "return " : "",
+                e->name().c_str(),
+                shouldCallWithContext ? "ctx" : "");
+        size_t nvars = e->vars().size();
+
+        for (size_t j = 0; j < nvars; j++) {
+            if (!e->vars()[j].isVoid()) {
+                fprintf(fp, "%s %s",
+                        j != 0 || shouldCallWithContext ? "," : "",
+                        e->vars()[j].name().c_str());
+            }
+        }
+        fprintf(fp, ");\n");
+        fprintf(fp, "}\n\n");
+    }
+    fclose(fp);
+    return 0;
+}
+
+
+int ApiGen::genOpcodes(const std::string &filename)
+{
+    FILE *fp = fopen(filename.c_str(), "wt");
+    if (fp == NULL) {
+        perror(filename.c_str());
+        return errno;
+    }
+
+    printHeader(fp);
+    fprintf(fp, "#ifndef __GUARD_%s_opcodes_h_\n", m_basename.c_str());
+    fprintf(fp, "#define __GUARD_%s_opcodes_h_\n\n", m_basename.c_str());
+    for (size_t i = 0; i < size(); i++) {
+        fprintf(fp, "#define OP_%s \t\t\t\t\t%u\n", at(i).name().c_str(), (unsigned int)i + m_baseOpcode);
+    }
+    fprintf(fp, "#define OP_last \t\t\t\t\t%u\n", (unsigned int)size() + m_baseOpcode);
+    fprintf(fp,"\n\n#endif\n");
+    fclose(fp);
+    return 0;
+
+}
+int ApiGen::genAttributesTemplate(const std::string &filename )
+{
+    FILE *fp = fopen(filename.c_str(), "wt");
+    if (fp == NULL) {
+        perror(filename.c_str());
+        return -1;
+    }
+
+    for (size_t i = 0; i < size(); i++) {
+        if (at(i).hasPointers()) {
+            fprintf(fp, "#");
+            at(i).print(fp);
+            fprintf(fp, "%s\n\n", at(i).name().c_str());
+        }
+    }
+    fclose(fp);
+    return 0;
+}
+
+int ApiGen::genEncoderHeader(const std::string &filename)
+{
+    FILE *fp = fopen(filename.c_str(), "wt");
+    if (fp == NULL) {
+        perror(filename.c_str());
+        return -1;
+    }
+
+    printHeader(fp);
+    std::string classname = m_basename + "_encoder_context_t";
+
+    fprintf(fp, "\n#ifndef GUARD_%s\n", classname.c_str());
+    fprintf(fp, "#define GUARD_%s\n\n", classname.c_str());
+
+    fprintf(fp, "#include \"IOStream.h\"\n");
+    fprintf(fp, "#include \"ChecksumCalculator.h\"\n");
+    fprintf(fp, "#include \"%s_%s_context.h\"\n\n\n", m_basename.c_str(), sideString(CLIENT_SIDE));
+
+    for (size_t i = 0; i < m_encoderHeaders.size(); i++) {
+        fprintf(fp, "#include %s\n", m_encoderHeaders[i].c_str());
+    }
+    fprintf(fp, "\n");
+
+    fprintf(fp, "struct %s : public %s_%s_context_t {\n\n",
+            classname.c_str(), m_basename.c_str(), sideString(CLIENT_SIDE));
+    fprintf(fp, "\tIOStream *m_stream;\n");
+    fprintf(fp, "\tChecksumCalculator *m_checksumCalculator;\n\n");
+
+    fprintf(fp, "\t%s(IOStream *stream, ChecksumCalculator *checksumCalculator);\n", classname.c_str());
+    fprintf(fp, "\tvirtual uint64_t lockAndWriteDma(void* data, uint32_t sz) { return 0; }\n");
+    fprintf(fp, "};\n\n");
+
+    fprintf(fp, "#endif  // GUARD_%s\n", classname.c_str());
+
+    fclose(fp);
+    return 0;
+}
+
+// Format the byte length expression for a given variable into a user-provided buffer
+// If the variable type is not a pointer, this is simply its size as a decimal constant
+// If the variable is a pointer, this will be an expression provided by the .attrib file
+// through the 'len' attribute.
+//
+// Returns 1 if the variable is a pointer, 0 otherwise
+//
+enum class EncodingSizeFlags {
+    None = 0,
+    DmaPtrOnly = 1,
+    ExcludeOut = 2,
+    UseExistingVar = 4,
+};
+
+static int getVarEncodingSizeExpression(
+        Var& var, EntryPoint* e, char* buff, size_t bufflen,
+        EncodingSizeFlags flags)
+{
+    if (!var.isPointer()) {
+        snprintf(buff, bufflen, "%u", (unsigned int) var.type()->bytes());
+        return 0;
+    }
+
+    if ((flags & EncodingSizeFlags::DmaPtrOnly) != 0) {
+        snprintf(buff, bufflen, "8");
+    } else if ((flags & EncodingSizeFlags::ExcludeOut) != 0 &&
+            !(var.pointerDir() & Var::POINTER_IN)) {
+        snprintf(buff, bufflen, "0");
+    } else if ((flags & EncodingSizeFlags::UseExistingVar) != 0) {
+        snprintf(buff, bufflen, "__size_%s", var.name().c_str());
+    } else {
+        const char* lenExpr = var.lenExpression().c_str();
+        const char* varname = var.name().c_str();
+        if (e != NULL && lenExpr[0] == '\0') {
+            fprintf(stderr, "%s: data len is undefined for '%s'\n",
+                    e->name().c_str(), varname);
+        }
+        if (var.nullAllowed()) {
+            snprintf(buff, bufflen, "((%s != NULL) ? %s : 0)", varname, lenExpr);
+        } else {
+            snprintf(buff, bufflen, "%s", lenExpr);
+        }
+    }
+    return 1;
+}
+
+static int writeVarEncodingSize(Var& var, bool excludeOutVars, FILE* fp)
+{
+    int ret = 0;
+    if (!var.isPointer()) {
+        fprintf(fp, "%u", (unsigned int) var.type()->bytes());
+    } else {
+        ret = 1;
+        if (var.isDMA()) {
+            fprintf(fp, "8");
+            return ret;
+        }
+
+        if (excludeOutVars && !(var.pointerDir() & Var::POINTER_IN)) {
+            fprintf(fp, "0");
+        } else {
+            fprintf(fp, "__size_%s", var.name().c_str());
+        }
+    }
+    return ret;
+}
+
+static void writeVarEncodingExpression(Var& var, FILE* fp)
+{
+    const char* varname = var.name().c_str();
+
+    if (var.isPointer()) {
+        // encode a pointer header
+        if (var.isDMA()) {
+            fprintf(fp, "\t*(uint64_t *)(ptr) = ctx->lockAndWriteDma(%s, __size_%s); ptr += 8;\n", varname, varname);
+        } else {
+            fprintf(fp, "\t*(unsigned int *)(ptr) = __size_%s; ptr += 4;\n", varname);
+
+            Var::PointerDir dir = var.pointerDir();
+            if (dir == Var::POINTER_INOUT || dir == Var::POINTER_IN) {
+                if (var.nullAllowed()) {
+                    fprintf(fp, "\tif (%s != NULL) ", varname);
+                } else {
+                    fprintf(fp, "\t");
+                }
+
+                if (var.packExpression().size() != 0) {
+                    fprintf(fp, "%s;", var.packExpression().c_str());
+                } else {
+                    fprintf(fp, "memcpy(ptr, %s, __size_%s);",
+                            varname, varname);
+                }
+
+                fprintf(fp, "ptr += __size_%s;\n", varname);
+            }
+        }
+    } else {
+        // encode a non pointer variable
+        if (!var.isVoid()) {
+            fprintf(fp, "\t\tmemcpy(ptr, &%s, %u); ptr += %u;\n",
+                    varname,
+                    (unsigned) var.type()->bytes(),
+                    (unsigned) var.type()->bytes());
+        }
+    }
+}
+
+#if WITH_LARGE_SUPPORT
+static void writeVarLargeEncodingExpression(Var& var, FILE* fp)
+{
+    const char* varname = var.name().c_str();
+
+    fprintf(fp, "\tstream->writeFully(&__size_%s,4);\n", varname);
+    fprintf(fp, "\tif (useChecksum) checksumCalculator->addBuffer(&__size_%s,4);\n", varname);
+    if (var.nullAllowed()) {
+        fprintf(fp, "\tif (%s != NULL) {\n", varname);
+    }
+    if (var.writeExpression() != "") {
+        fprintf(fp, "%s", var.writeExpression().c_str());
+    } else {
+        fprintf(fp, "\t\tstream->writeFully(%s, __size_%s);\n", varname, varname);
+        fprintf(fp, "\t\tif (useChecksum) checksumCalculator->addBuffer(%s, __size_%s);\n", varname, varname);
+    }
+    if (var.nullAllowed()) fprintf(fp, "\t}\n");
+}
+#endif /* WITH_LARGE_SUPPORT */
+
+static void writeEncodingChecksumValidatorOnReturn(const char* funcName, FILE* fp) {
+    fprintf(fp, "\tif (useChecksum) {\n"
+                "\t\tunsigned char *checksumBufPtr = NULL;\n"
+                "\t\tunsigned char checksumBuf[ChecksumCalculator::kMaxChecksumSize];\n"
+                "\t\tif (checksumSize > 0) checksumBufPtr = &checksumBuf[0];\n"
+                "\t\tstream->readback(checksumBufPtr, checksumSize);\n"
+                "\t\tif (!checksumCalculator->validate(checksumBufPtr, checksumSize)) {\n"
+                "\t\t\tALOGE(\"%s: GL communication error, please report this issue to b.android.com.\\n\");\n"
+                "\t\t\tabort();\n"
+                "\t\t}\n"
+                "\t}\n",
+            funcName
+    );
+}
+
+static void addGuestTimePrinting(const EntryPoint* e, bool hasTimeBeforeReadback,
+                                 FILE* fp) {
+#if INSTRUMENT_TIMING_GUEST
+    fprintf(fp, "\tclock_gettime(CLOCK_REALTIME, &ts1);\n");
+    fprintf(fp, "\tlong timeDiff = ts1.tv_sec*1000000 + ts1.tv_nsec/1000 - (ts0.tv_sec*1000000 + ts0.tv_nsec/1000);\n");
+    if (hasTimeBeforeReadback) {
+        fprintf(fp, "\tlong timeDiff2 = ts1.tv_sec*1000000 + ts1.tv_nsec/1000 - (ts2.tv_sec*1000000 + ts2.tv_nsec/1000);\n");
+        fprintf(fp, "\tALOGW(\"%s: %%ld (%%ld) us\\n\", timeDiff, timeDiff2);\n", e->name().c_str());
+    } else {
+        fprintf(fp, "\tALOGW(\"%s: %%ld us\\n\", timeDiff);\n", e->name().c_str());
+    }
+#endif
+}
+
+int ApiGen::genEncoderImpl(const std::string &filename)
+{
+    FILE *fp = fopen(filename.c_str(), "wt");
+    if (fp == NULL) {
+        perror(filename.c_str());
+        return -1;
+    }
+
+    printHeader(fp);
+    fprintf(fp, "\n\n");
+    fprintf(fp, "#include <string.h>\n");
+    fprintf(fp, "#include \"%s_opcodes.h\"\n\n", m_basename.c_str());
+    fprintf(fp, "#include \"%s_enc.h\"\n\n\n", m_basename.c_str());
+    fprintf(fp, "#include <vector>\n\n");
+    fprintf(fp, "#include <stdio.h>\n\n");
+    fprintf(fp, "namespace {\n\n");
+
+    // unsupport printout
+    fprintf(fp,
+            "void enc_unsupported()\n"
+            "{\n"
+            "\tALOGE(\"Function is unsupported\\n\");\n"
+            "}\n\n");
+
+    // entry points;
+    std::string classname = m_basename + "_encoder_context_t";
+
+    size_t n = size();
+    for (size_t i = 0; i < n; i++) {
+        EntryPoint *e = &at(i);
+
+        if (e->unsupported()) continue;
+
+        e->print(fp, true, "_enc", /* classname + "::" */"", "void *self");
+        fprintf(fp, "{\n");
+#if DLOG_ALL_ENCODES
+        fprintf(fp, "ALOGD(\"%%s: enter\", __FUNCTION__);\n");
+#endif
+
+#if INSTRUMENT_TIMING_GUEST
+        fprintf(fp, "\tstruct timespec ts0, ts1;\n");
+        fprintf(fp, "\tclock_gettime(CLOCK_REALTIME, &ts0);\n");
+#endif
+
+//      fprintf(fp, "\n\tDBG(\">>>> %s\\n\");\n", e->name().c_str());
+        fprintf(fp, "\n\t%s *ctx = (%s *)self;\n",
+                classname.c_str(),
+                classname.c_str());
+        fprintf(fp, "\tIOStream *stream = ctx->m_stream;\n"
+                    "\tChecksumCalculator *checksumCalculator = ctx->m_checksumCalculator;\n"
+                    "\tbool useChecksum = checksumCalculator->getVersion() > 0;\n\n");
+        VarsArray & evars = e->vars();
+        size_t  maxvars = evars.size();
+        size_t  j;
+
+        char    buff[256];
+
+        // Define the __size_XXX variables that contain the size of data
+        // associated with pointers.
+        for (j = 0; j < maxvars; j++) {
+            Var& var = evars[j];
+
+            if (!var.isPointer())
+                continue;
+
+            const char* varname = var.name().c_str();
+            fprintf(fp, "\tconst unsigned int __size_%s = ", varname);
+
+            getVarEncodingSizeExpression(var, e, buff, sizeof(buff),
+                                         EncodingSizeFlags::None);
+            fprintf(fp, "%s;\n", buff);
+        }
+
+        bool hasLargeFields = false;
+#if WITH_LARGE_SUPPORT
+        // We need to take care of 'isLarge' variable in a special way
+        // Anything before an isLarge variable can be packed into a single
+        // buffer, which is then commited. Each isLarge variable is a pointer
+        // to data that can be written to directly through the pipe, which
+        // will be instant when using a QEMU pipe
+
+        size_t  nvars   = 0;
+        size_t  npointers = 0;
+
+        // First, compute the total size, 8 bytes for the opcode + payload size (without checksum)
+        fprintf(fp, "\t unsigned char *ptr;\n");
+        fprintf(fp, "\t unsigned char *buf;\n");
+        fprintf(fp, "\t const size_t sizeWithoutChecksum = 8");
+
+        for (j = 0; j < maxvars; j++) {
+            fprintf(fp, " + ");
+            npointers += writeVarEncodingSize(evars[j], true, fp);
+        }
+        if (npointers > 0) {
+            fprintf(fp, " + %zu*4", npointers);
+        }
+        fprintf(fp, ";\n");
+
+        // Then, size of the checksum string
+        fprintf(fp, "\t const size_t checksumSize = checksumCalculator->checksumByteSize();\n");
+
+        // And, size of the whole thing
+        fprintf(fp, "\t const size_t totalSize = sizeWithoutChecksum + checksumSize;\n");
+
+        // We need to divide the packet into fragments. Each fragment contains
+        // either copied arguments to a temporary buffer, or direct writes for
+        // large variables.
+        //
+        // The first fragment must also contain the opcode+payload_size+checksum_size
+        //
+        nvars = 0;
+        while (nvars < maxvars || maxvars == 0) {
+
+            // Skip over non-large fields
+            for (j = nvars; j < maxvars; j++) {
+                if (evars[j].isLarge())
+                    break;
+            }
+
+            // Write a fragment if needed.
+            if (nvars == 0 || j > nvars) {
+                const char* plus = "";
+
+                if (nvars == 0 && j == maxvars) {
+                    // Simple shortcut for the common case where we don't have large variables;
+                    fprintf(fp, "\tbuf = stream->alloc(totalSize);\n");
+
+                } else {
+                    hasLargeFields = true;
+                    // allocate buffer from the stream until the first large variable
+                    fprintf(fp, "\tbuf = stream->alloc(");
+                    plus = "";
+
+                    if (nvars == 0) {
+                        fprintf(fp,"8"); plus = " + ";
+                    }
+                    if (j > nvars) {
+                        npointers = 0;
+                        for (j = nvars; j < maxvars && !evars[j].isLarge(); j++) {
+                            fprintf(fp, "%s", plus); plus = " + ";
+                            npointers += writeVarEncodingSize(evars[j], false, fp);
+                        }
+                        if (npointers > 0) {
+                            fprintf(fp, "%s%zu*4", plus, npointers); plus = " + ";
+                        }
+                    }
+                    fprintf(fp,");\n");
+                }
+                fprintf(fp, "\tptr = buf;\n");
+
+                // encode packet header if needed.
+                if (nvars == 0) {
+                    fprintf(fp, "\tint tmp = OP_%s;memcpy(ptr, &tmp, 4); ptr += 4;\n",  e->name().c_str());
+                    fprintf(fp, "\tmemcpy(ptr, &totalSize, 4);  ptr += 4;\n\n");
+                }
+
+                if (maxvars == 0) {
+                    fprintf(fp, "\n\tif (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf);\n");
+                    break;
+                }
+
+                // encode non-large fields in this fragment
+                for (j = nvars; j < maxvars && !evars[j].isLarge(); j++) {
+                    writeVarEncodingExpression(evars[j],fp);
+                }
+
+                fprintf(fp, "\n\tif (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf);\n");
+                // Ensure the fragment is commited if it is followed by a large variable
+                if (j < maxvars) {
+                    fprintf(fp, "\tstream->flush();\n");
+                }
+            }
+
+            // If we have one or more large variables, write them directly.
+            // As size + data
+            for ( ; j < maxvars && evars[j].isLarge(); j++) {
+                writeVarLargeEncodingExpression(evars[j], fp);
+            }
+
+            nvars = j;
+        }
+
+#else /* !WITH_LARGE_SUPPORT */
+        size_t nvars = evars.size();
+        size_t npointers = 0;
+        fprintf(fp, "\tunsigned char *ptr;\n");
+        fprintf(fp, "\tunsigned char *buf;\n");
+        fprintf(fp, "\tconst size_t sizeWithoutChecksum = 8");
+        for (size_t j = 0; j < nvars; j++) {
+            npointers += getVarEncodingSizeExpression(
+                    evars[j], e, buff, sizeof(buff),
+                    (evars[j].isDMA() ? EncodingSizeFlags::DmaPtrOnly
+                                      : EncodingSizeFlags::None) |
+                            EncodingSizeFlags::UseExistingVar |
+                            EncodingSizeFlags::ExcludeOut);
+            fprintf(fp, " + %s", buff);
+        }
+        fprintf(fp, " + %u * 4;\n", (unsigned int)npointers);
+        // Size of checksum
+        fprintf(fp, "\t const size_t checksumSize = checksumCalculator->checksumByteSize();\n");
+        // Size of the whole thing
+        fprintf(fp, "\t const size_t totalSize = sizeWithoutChecksum + checksumSize;\n");
+
+        // allocate buffer from the stream;
+        fprintf(fp, "\tptr = buf = stream->alloc(totalSize);\n\n");
+
+        // encode into the stream;
+        fprintf(fp, "\tint tmp = OP_%s; memcpy(ptr, &tmp, 4); ptr += 4;\n", e->name().c_str());
+        fprintf(fp, "\tmemcpy(ptr, &totalSize, 4);  ptr += 4;\n\n");
+
+        // out variables
+        for (size_t j = 0; j < nvars; j++) {
+            writeVarEncodingExpression(evars[j], fp);
+        }
+
+        fprintf(fp, "\tif (useChecksum) checksumCalculator->addBuffer(buf, ptr - buf);\n");
+#endif /* !WITH_LARGE_SUPPORT */
+
+        // checksum
+        if (hasLargeFields) {
+            fprintf(fp, "\tbuf = stream->alloc(checksumSize);\n");
+            fprintf(fp, "\tif (useChecksum) checksumCalculator->writeChecksum(buf, checksumSize);\n\n");
+        } else {
+            fprintf(fp, "\tif (useChecksum) checksumCalculator->writeChecksum(ptr, checksumSize); ptr += checksumSize;\n\n");
+        }
+
+        // in variables;
+        bool hasTimeBeforeReadback = false;
+        bool hasReadbackChecksum = false;
+        for (size_t j = 0; j < nvars; j++) {
+            if (evars[j].isPointer()) {
+                Var::PointerDir dir = evars[j].pointerDir();
+                if (dir == Var::POINTER_INOUT || dir == Var::POINTER_OUT) {
+                    const char* varname = evars[j].name().c_str();
+                    const char* indent = "\t";
+
+#if INSTRUMENT_TIMING_GUEST
+                    if (!hasTimeBeforeReadback) {
+                        hasTimeBeforeReadback = true;
+                        // Let's flush the stream before measuring the time.
+                        fprintf(fp, "\tstream->flush();\n");
+                        fprintf(fp, "\tstruct timespec ts2;\n");
+                        fprintf(fp, "\tclock_gettime(CLOCK_REALTIME, &ts2);\n");
+                    }
+#endif
+                    if (evars[j].nullAllowed()) {
+                        fprintf(fp, "\tif (%s != NULL) {\n",varname);
+                        indent = "\t\t";
+                    }
+
+                    if (evars[j].guestUnpackExpression() != "") {
+                        fprintf(fp, "%s%s;\n", indent, evars[j].guestUnpackExpression().c_str());
+                    } else {
+                        fprintf(fp, "%sstream->readback(%s, __size_%s);\n",
+                                indent, varname, varname);
+                    }
+                    fprintf(fp, "%sif (useChecksum) checksumCalculator->addBuffer(%s, __size_%s);\n",
+                            indent, varname, varname);
+                    if (evars[j].nullAllowed()) {
+                        fprintf(fp, "\t}\n");
+                    }
+                    hasReadbackChecksum = true;
+                }
+            }
+        }
+//XXX       fprintf(fp, "\n\tDBG(\"<<<< %s\\n\");\n", e->name().c_str());
+
+        // todo - return value for pointers
+        if (e->retval().isPointer()) {
+            fprintf(stderr, "WARNING: %s : return value of pointer is unsupported\n",
+                    e->name().c_str());
+            if (e->flushOnEncode()) {
+                fprintf(fp, "\tstream->flush();\n");
+            }
+            addGuestTimePrinting(e, hasTimeBeforeReadback, fp);
+            fprintf(fp, "\t return NULL;\n");
+        } else if (e->retval().type()->name() != "void") {
+#if INSTRUMENT_TIMING_GUEST
+            if (!hasTimeBeforeReadback) {
+                hasTimeBeforeReadback = true;
+                fprintf(fp, "\tstream->flush();\n");
+                fprintf(fp, "\tstruct timespec ts2;\n");
+                fprintf(fp, "\tclock_gettime(CLOCK_REALTIME, &ts2);\n");
+            }
+#endif
+
+            fprintf(fp, "\n\t%s retval;\n", e->retval().type()->name().c_str());
+            fprintf(fp, "\tstream->readback(&retval, %u);\n",(unsigned) e->retval().type()->bytes());
+            fprintf(fp, "\tif (useChecksum) checksumCalculator->addBuffer(&retval, %u);\n",
+                    (unsigned) e->retval().type()->bytes());
+            writeEncodingChecksumValidatorOnReturn(e->name().c_str(), fp);
+            addGuestTimePrinting(e, hasTimeBeforeReadback, fp);
+            fprintf(fp, "\treturn retval;\n");
+        } else {
+            if (e->flushOnEncode()) fprintf(fp, "\tstream->flush();\n");
+            if (hasReadbackChecksum) writeEncodingChecksumValidatorOnReturn(e->name().c_str(), fp);
+            addGuestTimePrinting(e, hasTimeBeforeReadback, fp);
+        }
+        fprintf(fp, "}\n\n");
+    }
+
+    fprintf(fp, "}  // namespace\n\n");
+
+    // constructor
+    fprintf(fp, "%s::%s(IOStream *stream, ChecksumCalculator *checksumCalculator)\n{\n", classname.c_str(), classname.c_str());
+    fprintf(fp, "\tm_stream = stream;\n");
+    fprintf(fp, "\tm_checksumCalculator = checksumCalculator;\n\n");
+
+    for (size_t i = 0; i < n; i++) {
+        EntryPoint *e = &at(i);
+        if (e->unsupported()) {
+            fprintf(fp, 
+                    "\tthis->%s = (%s_%s_proc_t) &enc_unsupported;\n",
+                    e->name().c_str(),
+                    e->name().c_str(),
+                    sideString(CLIENT_SIDE));
+        } else {
+            fprintf(fp,
+                    "\tthis->%s = &%s_enc;\n",
+                    e->name().c_str(),
+                    e->name().c_str());
+        }
+    }
+    fprintf(fp, "}\n\n");
+
+    fclose(fp);
+    return 0;
+}
+
+
+int ApiGen::genDecoderHeader(const std::string &filename)
+{
+    FILE *fp = fopen(filename.c_str(), "wt");
+    if (fp == NULL) {
+        perror(filename.c_str());
+        return -1;
+    }
+
+    printHeader(fp);
+    std::string classname = m_basename + "_decoder_context_t";
+
+    fprintf(fp, "\n#ifndef GUARD_%s\n", classname.c_str());
+    fprintf(fp, "#define GUARD_%s\n\n", classname.c_str());
+
+    fprintf(fp, "#include \"OpenglRender/IOStream.h\"\n");
+    fprintf(fp, "#include \"ChecksumCalculator.h\"\n");
+    fprintf(fp, "#include \"%s_%s_context.h\"\n\n\n", m_basename.c_str(), sideString(SERVER_SIDE));
+    fprintf(fp, "#include \"emugl/common/logging.h\"\n");
+#if INSTRUMENT_TIMING_HOST
+    fprintf(fp, "#include \"time.h\"\n");
+#endif
+
+    for (size_t i = 0; i < m_decoderHeaders.size(); i++) {
+        fprintf(fp, "#include %s\n", m_decoderHeaders[i].c_str());
+    }
+    fprintf(fp, "\n");
+
+    fprintf(fp, "struct %s : public %s_%s_context_t {\n\n",
+            classname.c_str(), m_basename.c_str(), sideString(SERVER_SIDE));
+    fprintf(fp, "\tsize_t decode(void *buf, size_t bufsize, IOStream *stream, ChecksumCalculator* checksumCalc);\n");
+    fprintf(fp, "\n};\n\n");
+    fprintf(fp, "#endif  // GUARD_%s\n", classname.c_str());
+
+    fclose(fp);
+    return 0;
+}
+
+int ApiGen::genContextImpl(const std::string &filename, SideType side)
+{
+    FILE *fp = fopen(filename.c_str(), "wt");
+    if (fp == NULL) {
+        perror(filename.c_str());
+        return -1;
+    }
+    printHeader(fp);
+
+    std::string classname = m_basename + "_" + sideString(side) + "_context_t";
+    size_t n = size();
+    fprintf(fp, "\n\n#include <string.h>\n");
+    fprintf(fp, "#include \"%s_%s_context.h\"\n\n\n", m_basename.c_str(), sideString(side));
+    fprintf(fp, "#include <stdio.h>\n\n");
+
+    fprintf(fp, "int %s::initDispatchByName(void *(*getProc)(const char *, void *userData), void *userData)\n{\n", classname.c_str());
+    for (size_t i = 0; i < n; i++) {
+        EntryPoint *e = &at(i);
+        if (side == SERVER_SIDE && e->customDecoder() && !e->notApi()) {
+            fprintf(fp, "\t%s = (%s_dec_%s_proc_t) getProc(\"%s\", userData);\n",
+                    e->name().c_str(),
+                    e->name().c_str(),
+                    sideString(side),
+                    e->name().c_str());
+        } else {
+            fprintf(fp, "\t%s = (%s_%s_proc_t) getProc(\"%s\", userData);\n",
+                    e->name().c_str(),
+                    e->name().c_str(),
+                    sideString(side),
+                    e->name().c_str());
+        }
+    }
+    fprintf(fp, "\treturn 0;\n");
+    fprintf(fp, "}\n\n");
+    fclose(fp);
+    return 0;
+}
+
+int ApiGen::genDecoderImpl(const std::string &filename)
+{
+    FILE *fp = fopen(filename.c_str(), "wt");
+    if (fp == NULL) {
+        perror(filename.c_str());
+        return -1;
+    }
+
+    printHeader(fp);
+
+    std::string classname = m_basename + "_decoder_context_t";
+
+    size_t n = size();
+
+    bool changesChecksum = false;
+    for (size_t i = 0; i < size(); ++i) {
+        const EntryPoint& ep = at(i);
+        if (ep.name().find("SelectChecksum") != std::string::npos) {
+            changesChecksum = true;
+            break;
+        }
+    }
+
+    fprintf(fp, "\n\n#include <string.h>\n");
+    fprintf(fp, "#include \"%s_opcodes.h\"\n\n", m_basename.c_str());
+    fprintf(fp, "#include \"%s_dec.h\"\n\n\n", m_basename.c_str());
+    fprintf(fp, "#include \"ProtocolUtils.h\"\n\n");
+    fprintf(fp, "#include \"ChecksumCalculatorThreadInfo.h\"\n\n");
+    fprintf(fp, "#include <stdio.h>\n\n");
+    fprintf(fp, "typedef unsigned int tsize_t; // Target \"size_t\", which is 32-bit for now. It may or may not be the same as host's size_t when emugen is compiled.\n\n");
+
+    // helper macros
+    fprintf(fp,
+            "#ifdef OPENGL_DEBUG_PRINTOUT\n"
+            "#  define DEBUG(...) do { if (emugl_cxt_logger) { emugl_cxt_logger(__VA_ARGS__); } } while(0)\n"
+            "#else\n"
+            "#  define DEBUG(...)  ((void)0)\n"
+            "#endif\n\n");
+
+    fprintf(fp,
+#if DECODER_CHECK_GL_ERRORS
+            "#define CHECK_GL_ERRORS\n"
+#endif
+            "#ifdef CHECK_GL_ERRORS\n"
+            "#  define SET_LASTCALL(name)  sprintf(lastCall, #name)\n"
+            "#else\n"
+            "#  define SET_LASTCALL(name)\n"
+            "#endif\n");
+
+    // helper templates
+    fprintf(fp, "using namespace emugl;\n\n");
+
+    // decoder switch;
+    fprintf(fp, "size_t %s::decode(void *buf, size_t len, IOStream *stream, ChecksumCalculator* checksumCalc) {\n", classname.c_str());
+    fprintf(fp,
+"\tif (len < 8) return 0; \n\
+#ifdef CHECK_GL_ERRORS\n\
+\tchar lastCall[256] = {0};\n\
+#endif\n\
+\tunsigned char *ptr = (unsigned char *)buf;\n\
+\tconst unsigned char* const end = (const unsigned char*)buf + len;\n");
+    if (!changesChecksum) {
+        fprintf(fp,
+R"(    const size_t checksumSize = checksumCalc->checksumByteSize();
+    const bool useChecksum = checksumSize > 0;
+)");
+    }
+    fprintf(fp,
+"\twhile (end - ptr >= 8) {\n\
+\t\tuint32_t opcode = *(uint32_t *)ptr;   \n\
+\t\tint32_t packetLen = *(int32_t *)(ptr + 4);\n\
+\t\tif (end - ptr < packetLen) return ptr - (unsigned char*)buf;\n");
+    if (changesChecksum) {
+        fprintf(fp,
+R"(        // Do this on every iteration, as some commands may change the checksum
+        // calculation parameters.
+        const size_t checksumSize = checksumCalc->checksumByteSize();
+        const bool useChecksum = checksumSize > 0;
+)");
+    }
+    fprintf(fp, "\t\tswitch(opcode) {\n");
+
+    for (size_t f = 0; f < n; f++) {
+        enum Pass_t {
+            PASS_FIRST = 0,
+            PASS_VariableDeclarations = PASS_FIRST,
+            PASS_Protocol,
+            PASS_TmpBuffAlloc,
+            PASS_MemAlloc,
+            PASS_DebugPrint,
+            PASS_FunctionCall,
+            PASS_FlushOutput,
+            PASS_Epilog,
+            PASS_LAST };
+        EntryPoint *e = &(*this)[f];
+
+        // construct a printout string;
+        std::string printString;
+        for (size_t i = 0; i < e->vars().size(); i++) {
+            Var *v = &e->vars()[i];
+            if (!v->isVoid())  printString += (v->isPointer() ? "%p(%u)" : v->type()->printFormat()) + " ";
+        }
+
+        // TODO - add for return value;
+        fprintf(fp, "\t\tcase OP_%s: {\n", e->name().c_str());
+
+#if INSTRUMENT_TIMING_HOST
+        fprintf(fp, "\t\t\tstruct timespec ts0, ts1, ts2;\n");
+        fprintf(fp, "\t\t\tclock_gettime(CLOCK_REALTIME, &ts0);\n");
+#endif
+        bool totalTmpBuffExist = false;
+        std::string totalTmpBuffOffset = "0";
+        std::string *tmpBufOffset = new std::string[e->vars().size()];
+
+        // construct retval type string
+        std::string retvalType;
+        if (!e->retval().isVoid()) {
+            retvalType = e->retval().type()->name();
+        }
+
+        for (int pass = PASS_FIRST; pass < PASS_LAST; pass++) {
+#if INSTRUMENT_TIMING_HOST
+            if (pass == PASS_FunctionCall) {
+                fprintf(fp, "\t\t\tclock_gettime(CLOCK_REALTIME, &ts2);\n");
+            }
+#endif
+            if (pass == PASS_FunctionCall &&
+                !e->retval().isVoid() &&
+                !e->retval().isPointer()) {
+                fprintf(fp, "\t\t\t*(%s *)(&tmpBuf[%s]) = ", retvalType.c_str(),
+                        totalTmpBuffOffset.c_str());
+            }
+
+            if (pass == PASS_FunctionCall) {
+                if (e->customDecoder() && !e->notApi()) {
+                    fprintf(fp, "\t\t\tthis->%s_dec(", e->name().c_str());
+                } else {
+                    fprintf(fp, "\t\t\tthis->%s(", e->name().c_str());
+                }
+                if (e->customDecoder()) {
+                    fprintf(fp, "this"); // add a context to the call
+                }
+            } else if (pass == PASS_DebugPrint) {
+                if (strstr(m_basename.c_str(), "gl")) {
+                    fprintf(fp, "\t\t#ifdef CHECK_GL_ERRORS\n");
+                    fprintf(fp, "\t\tGLint err = this->glGetError();\n");
+                    fprintf(fp, "\t\tif (err) fprintf(stderr, \"%s Error (pre-call): 0x%%X before %s\\n\", err);\n",
+                            m_basename.c_str(), e->name().c_str());
+                    fprintf(fp, "\t\t#endif\n");
+                }
+                fprintf(fp,
+                        "\t\t\tDEBUG(\"%s(%%p): %s(%s)\\n\", stream",
+                        m_basename.c_str(),
+                        e->name().c_str(),
+                        printString.c_str());
+                if (e->vars().size() > 0 && !e->vars()[0].isVoid()) {
+                    fprintf(fp, ", ");
+                }
+            }
+
+            std::string varoffset = "8"; // skip the header
+            VarsArray & evars = e->vars();
+            // allocate memory for out pointers;
+            for (size_t j = 0; j < evars.size(); j++) {
+                Var *v = & evars[j];
+                if (v->isVoid()) {
+                    continue;
+                }
+                const char* var_name = v->name().c_str();
+                const char* var_type_name = v->type()->name().c_str();
+                const unsigned var_type_bytes = v->type()->bytes();
+
+                if ((pass == PASS_FunctionCall) &&
+                    (j != 0 || e->customDecoder())) {
+                    fprintf(fp, ", ");
+                }
+                if (pass == PASS_DebugPrint && j != 0) {
+                    fprintf(fp, ", ");
+                }
+
+                if (v->isPointer() && v->isDMA()) {
+                    if (pass == PASS_VariableDeclarations) {
+                        fprintf(fp,
+                                "\t\t\tuint64_t var_%s_guest_paddr = Unpack<uint64_t,uint64_t>(ptr + %s);\n"
+                                "\t\t\t%s var_%s = stream->getDmaForReading(var_%s_guest_paddr);\n",
+                                var_name,
+                                varoffset.c_str(),
+                                var_type_name,
+                                var_name,
+                                var_name);
+                    }
+                    if (pass == PASS_FunctionCall ||
+                        pass == PASS_DebugPrint) {
+                        fprintf(fp, "var_%s", var_name);
+                    }
+                    varoffset += " + 8";
+                }
+
+                if (!v->isPointer()) {
+                    if (pass == PASS_VariableDeclarations) {
+                        fprintf(fp,
+                                "\t\t\t%s var_%s = Unpack<%s,uint%u_t>(ptr + %s);\n",
+                                var_type_name,
+                                var_name,
+                                var_type_name,
+                                var_type_bytes * 8U,
+                                varoffset.c_str());
+                    }
+
+                    if (pass == PASS_FunctionCall ||
+                        pass == PASS_DebugPrint) {
+                        fprintf(fp, "var_%s", var_name);
+                    }
+                    varoffset += " + " + toString(var_type_bytes);
+                    continue;
+                }
+
+                if (pass == PASS_VariableDeclarations) {
+                    fprintf(fp,
+                            "\t\t\tuint32_t size_%s __attribute__((unused)) = Unpack<uint32_t,uint32_t>(ptr + %s);\n",
+                            var_name,
+                            varoffset.c_str());
+                }
+
+                if (!v->isDMA()) {
+                    if (v->pointerDir() & Var::POINTER_IN) {
+                        if (pass == PASS_VariableDeclarations) {
+    #if USE_ALIGNED_BUFFERS
+                            fprintf(fp,
+                                    "\t\t\tInputBuffer inptr_%s(ptr + %s + 4, size_%s);\n",
+                                    var_name,
+                                    varoffset.c_str(),
+                                    var_name);
+                            if (v->unpackExpression().size() > 0) {
+                                fprintf(fp,
+                                    "\t\t\tvoid* inptr_%s_unpacked;\n"
+                                    "\t\t\t%s;\n",
+                                    var_name,
+                                    v->unpackExpression().c_str());
+                            }
+
+                        }
+                        if (pass == PASS_FunctionCall &&
+                            v->pointerDir() == Var::POINTER_IN) {
+                            if (v->nullAllowed()) {
+                                fprintf(fp,
+                                        "size_%s == 0 ? nullptr : (%s)(inptr_%s.get())",
+                                        var_name,
+                                        var_type_name,
+                                        var_name);
+                            } else {
+                                if (v->unpackExpression().size() > 0) {
+                                    fprintf(fp,
+                                            "(%s)(inptr_%s_unpacked)",
+                                            var_type_name,
+                                            var_name);
+                                } else {
+                                    fprintf(fp,
+                                            "(%s)(inptr_%s.get())",
+                                            var_type_name,
+                                            var_name);
+                                }
+                            }
+                        } else if (pass == PASS_DebugPrint &&
+                                   v->pointerDir() == Var::POINTER_IN) {
+                            fprintf(fp,
+                                    "(%s)(inptr_%s.get()), size_%s",
+                                    var_type_name,
+                                    var_name,
+                                    var_name);
+                        }
+    #else  // !USE_ALIGNED_BUFFERS
+                            fprintf(fp,
+                                    "unsigned char *inptr_%s = (ptr + %s + 4);\n",
+                                    var_name,
+                                    varoffset.c_str());
+                        }
+                        if (pass == PASS_FunctionCall &&
+                            v->pointerDir() == Var::POINTER_IN) {
+                            if (v->nullAllowed()) {
+                                fprintf(fp,
+                                        "size_%s == 0 ? NULL : (%s)(inptr_%s)",
+                                        var_name,
+                                        var_type_name,
+                                        var_name);
+                            } else {
+                                fprintf(fp,
+                                        "(%s)(inptr_%s)",
+                                        var_type_name,
+                                        var_name);
+                            }
+                        } else if (pass == PASS_DebugPrint &&
+                                   v->pointerDir() == Var::POINTER_IN) {
+                            fprintf(fp,
+                                    "(%s)(inptr_%s), size_%s",
+                                    var_type_name,
+                                    var_name,
+                                    var_name);
+                        }
+    #endif  // !USE_ALIGNED_BUFFERS
+                        varoffset += " + 4 + size_";
+                        varoffset += var_name;
+                    }
+                    if (v->pointerDir() & Var::POINTER_OUT)  { // out pointer;
+                        if (pass == PASS_TmpBuffAlloc) {
+                            if (!totalTmpBuffExist) {
+                                fprintf(fp,
+                                        "\t\t\tsize_t totalTmpSize = size_%s;\n",
+                                        var_name);
+                            } else {
+                                fprintf(fp,
+                                        "\t\t\ttotalTmpSize += size_%s;\n",
+                                        var_name);
+                            }
+                            tmpBufOffset[j] = totalTmpBuffOffset;
+                            totalTmpBuffOffset += " + size_";
+                            totalTmpBuffOffset += var_name;
+                            totalTmpBuffExist = true;
+                        } else if (pass == PASS_MemAlloc) {
+    #if USE_ALIGNED_BUFFERS
+                            fprintf(fp,
+                                    "\t\t\tOutputBuffer outptr_%s(&tmpBuf[%s], size_%s);\n",
+                                    var_name,
+                                    tmpBufOffset[j].c_str(),
+                                    var_name);
+                            // If both input and output variable, initialize with the input.
+                            if (v->pointerDir() == Var::POINTER_INOUT) {
+                                fprintf(fp,
+                                        "\t\t\tmemcpy(outptr_%s.get(), inptr_%s.get(), size_%s);\n",
+                                        var_name,
+                                        var_name,
+                                        var_name);
+                            }
+
+                            if (v->hostPackExpression() != "") {
+                                fprintf(fp, "\t\t\tvoid* forPacking_%s = nullptr;\n", var_name);
+                            }
+                            if (v->hostPackTmpAllocExpression() != "") {
+                                fprintf(fp, "\t\t\t%s;\n", v->hostPackTmpAllocExpression().c_str());
+                            }
+                        } else if (pass == PASS_FunctionCall) {
+                            if (v->hostPackExpression() != "") {
+                                fprintf(fp,
+                                        "(%s)(forPacking_%s)",
+                                        var_type_name,
+                                        var_name);
+                            } else {
+                                if (v->nullAllowed()) {
+                                    fprintf(fp,
+                                            "size_%s == 0 ? nullptr : (%s)(outptr_%s.get())",
+                                            var_name,
+                                            var_type_name,
+                                            var_name);
+                                } else {
+                                    fprintf(fp,
+                                            "(%s)(outptr_%s.get())",
+                                            var_type_name,
+                                            var_name);
+                                }
+                            }
+                        } else if (pass == PASS_DebugPrint) {
+                            fprintf(fp,
+                                    "(%s)(outptr_%s.get()), size_%s",
+                                    var_type_name,
+                                    var_name,
+                                    var_name);
+                        }
+                        if (pass == PASS_FlushOutput) {
+                            if (v->hostPackExpression() != "") {
+                                fprintf(fp,
+                                        "\t\t\tif (size_%s) {\n"
+                                        "\t\t\t%s; }\n",
+                                        var_name,
+                                        v->hostPackExpression().c_str());
+                            }
+                            fprintf(fp,
+                                    "\t\t\toutptr_%s.flush();\n",
+                                    var_name);
+                        }
+    #else  // !USE_ALIGNED_BUFFERS
+                            fprintf(fp,
+                                    "\t\t\tunsigned char *outptr_%s = &tmpBuf[%s];\n",
+                                    var_name,
+                                    tmpBufOffset[j].c_str());
+                            fprintf(fp,
+                                    "\t\t\tmemset(outptr_%s, 0, %s);\n",
+                                    var_name,
+                                    toString(v->type()->bytes()).c_str());
+                        } else if (pass == PASS_FunctionCall) {
+                            if (v->nullAllowed()) {
+                                fprintf(fp,
+                                        "size_%s == 0 ? NULL : (%s)(outptr_%s)",
+                                        var_name,
+                                        var_type_name,
+                                        var_name);
+                            } else {
+                                fprintf(fp,
+                                        "(%s)(outptr_%s)",
+                                        var_type_name,
+                                        var_name);
+                            }
+                        } else if (pass == PASS_DebugPrint) {
+                            fprintf(fp,
+                                    "(%s)(outptr_%s), size_%s",
+                                    var_type_name,
+                                    var_name,
+                                    varoffset.c_str());
+                        }
+    #endif  // !USE_ALIGNED_BUFFERS
+                    if (v->pointerDir() == Var::POINTER_OUT) {
+                        varoffset += " + 4";
+                    }
+                    }
+                }
+            }
+
+            if (pass == PASS_Protocol) {
+                fprintf(fp,
+                        "\t\t\tif (useChecksum) {\n"
+                        "\t\t\t\tChecksumCalculatorThreadInfo::validOrDie(checksumCalc, ptr, %s, "
+                        "ptr + %s, checksumSize, "
+                        "\n\t\t\t\t\t\"%s::decode,"
+                        " OP_%s: GL checksumCalculator failure\\n\");\n"
+                        "\t\t\t}\n",
+                        varoffset.c_str(),
+                        varoffset.c_str(),
+                        classname.c_str(),
+                        e->name().c_str()
+                        );
+
+                varoffset += " + 4";
+            }
+
+            if (pass == PASS_FunctionCall ||
+                pass == PASS_DebugPrint) {
+                fprintf(fp, ");\n");
+
+                if (pass == PASS_FunctionCall) {
+                    // unlock all dma buffers that have been passed
+                    for (size_t j = 0; j < evars.size(); j++) {
+                        Var *v = & evars[j];
+                        if (v->isVoid()) {
+                            continue;
+                        }
+                        const char* var_name = v->name().c_str();
+                        if (v->isDMA()) {
+                            fprintf(fp,
+                                    "\t\t\tstream->unlockDma(var_%s_guest_paddr);\n",
+                                    var_name);
+                        }
+                    }
+                }
+            }
+
+            if (pass == PASS_TmpBuffAlloc) {
+                if (!e->retval().isVoid() && !e->retval().isPointer()) {
+                    if (!totalTmpBuffExist)
+                        fprintf(fp,
+                                "\t\t\tsize_t totalTmpSize = sizeof(%s);\n",
+                                retvalType.c_str());
+                    else
+                        fprintf(fp,
+                                "\t\t\ttotalTmpSize += sizeof(%s);\n",
+                                retvalType.c_str());
+
+                    totalTmpBuffExist = true;
+                }
+                if (totalTmpBuffExist) {
+                    fprintf(fp,
+                            "\t\t\ttotalTmpSize += checksumSize;\n"
+                            "\t\t\tunsigned char *tmpBuf = stream->alloc(totalTmpSize);\n");
+                }
+            }
+
+            if (pass == PASS_Epilog) {
+                // send back out pointers data as well as retval
+                if (totalTmpBuffExist) {
+                    fprintf(fp,
+                            "\t\t\tif (useChecksum) {\n"
+                            "\t\t\t\tChecksumCalculatorThreadInfo::writeChecksum(checksumCalc, "
+                            "&tmpBuf[0], totalTmpSize - checksumSize, "
+                            "&tmpBuf[totalTmpSize - checksumSize], checksumSize);\n"
+                            "\t\t\t}\n"
+                            "\t\t\tstream->flush();\n");
+                }
+            }
+        } // pass;
+
+#if INSTRUMENT_TIMING_HOST
+        fprintf(fp, "\t\t\tclock_gettime(CLOCK_REALTIME, &ts1);\n");
+        fprintf(fp, "\t\t\tlong timeDiff = ts1.tv_sec*1000000 + ts1.tv_nsec/1000 - (ts0.tv_sec*1000000 + ts0.tv_nsec/1000);\n");
+        fprintf(fp, "\t\t\tlong timeDiff2 = ts1.tv_sec*1000000 + ts1.tv_nsec/1000 - (ts2.tv_sec*1000000 + ts2.tv_nsec/1000);\n");
+        fprintf(fp, "\t\t\tprintf(\"(timing) %%4ld.%%06ld %s: %%ld (%%ld) us\\n\", "
+                    "ts1.tv_sec, ts1.tv_nsec/1000, timeDiff, timeDiff2);\n", e->name().c_str());
+#endif
+        fprintf(fp, "\t\t\tSET_LASTCALL(\"%s\");\n", e->name().c_str());
+        fprintf(fp, "\t\t\tbreak;\n");
+        fprintf(fp, "\t\t}\n");
+
+        delete [] tmpBufOffset;
+    }
+    fprintf(fp, "\t\tdefault:\n");
+    fprintf(fp, "\t\t\treturn ptr - (unsigned char*)buf;\n");
+    fprintf(fp, "\t\t} //switch\n");
+    if (strstr(m_basename.c_str(), "gl")) {
+        fprintf(fp, "\t\t#ifdef CHECK_GL_ERRORS\n");
+        fprintf(fp, "\t\tGLint err = this->glGetError();\n");
+        fprintf(fp, "\t\tif (err) fprintf(stderr, \"%s Error (post-call): 0x%%X in %%s\\n\", err, lastCall);\n", m_basename.c_str());
+        fprintf(fp, "\t\t#endif\n");
+    }
+
+    fprintf(fp, "\t\tptr += packetLen;\n");
+    fprintf(fp, "\t} // while\n");
+    fprintf(fp, "\treturn ptr - (unsigned char*)buf;\n");
+    fprintf(fp, "}\n");
+
+    fclose(fp);
+    return 0;
+}
+
+int ApiGen::readSpec(const std::string & filename)
+{
+    FILE *specfp = fopen(filename.c_str(), "rt");
+    if (specfp == NULL) {
+        return -1;
+    }
+
+    char line[1000];
+    unsigned int lc = 0;
+    while (fgets(line, sizeof(line), specfp) != NULL) {
+        lc++;
+        EntryPoint ref;
+        if (ref.parse(lc, std::string(line))) {
+            push_back(ref);
+            updateMaxEntryPointsParams(ref.vars().size());
+        }
+    }
+    fclose(specfp);
+    return 0;
+}
+
+int ApiGen::readAttributes(const std::string & attribFilename)
+{
+    enum { ST_NAME, ST_ATT } state;
+
+    FILE *fp = fopen(attribFilename.c_str(), "rt");
+    if (fp == NULL) {
+        perror(attribFilename.c_str());
+        return -1;
+    }
+    char buf[1000];
+
+    state = ST_NAME;
+    EntryPoint *currentEntry = NULL;
+    size_t lc = 0;
+    bool globalAttributes = false;
+    while (fgets(buf, sizeof(buf), fp) != NULL) {
+        lc++;
+        std::string line(buf);
+        if (line.size() == 0) continue; // could that happen?
+
+        if (line.at(0) == '#') continue; // comment
+
+        size_t first = line.find_first_not_of(" \t\n");
+        if (state == ST_ATT && (first == std::string::npos || first == 0)) state = ST_NAME;
+
+        line = trim(line);
+        if (line.size() == 0 || line.at(0) == '#') continue;
+
+        switch(state) {
+        case ST_NAME:
+            if (line == "GLOBAL") {
+                globalAttributes = true;
+            } else {
+                globalAttributes = false;
+                currentEntry = findEntryByName(line);
+                if (currentEntry == NULL) {
+                    fprintf(stderr, "WARNING: %u: attribute of non existant entry point %s\n", (unsigned int)lc, line.c_str());
+                }
+            }
+            state = ST_ATT;
+            break;
+        case ST_ATT:
+            if (globalAttributes) {
+                setGlobalAttribute(line, lc);
+            } else  if (currentEntry != NULL) {
+                currentEntry->setAttribute(line, lc);
+            }
+            break;
+        }
+    }
+    return 0;
+}
+
+
+int ApiGen::setGlobalAttribute(const std::string & line, size_t lc)
+{
+    size_t pos = 0;
+    size_t last;
+    std::string token = getNextToken(line, pos, &last, WHITESPACE);
+    pos = last;
+
+    if (token == "base_opcode") {
+        std::string str = getNextToken(line, pos, &last, WHITESPACE);
+        if (str.size() == 0) {
+            fprintf(stderr, "line %u: missing value for base_opcode\n", (unsigned) lc);
+        } else {
+            setBaseOpcode(atoi(str.c_str()));
+        }
+    } else  if (token == "encoder_headers") {
+        std::string str = getNextToken(line, pos, &last, WHITESPACE);
+        pos = last;
+        while (str.size() != 0) {
+            encoderHeaders().push_back(str);
+            str = getNextToken(line, pos, &last, WHITESPACE);
+            pos = last;
+        }
+    } else if (token == "client_context_headers") {
+        std::string str = getNextToken(line, pos, &last, WHITESPACE);
+        pos = last;
+        while (str.size() != 0) {
+            clientContextHeaders().push_back(str);
+            str = getNextToken(line, pos, &last, WHITESPACE);
+            pos = last;
+        }
+    } else if (token == "server_context_headers") {
+        std::string str = getNextToken(line, pos, &last, WHITESPACE);
+        pos = last;
+        while (str.size() != 0) {
+            serverContextHeaders().push_back(str);
+            str = getNextToken(line, pos, &last, WHITESPACE);
+            pos = last;
+        }
+    } else if (token == "decoder_headers") {
+        std::string str = getNextToken(line, pos, &last, WHITESPACE);
+        pos = last;
+        while (str.size() != 0) {
+            decoderHeaders().push_back(str);
+            str = getNextToken(line, pos, &last, WHITESPACE);
+            pos = last;
+        }
+    }
+    else {
+        fprintf(stderr, "WARNING: %u : unknown global attribute %s\n", (unsigned int)lc, line.c_str());
+    }
+
+    return 0;
+}
diff --git a/host/commands/emugen/ApiGen.h b/host/commands/emugen/ApiGen.h
new file mode 100644
index 0000000000000000000000000000000000000000..c4e87b48a1e276c472918c17e3711a211d673765
--- /dev/null
+++ b/host/commands/emugen/ApiGen.h
@@ -0,0 +1,97 @@
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#ifndef __API_GEN_H_
+#define __API_GEN_H_
+
+#include <vector>
+#include <string.h>
+#include "EntryPoint.h"
+
+
+class ApiGen : private std::vector<EntryPoint> {
+
+public:
+    typedef std::vector<std::string> StringVec;
+    typedef enum { CLIENT_SIDE, SERVER_SIDE, WRAPPER_SIDE } SideType;
+
+    ApiGen(const std::string & basename) :
+        m_basename(basename),
+        m_maxEntryPointsParams(0),
+        m_baseOpcode(0)
+    { }
+    virtual ~ApiGen() {}
+    int readSpec(const std::string & filename);
+    int readAttributes(const std::string & attribFilename);
+    size_t maxEntryPointsParams() {  return m_maxEntryPointsParams; }
+    void updateMaxEntryPointsParams(size_t val) {
+        if (m_maxEntryPointsParams == 0 || val > m_maxEntryPointsParams) m_maxEntryPointsParams = val;
+    }
+    int baseOpcode() { return m_baseOpcode; }
+    void setBaseOpcode(int base) { m_baseOpcode = base; }
+
+    const char *sideString(SideType side) {
+        const char *retval;
+        switch(side) {
+        case CLIENT_SIDE:
+            retval = "client";
+            break;
+        case SERVER_SIDE:
+            retval = "server";
+            break;
+        case WRAPPER_SIDE:
+            retval = "wrapper";
+            break;
+        default:
+            retval = "unknown";
+        }
+        return retval;
+    }
+
+    StringVec & clientContextHeaders() { return m_clientContextHeaders; }
+    StringVec & encoderHeaders() { return m_encoderHeaders; }
+    StringVec & serverContextHeaders() { return m_serverContextHeaders; }
+    StringVec & decoderHeaders() { return m_decoderHeaders; }
+
+    EntryPoint * findEntryByName(const std::string & name);
+    int genOpcodes(const std::string &filename);
+    int genAttributesTemplate(const std::string &filename);
+    int genProcTypes(const std::string &filename, SideType side);
+    int genFuncTable(const std::string &filename, SideType side);
+
+    int genContext(const std::string &filename, SideType side);
+    int genContextImpl(const std::string &filename, SideType side);
+
+    int genEntryPoints(const std::string &filename, SideType side);
+
+    int genEncoderHeader(const std::string &filename);
+    int genEncoderImpl(const std::string &filename);
+
+    int genDecoderHeader(const std::string &filename);
+    int genDecoderImpl(const std::string &filename);
+
+protected:
+    virtual void printHeader(FILE *fp) const;
+    std::string m_basename;
+    StringVec m_clientContextHeaders;
+    StringVec m_encoderHeaders;
+    StringVec m_serverContextHeaders;
+    StringVec m_decoderHeaders;
+    size_t m_maxEntryPointsParams; // record the maximum number of parameters in the entry points;
+    int m_baseOpcode;
+    int setGlobalAttribute(const std::string & line, size_t lc);
+};
+
+#endif
diff --git a/host/commands/emugen/EntryPoint.cpp b/host/commands/emugen/EntryPoint.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d7ce63566aa4294c00a5e82fdaad170140ef6dc5
--- /dev/null
+++ b/host/commands/emugen/EntryPoint.cpp
@@ -0,0 +1,394 @@
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#include "EntryPoint.h"
+
+#include "Parser.h"
+#include "TypeFactory.h"
+#include "strUtils.h"
+
+#include <sstream>
+#include <string>
+
+#include <stdio.h>
+
+EntryPoint::EntryPoint()
+{
+    reset();
+}
+
+EntryPoint::~EntryPoint()
+{
+}
+
+void EntryPoint::reset()
+{
+    m_unsupported = false;
+    m_customDecoder = false;
+    m_notApi = false;
+    m_flushOnEncode = false;
+    m_vars.empty();
+}
+
+// return true for valid line (need to get into the entry points list)
+bool EntryPoint::parse(unsigned int lc, const std::string & str)
+{
+    size_t pos, last;
+    std::string field;
+
+    reset();
+    std::string linestr = trim(str);
+
+    if (linestr.size() == 0) return false;
+    if (linestr.at(0) == '#') return false;
+
+    // skip PREFIX
+    field = getNextToken(linestr, 0, &last, "(");
+    pos = last + 1;
+    // return type
+    field = getNextToken(linestr, pos, &last, ",)");
+
+    std::string error;
+    std::string retTypeName;
+    if (!parseTypeDeclaration(field, &retTypeName, &error)) {
+        fprintf(stderr,
+                "line: %d: Parsing error in field <%s>: %s\n",
+                lc, 
+                field.c_str(), 
+                error.c_str());
+        return false;
+    }
+    pos = last + 1;
+    const VarType *theType = TypeFactory::instance()->getVarTypeByName(retTypeName);
+    if (theType->name() == "UNKNOWN") {
+        fprintf(stderr, "UNKNOWN retval: %s\n", linestr.c_str());
+    }
+
+    m_retval.init(std::string(""),
+                  theType,
+                  std::string(""),
+                  Var::POINTER_OUT,
+                  std::string(""),
+                  std::string(""),
+                  std::string(""));
+
+    // function name
+    m_name = getNextToken(linestr, pos, &last, ",)");
+    pos = last + 1;
+
+    // parameters;
+    int nvars = 0;
+    while (pos < linestr.size() - 1) {
+        field = getNextToken(linestr, pos, &last, ",)");
+        if (field == "void") {
+            // 'void' is used as a special case for functions that don't take
+            // parameters at all.
+            break;
+        }
+        std::string vartype, varname;
+        if (!parseParameterDeclaration(field, &vartype, &varname, &error)) {
+            fprintf(stderr,
+                    "line: %d: Parsing error in field <%s> (%s)\n",
+                    lc,
+                    field.c_str(),
+                    error.c_str());
+            return false;
+        }
+        nvars++;
+        const VarType *v = TypeFactory::instance()->getVarTypeByName(vartype);
+        if (v->id() == 0) {
+            fprintf(stderr, "%d: Unknown type: %s\n", lc, vartype.c_str());
+        } else {
+            if (varname == "" &&
+                !(v->name() == "void" && !v->isPointer())) {
+                std::ostringstream oss;
+                oss << "var" << nvars;
+                varname = oss.str();
+            }
+
+            m_vars.push_back(Var(varname, v, std::string(""), Var::POINTER_IN, "", "", ""));
+        }
+        pos = last + 1;
+    }
+    return true;
+}
+
+void EntryPoint::print(FILE *fp, bool newline,
+                       const std::string & name_suffix,
+                       const std::string & name_prefix,
+                       const std::string & ctx_param ) const
+{
+    fprintf(fp, "%s %s%s%s(",
+            m_retval.type()->name().c_str(),
+            name_prefix.c_str(),
+            m_name.c_str(),
+            name_suffix.c_str());
+
+    if (ctx_param != "") fprintf(fp, "%s ", ctx_param.c_str());
+
+    for (size_t i = 0; i < m_vars.size(); i++) {
+        if (m_vars[i].isVoid()) continue;
+        if (i != 0 || ctx_param != "") fprintf(fp, ", ");
+        fprintf(fp, "%s %s", m_vars[i].type()->name().c_str(),
+                m_vars[i].name().c_str());
+    }
+    fprintf(fp, ")%s", newline? "\n" : "");
+}
+
+Var * EntryPoint::var(const std::string & name)
+{
+    Var *v = NULL;
+    for (size_t i = 0; i < m_vars.size(); i++) {
+        if (m_vars[i].name() == name) {
+            v = &m_vars[i];
+            break;
+        }
+    }
+    return v;
+}
+
+const Var * EntryPoint::var(const std::string & name) const
+{
+    const Var *v = NULL;
+    for (size_t i = 0; i < m_vars.size(); i++) {
+        if (m_vars[i].name() == name) {
+            v = &m_vars[i];
+            break;
+        }
+    }
+    return v;
+}
+
+bool EntryPoint::hasPointers()
+{
+    bool pointers = false;
+    if (m_retval.isPointer()) pointers = true;
+    if (!pointers) {
+        for (size_t i = 0; i < m_vars.size(); i++) {
+            if (m_vars[i].isPointer()) {
+                pointers = true;
+                break;
+            }
+        }
+    }
+    return pointers;
+}
+
+int EntryPoint::validateVarAttr(const std::string& varname, size_t lc) const {
+    if (varname.size() == 0) {
+        fprintf(stderr, "ERROR: %u: Missing variable name in attribute\n", (unsigned int)lc);
+        return -1;
+    }
+    const 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;
+    }
+    return 0;
+}
+
+int EntryPoint::setAttribute(const std::string &line, size_t lc)
+{
+    size_t pos = 0;
+    size_t last;
+    std::string token = getNextToken(line, 0, &last, WHITESPACE);
+    int err = 0;
+    Var* v = nullptr;
+
+    if (token == "len") {
+        pos = last;
+        std::string varname = getNextToken(line, pos, &last, WHITESPACE);
+        err = validateVarAttr(varname, lc);
+        if (err < 0) return err;
+
+        // set the size expression into var
+        v = var(varname);
+        pos = last;
+        v->setLenExpression(line.substr(pos));
+    } else if (token == "param_check") {
+        pos = last;
+        std::string varname = getNextToken(line, pos, &last, WHITESPACE);
+        err = validateVarAttr(varname, lc);
+        if (err < 0) return err;
+
+        v = var(varname);
+        pos = last;
+        v->setParamCheckExpression(line.substr(pos));
+
+    } else if (token == "dir") {
+        pos = last;
+        std::string varname = getNextToken(line, pos, &last, WHITESPACE);
+        err = validateVarAttr(varname, lc);
+        if (err < 0) return err;
+
+        v = var(varname);
+        pos = last;
+
+        std::string pointerDirStr = getNextToken(line, pos, &last, WHITESPACE);
+        if (pointerDirStr.size() == 0) {
+            fprintf(stderr, "ERROR: %u: missing pointer directions\n", (unsigned int)lc);
+            return -3;
+        }
+
+        if (pointerDirStr == "out") {
+            v->setPointerDir(Var::POINTER_OUT);
+        } else if (pointerDirStr == "inout") {
+            v->setPointerDir(Var::POINTER_INOUT);
+        } else if (pointerDirStr == "in") {
+            v->setPointerDir(Var::POINTER_IN);
+        } else {
+            fprintf(stderr, "ERROR: %u: unknown pointer direction %s\n",
+                    (unsigned int)lc, pointerDirStr.c_str());
+        }
+    } else if (token == "var_flag") {
+        pos = last;
+        std::string varname = getNextToken(line, pos, &last, WHITESPACE);
+        err = validateVarAttr(varname, lc);
+        if (err < 0) return err;
+
+        v = var(varname);
+        int count = 0;
+        for (;;) {
+            pos = last;
+            std::string flag = getNextToken(line, pos, &last, WHITESPACE);
+            if (flag.size() == 0) {
+                if (count == 0) {
+                    fprintf(stderr, "ERROR: %u: missing flag\n", (unsigned int) lc);
+                    return -3;
+                }
+                break;
+            }
+            count++;
+
+            if (flag == "nullAllowed") {
+                if (v->isPointer()) {
+                    v->setNullAllowed(true);
+                } else {
+                    fprintf(stderr, "WARNING: %u: setting nullAllowed for non-pointer variable %s\n",
+                            (unsigned int) lc, v->name().c_str());
+                }
+            } else if (flag == "isLarge") {
+                if (v->isPointer()) {
+                    v->setIsLarge(true);
+                } else {
+                    fprintf(stderr, "WARNING: %u: setting isLarge flag for a non-pointer variable %s\n",
+                            (unsigned int) lc, v->name().c_str());
+                }
+            } else if (flag == "DMA") {
+                v->setDMA(true);
+            } else {
+                fprintf(stderr, "WARNING: %u: unknow flag %s\n", (unsigned int)lc, flag.c_str());
+            }
+        }
+    } else if (token == "custom_pack") {
+        pos = last;
+        std::string varname = getNextToken(line, pos, &last, WHITESPACE);
+        err = validateVarAttr(varname, lc);
+        if (err < 0) return err;
+
+        v = var(varname);
+        pos = last;
+        v->setPackExpression(line.substr(pos));
+    } else if (token == "custom_unpack") {
+        pos = last;
+        std::string varname = getNextToken(line, pos, &last, WHITESPACE);
+
+        err = validateVarAttr(varname, lc);
+        if (err < 0) return err;
+
+        v = var(varname);
+        pos = last;
+        v->setUnpackExpression(line.substr(pos));
+    } else if (token == "custom_host_pack_tmp_alloc") {
+        pos = last;
+        std::string varname = getNextToken(line, pos, &last, WHITESPACE);
+        err = validateVarAttr(varname, lc);
+        if (err < 0) return err;
+
+        v = var(varname);
+        if (v->pointerDir() == Var::POINTER_IN) {
+            fprintf(stderr, "ERROR: %u: variable %s is not an output or inout\n",
+                    (unsigned int)lc, varname.c_str());
+            return -2;
+        }
+
+        pos = last;
+        v->setHostPackTmpAllocExpression(line.substr(pos));
+    } else if (token == "custom_host_pack") {
+        pos = last;
+        std::string varname = getNextToken(line, pos, &last, WHITESPACE);
+        err = validateVarAttr(varname, lc);
+        if (err < 0) return err;
+
+        v = var(varname);
+        if (v->pointerDir() == Var::POINTER_IN) {
+            fprintf(stderr, "ERROR: %u: variable %s is not an output or inout\n",
+                    (unsigned int)lc, varname.c_str());
+            return -2;
+        }
+
+        pos = last;
+        v->setHostPackExpression(line.substr(pos));
+    } else if (token == "custom_guest_unpack") {
+        pos = last;
+        std::string varname = getNextToken(line, pos, &last, WHITESPACE);
+        err = validateVarAttr(varname, lc);
+        if (err < 0) return err;
+
+        v = var(varname);
+        if (v->pointerDir() == Var::POINTER_IN) {
+            fprintf(stderr, "ERROR: %u: variable %s is not an output or inout\n",
+                    (unsigned int)lc, varname.c_str());
+            return -2;
+        }
+
+        pos = last;
+        v->setGuestUnpackExpression(line.substr(pos));
+    } else if (token == "custom_write") {
+        pos = last;
+        std::string varname = getNextToken(line, pos, &last, WHITESPACE);
+        err = validateVarAttr(varname, lc);
+        if (err < 0) return err;
+
+        // set the size expression into var
+        v = var(varname);
+        pos = last;
+        v->setWriteExpression(line.substr(pos));
+    } else if (token == "flag") {
+        pos = last;
+        std::string flag = getNextToken(line, pos, &last, WHITESPACE);
+        if (flag.size() == 0) {
+            fprintf(stderr, "ERROR: %u: missing flag\n", (unsigned int) lc);
+            return -4;
+        }
+
+        if (flag == "unsupported") {
+            setUnsupported(true);
+        } else if (flag == "custom_decoder") {
+            setCustomDecoder(true);
+        } else if (flag == "not_api") {
+            setNotApi(true);
+        } else if (flag == "flushOnEncode") {
+            setFlushOnEncode(true);
+        } else {
+            fprintf(stderr, "WARNING: %u: unknown flag %s\n", (unsigned int)lc, flag.c_str());
+        }
+    } else {
+        fprintf(stderr, "WARNING: %u: unknown attribute %s\n", (unsigned int)lc, token.c_str());
+    }
+
+    return 0;
+}
diff --git a/host/commands/emugen/EntryPoint.h b/host/commands/emugen/EntryPoint.h
new file mode 100644
index 0000000000000000000000000000000000000000..bc3fd693787cf201c8e8b300c4ece353036914b7
--- /dev/null
+++ b/host/commands/emugen/EntryPoint.h
@@ -0,0 +1,71 @@
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#ifndef __EntryPoint__H__
+#define __EntryPoint__H__
+
+#include <string>
+#include <vector>
+#include <stdio.h>
+
+#include "Var.h"
+
+//---------------------------------------------------
+
+typedef std::vector<Var> VarsArray;
+
+class EntryPoint {
+public:
+    EntryPoint();
+    virtual ~EntryPoint();
+    bool parse(unsigned int lc, const std::string & str);
+    void reset(); // reset the class to empty;
+    void print(FILE *fp = stdout, bool newline = true,
+               const std::string & name_suffix = std::string(""),
+               const std::string & name_prefix = std::string(""),
+               const std::string & ctx_param = std::string("")) const;
+    const std::string & name() const { return m_name; }
+    VarsArray & vars() { return m_vars; }
+    Var & retval() { return m_retval; }
+    Var * var(const std::string & name);
+    const Var * var(const std::string & name) const;
+    bool hasPointers();
+    bool unsupported() const { return m_unsupported; }
+    void setUnsupported(bool state) { m_unsupported = state; }
+    bool customDecoder() { return m_customDecoder; }
+    void setCustomDecoder(bool state) { m_customDecoder = state; }
+    bool notApi() const { return m_notApi; }
+    void setNotApi(bool state) { m_notApi = state; }
+    bool flushOnEncode() const { return m_flushOnEncode; }
+    void setFlushOnEncode(bool state) { m_flushOnEncode = state; }
+    int validateVarAttr(const std::string& varname, size_t lc) const;
+    int setAttribute(const std::string &line, size_t lc);
+
+private:
+    std::string m_name;
+    Var m_retval;
+    VarsArray m_vars;
+    bool m_unsupported;
+    bool m_customDecoder;
+    bool m_notApi;
+    bool m_flushOnEncode;
+
+    void err(unsigned int lc, const char *msg) {
+        fprintf(stderr, "line %d: %s\n", lc, msg);
+    }
+};
+
+
+#endif
diff --git a/host/commands/emugen/Parser.cpp b/host/commands/emugen/Parser.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0839f20234a33496b0c0a73b514e83ba85e5f52c
--- /dev/null
+++ b/host/commands/emugen/Parser.cpp
@@ -0,0 +1,191 @@
+/*
+* Copyright 2014 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#include "Parser.h"
+
+#include <vector>
+
+#define WHITESPACE " \t\n"
+
+// Parse the |input| string as a list of type-specific tokens.
+// This tokenizes the input, using whitespace as separators and '*' as
+// a single token too. On success, return true and sets |*out| to the
+// list of tokens. On failure, return false.
+//
+// Example: 'const char**foo' -> ['const', 'char', '*', '*', 'foo']
+//
+static bool parseTypeTokens(const std::string& input,
+                            std::vector<std::string>* out,
+                            std::string* error) {
+    out->clear();
+    size_t pos = 0U;
+
+    // Parse all tokens in the input, treat '*' as a single token.
+    // I.e.
+    for (;;) {
+        // skip leading whitespace.
+        pos = input.find_first_not_of(WHITESPACE, pos);
+        if (pos == std::string::npos) {
+            break;  // end of parse.
+        }
+
+        // If this is a star, ensure it follows a type name.
+        // otherwise treat it as part of the final type.
+        if (input[pos] == '*') {
+            out->push_back(std::string("*"));
+            pos += 1U;
+            continue;
+        }
+
+        // find end of type/token.
+        size_t end = input.find_first_of(WHITESPACE "*", pos);
+        if (end == std::string::npos) {
+            end = input.size();
+        }
+
+        std::string str = input.substr(pos, end - pos);
+        if (str.size() == 0) {
+            // Sanity check: should not happen.
+            if (error != NULL) {
+                *error = "Unexpected empty token !?";
+            }
+            return false;
+        }
+
+        out->push_back(str);
+        pos = end;
+    }
+
+    if (error != NULL) {
+        // Sanity check: require non-empty input
+        if (out->empty()) {
+            *error = "Empty parameter declaration!";
+            return false;
+        }
+
+        // Sanity check: There must be base type name before any '*'
+        for (size_t n = 0; n < out->size(); ++n) {
+            std::string& token = (*out)[n];
+            if (token == "*") {
+                *error = "Unexpected '*' before type name";
+                return false;
+            } else if (token != "const") {
+                break;
+            }
+        }
+    }
+
+    return true;
+}
+
+// Given |tokens|, an input vector of strings, join the first |count| items
+// into a normalized type string, and return it.
+static std::string buildTypeString(const std::vector<std::string>& tokens,
+                                   size_t count) {
+    std::string result;
+
+    for (size_t n = 0; n < count; ++n) {
+        const std::string& token = tokens[n];
+        if (n > 0 && token != "*") {
+            result.append(" ");
+        }
+        result.append(token);
+    }
+    return result;
+}
+
+
+std::string normalizeTypeDeclaration(const std::string& input) {
+    std::vector<std::string> tokens;
+    if (!parseTypeTokens(input, &tokens, NULL)) {
+        return "";
+    }
+    return buildTypeString(tokens, tokens.size());
+}
+
+bool parseTypeDeclaration(const std::string& input,
+                          std::string* typeName,
+                          std::string* error) {
+    // The type name can be made of several tokens, e.g. 'unsigned int'
+    // use an array to store them, and a count variable. Each item can be
+    // one of '*', 'const' or a type name component (e.g. 'struct', 'unsigned')
+    std::vector<std::string> tokens;
+
+    if (!parseTypeTokens(input, &tokens, error)) {
+        return false;
+    }
+
+    // Sanity check, there must be a least one non-special tokens.
+    size_t nonSpecialCount = 0;
+    for (size_t n = 0; n < tokens.size(); ++n) {
+        if (tokens[n] != "*" && tokens[n] != "const") {
+            nonSpecialCount++;
+        }
+    }
+    if (nonSpecialCount == 0) {
+        *error = "Missing type name";
+        return false;
+    }
+    // Build the type name from all tokens before it.
+    *typeName = buildTypeString(tokens, tokens.size());
+    return true;
+}
+
+
+bool parseParameterDeclaration(const std::string& param,
+                               std::string* typeName,
+                               std::string* variableName,
+                               std::string* error) {
+    std::vector<std::string> tokens;
+
+    if (!parseTypeTokens(param, &tokens, error)) {
+        return false;
+    }
+
+    // Sanity check, there must be a least two non-special tokens.
+    size_t nonSpecialCount = 0;
+    for (size_t n = 0; n < tokens.size(); ++n) {
+        if (tokens[n] != "*" && tokens[n] != "const") {
+            nonSpecialCount++;
+        }
+    }
+    if (nonSpecialCount == 0) {
+        *error = "Missing type name";
+        return false;
+    }
+    if (nonSpecialCount == 1) {
+        *error = "Missing variable name";
+        return false;
+    }
+
+    // Sanity check: variable name must not be followed by 'const' or '*'
+    const std::string& lastToken = tokens[tokens.size() - 1U];
+    if (lastToken == "*") {
+        *error = "Extra '*' after variable name";
+        return false;
+    }
+    if (lastToken == "const") {
+        *error = "Extra 'const' after variable name";
+        return false;
+    }
+
+    // Extract the variable name as the last token.
+    if (variableName) {
+        *variableName = lastToken;
+    }
+    // Build the type name from all tokens before it.
+    *typeName = buildTypeString(tokens, tokens.size() - 1U);
+    return true;
+}
diff --git a/host/commands/emugen/Parser.h b/host/commands/emugen/Parser.h
new file mode 100644
index 0000000000000000000000000000000000000000..f62c0763bac039f16847bd36479909cfb4dd1338
--- /dev/null
+++ b/host/commands/emugen/Parser.h
@@ -0,0 +1,68 @@
+/*
+* Copyright 2014 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#ifndef PARSER_H
+#define PARSER_H
+
+#include <string>
+
+// Normalize a type declaration. This gets rid of leading/trailing whitespace
+// as well as ensure there is a single space separating all input tokens,
+// with the exception of '*' which is treated specially by never being
+// prepended with a space.
+// |input| is the input type declaration. Return normalized form.
+// Note that this doesn't try to validate the input.
+std::string normalizeTypeDeclaration(const std::string& input);
+
+// Parse a return type declaration. |input| is the type declaration
+// (e.g. 'const char**'). On success return true and sets |*typeName| to
+// the appropriate normalized type string. On failure, return false and
+// sets |*error| with a human-friendly message explaining the reason for
+// failure.
+//
+// Note that the returned type string is normalized, see comment for
+// parseParameterDeclaration() for examples.
+//
+// NOTE: This does not support declarations of arrays or functions!
+//
+bool parseTypeDeclaration(const std::string& input,
+                          std::string* typeName,
+                          std::string* error);
+
+// Parse a function parameter declaration and extract the type and variable
+// name from it. |param| is the individual parameter declaration from the
+// function's signature (e.g. 'const char *items')
+//
+// On success, returns true and sets |*vartype| and |*varname| to the
+// appropriate type name and variable name. |varname| can be NULL if the caller
+// isn't interested in the variable name.
+//
+// On failure, return false and sets |*error| to a human-friendly message
+// explaining the reason for failure.
+//
+// Note that the returned type name is normalized with regards to whitespace
+// and star location, e.g.:
+//
+//      const void *items           -> 'const void*'
+//      char* *items                -> 'char**'
+//      const void * const * items  -> 'const void* const*'
+//      unsigned int *const data    -> 'unsigned int* const'
+//
+bool parseParameterDeclaration(const std::string& param,
+                               std::string* typeName,
+                               std::string* variableName,
+                               std::string* error);
+
+#endif  // PARSER_H
diff --git a/host/commands/emugen/Parser_unittest.cpp b/host/commands/emugen/Parser_unittest.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..904b247372c0167cbf9ce0748eb95f53ab987844
--- /dev/null
+++ b/host/commands/emugen/Parser_unittest.cpp
@@ -0,0 +1,120 @@
+/*
+* Copyright 2014 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#include "Parser.h"
+
+#include <gtest/gtest.h>
+
+#define ARRAYLEN(x)  (sizeof(x) / sizeof(x[0]))
+
+TEST(ParserTest, normalizeTypeDeclaration) {
+    static const struct {
+        const char* expected;
+        const char* input;
+    } kData[] = {
+        { "char", "char" },
+        { "const unsigned int", "   const   unsigned\tint\n" },
+        { "char* const**", "char *const* *" },
+    };
+    const size_t kDataSize = ARRAYLEN(kData);
+    for (size_t n = 0; n < kDataSize; ++n) {
+        std::string result;
+        std::string text = "When parsing '";
+        text += kData[n].input;
+        text += "'";
+
+        result = normalizeTypeDeclaration(kData[n].input);
+        EXPECT_STREQ(kData[n].expected, result.c_str()) << text;
+    }
+}
+
+TEST(ParserTest, parseTypeDeclaration) {
+    static const struct {
+        const char* input;
+        bool expected;
+        const char* expectedType;
+        const char* expectedError;
+    } kData[] = {
+        { "const", false, NULL, "Missing type name" },
+        { "const const", false, NULL, "Missing type name" },
+        { "foo", true, "foo", NULL },
+        { "void", true, "void", NULL },
+        { "const foo", true, "const foo", NULL },
+        { "foo *", true, "foo*", NULL },
+        { "char foo", true, "char foo", NULL },
+        { "\tunsigned \t  int\n", true, "unsigned int", NULL },
+        { "const * char", false, NULL, "Unexpected '*' before type name" },
+        { "const char * ", true, "const char*", NULL },
+        { "const void*const * *", true, "const void* const**", NULL },
+    };
+    const size_t kDataSize = ARRAYLEN(kData);
+    for (size_t n = 0; n < kDataSize; ++n) {
+        std::string varname, vartype, error;
+        std::string text = "When parsing '";
+        text += kData[n].input;
+        text += "'";
+
+        EXPECT_EQ(kData[n].expected,
+                  parseTypeDeclaration(kData[n].input,
+                                       &vartype,
+                                       &error)) << text;
+        if (kData[n].expected) {
+            EXPECT_STREQ(kData[n].expectedType, vartype.c_str()) << text;
+        } else {
+            EXPECT_STREQ(kData[n].expectedError, error.c_str()) << text;
+        }
+    }
+}
+
+TEST(ParserTest, parseParameterDeclaration) {
+    static const struct {
+        const char* input;
+        bool expected;
+        const char* expectedType;
+        const char* expectedVariable;
+        const char* expectedError;
+    } kData[] = {
+        { "foo", false, NULL, NULL, "Missing variable name" },
+        { "const", false, NULL, NULL, "Missing type name" },
+        { "const foo", false, NULL, NULL, "Missing variable name" },
+        { "const const", false, NULL, NULL, "Missing type name" },
+        { "char foo", true, "char", "foo", NULL },
+        { "unsigned   int\t bar\n", true, "unsigned int", "bar", NULL },
+        { "const * char foo", false, NULL, NULL, "Unexpected '*' before type name" },
+        { "const char * foo", true, "const char*", "foo", NULL },
+        { "const void*const *data", true, "const void* const*", "data", NULL },
+        { "char foo const", false, NULL, NULL, "Extra 'const' after variable name" },
+        { "int bar*", false, NULL, NULL, "Extra '*' after variable name" },
+    };
+    const size_t kDataSize = ARRAYLEN(kData);
+    for (size_t n = 0; n < kDataSize; ++n) {
+        std::string varname, vartype, error;
+        std::string text = "When parsing '";
+        text += kData[n].input;
+        text += "'";
+
+        EXPECT_EQ(kData[n].expected,
+                  parseParameterDeclaration(kData[n].input,
+                                            &vartype,
+                                            &varname,
+                                            &error)) << text;
+        if (kData[n].expected) {
+            EXPECT_STREQ(kData[n].expectedType, vartype.c_str()) << text;
+            EXPECT_STREQ(kData[n].expectedVariable, varname.c_str()) << text;
+        } else {
+            EXPECT_STREQ(kData[n].expectedError, error.c_str()) << text;
+        }
+    }
+}
diff --git a/host/commands/emugen/README b/host/commands/emugen/README
new file mode 100644
index 0000000000000000000000000000000000000000..0fe85f941282b4d2986a0c3ecb9bcec936251a8a
--- /dev/null
+++ b/host/commands/emugen/README
@@ -0,0 +1,332 @@
+Introduction:
+-------------
+The emugen tool is a tool to generate a wire protocol implementation
+based on provided API.  The tool generates c++ encoder code that takes
+API calls and encodes them into the wire and decoder code that decodes
+the wire stream and calls server matching API.
+The emugen tool includes additional functionality that enables to
+generate an wrapper library. The wrapper library provides entry points
+for the specified API, where each entry routes the call via a dispatch
+table. The dispatch table may be initialized as required by a specific application.
+
+The following paragraphs includes the following:
+    * Wire Protocol Description
+    * Input files description & format
+    * Generated code description.
+
+
+Note: In this document, the caller is referred to as Encoder or Client
+and the callee is referred to as the Decoder or Server. These terms
+are used interchangeably by the context.
+
+
+
+Wire Protocol packet structure:
+-------------------------------
+A general Encoder->Decoder packet is structured as following:
+struct Packet {
+	unsigned int opcode;
+	unsigned int packet_len;
+	… parameter 1
+	… parameter 2
+};
+A general Decoder->Encoder reply is expected to be received in the
+context of the ‘call’ that triggered it, thus it includes the reply
+data only, with no context headers. In precise term terms, a reply
+packet will look like:
+
+struct {
+	...// reply data
+};
+
+consider the following function call:
+int foo(int p1, short s1)
+will be encoded into :
+{
+	101, // foo opcode
+	14, // sizeof(opcode) + sizeof(packet_len) + sizeof(int) + sizeof(short)
+	p1, // 4 bytes
+	s1 // 2 bytes
+}
+
+Since ‘foo’ returns value, the caller is expected to read back the return packet from the server->client stream. The return value in this example is in thus the return packet is:
+{
+	int retval;
+}
+
+
+Pointer decoding:
+----------------
+The wire protocol also allows exchanging of pointer data
+(arrays). Pointers are defined with directions:
+
+	in : Data is sent from the caller to the calle
+	out: Data is sent from the callee to the caller
+	in_out: data is sent from the caller and return in place.
+
+‘in’ and ‘in_out’ encoded with their len:
+{
+	unsinged int pointer_data_len;
+	unsigned char data[pointer_data_len];… // pointer data
+}
+
+‘out’ pointers are encoded by data length only:
+{
+unsigned int pointer_data_len;
+}
+
+‘out’ and ‘in_out’ pointer’s data is returned in the return
+packet. For example, consider the following call:
+
+int foo(int n, int *ptr); // assume that ‘data’ is in_out pointer which contains ‘n’ ints
+
+The caller packet will have the following form:
+{
+	101, // foo opcode
+	xx, sizeof(opcode) + sizeof(datalen) + sizeof(int) + sizeof(unsigned int) + n * sizeof(int);
+	n, // the n parameter
+	n * sizeof(int), // size of the data in ptr
+	… // n* sizeof(int) bytes
+}
+
+The return packet is;
+{
+	…. // n * sizeof(int) bytes of data return in ptr
+	retval // sizeof(int) - the return value of the function;
+}
+
+Endianess
+---------
+The Wire protocol is designed to impose minimum overhead on the client
+side. Thus, the data endianness that is sent across the wire is
+determined by the ‘client’ side. It is up to the server side to
+determine the client endianess and marshal the packets as required.
+
+
+
+Emugen input files - protocol specification
+-------------------------------------------
+The protocol generated by emugen consists of two input files:
+
+1. basename.in - A sepcification of the protocol RPC procedures. This
+part of the specification is expected to be generated automatically
+from c/c++ header files or similar.
+
+‘basename’ is the basename for the protocol and will be used to prefix
+the files that are generated for this protocol.  A line in the .in
+file has the following format:
+
+[prefix](retvalType, FuncName, <param type> [param name],...)
+where 
+	retvalType - The function return value type
+	FuncName - function name
+	<param type> mandatory parameter type
+	[param name] - optional parameter name
+Examples:
+GL_ENTRY(void, glVertex1f, float v) 
+XXX(int *, foo, int n, float, short)
+XXX(void, glFlush, void)
+
+Note: Empty lines in the file are ignored. A line starts with # is a comment
+
+2. basename.attrib - Attributes information of the API. 
+This file includes additional flags, pointers datalen information and
+global attributes of the protocol. For uptodate format of the file,
+please refer to the specification file in the project source
+tree. The format of the .attrib file is described below.
+
+3. basename.types - Types information
+
+This files describes the types that are described by the API. A type
+is defined as follows:
+<type name> <size in bits> <print format string> <is a pointer? true|false>
+where:
+<type name> is the name of the type as described in the API
+<size in bits> 0, 8, 16, 32 sizes are accepted
+<print format string> a string to format the value of the type, as
+acceted by printf(3)
+<is pointer?> true or false string species whether the type should be
+treated as a pointer.
+
+example:
+GLint 32 %d false
+GLint* 32 %p true
+GLptr  32 %p true
+
+Encoder generated code files 
+----------------------------
+In order to generate the encoder files, one should run the ‘emugen’
+tool as follows:
+
+emugen -i <input directory> -E <encoder files output directory> <basename>
+where:
+	<input directory> containes the api specification files  (basename.in + basename.attrib)
+	<encoder directory> - a directory name to generate the encoder output files
+	basename - The basename for the api.
+
+Assuming the basename is ‘api’, The following files are generated:
+
+api_opcodes.h - defines the protocol opcodes. The first opcode value
+is 0, unless defined otherwise in the .attrib file
+
+api_entry.cpp - defines entry points for the functions that are
+defined by the protocol. this File also includes a function call
+‘setContextAccessor(void *(*f)()). This function should be used to
+provide a callback function that is used by the functions to access
+the encoder context. For example, such callback could fetch the
+context from a Thread Local Storage (TLS) location.
+
+api_client_proc.h - type defintions for the protocol procedures. 
+
+api_client_context.h - defines the client side dispatch table data
+structure that stores the encoding functions. This data structure also
+includes ‘accessors’ methods such that library user can override
+default entries for special case handling.
+
+api_client_context.cpp - defines an initialization function for
+dispatch table
+
+api_enc.h - This header file defines the encoder data strcuture. The
+encoder data structure inherits its functionality from the
+‘client_context’ class above and adds encoding and streaming
+functionality.
+
+api_enc.cpp - Encoder implementation. 
+
+Decoder generated files
+-----------------------
+In order to generate the decoder files, one should run the ‘emugen’
+tool as follows:
+emugen -i <input directory> -D <decoder files output directory> basename
+where:
+	<input directory> containes the api specification files  (basename.in + basename.attrib)
+	<decoder directory> - a directory name to generate the decoder output files
+	basename - The basename for the api.
+
+With resepct to the example above, Emugen will generate the following
+files:
+
+api_opcodes.h - Protocol opcodes
+
+api_server_proc.h - type definitions for the server side procedures
+
+api_server_context.h - dispatch table the decoder functions
+
+api_server_context.cpp - dispatch table initialization function
+api_dec.h - Decoder header file
+
+api_dec.cpp - Decoder implementation. In addtion, this file includes
+an intiailization function that uses a user provided callback to
+initialize the API server implementation. An example for such
+initialization is loading a set of functions from a shared library
+module.
+
+Wrapper generated files
+-----------------------
+In order to generate a wrapper library files, one should run the
+'emugen' tool as follows:
+
+emugen -i <input directory> -W <wrapper files output directory> basename
+where:
+	<input directory> containes the api specification files  (basename.in + basename.attrib)
+	<wrapper directory> - a directory name to generate the wrapper output files
+	basename - The basename for the api.
+
+With resepct to the example above, Emugen will generate the following
+files:
+
+api_wrapper_proc.h - type definitions for the wrapper procedures
+
+api_wrapper_context.h - dispatch table the wrapper functions
+
+api_wrapper_context.cpp - dispatch table initialization function
+api_wrapper_entry.cpp - entry points for the API
+
+
+.attrib file format description:
+-------------------------------
+The .attrib file is an input file to emugen and is used to provide
+ additional information that is required for the code generation.
+The file format is as follows:
+
+a line that starts with # is ignored (comment)
+a empty line just whitespace of (" " "\t" "\n") is ignored.
+
+The file is divided into 'sections', each describes a specific API
+function call. A section starts with the name of the function in
+column 0.
+
+A section that starts with the reserved word 'GLOBAL' provides global
+attributes.
+
+below are few sections examples:
+
+GLOBAL
+  encoder_headers string.h kuku.h
+
+glVertex3fv
+	len data (size)
+glTexImage2D
+       len pixels (pixels == NULL? 0 : (format_pixel_size(internalformat) * width * height * type_size(type)))
+
+
+Global section flags description:
+
+base_opcode
+    set the base opcode value for this api
+    format: base_opcode 100
+
+encoder_headers
+    a list of headers that will be included in the encoder header file
+    format: encoder_headers <stdio.h> "kuku.h"
+
+client_context_headers
+    a list of headers that will be included in the client context header file
+    format: client_context_headers <stdio.h> "kuku.h"
+
+decoder_headers
+    a list of headers that will be included in the decoder header file
+    format: decoder_headers <stdio.h> "kuku.h"
+
+server_context_headers
+    a list of headers that will be included in the server context header file
+    format: server_context_headers <stdio.h> "kuku.h"
+
+
+Entry point flags description:
+
+ len
+	desciption : provide an expression to calcualte an expression data len
+	format: len <var name> <c expression that calcluates the data len>
+
+custom_pack
+	description: provide an expression to pack data into the stream.
+	format: custom_pack <var name> <c++ expression that pack data from var into the stream>
+	The stream is represented by a (unsigned char *)ptr. The expression may also refer
+	to other function parameters. In addition, the expression may refer to 'void *self' which
+	is the encoding context as provided by the caller.
+
+ dir
+	description : set a pointer direction (in - for data that goes
+	to the codec, out from data that returns from the codec.
+     	format: dir <varname> <[in | out | inout]>
+
+ var_flag 
+ 	 description : set variable flags
+ 	 format: var_flag <varname> < nullAllowed | isLarge | ... >
+
+        nullAllowed -> for pointer variables, indicates that NULL is a valid value
+        isLarge     -> for pointer variables, indicates that the data should be sent without an intermediate copy
+
+ flag
+	description: set entry point flag; 
+	format: flag < unsupported | ... >
+	supported flags are:
+	unsupported - The encoder side implementation is pointed to "unsuppored reporting function". 
+	custom_decoder - The decoder is expected to be provided with
+		       	 custom implementation. The call to the
+		       	 deocder function includes a pointer to the
+		       	 context
+    not_api - the function is not native gl api
+
+
diff --git a/host/commands/emugen/README.md b/host/commands/emugen/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..dfc130aa075b0d8b31a1a2aaed6645500f13875c
--- /dev/null
+++ b/host/commands/emugen/README.md
@@ -0,0 +1,17 @@
+# emugen (cuttlefish)
+
+This directory contains a fork of the emugen tool from the external/qemu project
+on the emu-master-dev branch. The tool is unmodified except for the following
+changes:
+
+1) The android/base/EnumFlags.h header has been forked, to avoid having to copy
+   over all of the host-side android-base port.
+
+2) The unittest infrastructure and all unittests have been removed.
+
+3) This README.md file replaces the upstream README file.
+
+4) The binary builds to `emugen_cuttlefish` so as to avoid conflicts.
+
+Do not contribute change only to this project; contribute them to external/qemu
+upstream, then cherry-pick them over.
diff --git a/host/commands/emugen/TypeFactory.cpp b/host/commands/emugen/TypeFactory.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1e0cc96e0517cdc3cbe61d9d75eee1e4be0b67d6
--- /dev/null
+++ b/host/commands/emugen/TypeFactory.cpp
@@ -0,0 +1,157 @@
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#include "TypeFactory.h"
+
+#include "Parser.h"
+#include "VarType.h"
+#include "strUtils.h"
+
+#include <map>
+#include <string>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+
+TypeFactory * TypeFactory::m_instance = NULL;
+
+typedef std::map<std::string, VarType> TypeMap;
+static  TypeMap g_varMap;
+static bool g_initialized = false;
+static int g_typeId = 0;
+
+
+#define ADD_TYPE(name, size, printformat,ispointer)                                           \
+    g_varMap.insert(std::pair<std::string, VarType>(name, VarType(g_typeId++, name, (size + 7) >> 3, printformat , ispointer)));
+
+void TypeFactory::initBaseTypes()
+{
+    g_initialized = true;
+    ADD_TYPE("UNKNOWN", 0, "0x%x", false);
+    ADD_TYPE("void", 0, "0x%x", false);
+    ADD_TYPE("char", 8, "%c", false);
+    ADD_TYPE("int", 32, "%d", false);
+    ADD_TYPE("float", 32, "%d", false);
+    ADD_TYPE("short", 16, "%d", false);
+}
+
+int TypeFactory::initFromFile(const std::string &filename)
+{
+    if (!g_initialized) {
+        initBaseTypes();
+    }
+
+    FILE *fp = fopen(filename.c_str(), "rt");
+    if (fp == NULL) {
+        perror(filename.c_str());
+        return -1;
+    }
+    char line[1000];
+    int lc = 0;
+    while(fgets(line, sizeof(line), fp) != NULL) {
+        lc++;
+        std::string str = trim(line);
+        if (str.size() == 0 || str.at(0) == '#') {
+            continue;
+        }
+        size_t pos = 0, last;
+        std::string name;
+        name = getNextToken(str, pos, &last, WHITESPACE);
+        name = normalizeTypeDeclaration(name);
+        if (name.size() == 0) {
+            fprintf(stderr, "Error: %d : missing type name\n", lc);
+            return -2;
+        }
+        pos = last + 1;
+        std::string size;
+        size = getNextToken(str, pos, &last, WHITESPACE);
+        if (size.size() == 0) {
+            fprintf(stderr, "Error: %d : missing type width\n", lc);
+            return -2;
+        }
+        pos = last + 1;
+        std::string printString;
+        printString = getNextToken(str, pos, &last, WHITESPACE);
+        if (printString.size() == 0) {
+            fprintf(stderr, "Error: %d : missing print-string\n", lc);
+            return -2;
+        }
+
+        // The ispointer definition is optional since we can just
+        // look at the type name, and determine it is a pointer if
+        // it ends with '*'.
+        bool isPointer = (name[name.size() - 1U] == '*');
+
+        pos = last + 1;
+        std::string pointerDef;
+        pointerDef = getNextToken(str, pos, &last, WHITESPACE);
+        if (pointerDef.size() != 0) {
+            // Just a little sanity check.
+            if (std::string("true")==pointerDef) {
+                if (!isPointer) {
+                    fprintf(stderr, "Error: %d: invalid isPointer definition: 'true' but name does not end with '*'!\n", lc);
+                    return -2;
+                }
+            } else if (std::string("false")==pointerDef) {
+                if (isPointer) {
+                    fprintf(stderr, "Error: %d: invalid isPointer definition: 'false' but name does end with '*'!\n", lc);
+                    return -2;
+                }
+            } else {
+                fprintf(stderr, "Error: %d : invalid isPointer definition, must be either \"true\" or \"false\"\n", lc);
+                return -2;
+            }
+        }
+
+        size_t bitSize = atoi(size.c_str());
+        size_t byteSize = (bitSize + 7) >> 3;
+
+        if (getVarTypeByName(name)->id() != 0) {
+            fprintf(stderr,
+                    "Warining: %d : type %s is already known, definition in line %d is taken\n",
+                    lc, name.c_str(), lc);
+        }
+        g_varMap.insert(std::pair<std::string, VarType>(
+                name, VarType(g_typeId++,
+                              name,
+                              byteSize,
+                              printString,
+                              isPointer)));
+        std::string constName = "const " + name;
+        g_varMap.insert(std::pair<std::string, VarType>(
+                constName, VarType(g_typeId++,
+                                   constName,
+                                   byteSize,
+                                   printString,
+                                   isPointer))); //add a const type
+    }
+    g_initialized = true;
+    return 0;
+}
+
+
+const VarType * TypeFactory::getVarTypeByName(const std::string & type)
+{
+    if (!g_initialized) {
+        initBaseTypes();
+    }
+    TypeMap::iterator i = g_varMap.find(type);
+    if (i == g_varMap.end()) {
+        i = g_varMap.find("UNKNOWN");
+    }
+    return &(i->second);
+}
+
diff --git a/host/commands/emugen/TypeFactory.h b/host/commands/emugen/TypeFactory.h
new file mode 100644
index 0000000000000000000000000000000000000000..deee2ca49f3ec500e35ae14adf4a7f7ee3df8b01
--- /dev/null
+++ b/host/commands/emugen/TypeFactory.h
@@ -0,0 +1,37 @@
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#ifndef __TYPE__FACTORY__H__
+#define __TYPE__FACTORY__H__
+
+#include <string>
+#include "VarType.h"
+
+class TypeFactory {
+public:
+    static TypeFactory *instance() {
+        if (m_instance == NULL) {
+            m_instance = new TypeFactory;
+        }
+        return m_instance;
+    }
+    const VarType * getVarTypeByName(const std::string &type);
+    int  initFromFile(const std::string &filename);
+private:
+    static TypeFactory *m_instance;
+    void initBaseTypes();
+    TypeFactory() {}
+};
+#endif
diff --git a/host/commands/emugen/Var.h b/host/commands/emugen/Var.h
new file mode 100644
index 0000000000000000000000000000000000000000..823058d6e914e368e4a37e775a98113d8308e884
--- /dev/null
+++ b/host/commands/emugen/Var.h
@@ -0,0 +1,118 @@
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#ifndef __VAR__H__
+#define __VAR__H__
+
+#include "VarType.h"
+#include <string>
+#include <stdio.h>
+
+class Var {
+public:
+    // pointer data direction - from the client point of view.
+    typedef enum { POINTER_OUT = 0x1, POINTER_IN = 0x2, POINTER_INOUT = 0x3 } PointerDir;
+    Var() = default;
+
+    Var(const std::string & name,
+        const VarType * vartype,
+        const std::string & lenExpression,
+        PointerDir dir,
+        const std::string &packExpression,
+        const std::string &unpackExpression,
+        const std::string &writeExpression) :
+        m_name(name),
+        m_type(const_cast<VarType *>(vartype)),
+        m_lenExpression(lenExpression),
+        m_pointerDir(dir),
+        m_packExpression(packExpression),
+        m_unpackExpression(unpackExpression),
+        m_host_packTmpAllocExpression(""),
+        m_host_packExpression(""),
+        m_guest_unpackExpression(""),
+        m_writeExpression(writeExpression)
+    {
+    }
+
+    void init(const std::string name, const VarType * vartype,
+              std::string lenExpression,
+              PointerDir dir,
+              std::string packExpression,
+              std::string unpackExpression,
+              std::string writeExpression) {
+        m_name = name;
+        m_type = vartype;
+        m_lenExpression = lenExpression;
+        m_packExpression = packExpression;
+        m_unpackExpression = unpackExpression;
+        m_host_packTmpAllocExpression = "";
+        m_host_packExpression = "";
+        m_guest_unpackExpression = "";
+        m_writeExpression = writeExpression;
+        m_pointerDir = dir;
+        m_nullAllowed = false;
+        m_isLarge = false;
+
+    }
+
+    const std::string & name() const { return m_name; }
+    const VarType * type() const { return m_type; }
+    bool isPointer() const { return m_type->isPointer(); }
+    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 & unpackExpression() const { return(m_unpackExpression); }
+    const std::string & hostPackTmpAllocExpression() const { return(m_host_packTmpAllocExpression); }
+    const std::string & hostPackExpression() const { return(m_host_packExpression); }
+    const std::string & guestUnpackExpression() const { return(m_guest_unpackExpression); }
+    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 setUnpackExpression(const std::string & unpackExpression) { m_unpackExpression = unpackExpression; }
+    void setHostPackTmpAllocExpression(const std::string & expr) { m_host_packTmpAllocExpression = expr; }
+    void setHostPackExpression(const std::string & expr) { m_host_packExpression = expr; }
+    void setGuestUnpackExpression(const std::string & expr) { m_guest_unpackExpression = expr; }
+    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; }
+    void setNullAllowed(bool state) { m_nullAllowed = state; }
+    void setIsLarge(bool state) { m_isLarge = state; }
+    void setDMA(bool state) { m_isDMA = state; }
+    bool nullAllowed() const { return m_nullAllowed; }
+    bool isLarge() const { return m_isLarge; }
+    bool isDMA() const { return m_isDMA; }
+    void printType(FILE *fp) { fprintf(fp, "%s", m_type->name().c_str()); }
+    void printTypeName(FILE *fp) { printType(fp); fprintf(fp, " %s", m_name.c_str()); }
+
+private:
+    std::string m_name;
+    const VarType * m_type = nullptr;
+    std::string m_lenExpression; // an expression to calcualte a pointer data size
+    PointerDir m_pointerDir = POINTER_IN;
+    bool m_nullAllowed = false;
+    bool m_isLarge = false;
+    bool m_isDMA = false;
+    std::string m_packExpression; // an expression to pack data into the stream
+    std::string m_unpackExpression; // an expression to unpack data that has arrived from the stream
+    std::string m_host_packTmpAllocExpression; // an expression to create temporaries for getting into packed form for readbacks
+    std::string m_host_packExpression; // an expression to pack data into the stream but for readbacks
+    std::string m_guest_unpackExpression; // an expression to unpack readbacks on the guest
+    std::string m_writeExpression; // an expression to write data into the stream
+    std::string m_paramCheckExpression; //an expression to check parameter value
+};
+
+#endif
diff --git a/host/commands/emugen/VarType.h b/host/commands/emugen/VarType.h
new file mode 100644
index 0000000000000000000000000000000000000000..b6937a002cfa7d828a8b4d26227194898aff56f5
--- /dev/null
+++ b/host/commands/emugen/VarType.h
@@ -0,0 +1,62 @@
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#ifndef __VARTYPE__H__
+#define __VARTYPE__H__
+
+#include <string>
+
+// VarType models the types of values used on the wire protocol by
+// both encoders and decoders. Each type is identified by a unique id,
+// and a name, and provides a size in bytes for the values, a printf-like
+// formatter string, and a flag telling if the value corresponds to a
+// pointer.
+class VarType {
+public:
+    VarType() :
+            m_id(0),
+            m_name("default_constructed"),
+            m_byteSize(0),
+            m_printFormat("0x%x"),
+            m_isPointer(false) {}
+
+    VarType(size_t id,
+            const std::string& name,
+            size_t byteSize,
+            const std::string& printFormat,
+            bool isPointer) :
+            m_id(id),
+            m_name(name),
+            m_byteSize(byteSize),
+            m_printFormat(printFormat),
+            m_isPointer(isPointer) {}
+
+    ~VarType() {}
+
+    size_t id() const { return m_id; }
+    const std::string& name() const { return m_name; }
+    size_t bytes() const { return m_byteSize; }
+    const std::string& printFormat() const { return m_printFormat; }
+    bool isPointer() const { return m_isPointer; }
+
+private:
+    size_t m_id;
+    std::string m_name;
+    size_t m_byteSize;
+    std::string m_printFormat;
+    bool m_isPointer;
+};
+
+#endif
diff --git a/host/commands/emugen/android/base/EnumFlags.h b/host/commands/emugen/android/base/EnumFlags.h
new file mode 100644
index 0000000000000000000000000000000000000000..fec56b9282796c68878241754bd3859638836b34
--- /dev/null
+++ b/host/commands/emugen/android/base/EnumFlags.h
@@ -0,0 +1,117 @@
+// Copyright 2015 The Android Open Source Project
+//
+// This software is licensed under the terms of the GNU General Public
+// License version 2, as published by the Free Software Foundation, and
+// may be copied, distributed, and modified under those terms.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+#pragma once
+
+#include <type_traits>
+
+// This header defines some utitily methods to manipulate scoped enums as flags
+// C++11 scoped enums by default don't support flag operations (e.g. if (a & b))
+// We need to define bitwise operations for them to be able to have strongly
+// typed flags in our code.
+//
+// To enable the flag operators for your enum, most probably you just need to
+// include this file. The only exception is if your enum is located in some
+// namespace other than android, android::base or global. In that case you also
+// need to add the following using to bring in the operators:
+//
+// using namespace ::android::base::EnumFlags;
+
+namespace android {
+namespace base {
+namespace EnumFlags {
+
+// A predicate which checks if template agument is a scoped enum
+template<class E>
+using is_scoped_enum = std::integral_constant<
+        bool,
+        std::is_enum<E>::value && !std::is_convertible<E, int>::value>;
+
+template <class E>
+using underlying_enum_type = typename std::underlying_type<E>::type;
+
+template <class E, class Res = E>
+using enable_if_scoped_enum =
+    typename std::enable_if<is_scoped_enum<E>::value, Res>::type;
+
+template <class E>
+enable_if_scoped_enum<E> operator|(E l, E r) {
+    return static_cast<E>(static_cast<underlying_enum_type<E>>(l)
+                          | static_cast<underlying_enum_type<E>>(r));
+}
+
+template <class E>
+enable_if_scoped_enum<E> operator&(E l, E r) {
+    return static_cast<E>(static_cast<underlying_enum_type<E>>(l)
+                          & static_cast<underlying_enum_type<E>>(r));
+}
+
+template <class E>
+enable_if_scoped_enum<E> operator~(E e) {
+    return static_cast<E>(~static_cast<underlying_enum_type<E>>(e));
+}
+
+template <class E>
+enable_if_scoped_enum<E> operator|=(E& l, E r) {
+    return l = (l | r);
+}
+
+template <class E>
+enable_if_scoped_enum<E> operator&=(E& l, E r) {
+    return l = (l & r);
+}
+
+template <class E>
+enable_if_scoped_enum<E, bool> operator!(E e) {
+    return !static_cast<underlying_enum_type<E>>(e);
+}
+
+template <class E>
+enable_if_scoped_enum<E, bool> operator!=(E e, int val) {
+    return static_cast<underlying_enum_type<E>>(e) !=
+            static_cast<underlying_enum_type<E>>(val);
+}
+
+template <class E>
+enable_if_scoped_enum<E, bool> operator!=(int val, E e) {
+    return e != val;
+}
+
+template <class E>
+enable_if_scoped_enum<E, bool> operator==(E e, int val) {
+    return static_cast<underlying_enum_type<E>>(e) ==
+            static_cast<underlying_enum_type<E>>(val);
+}
+
+template <class E>
+enable_if_scoped_enum<E, bool> operator==(int val, E e) {
+    return e == val;
+}
+
+template <class E>
+enable_if_scoped_enum<E, bool> nonzero(E e) {
+    return static_cast<underlying_enum_type<E>>(e) != 0;
+}
+
+}  // namespace EnumFlags
+
+// For the ADL to kick in let's make sure we bring all the operators into our
+// main AndroidEmu namespaces...
+using namespace ::android::base::EnumFlags;
+
+}  // namespace base
+
+using namespace ::android::base::EnumFlags;
+
+}  // namespace android
+
+// ... and into the global one, where most of the client functions are
+using namespace ::android::base::EnumFlags;
diff --git a/host/commands/emugen/errors.h b/host/commands/emugen/errors.h
new file mode 100644
index 0000000000000000000000000000000000000000..d09c292910549d6986bddf57b4df1d4485e17cb4
--- /dev/null
+++ b/host/commands/emugen/errors.h
@@ -0,0 +1,24 @@
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#ifndef _ERRORS_H_
+#define _ERRORS_H_
+
+#define BAD_USAGE -1
+#define BAD_SPEC_FILE -2
+#define BAD_TYPES_FILE -3
+#define BAD_ATTRIBUTES_FILE -4
+
+#endif
diff --git a/host/commands/emugen/getopt.c b/host/commands/emugen/getopt.c
new file mode 100644
index 0000000000000000000000000000000000000000..d11be644b5feeec87410f56841d92d8d2043c805
--- /dev/null
+++ b/host/commands/emugen/getopt.c
@@ -0,0 +1,76 @@
+#include "getopt.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#define  _getprogname() nargv[0]
+
+int opterr = 1;
+int optind = 1;
+int optopt = 0;
+char* optarg;
+
+int getopt(int argc, char* const argv[], const char* ostr) {
+    static const char kEmpty[] = "";
+    static const char* place = kEmpty;
+    if (!*place) {
+        if (optind >= argc)
+            return -1;
+
+        const char* arg = argv[optind];
+        if (arg[0] != '-') {
+            // Not an option.
+            return -1;
+        }
+        if (arg[1] == '-' && !arg[2]) {
+            // '--' -> end of options.
+            return -1;
+        }
+        if (!arg[1]) {
+            // Single '-', If the program wants it, treat it as an option.
+            // Otherwise, it's the end of options.
+            if (!strchr(ostr, '-')) {
+                return -1;
+            }
+            optopt = '-';
+            place = arg + 1;
+        } else {
+            optopt = arg[1];
+            place = arg + 2;
+        }
+    };
+
+    char* oindex = strchr(ostr, optopt);
+    if (!oindex) {
+        // Unsupported option.
+        (void)fprintf(stderr, "%s: illegal option -- %c\n", argv[0], optopt);
+        return '?';
+    }
+    if (oindex[1] != ':') {
+        // No argument needed.
+        optarg = NULL;
+        if (!*place)
+            optind++;
+        return optopt;
+    }
+
+    // This option needs an argument. Either after the option character,
+    // or the argument that follows.
+    if (*place) {
+        optarg = (char *)place;
+    } else if (argc > ++optind) {
+        optarg = (char *)argv[optind++];
+    } else if (oindex[2] == ':') {
+        // Optional argument is missing.
+        place = kEmpty;
+        optarg = NULL;
+        return optopt;
+    } else {
+        // Missing argument.
+        place = kEmpty;
+        (void)fprintf(stderr, "%s: option requires an argument --%c\n",
+                      argv[0], optopt);
+        return ':';
+    }
+    return optopt;
+}
diff --git a/host/commands/emugen/getopt.h b/host/commands/emugen/getopt.h
new file mode 100644
index 0000000000000000000000000000000000000000..cc04850a22c4cc112e8f3c68d6391341b1486813
--- /dev/null
+++ b/host/commands/emugen/getopt.h
@@ -0,0 +1,18 @@
+#ifndef GETOPT_H
+#define GETOPT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int optind;
+extern char* optarg;
+extern int optopt;
+
+int getopt(int argc, char* const argv[], const char* ostr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  // GETOPT_H
diff --git a/host/commands/emugen/main.cpp b/host/commands/emugen/main.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6200349f7fc85608b7e57010e36ed359edb4b15d
--- /dev/null
+++ b/host/commands/emugen/main.cpp
@@ -0,0 +1,164 @@
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include "errors.h"
+#include "EntryPoint.h"
+#include "strUtils.h"
+#include "ApiGen.h"
+#include "TypeFactory.h"
+#include "getopt.h"
+
+const std::string SPEC_EXTENSION = std::string(".in");
+const std::string ATTRIB_EXTENSION = std::string(".attrib");
+const std::string TYPES_EXTENTION = std::string(".types");
+
+
+void usage(const char *filename)
+{
+    fprintf(stderr, "Usage: %s [options] <base name>\n", filename);
+    fprintf(stderr, "\t-h: This message\n");
+    fprintf(stderr, "\t-E <dir>: generate encoder into dir\n");
+    fprintf(stderr, "\t-D <dir>: generate decoder into dir\n");
+    fprintf(stderr, "\t-i: input dir, local directory by default\n");
+    fprintf(stderr, "\t-T : generate attribute template into the input directory\n\t\tno other files are generated\n");
+    fprintf(stderr, "\t-W : generate wrapper into dir\n");
+}
+
+int main(int argc, char *argv[])
+{
+    std::string encoderDir = "";
+    std::string decoderDir = "";
+    std::string wrapperDir = "";
+    std::string inDir = ".";
+    bool generateAttributesTemplate = false;
+
+    int c;
+    while((c = getopt(argc, argv, "TE:D:i:hW:")) != -1) {
+        switch(c) {
+        case 'W':
+            wrapperDir = std::string(optarg);
+            break;
+        case 'T':
+            generateAttributesTemplate = true;
+            break;
+        case 'h':
+            usage(argv[0]);
+            exit(0);
+            break;
+        case 'E':
+            encoderDir = std::string(optarg);
+            break;
+        case 'D':
+            decoderDir = std::string(optarg);
+            break;
+        case 'i':
+            inDir = std::string(optarg);
+            break;
+        case ':':
+            fprintf(stderr, "Missing argument !!\n");
+            [[fallthrough]];
+        default:
+            usage(argv[0]);
+            exit(0);
+        }
+    }
+
+    if (optind >= argc) {
+        fprintf(stderr, "Usage: %s [options] <base name> \n", argv[0]);
+        return BAD_USAGE;
+    }
+
+    if (encoderDir.size() == 0 &&
+        decoderDir.size() == 0 &&
+        generateAttributesTemplate == false &&
+        wrapperDir.size() == 0) {
+        fprintf(stderr, "No output specified - aborting\n");
+        return BAD_USAGE;
+    }
+
+    std::string baseName = std::string(argv[optind]);
+    ApiGen apiEntries(baseName);
+
+    // init types;
+    std::string typesFilename = inDir + "/" + baseName + TYPES_EXTENTION;
+
+    if (TypeFactory::instance()->initFromFile(typesFilename) < 0) {
+        fprintf(stderr, "missing or error reading types file: %s...ignored\n", typesFilename.c_str());
+    }
+
+    std::string filename = inDir + "/" + baseName + SPEC_EXTENSION;
+    if (apiEntries.readSpec(filename) < 0) {
+        perror(filename.c_str());
+        return BAD_SPEC_FILE;
+    }
+
+
+    if (generateAttributesTemplate) {
+        apiEntries.genAttributesTemplate(inDir + "/" + baseName + ATTRIB_EXTENSION);
+        exit(0);
+    }
+
+    std::string attribFileName = inDir + "/" + baseName + ATTRIB_EXTENSION;
+    if (apiEntries.readAttributes(attribFileName) < 0) {
+        perror(attribFileName.c_str());
+        fprintf(stderr, "failed to parse attributes\n");
+        exit(1);
+    }
+
+    if (encoderDir.size() != 0) {
+
+        apiEntries.genOpcodes(encoderDir + "/" + baseName + "_opcodes.h");
+        apiEntries.genContext(encoderDir + "/" + baseName + "_client_context.h", ApiGen::CLIENT_SIDE);
+        apiEntries.genContextImpl(encoderDir + "/" + baseName + "_client_context.cpp", ApiGen::CLIENT_SIDE);
+
+        apiEntries.genProcTypes(encoderDir + "/" + baseName + "_client_proc.h", ApiGen::CLIENT_SIDE);
+        apiEntries.genFuncTable(encoderDir + "/" + baseName + "_ftable.h", ApiGen::CLIENT_SIDE);
+
+        apiEntries.genEntryPoints(encoderDir + "/" + baseName + "_entry.cpp", ApiGen::CLIENT_SIDE);
+        apiEntries.genEncoderHeader(encoderDir + "/" + baseName + "_enc.h");
+        apiEntries.genEncoderImpl(encoderDir + "/" + baseName + "_enc.cpp");
+    }
+
+    if (decoderDir.size() != 0) {
+        apiEntries.genOpcodes(decoderDir + "/" + baseName + "_opcodes.h");
+        apiEntries.genProcTypes(decoderDir + "/" + baseName + "_server_proc.h", ApiGen::SERVER_SIDE);
+        apiEntries.genContext(decoderDir + "/" + baseName + "_server_context.h", ApiGen::SERVER_SIDE);
+        apiEntries.genContextImpl(decoderDir + "/" + baseName + "_server_context.cpp", ApiGen::SERVER_SIDE);
+        apiEntries.genDecoderHeader(decoderDir + "/" + baseName + "_dec.h");
+        apiEntries.genDecoderImpl(decoderDir + "/" + baseName + "_dec.cpp");
+    }
+
+    if (wrapperDir.size() != 0) {
+        apiEntries.genProcTypes(wrapperDir + "/" + baseName + "_wrapper_proc.h", ApiGen::WRAPPER_SIDE);
+        apiEntries.genContext(wrapperDir + "/" + baseName + "_wrapper_context.h", ApiGen::WRAPPER_SIDE);
+        apiEntries.genContextImpl(wrapperDir + "/" + baseName + "_wrapper_context.cpp", ApiGen::WRAPPER_SIDE);
+        apiEntries.genEntryPoints(wrapperDir + "/" + baseName + "_wrapper_entry.cpp", ApiGen::WRAPPER_SIDE);
+    }
+
+#ifdef DEBUG_DUMP
+    int withPointers = 0;
+    printf("%d functions found\n", int(apiEntries.size()));
+    for (int i = 0; i < apiEntries.size(); i++) {
+        if (apiEntries[i].hasPointers()) {
+            withPointers++;
+            apiEntries[i].print();
+        }
+    }
+    fprintf(stdout, "%d entries has poitners\n", withPointers);
+#endif
+
+}
diff --git a/host/commands/emugen/strUtils.cpp b/host/commands/emugen/strUtils.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..357054b5c686b90f6380df425d0c65322bc36c96
--- /dev/null
+++ b/host/commands/emugen/strUtils.cpp
@@ -0,0 +1,49 @@
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#include "strUtils.h"
+
+using namespace std;
+
+
+std::string getNextToken(const std::string & str, size_t pos, size_t * last, const std::string & delim)
+{
+    if (str.size() == 0 || pos >= str.size()) return "";
+
+    pos = str.find_first_not_of(WHITESPACE, pos);
+    if (pos == std::string::npos) return "";
+
+    *last = str.find_first_of(delim, pos);
+    if (*last == std::string::npos) *last = str.size();
+    std::string retval = str.substr(pos, *last - pos);
+    retval = trim(retval);
+    return retval;
+}
+
+
+std::string trim(const string & str)
+{
+  string result;
+  string::size_type start = str.find_first_not_of(WHITESPACE, 0);
+  string::size_type end = str.find_last_not_of(WHITESPACE);
+  if (start == string::npos || end == string::npos) {
+    result = string("");
+  } else {
+    result = str.substr(start, end - start + 1);
+  }
+  return result;
+}
+
+
diff --git a/host/commands/emugen/strUtils.h b/host/commands/emugen/strUtils.h
new file mode 100644
index 0000000000000000000000000000000000000000..3fa0908d3d86131bac47eb6da0cf2dce89916e2f
--- /dev/null
+++ b/host/commands/emugen/strUtils.h
@@ -0,0 +1,33 @@
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#ifndef STR_UTILS_H_
+#define STR_UTILS_H_
+
+#include <string>
+#include <sstream>
+
+#define WHITESPACE " \t\n"
+
+std::string trim(const std::string & str);
+std::string getNextToken(const std::string & str, size_t pos, size_t * last, const std::string & delim);
+template <class T> std::string inline toString(const T& t) {
+    std::stringstream ss;
+    ss << t;
+    return ss.str();
+
+}
+
+#endif
diff --git a/host/commands/emugen/tests/run-tests.sh b/host/commands/emugen/tests/run-tests.sh
new file mode 100755
index 0000000000000000000000000000000000000000..67409edcc2353f64787b6b88e47db8255b2a70f6
--- /dev/null
+++ b/host/commands/emugen/tests/run-tests.sh
@@ -0,0 +1,129 @@
+#!/bin/sh
+
+# Copyright 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+set -e
+
+export LANG=C
+export LC_ALL=C
+
+PROGDIR=$(dirname "$0")
+PROGNAME=$(basename "$0")
+
+fatal () {
+    echo "ERROR: $@"
+    exit 1
+}
+
+OPT_EMUGEN=
+OPT_HELP=
+OPT_OUT_DIR=
+OPT_TOOL=
+
+for OPT; do
+    OPTARG=$(expr "x$OPT" : "x[^=]*=\\(.*\\)" || true)
+    case $OPT in
+    --help|-h|-?)
+        OPT_HELP=true
+        ;;
+    --emugen=*)
+        OPT_EMUGEN=$OPTARG
+        ;;
+    --out-dir=*)
+        OPT_OUT_DIR=$OPTARG
+        ;;
+    --tool=*)
+        OPT_TOOL=$OPTARG
+        ;;
+    -*)
+        fatal "Invalid option '$OPT', see --help."
+        ;;
+    *)
+        fatal "This script doesn't take arguments, see --help."
+        ;;
+    esac
+done
+
+if [ "$OPT_HELP" ]; then
+    cat <<EOF
+Usage: $PROGNAME [options]
+
+Run the emugen test suite. This scripts looks for sub-directories
+named t.<number>/input, and uses them as input to 'emugen'. It then
+compares the output to t.<number>/expected/ content.
+
+Valid options:
+    --help|-h|-?         Print this help.
+    --out-dir=<dir>      Generate outputs into <dir>.
+    --emugen=<program>   Emugen program path, if not in path.
+    --tool=<tool>        Launch visual diff tool in case of differences.
+EOF
+    exit 0
+fi
+
+# Find emugen program
+EMUGEN=
+if [ "$OPT_EMUGEN" ]; then
+    EMUGEN=$OPT_EMUGEN
+else
+    EMUGEN=$(which emugen 2>/dev/null || true)
+    if [ -z "$EMUGEN" ]; then
+        fatal "Cannot find 'emugen' program in PATH, use --emugen=<program> option."
+    fi
+    echo "Auto-config: --emugen=$EMUGEN"
+fi
+if [ ! -f "$EMUGEN" ]; then
+    fatal "Emugen program doesn't exist: $EMUGEN"
+fi
+
+# Create output directory.
+OUT_DIR=
+if [ "$OPT_OUT_DIR" ]; then
+    OUT_DIR=$OPT_OUT_DIR
+else
+    OUT_DIR=/tmp/$USER-emugen-testing
+    echo "Auto-config: --out-dir=$OUT_DIR"
+fi
+mkdir -p "$OUT_DIR" && rm -rf "$OUT_DIR/emugen"
+
+OUT_DIR=$OUT_DIR/emugen
+
+# Find test directories
+TEST_DIRS=$(cd "$PROGDIR" && find . -name "t.*" | sed -e 's|^\./||')
+for TEST_DIR in $TEST_DIRS; do
+    IN=$PROGDIR/$TEST_DIR/input
+    PREFIXES=$(cd $IN && find . -name "*.in" | sed -e 's|^\./||g' -e 's|\.in$||g')
+    OUT=$OUT_DIR/$TEST_DIR
+    mkdir -p "$OUT/encoder"
+    mkdir -p "$OUT/decoder"
+    mkdir -p "$OUT/wrapper"
+    for PREFIX in $PREFIXES; do
+        echo "Processing $IN/foo.*"
+        $EMUGEN -i "$PROGDIR/$TEST_DIR/input" -D "$OUT/decoder" -E "$OUT/encoder" -W "$OUT/wrapper" $PREFIX
+    done
+    if ! diff -qr "$PROGDIR/$TEST_DIR/expected" "$OUT"; then
+        if [ "$OPT_TOOL" ]; then
+            $OPT_TOOL "$PROGDIR/$TEST_DIR/expected" "$OUT"
+        else
+            echo "ERROR: Invalid differences between actual and expected output!"
+            diff -burN "$PROGDIR/$TEST_DIR/expected" "$OUT"
+            exit 1
+        fi
+    fi
+done
+
+echo "All good!"
+exit 0
diff --git a/host/commands/emugen/tests/t.001/expected/decoder/foo_dec.cpp b/host/commands/emugen/tests/t.001/expected/decoder/foo_dec.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ec16b177fcf65bcf0f710207ab6d11d82c083d10
--- /dev/null
+++ b/host/commands/emugen/tests/t.001/expected/decoder/foo_dec.cpp
@@ -0,0 +1,178 @@
+// Generated Code - DO NOT EDIT !!
+// generated by 'emugen'
+
+
+#include <string.h>
+#include "foo_opcodes.h"
+
+#include "foo_dec.h"
+
+
+#include "ProtocolUtils.h"
+
+#include "ChecksumCalculatorThreadInfo.h"
+
+#include <stdio.h>
+
+typedef unsigned int tsize_t; // Target "size_t", which is 32-bit for now. It may or may not be the same as host's size_t when emugen is compiled.
+
+#ifdef OPENGL_DEBUG_PRINTOUT
+#  define DEBUG(...) do { if (emugl_cxt_logger) { emugl_cxt_logger(__VA_ARGS__); } } while(0)
+#else
+#  define DEBUG(...)  ((void)0)
+#endif
+
+#ifdef CHECK_GL_ERRORS
+#  define SET_LASTCALL(name)  sprintf(lastCall, #name)
+#else
+#  define SET_LASTCALL(name)
+#endif
+using namespace emugl;
+
+size_t foo_decoder_context_t::decode(void *buf, size_t len, IOStream *stream, ChecksumCalculator* checksumCalc) {
+	if (len < 8) return 0; 
+#ifdef CHECK_GL_ERRORS
+	char lastCall[256] = {0};
+#endif
+	unsigned char *ptr = (unsigned char *)buf;
+	const unsigned char* const end = (const unsigned char*)buf + len;
+    const size_t checksumSize = checksumCalc->checksumByteSize();
+    const bool useChecksum = checksumSize > 0;
+	while (end - ptr >= 8) {
+		uint32_t opcode = *(uint32_t *)ptr;   
+		int32_t packetLen = *(int32_t *)(ptr + 4);
+		if (end - ptr < packetLen) return ptr - (unsigned char*)buf;
+		switch(opcode) {
+		case OP_fooAlphaFunc: {
+			FooInt var_func = Unpack<FooInt,uint32_t>(ptr + 8);
+			FooFloat var_ref = Unpack<FooFloat,uint32_t>(ptr + 8 + 4);
+			if (useChecksum) {
+				ChecksumCalculatorThreadInfo::validOrDie(checksumCalc, ptr, 8 + 4 + 4, ptr + 8 + 4 + 4, checksumSize, 
+					"foo_decoder_context_t::decode, OP_fooAlphaFunc: GL checksumCalculator failure\n");
+			}
+			DEBUG("foo(%p): fooAlphaFunc(%d %f )\n", stream, var_func, var_ref);
+			this->fooAlphaFunc(var_func, var_ref);
+			SET_LASTCALL("fooAlphaFunc");
+			break;
+		}
+		case OP_fooIsBuffer: {
+			uint32_t size_stuff __attribute__((unused)) = Unpack<uint32_t,uint32_t>(ptr + 8);
+			InputBuffer inptr_stuff(ptr + 8 + 4, size_stuff);
+			if (useChecksum) {
+				ChecksumCalculatorThreadInfo::validOrDie(checksumCalc, ptr, 8 + 4 + size_stuff, ptr + 8 + 4 + size_stuff, checksumSize, 
+					"foo_decoder_context_t::decode, OP_fooIsBuffer: GL checksumCalculator failure\n");
+			}
+			size_t totalTmpSize = sizeof(FooBoolean);
+			totalTmpSize += checksumSize;
+			unsigned char *tmpBuf = stream->alloc(totalTmpSize);
+			DEBUG("foo(%p): fooIsBuffer(%p(%u) )\n", stream, (void*)(inptr_stuff.get()), size_stuff);
+			*(FooBoolean *)(&tmpBuf[0]) = 			this->fooIsBuffer((void*)(inptr_stuff.get()));
+			if (useChecksum) {
+				ChecksumCalculatorThreadInfo::writeChecksum(checksumCalc, &tmpBuf[0], totalTmpSize - checksumSize, &tmpBuf[totalTmpSize - checksumSize], checksumSize);
+			}
+			stream->flush();
+			SET_LASTCALL("fooIsBuffer");
+			break;
+		}
+		case OP_fooUnsupported: {
+			uint32_t size_params __attribute__((unused)) = Unpack<uint32_t,uint32_t>(ptr + 8);
+			InputBuffer inptr_params(ptr + 8 + 4, size_params);
+			if (useChecksum) {
+				ChecksumCalculatorThreadInfo::validOrDie(checksumCalc, ptr, 8 + 4 + size_params, ptr + 8 + 4 + size_params, checksumSize, 
+					"foo_decoder_context_t::decode, OP_fooUnsupported: GL checksumCalculator failure\n");
+			}
+			DEBUG("foo(%p): fooUnsupported(%p(%u) )\n", stream, (void*)(inptr_params.get()), size_params);
+			this->fooUnsupported((void*)(inptr_params.get()));
+			SET_LASTCALL("fooUnsupported");
+			break;
+		}
+		case OP_fooDoEncoderFlush: {
+			FooInt var_param = Unpack<FooInt,uint32_t>(ptr + 8);
+			if (useChecksum) {
+				ChecksumCalculatorThreadInfo::validOrDie(checksumCalc, ptr, 8 + 4, ptr + 8 + 4, checksumSize, 
+					"foo_decoder_context_t::decode, OP_fooDoEncoderFlush: GL checksumCalculator failure\n");
+			}
+			DEBUG("foo(%p): fooDoEncoderFlush(%d )\n", stream, var_param);
+			this->fooDoEncoderFlush(var_param);
+			SET_LASTCALL("fooDoEncoderFlush");
+			break;
+		}
+		case OP_fooTakeConstVoidPtrConstPtr: {
+			uint32_t size_param __attribute__((unused)) = Unpack<uint32_t,uint32_t>(ptr + 8);
+			InputBuffer inptr_param(ptr + 8 + 4, size_param);
+			if (useChecksum) {
+				ChecksumCalculatorThreadInfo::validOrDie(checksumCalc, ptr, 8 + 4 + size_param, ptr + 8 + 4 + size_param, checksumSize, 
+					"foo_decoder_context_t::decode, OP_fooTakeConstVoidPtrConstPtr: GL checksumCalculator failure\n");
+			}
+			DEBUG("foo(%p): fooTakeConstVoidPtrConstPtr(%p(%u) )\n", stream, (const void* const*)(inptr_param.get()), size_param);
+			this->fooTakeConstVoidPtrConstPtr((const void* const*)(inptr_param.get()));
+			SET_LASTCALL("fooTakeConstVoidPtrConstPtr");
+			break;
+		}
+		case OP_fooSetComplexStruct: {
+			uint32_t size_obj __attribute__((unused)) = Unpack<uint32_t,uint32_t>(ptr + 8);
+			InputBuffer inptr_obj(ptr + 8 + 4, size_obj);
+			void* inptr_obj_unpacked;
+			 FooStruct unpacked; inptr_obj_unpacked = (void*)(&unpacked); fooStructUnpack((unsigned char*)(inptr_obj.get()), size_obj, inptr_obj_unpacked);
+			if (useChecksum) {
+				ChecksumCalculatorThreadInfo::validOrDie(checksumCalc, ptr, 8 + 4 + size_obj, ptr + 8 + 4 + size_obj, checksumSize, 
+					"foo_decoder_context_t::decode, OP_fooSetComplexStruct: GL checksumCalculator failure\n");
+			}
+			DEBUG("foo(%p): fooSetComplexStruct(%p(%u) )\n", stream, (const FooStruct*)(inptr_obj.get()), size_obj);
+			this->fooSetComplexStruct((const FooStruct*)(inptr_obj_unpacked));
+			SET_LASTCALL("fooSetComplexStruct");
+			break;
+		}
+		case OP_fooGetComplexStruct: {
+			uint32_t size_obj __attribute__((unused)) = Unpack<uint32_t,uint32_t>(ptr + 8);
+			if (useChecksum) {
+				ChecksumCalculatorThreadInfo::validOrDie(checksumCalc, ptr, 8 + 4, ptr + 8 + 4, checksumSize, 
+					"foo_decoder_context_t::decode, OP_fooGetComplexStruct: GL checksumCalculator failure\n");
+			}
+			size_t totalTmpSize = size_obj;
+			totalTmpSize += checksumSize;
+			unsigned char *tmpBuf = stream->alloc(totalTmpSize);
+			OutputBuffer outptr_obj(&tmpBuf[0], size_obj);
+			void* forPacking_obj = nullptr;
+			 FooStruct tmp; forPacking_obj = (void*)tmp;
+			DEBUG("foo(%p): fooGetComplexStruct(%p(%u) )\n", stream, (FooStruct*)(outptr_obj.get()), size_obj);
+			this->fooGetComplexStruct((FooStruct*)(forPacking_obj));
+			if (size_obj) {
+			 fooStructPack((unsigned char*)outptr_obj.get(), (FooStruct*)forPacking_obj); }
+			outptr_obj.flush();
+			if (useChecksum) {
+				ChecksumCalculatorThreadInfo::writeChecksum(checksumCalc, &tmpBuf[0], totalTmpSize - checksumSize, &tmpBuf[totalTmpSize - checksumSize], checksumSize);
+			}
+			stream->flush();
+			SET_LASTCALL("fooGetComplexStruct");
+			break;
+		}
+		case OP_fooInout: {
+			uint32_t size_count __attribute__((unused)) = Unpack<uint32_t,uint32_t>(ptr + 8);
+			InputBuffer inptr_count(ptr + 8 + 4, size_count);
+			if (useChecksum) {
+				ChecksumCalculatorThreadInfo::validOrDie(checksumCalc, ptr, 8 + 4 + size_count, ptr + 8 + 4 + size_count, checksumSize, 
+					"foo_decoder_context_t::decode, OP_fooInout: GL checksumCalculator failure\n");
+			}
+			size_t totalTmpSize = size_count;
+			totalTmpSize += checksumSize;
+			unsigned char *tmpBuf = stream->alloc(totalTmpSize);
+			OutputBuffer outptr_count(&tmpBuf[0], size_count);
+			memcpy(outptr_count.get(), inptr_count.get(), size_count);
+			DEBUG("foo(%p): fooInout(%p(%u) )\n", stream, (uint32_t*)(outptr_count.get()), size_count);
+			this->fooInout((uint32_t*)(outptr_count.get()));
+			outptr_count.flush();
+			if (useChecksum) {
+				ChecksumCalculatorThreadInfo::writeChecksum(checksumCalc, &tmpBuf[0], totalTmpSize - checksumSize, &tmpBuf[totalTmpSize - checksumSize], checksumSize);
+			}
+			stream->flush();
+			SET_LASTCALL("fooInout");
+			break;
+		}
+		default:
+			return ptr - (unsigned char*)buf;
+		} //switch
+		ptr += packetLen;
+	} // while
+	return ptr - (unsigned char*)buf;
+}
diff --git a/host/commands/emugen/tests/t.001/expected/decoder/foo_dec.h b/host/commands/emugen/tests/t.001/expected/decoder/foo_dec.h
new file mode 100644
index 0000000000000000000000000000000000000000..d02509070b6d12b67f197f773a5eecfeef5c137f
--- /dev/null
+++ b/host/commands/emugen/tests/t.001/expected/decoder/foo_dec.h
@@ -0,0 +1,20 @@
+// Generated Code - DO NOT EDIT !!
+// generated by 'emugen'
+
+#ifndef GUARD_foo_decoder_context_t
+#define GUARD_foo_decoder_context_t
+
+#include "OpenglRender/IOStream.h"
+#include "ChecksumCalculator.h"
+#include "foo_server_context.h"
+
+
+#include "emugl/common/logging.h"
+
+struct foo_decoder_context_t : public foo_server_context_t {
+
+	size_t decode(void *buf, size_t bufsize, IOStream *stream, ChecksumCalculator* checksumCalc);
+
+};
+
+#endif  // GUARD_foo_decoder_context_t
diff --git a/host/commands/emugen/tests/t.001/expected/decoder/foo_opcodes.h b/host/commands/emugen/tests/t.001/expected/decoder/foo_opcodes.h
new file mode 100644
index 0000000000000000000000000000000000000000..ee453406f4e144dd9a1e74ec60ad1e22755fbb3e
--- /dev/null
+++ b/host/commands/emugen/tests/t.001/expected/decoder/foo_opcodes.h
@@ -0,0 +1,17 @@
+// Generated Code - DO NOT EDIT !!
+// generated by 'emugen'
+#ifndef __GUARD_foo_opcodes_h_
+#define __GUARD_foo_opcodes_h_
+
+#define OP_fooAlphaFunc 					200
+#define OP_fooIsBuffer 					201
+#define OP_fooUnsupported 					202
+#define OP_fooDoEncoderFlush 					203
+#define OP_fooTakeConstVoidPtrConstPtr 					204
+#define OP_fooSetComplexStruct 					205
+#define OP_fooGetComplexStruct 					206
+#define OP_fooInout 					207
+#define OP_last 					208
+
+
+#endif
diff --git a/host/commands/emugen/tests/t.001/expected/decoder/foo_server_context.cpp b/host/commands/emugen/tests/t.001/expected/decoder/foo_server_context.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5371fff2f6b2094decfaab39be999c3087afdd4e
--- /dev/null
+++ b/host/commands/emugen/tests/t.001/expected/decoder/foo_server_context.cpp
@@ -0,0 +1,23 @@
+// Generated Code - DO NOT EDIT !!
+// generated by 'emugen'
+
+
+#include <string.h>
+#include "foo_server_context.h"
+
+
+#include <stdio.h>
+
+int foo_server_context_t::initDispatchByName(void *(*getProc)(const char *, void *userData), void *userData)
+{
+	fooAlphaFunc = (fooAlphaFunc_server_proc_t) getProc("fooAlphaFunc", userData);
+	fooIsBuffer = (fooIsBuffer_server_proc_t) getProc("fooIsBuffer", userData);
+	fooUnsupported = (fooUnsupported_server_proc_t) getProc("fooUnsupported", userData);
+	fooDoEncoderFlush = (fooDoEncoderFlush_server_proc_t) getProc("fooDoEncoderFlush", userData);
+	fooTakeConstVoidPtrConstPtr = (fooTakeConstVoidPtrConstPtr_server_proc_t) getProc("fooTakeConstVoidPtrConstPtr", userData);
+	fooSetComplexStruct = (fooSetComplexStruct_server_proc_t) getProc("fooSetComplexStruct", userData);
+	fooGetComplexStruct = (fooGetComplexStruct_server_proc_t) getProc("fooGetComplexStruct", userData);
+	fooInout = (fooInout_server_proc_t) getProc("fooInout", userData);
+	return 0;
+}
+
diff --git a/host/commands/emugen/tests/t.001/expected/decoder/foo_server_context.h b/host/commands/emugen/tests/t.001/expected/decoder/foo_server_context.h
new file mode 100644
index 0000000000000000000000000000000000000000..4f44919259e171bed1d994b20634ddd8b2e59628
--- /dev/null
+++ b/host/commands/emugen/tests/t.001/expected/decoder/foo_server_context.h
@@ -0,0 +1,25 @@
+// Generated Code - DO NOT EDIT !!
+// generated by 'emugen'
+#ifndef __foo_server_context_t_h
+#define __foo_server_context_t_h
+
+#include "foo_server_proc.h"
+
+#include "foo_types.h"
+
+
+struct foo_server_context_t {
+
+	fooAlphaFunc_server_proc_t fooAlphaFunc;
+	fooIsBuffer_server_proc_t fooIsBuffer;
+	fooUnsupported_server_proc_t fooUnsupported;
+	fooDoEncoderFlush_server_proc_t fooDoEncoderFlush;
+	fooTakeConstVoidPtrConstPtr_server_proc_t fooTakeConstVoidPtrConstPtr;
+	fooSetComplexStruct_server_proc_t fooSetComplexStruct;
+	fooGetComplexStruct_server_proc_t fooGetComplexStruct;
+	fooInout_server_proc_t fooInout;
+	virtual ~foo_server_context_t() {}
+	int initDispatchByName( void *(*getProc)(const char *name, void *userData), void *userData);
+};
+
+#endif
diff --git a/host/commands/emugen/tests/t.001/expected/decoder/foo_server_proc.h b/host/commands/emugen/tests/t.001/expected/decoder/foo_server_proc.h
new file mode 100644
index 0000000000000000000000000000000000000000..593e4c41142723ce21b081b9181d27e725a14026
--- /dev/null
+++ b/host/commands/emugen/tests/t.001/expected/decoder/foo_server_proc.h
@@ -0,0 +1,22 @@
+// Generated Code - DO NOT EDIT !!
+// generated by 'emugen'
+#ifndef __foo_server_proc_t_h
+#define __foo_server_proc_t_h
+
+
+
+#include "foo_types.h"
+#ifndef foo_APIENTRY
+#define foo_APIENTRY 
+#endif
+typedef void (foo_APIENTRY *fooAlphaFunc_server_proc_t) (FooInt, FooFloat);
+typedef FooBoolean (foo_APIENTRY *fooIsBuffer_server_proc_t) (void*);
+typedef void (foo_APIENTRY *fooUnsupported_server_proc_t) (void*);
+typedef void (foo_APIENTRY *fooDoEncoderFlush_server_proc_t) (FooInt);
+typedef void (foo_APIENTRY *fooTakeConstVoidPtrConstPtr_server_proc_t) (const void* const*);
+typedef void (foo_APIENTRY *fooSetComplexStruct_server_proc_t) (const FooStruct*);
+typedef void (foo_APIENTRY *fooGetComplexStruct_server_proc_t) (FooStruct*);
+typedef void (foo_APIENTRY *fooInout_server_proc_t) (uint32_t*);
+
+
+#endif
diff --git a/host/commands/emugen/tests/t.001/expected/encoder/foo_client_context.cpp b/host/commands/emugen/tests/t.001/expected/encoder/foo_client_context.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d28b5a0547f681b77136a0d1849b20370e889a58
--- /dev/null
+++ b/host/commands/emugen/tests/t.001/expected/encoder/foo_client_context.cpp
@@ -0,0 +1,23 @@
+// Generated Code - DO NOT EDIT !!
+// generated by 'emugen'
+
+
+#include <string.h>
+#include "foo_client_context.h"
+
+
+#include <stdio.h>
+
+int foo_client_context_t::initDispatchByName(void *(*getProc)(const char *, void *userData), void *userData)
+{
+	fooAlphaFunc = (fooAlphaFunc_client_proc_t) getProc("fooAlphaFunc", userData);
+	fooIsBuffer = (fooIsBuffer_client_proc_t) getProc("fooIsBuffer", userData);
+	fooUnsupported = (fooUnsupported_client_proc_t) getProc("fooUnsupported", userData);
+	fooDoEncoderFlush = (fooDoEncoderFlush_client_proc_t) getProc("fooDoEncoderFlush", userData);
+	fooTakeConstVoidPtrConstPtr = (fooTakeConstVoidPtrConstPtr_client_proc_t) getProc("fooTakeConstVoidPtrConstPtr", userData);
+	fooSetComplexStruct = (fooSetComplexStruct_client_proc_t) getProc("fooSetComplexStruct", userData);
+	fooGetComplexStruct = (fooGetComplexStruct_client_proc_t) getProc("fooGetComplexStruct", userData);
+	fooInout = (fooInout_client_proc_t) getProc("fooInout", userData);
+	return 0;
+}
+
diff --git a/host/commands/emugen/tests/t.001/expected/encoder/foo_client_context.h b/host/commands/emugen/tests/t.001/expected/encoder/foo_client_context.h
new file mode 100644
index 0000000000000000000000000000000000000000..d1c1675c0615a7df8928f30c994682e37f012a7d
--- /dev/null
+++ b/host/commands/emugen/tests/t.001/expected/encoder/foo_client_context.h
@@ -0,0 +1,30 @@
+// Generated Code - DO NOT EDIT !!
+// generated by 'emugen'
+#ifndef __foo_client_context_t_h
+#define __foo_client_context_t_h
+
+#include "foo_client_proc.h"
+
+#include "foo_types.h"
+
+
+struct foo_client_context_t {
+
+	fooAlphaFunc_client_proc_t fooAlphaFunc;
+	fooIsBuffer_client_proc_t fooIsBuffer;
+	fooUnsupported_client_proc_t fooUnsupported;
+	fooDoEncoderFlush_client_proc_t fooDoEncoderFlush;
+	fooTakeConstVoidPtrConstPtr_client_proc_t fooTakeConstVoidPtrConstPtr;
+	fooSetComplexStruct_client_proc_t fooSetComplexStruct;
+	fooGetComplexStruct_client_proc_t fooGetComplexStruct;
+	fooInout_client_proc_t fooInout;
+	virtual ~foo_client_context_t() {}
+
+	typedef foo_client_context_t *CONTEXT_ACCESSOR_TYPE(void);
+	static void setContextAccessor(CONTEXT_ACCESSOR_TYPE *f);
+	int initDispatchByName( void *(*getProc)(const char *name, void *userData), void *userData);
+	virtual void setError(unsigned int  error){ (void)error; };
+	virtual unsigned int getError(){ return 0; };
+};
+
+#endif
diff --git a/host/commands/emugen/tests/t.001/expected/encoder/foo_client_proc.h b/host/commands/emugen/tests/t.001/expected/encoder/foo_client_proc.h
new file mode 100644
index 0000000000000000000000000000000000000000..d9bbcb6663a088357bc3e242ecf85236c3e83286
--- /dev/null
+++ b/host/commands/emugen/tests/t.001/expected/encoder/foo_client_proc.h
@@ -0,0 +1,22 @@
+// Generated Code - DO NOT EDIT !!
+// generated by 'emugen'
+#ifndef __foo_client_proc_t_h
+#define __foo_client_proc_t_h
+
+
+
+#include "foo_types.h"
+#ifndef foo_APIENTRY
+#define foo_APIENTRY 
+#endif
+typedef void (foo_APIENTRY *fooAlphaFunc_client_proc_t) (void * ctx, FooInt, FooFloat);
+typedef FooBoolean (foo_APIENTRY *fooIsBuffer_client_proc_t) (void * ctx, void*);
+typedef void (foo_APIENTRY *fooUnsupported_client_proc_t) (void * ctx, void*);
+typedef void (foo_APIENTRY *fooDoEncoderFlush_client_proc_t) (void * ctx, FooInt);
+typedef void (foo_APIENTRY *fooTakeConstVoidPtrConstPtr_client_proc_t) (void * ctx, const void* const*);
+typedef void (foo_APIENTRY *fooSetComplexStruct_client_proc_t) (void * ctx, const FooStruct*);
+typedef void (foo_APIENTRY *fooGetComplexStruct_client_proc_t) (void * ctx, FooStruct*);
+typedef void (foo_APIENTRY *fooInout_client_proc_t) (void * ctx, uint32_t*);
+
+
+#endif
diff --git a/host/commands/emugen/tests/t.001/expected/encoder/foo_enc.cpp b/host/commands/emugen/tests/t.001/expected/encoder/foo_enc.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..13a4dd56b26fd4cb0d8ff2cfe3909031af78d62f
--- /dev/null
+++ b/host/commands/emugen/tests/t.001/expected/encoder/foo_enc.cpp
@@ -0,0 +1,263 @@
+// Generated Code - DO NOT EDIT !!
+// generated by 'emugen'
+
+
+#include <string.h>
+#include "foo_opcodes.h"
+
+#include "foo_enc.h"
+
+
+#include <vector>
+
+#include <stdio.h>
+
+namespace {
+
+void enc_unsupported()
+{
+	ALOGE("Function is unsupported\n");
+}
+
+void fooAlphaFunc_enc(void *self , FooInt func, FooFloat ref)
+{
+
+	foo_encoder_context_t *ctx = (foo_encoder_context_t *)self;
+	IOStream *stream = ctx->m_stream;
+	ChecksumCalculator *checksumCalculator = ctx->m_checksumCalculator;
+	bool useChecksum = checksumCalculator->getVersion() > 0;
+
+	 unsigned char *ptr;
+	 unsigned char *buf;
+	 const size_t sizeWithoutChecksum = 8 + 4 + 4;
+	 const size_t checksumSize = checksumCalculator->checksumByteSize();
+	 const size_t totalSize = sizeWithoutChecksum + checksumSize;
+	buf = stream->alloc(totalSize);
+	ptr = buf;
+	int tmp = OP_fooAlphaFunc;memcpy(ptr, &tmp, 4); ptr += 4;
+	memcpy(ptr, &totalSize, 4);  ptr += 4;
+
+		memcpy(ptr, &func, 4); ptr += 4;
+		memcpy(ptr, &ref, 4); ptr += 4;
+
+	if (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf);
+	if (useChecksum) checksumCalculator->writeChecksum(ptr, checksumSize); ptr += checksumSize;
+
+}
+
+FooBoolean fooIsBuffer_enc(void *self , void* stuff)
+{
+
+	foo_encoder_context_t *ctx = (foo_encoder_context_t *)self;
+	IOStream *stream = ctx->m_stream;
+	ChecksumCalculator *checksumCalculator = ctx->m_checksumCalculator;
+	bool useChecksum = checksumCalculator->getVersion() > 0;
+
+	const unsigned int __size_stuff =  (4 * sizeof(float));
+	 unsigned char *ptr;
+	 unsigned char *buf;
+	 const size_t sizeWithoutChecksum = 8 + __size_stuff + 1*4;
+	 const size_t checksumSize = checksumCalculator->checksumByteSize();
+	 const size_t totalSize = sizeWithoutChecksum + checksumSize;
+	buf = stream->alloc(totalSize);
+	ptr = buf;
+	int tmp = OP_fooIsBuffer;memcpy(ptr, &tmp, 4); ptr += 4;
+	memcpy(ptr, &totalSize, 4);  ptr += 4;
+
+	*(unsigned int *)(ptr) = __size_stuff; ptr += 4;
+	memcpy(ptr, stuff, __size_stuff);ptr += __size_stuff;
+
+	if (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf);
+	if (useChecksum) checksumCalculator->writeChecksum(ptr, checksumSize); ptr += checksumSize;
+
+
+	FooBoolean retval;
+	stream->readback(&retval, 1);
+	if (useChecksum) checksumCalculator->addBuffer(&retval, 1);
+	if (useChecksum) {
+		unsigned char *checksumBufPtr = NULL;
+		unsigned char checksumBuf[ChecksumCalculator::kMaxChecksumSize];
+		if (checksumSize > 0) checksumBufPtr = &checksumBuf[0];
+		stream->readback(checksumBufPtr, checksumSize);
+		if (!checksumCalculator->validate(checksumBufPtr, checksumSize)) {
+			ALOGE("fooIsBuffer: GL communication error, please report this issue to b.android.com.\n");
+			abort();
+		}
+	}
+	return retval;
+}
+
+void fooDoEncoderFlush_enc(void *self , FooInt param)
+{
+
+	foo_encoder_context_t *ctx = (foo_encoder_context_t *)self;
+	IOStream *stream = ctx->m_stream;
+	ChecksumCalculator *checksumCalculator = ctx->m_checksumCalculator;
+	bool useChecksum = checksumCalculator->getVersion() > 0;
+
+	 unsigned char *ptr;
+	 unsigned char *buf;
+	 const size_t sizeWithoutChecksum = 8 + 4;
+	 const size_t checksumSize = checksumCalculator->checksumByteSize();
+	 const size_t totalSize = sizeWithoutChecksum + checksumSize;
+	buf = stream->alloc(totalSize);
+	ptr = buf;
+	int tmp = OP_fooDoEncoderFlush;memcpy(ptr, &tmp, 4); ptr += 4;
+	memcpy(ptr, &totalSize, 4);  ptr += 4;
+
+		memcpy(ptr, &param, 4); ptr += 4;
+
+	if (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf);
+	if (useChecksum) checksumCalculator->writeChecksum(ptr, checksumSize); ptr += checksumSize;
+
+	stream->flush();
+}
+
+void fooTakeConstVoidPtrConstPtr_enc(void *self , const void* const* param)
+{
+
+	foo_encoder_context_t *ctx = (foo_encoder_context_t *)self;
+	IOStream *stream = ctx->m_stream;
+	ChecksumCalculator *checksumCalculator = ctx->m_checksumCalculator;
+	bool useChecksum = checksumCalculator->getVersion() > 0;
+
+	const unsigned int __size_param = ;
+	 unsigned char *ptr;
+	 unsigned char *buf;
+	 const size_t sizeWithoutChecksum = 8 + __size_param + 1*4;
+	 const size_t checksumSize = checksumCalculator->checksumByteSize();
+	 const size_t totalSize = sizeWithoutChecksum + checksumSize;
+	buf = stream->alloc(totalSize);
+	ptr = buf;
+	int tmp = OP_fooTakeConstVoidPtrConstPtr;memcpy(ptr, &tmp, 4); ptr += 4;
+	memcpy(ptr, &totalSize, 4);  ptr += 4;
+
+	*(unsigned int *)(ptr) = __size_param; ptr += 4;
+	memcpy(ptr, param, __size_param);ptr += __size_param;
+
+	if (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf);
+	if (useChecksum) checksumCalculator->writeChecksum(ptr, checksumSize); ptr += checksumSize;
+
+}
+
+void fooSetComplexStruct_enc(void *self , const FooStruct* obj)
+{
+
+	foo_encoder_context_t *ctx = (foo_encoder_context_t *)self;
+	IOStream *stream = ctx->m_stream;
+	ChecksumCalculator *checksumCalculator = ctx->m_checksumCalculator;
+	bool useChecksum = checksumCalculator->getVersion() > 0;
+
+	const unsigned int __size_obj =  fooStructEncodingSize(obj);
+	 unsigned char *ptr;
+	 unsigned char *buf;
+	 const size_t sizeWithoutChecksum = 8 + __size_obj + 1*4;
+	 const size_t checksumSize = checksumCalculator->checksumByteSize();
+	 const size_t totalSize = sizeWithoutChecksum + checksumSize;
+	buf = stream->alloc(totalSize);
+	ptr = buf;
+	int tmp = OP_fooSetComplexStruct;memcpy(ptr, &tmp, 4); ptr += 4;
+	memcpy(ptr, &totalSize, 4);  ptr += 4;
+
+	*(unsigned int *)(ptr) = __size_obj; ptr += 4;
+	 fooStructPack(ptr, obj);ptr += __size_obj;
+
+	if (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf);
+	if (useChecksum) checksumCalculator->writeChecksum(ptr, checksumSize); ptr += checksumSize;
+
+}
+
+void fooGetComplexStruct_enc(void *self , FooStruct* obj)
+{
+
+	foo_encoder_context_t *ctx = (foo_encoder_context_t *)self;
+	IOStream *stream = ctx->m_stream;
+	ChecksumCalculator *checksumCalculator = ctx->m_checksumCalculator;
+	bool useChecksum = checksumCalculator->getVersion() > 0;
+
+	const unsigned int __size_obj =  fooStructEncodingSize(obj);
+	 unsigned char *ptr;
+	 unsigned char *buf;
+	 const size_t sizeWithoutChecksum = 8 + 0 + 1*4;
+	 const size_t checksumSize = checksumCalculator->checksumByteSize();
+	 const size_t totalSize = sizeWithoutChecksum + checksumSize;
+	buf = stream->alloc(totalSize);
+	ptr = buf;
+	int tmp = OP_fooGetComplexStruct;memcpy(ptr, &tmp, 4); ptr += 4;
+	memcpy(ptr, &totalSize, 4);  ptr += 4;
+
+	*(unsigned int *)(ptr) = __size_obj; ptr += 4;
+
+	if (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf);
+	if (useChecksum) checksumCalculator->writeChecksum(ptr, checksumSize); ptr += checksumSize;
+
+	 std::vector<unsigned char> forUnpacking_obj(__size_obj); stream->readback(&forUnpacking_obj[0], __size_obj); fooStructUnpack(&forUnpacking_obj[0], obj);
+	if (useChecksum) checksumCalculator->addBuffer(obj, __size_obj);
+	if (useChecksum) {
+		unsigned char *checksumBufPtr = NULL;
+		unsigned char checksumBuf[ChecksumCalculator::kMaxChecksumSize];
+		if (checksumSize > 0) checksumBufPtr = &checksumBuf[0];
+		stream->readback(checksumBufPtr, checksumSize);
+		if (!checksumCalculator->validate(checksumBufPtr, checksumSize)) {
+			ALOGE("fooGetComplexStruct: GL communication error, please report this issue to b.android.com.\n");
+			abort();
+		}
+	}
+}
+
+void fooInout_enc(void *self , uint32_t* count)
+{
+
+	foo_encoder_context_t *ctx = (foo_encoder_context_t *)self;
+	IOStream *stream = ctx->m_stream;
+	ChecksumCalculator *checksumCalculator = ctx->m_checksumCalculator;
+	bool useChecksum = checksumCalculator->getVersion() > 0;
+
+	const unsigned int __size_count =  sizeof(uint32_t);
+	 unsigned char *ptr;
+	 unsigned char *buf;
+	 const size_t sizeWithoutChecksum = 8 + __size_count + 1*4;
+	 const size_t checksumSize = checksumCalculator->checksumByteSize();
+	 const size_t totalSize = sizeWithoutChecksum + checksumSize;
+	buf = stream->alloc(totalSize);
+	ptr = buf;
+	int tmp = OP_fooInout;memcpy(ptr, &tmp, 4); ptr += 4;
+	memcpy(ptr, &totalSize, 4);  ptr += 4;
+
+	*(unsigned int *)(ptr) = __size_count; ptr += 4;
+	memcpy(ptr, count, __size_count);ptr += __size_count;
+
+	if (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf);
+	if (useChecksum) checksumCalculator->writeChecksum(ptr, checksumSize); ptr += checksumSize;
+
+	stream->readback(count, __size_count);
+	if (useChecksum) checksumCalculator->addBuffer(count, __size_count);
+	if (useChecksum) {
+		unsigned char *checksumBufPtr = NULL;
+		unsigned char checksumBuf[ChecksumCalculator::kMaxChecksumSize];
+		if (checksumSize > 0) checksumBufPtr = &checksumBuf[0];
+		stream->readback(checksumBufPtr, checksumSize);
+		if (!checksumCalculator->validate(checksumBufPtr, checksumSize)) {
+			ALOGE("fooInout: GL communication error, please report this issue to b.android.com.\n");
+			abort();
+		}
+	}
+}
+
+}  // namespace
+
+foo_encoder_context_t::foo_encoder_context_t(IOStream *stream, ChecksumCalculator *checksumCalculator)
+{
+	m_stream = stream;
+	m_checksumCalculator = checksumCalculator;
+
+	this->fooAlphaFunc = &fooAlphaFunc_enc;
+	this->fooIsBuffer = &fooIsBuffer_enc;
+	this->fooUnsupported = (fooUnsupported_client_proc_t) &enc_unsupported;
+	this->fooDoEncoderFlush = &fooDoEncoderFlush_enc;
+	this->fooTakeConstVoidPtrConstPtr = &fooTakeConstVoidPtrConstPtr_enc;
+	this->fooSetComplexStruct = &fooSetComplexStruct_enc;
+	this->fooGetComplexStruct = &fooGetComplexStruct_enc;
+	this->fooInout = &fooInout_enc;
+}
+
diff --git a/host/commands/emugen/tests/t.001/expected/encoder/foo_enc.h b/host/commands/emugen/tests/t.001/expected/encoder/foo_enc.h
new file mode 100644
index 0000000000000000000000000000000000000000..beaabd43ff69fc7949465338a33cb49073f71c35
--- /dev/null
+++ b/host/commands/emugen/tests/t.001/expected/encoder/foo_enc.h
@@ -0,0 +1,24 @@
+// Generated Code - DO NOT EDIT !!
+// generated by 'emugen'
+
+#ifndef GUARD_foo_encoder_context_t
+#define GUARD_foo_encoder_context_t
+
+#include "IOStream.h"
+#include "ChecksumCalculator.h"
+#include "foo_client_context.h"
+
+
+#include "fooUtils.h"
+#include "fooBase.h"
+
+struct foo_encoder_context_t : public foo_client_context_t {
+
+	IOStream *m_stream;
+	ChecksumCalculator *m_checksumCalculator;
+
+	foo_encoder_context_t(IOStream *stream, ChecksumCalculator *checksumCalculator);
+	virtual uint64_t lockAndWriteDma(void* data, uint32_t sz) { return 0; }
+};
+
+#endif  // GUARD_foo_encoder_context_t
diff --git a/host/commands/emugen/tests/t.001/expected/encoder/foo_entry.cpp b/host/commands/emugen/tests/t.001/expected/encoder/foo_entry.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..92e8ef43a9fa71cc033b6ebd306691fe57ddcbcd
--- /dev/null
+++ b/host/commands/emugen/tests/t.001/expected/encoder/foo_entry.cpp
@@ -0,0 +1,72 @@
+// Generated Code - DO NOT EDIT !!
+// generated by 'emugen'
+#include <stdio.h>
+#include <stdlib.h>
+#include "foo_client_context.h"
+
+extern "C" {
+	void fooAlphaFunc(FooInt func, FooFloat ref);
+	FooBoolean fooIsBuffer(void* stuff);
+	void fooUnsupported(void* params);
+	void fooDoEncoderFlush(FooInt param);
+	void fooTakeConstVoidPtrConstPtr(const void* const* param);
+	void fooSetComplexStruct(const FooStruct* obj);
+	void fooGetComplexStruct(FooStruct* obj);
+	void fooInout(uint32_t* count);
+};
+
+#ifndef GET_CONTEXT
+static foo_client_context_t::CONTEXT_ACCESSOR_TYPE *getCurrentContext = NULL;
+void foo_client_context_t::setContextAccessor(CONTEXT_ACCESSOR_TYPE *f) { getCurrentContext = f; }
+#define GET_CONTEXT foo_client_context_t * ctx = getCurrentContext()
+#endif
+
+void fooAlphaFunc(FooInt func, FooFloat ref)
+{
+	GET_CONTEXT;
+	ctx->fooAlphaFunc(ctx, func, ref);
+}
+
+FooBoolean fooIsBuffer(void* stuff)
+{
+	GET_CONTEXT;
+	 if (n == NULL) { LOG(ERROR) << "NULL stuff"; return; }
+	return ctx->fooIsBuffer(ctx, stuff);
+}
+
+void fooUnsupported(void* params)
+{
+	GET_CONTEXT;
+	ctx->fooUnsupported(ctx, params);
+}
+
+void fooDoEncoderFlush(FooInt param)
+{
+	GET_CONTEXT;
+	ctx->fooDoEncoderFlush(ctx, param);
+}
+
+void fooTakeConstVoidPtrConstPtr(const void* const* param)
+{
+	GET_CONTEXT;
+	ctx->fooTakeConstVoidPtrConstPtr(ctx, param);
+}
+
+void fooSetComplexStruct(const FooStruct* obj)
+{
+	GET_CONTEXT;
+	ctx->fooSetComplexStruct(ctx, obj);
+}
+
+void fooGetComplexStruct(FooStruct* obj)
+{
+	GET_CONTEXT;
+	ctx->fooGetComplexStruct(ctx, obj);
+}
+
+void fooInout(uint32_t* count)
+{
+	GET_CONTEXT;
+	ctx->fooInout(ctx, count);
+}
+
diff --git a/host/commands/emugen/tests/t.001/expected/encoder/foo_ftable.h b/host/commands/emugen/tests/t.001/expected/encoder/foo_ftable.h
new file mode 100644
index 0000000000000000000000000000000000000000..0b759b52ca2537692870bf2652cabf579f900f71
--- /dev/null
+++ b/host/commands/emugen/tests/t.001/expected/encoder/foo_ftable.h
@@ -0,0 +1,23 @@
+// Generated Code - DO NOT EDIT !!
+// generated by 'emugen'
+#ifndef __foo_client_ftable_t_h
+#define __foo_client_ftable_t_h
+
+
+static const struct _foo_funcs_by_name {
+	const char *name;
+	void *proc;
+} foo_funcs_by_name[] = {
+	{"fooAlphaFunc", (void*)fooAlphaFunc},
+	{"fooIsBuffer", (void*)fooIsBuffer},
+	{"fooUnsupported", (void*)fooUnsupported},
+	{"fooDoEncoderFlush", (void*)fooDoEncoderFlush},
+	{"fooTakeConstVoidPtrConstPtr", (void*)fooTakeConstVoidPtrConstPtr},
+	{"fooSetComplexStruct", (void*)fooSetComplexStruct},
+	{"fooGetComplexStruct", (void*)fooGetComplexStruct},
+	{"fooInout", (void*)fooInout},
+};
+static const int foo_num_funcs = sizeof(foo_funcs_by_name) / sizeof(struct _foo_funcs_by_name);
+
+
+#endif
diff --git a/host/commands/emugen/tests/t.001/expected/encoder/foo_opcodes.h b/host/commands/emugen/tests/t.001/expected/encoder/foo_opcodes.h
new file mode 100644
index 0000000000000000000000000000000000000000..ee453406f4e144dd9a1e74ec60ad1e22755fbb3e
--- /dev/null
+++ b/host/commands/emugen/tests/t.001/expected/encoder/foo_opcodes.h
@@ -0,0 +1,17 @@
+// Generated Code - DO NOT EDIT !!
+// generated by 'emugen'
+#ifndef __GUARD_foo_opcodes_h_
+#define __GUARD_foo_opcodes_h_
+
+#define OP_fooAlphaFunc 					200
+#define OP_fooIsBuffer 					201
+#define OP_fooUnsupported 					202
+#define OP_fooDoEncoderFlush 					203
+#define OP_fooTakeConstVoidPtrConstPtr 					204
+#define OP_fooSetComplexStruct 					205
+#define OP_fooGetComplexStruct 					206
+#define OP_fooInout 					207
+#define OP_last 					208
+
+
+#endif
diff --git a/host/commands/emugen/tests/t.001/expected/wrapper/foo_wrapper_context.cpp b/host/commands/emugen/tests/t.001/expected/wrapper/foo_wrapper_context.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e8781cccb15d340a59e7ef00dcb468f860b53429
--- /dev/null
+++ b/host/commands/emugen/tests/t.001/expected/wrapper/foo_wrapper_context.cpp
@@ -0,0 +1,23 @@
+// Generated Code - DO NOT EDIT !!
+// generated by 'emugen'
+
+
+#include <string.h>
+#include "foo_wrapper_context.h"
+
+
+#include <stdio.h>
+
+int foo_wrapper_context_t::initDispatchByName(void *(*getProc)(const char *, void *userData), void *userData)
+{
+	fooAlphaFunc = (fooAlphaFunc_wrapper_proc_t) getProc("fooAlphaFunc", userData);
+	fooIsBuffer = (fooIsBuffer_wrapper_proc_t) getProc("fooIsBuffer", userData);
+	fooUnsupported = (fooUnsupported_wrapper_proc_t) getProc("fooUnsupported", userData);
+	fooDoEncoderFlush = (fooDoEncoderFlush_wrapper_proc_t) getProc("fooDoEncoderFlush", userData);
+	fooTakeConstVoidPtrConstPtr = (fooTakeConstVoidPtrConstPtr_wrapper_proc_t) getProc("fooTakeConstVoidPtrConstPtr", userData);
+	fooSetComplexStruct = (fooSetComplexStruct_wrapper_proc_t) getProc("fooSetComplexStruct", userData);
+	fooGetComplexStruct = (fooGetComplexStruct_wrapper_proc_t) getProc("fooGetComplexStruct", userData);
+	fooInout = (fooInout_wrapper_proc_t) getProc("fooInout", userData);
+	return 0;
+}
+
diff --git a/host/commands/emugen/tests/t.001/expected/wrapper/foo_wrapper_context.h b/host/commands/emugen/tests/t.001/expected/wrapper/foo_wrapper_context.h
new file mode 100644
index 0000000000000000000000000000000000000000..c9853d29820135c47a21fc60b14d98bf9b0d4491
--- /dev/null
+++ b/host/commands/emugen/tests/t.001/expected/wrapper/foo_wrapper_context.h
@@ -0,0 +1,28 @@
+// Generated Code - DO NOT EDIT !!
+// generated by 'emugen'
+#ifndef __foo_wrapper_context_t_h
+#define __foo_wrapper_context_t_h
+
+#include "foo_server_proc.h"
+
+#include "foo_types.h"
+
+
+struct foo_wrapper_context_t {
+
+	fooAlphaFunc_wrapper_proc_t fooAlphaFunc;
+	fooIsBuffer_wrapper_proc_t fooIsBuffer;
+	fooUnsupported_wrapper_proc_t fooUnsupported;
+	fooDoEncoderFlush_wrapper_proc_t fooDoEncoderFlush;
+	fooTakeConstVoidPtrConstPtr_wrapper_proc_t fooTakeConstVoidPtrConstPtr;
+	fooSetComplexStruct_wrapper_proc_t fooSetComplexStruct;
+	fooGetComplexStruct_wrapper_proc_t fooGetComplexStruct;
+	fooInout_wrapper_proc_t fooInout;
+	virtual ~foo_wrapper_context_t() {}
+
+	typedef foo_wrapper_context_t *CONTEXT_ACCESSOR_TYPE(void);
+	static void setContextAccessor(CONTEXT_ACCESSOR_TYPE *f);
+	int initDispatchByName( void *(*getProc)(const char *name, void *userData), void *userData);
+};
+
+#endif
diff --git a/host/commands/emugen/tests/t.001/expected/wrapper/foo_wrapper_entry.cpp b/host/commands/emugen/tests/t.001/expected/wrapper/foo_wrapper_entry.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..733c8248d1e2f39b4f83803adc66db9fc9bf194f
--- /dev/null
+++ b/host/commands/emugen/tests/t.001/expected/wrapper/foo_wrapper_entry.cpp
@@ -0,0 +1,71 @@
+// Generated Code - DO NOT EDIT !!
+// generated by 'emugen'
+#include <stdio.h>
+#include <stdlib.h>
+#include "foo_wrapper_context.h"
+
+extern "C" {
+	void fooAlphaFunc(FooInt func, FooFloat ref);
+	FooBoolean fooIsBuffer(void* stuff);
+	void fooUnsupported(void* params);
+	void fooDoEncoderFlush(FooInt param);
+	void fooTakeConstVoidPtrConstPtr(const void* const* param);
+	void fooSetComplexStruct(const FooStruct* obj);
+	void fooGetComplexStruct(FooStruct* obj);
+	void fooInout(uint32_t* count);
+};
+
+#ifndef GET_CONTEXT
+static foo_wrapper_context_t::CONTEXT_ACCESSOR_TYPE *getCurrentContext = NULL;
+void foo_wrapper_context_t::setContextAccessor(CONTEXT_ACCESSOR_TYPE *f) { getCurrentContext = f; }
+#define GET_CONTEXT foo_wrapper_context_t * ctx = getCurrentContext()
+#endif
+
+void fooAlphaFunc(FooInt func, FooFloat ref)
+{
+	GET_CONTEXT;
+	ctx->fooAlphaFunc( func, ref);
+}
+
+FooBoolean fooIsBuffer(void* stuff)
+{
+	GET_CONTEXT;
+	return ctx->fooIsBuffer( stuff);
+}
+
+void fooUnsupported(void* params)
+{
+	GET_CONTEXT;
+	ctx->fooUnsupported( params);
+}
+
+void fooDoEncoderFlush(FooInt param)
+{
+	GET_CONTEXT;
+	ctx->fooDoEncoderFlush( param);
+}
+
+void fooTakeConstVoidPtrConstPtr(const void* const* param)
+{
+	GET_CONTEXT;
+	ctx->fooTakeConstVoidPtrConstPtr( param);
+}
+
+void fooSetComplexStruct(const FooStruct* obj)
+{
+	GET_CONTEXT;
+	ctx->fooSetComplexStruct( obj);
+}
+
+void fooGetComplexStruct(FooStruct* obj)
+{
+	GET_CONTEXT;
+	ctx->fooGetComplexStruct( obj);
+}
+
+void fooInout(uint32_t* count)
+{
+	GET_CONTEXT;
+	ctx->fooInout( count);
+}
+
diff --git a/host/commands/emugen/tests/t.001/expected/wrapper/foo_wrapper_proc.h b/host/commands/emugen/tests/t.001/expected/wrapper/foo_wrapper_proc.h
new file mode 100644
index 0000000000000000000000000000000000000000..66ced3138818e131ac8abfede4ddd417ad5cf7f4
--- /dev/null
+++ b/host/commands/emugen/tests/t.001/expected/wrapper/foo_wrapper_proc.h
@@ -0,0 +1,22 @@
+// Generated Code - DO NOT EDIT !!
+// generated by 'emugen'
+#ifndef __foo_wrapper_proc_t_h
+#define __foo_wrapper_proc_t_h
+
+
+
+#include "foo_types.h"
+#ifndef foo_APIENTRY
+#define foo_APIENTRY 
+#endif
+typedef void (foo_APIENTRY *fooAlphaFunc_wrapper_proc_t) (FooInt, FooFloat);
+typedef FooBoolean (foo_APIENTRY *fooIsBuffer_wrapper_proc_t) (void*);
+typedef void (foo_APIENTRY *fooUnsupported_wrapper_proc_t) (void*);
+typedef void (foo_APIENTRY *fooDoEncoderFlush_wrapper_proc_t) (FooInt);
+typedef void (foo_APIENTRY *fooTakeConstVoidPtrConstPtr_wrapper_proc_t) (const void* const*);
+typedef void (foo_APIENTRY *fooSetComplexStruct_wrapper_proc_t) (const FooStruct*);
+typedef void (foo_APIENTRY *fooGetComplexStruct_wrapper_proc_t) (FooStruct*);
+typedef void (foo_APIENTRY *fooInout_wrapper_proc_t) (uint32_t*);
+
+
+#endif
diff --git a/host/commands/emugen/tests/t.001/input/foo.attrib b/host/commands/emugen/tests/t.001/input/foo.attrib
new file mode 100644
index 0000000000000000000000000000000000000000..9b66c57966f004ecd926241cd6e47a574c3e5c15
--- /dev/null
+++ b/host/commands/emugen/tests/t.001/input/foo.attrib
@@ -0,0 +1,32 @@
+GLOBAL
+    base_opcode 200
+    encoder_headers "fooUtils.h" "fooBase.h"
+
+fooIsBuffer
+    dir stuff in
+    len stuff (4 * sizeof(float))
+    param_check stuff if (n == NULL) { LOG(ERROR) << "NULL stuff"; return; }
+
+fooUnsupported
+    dir params in
+    flag unsupported
+
+fooDoEncoderFlush
+    flag flushOnEncode
+
+fooSetComplexStruct
+    dir obj in
+    len obj fooStructEncodingSize(obj)
+    custom_pack obj fooStructPack(ptr, obj)
+    custom_unpack obj FooStruct unpacked; inptr_obj_unpacked = (void*)(&unpacked); fooStructUnpack((unsigned char*)(inptr_obj.get()), size_obj, inptr_obj_unpacked)
+
+fooGetComplexStruct
+    dir obj out
+    len obj fooStructEncodingSize(obj)
+    custom_host_pack_tmp_alloc obj FooStruct tmp; forPacking_obj = (void*)tmp
+    custom_host_pack obj fooStructPack((unsigned char*)outptr_obj.get(), (FooStruct*)forPacking_obj)
+    custom_guest_unpack obj std::vector<unsigned char> forUnpacking_obj(__size_obj); stream->readback(&forUnpacking_obj[0], __size_obj); fooStructUnpack(&forUnpacking_obj[0], obj)
+
+fooInout
+    dir count inout
+    len count sizeof(uint32_t)
diff --git a/host/commands/emugen/tests/t.001/input/foo.in b/host/commands/emugen/tests/t.001/input/foo.in
new file mode 100644
index 0000000000000000000000000000000000000000..b12ad99f9f79ec418c9a193d7cec791f263d21b3
--- /dev/null
+++ b/host/commands/emugen/tests/t.001/input/foo.in
@@ -0,0 +1,8 @@
+FOO_ENTRY(void, fooAlphaFunc, FooInt func, FooFloat ref)
+FOO_ENTRY(FooBoolean, fooIsBuffer, void* stuff)
+FOO_ENTRY(void, fooUnsupported, void* params)
+FOO_ENTRY(void, fooDoEncoderFlush, FooInt param)
+FOO_ENTRY(void, fooTakeConstVoidPtrConstPtr, const void* const* param)
+FOO_ENTRY(void, fooSetComplexStruct, const FooStruct* obj)
+FOO_ENTRY(void, fooGetComplexStruct, FooStruct* obj)
+FOO_ENTRY(void, fooInout, uint32_t* count)
diff --git a/host/commands/emugen/tests/t.001/input/foo.types b/host/commands/emugen/tests/t.001/input/foo.types
new file mode 100644
index 0000000000000000000000000000000000000000..45e17c913de241fe952dc890ff6d87204fcba8ff
--- /dev/null
+++ b/host/commands/emugen/tests/t.001/input/foo.types
@@ -0,0 +1,12 @@
+FooBoolean 8 %d
+FooInt 32 %d
+FooShort 16 %d
+FooFloat 32 %f
+FooEnum 32 %08x
+FooVoid 0 %x
+FooChar 8 %d
+FooChar* 32 0x%08x
+void* 32 0x%08x
+void*const* 32 0x%08x
+FooStruct* 32 0x%08x
+uint32_t* 32 0x%08x
diff --git a/host/commands/gen_entries.py b/host/commands/gen_entries.py
new file mode 100755
index 0000000000000000000000000000000000000000..fbfdb4dafbb7b297f36075118b08929cf299fda9
--- /dev/null
+++ b/host/commands/gen_entries.py
@@ -0,0 +1,317 @@
+#!/usr/bin/env python
+
+# Copyright 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Utility functions used to parse a list of DLL entry points.
+# Expected format:
+#
+#   <empty-line>   -> ignored
+#   #<comment>     -> ignored
+#   %<verbatim>    -> verbatim output for header files.
+#   !<prefix>      -> prefix name for header files.
+#   <return-type> <function-name> <signature> ; -> entry point declaration.
+#
+# Anything else is an error.
+
+import re
+import sys
+import argparse
+
+re_func = re.compile(r"""^(.*[\* ])([A-Za-z_][A-Za-z0-9_]*)\((.*)\);$""")
+re_param = re.compile(r"""^(.*[\* ])([A-Za-z_][A-Za-z0-9_]*)$""")
+
+class Entry:
+    """Small class used to model a single DLL entry point."""
+    def __init__(self, func_name, return_type, parameters):
+        """Initialize Entry instance. |func_name| is the function name,
+           |return_type| its return type, and |parameters| is a list of
+           (type,name) tuples from the entry's signature.
+        """
+        self.func_name = func_name
+        self.return_type = return_type
+        self.parameters = ""
+        self.vartypes = []
+        self.varnames = []
+        self.call = ""
+        comma = ""
+        for param in parameters:
+            self.vartypes.append(param[0])
+            self.varnames.append(param[1])
+            self.parameters += "%s%s %s" % (comma, param[0], param[1])
+            self.call += "%s%s" % (comma, param[1])
+            comma = ", "
+
+def banner_command(argv):
+    """Return sanitized command-line description.
+       |argv| must be a list of command-line parameters, e.g. sys.argv.
+       Return a string corresponding to the command, with platform-specific
+       paths removed."""
+
+    # Remove path from first parameter
+    argv = argv[:]
+    argv[0] = "host/commands/gen-entries.py"
+    return ' '.join(argv)
+
+def parse_entries_file(lines):
+    """Parse an .entries file and return a tuple of:
+        entries: list of Entry instances from the file.
+        prefix_name: prefix name from the file, or None.
+        verbatim: list of verbatim lines from the file.
+        errors: list of errors in the file, prefixed by line number.
+    """
+    entries = []
+    verbatim = []
+    errors = []
+    lineno = 0
+    prefix_name = None
+    for line in lines:
+        lineno += 1
+        line = line.strip()
+        if len(line) == 0:  # Ignore empty lines
+            continue
+        if line[0] == '#':  # Ignore comments
+            continue
+        if line[0] == '!':  # Prefix name
+            prefix_name = line[1:]
+            continue
+        if line[0] == '%':  # Verbatim line copy
+            verbatim.append(line[1:])
+            continue
+        # Must be a function signature.
+        m = re_func.match(line)
+        if not m:
+            errors.append("%d: '%s'" % (lineno, line))
+            continue
+
+        return_type, func_name, parameters = m.groups()
+        return_type = return_type.strip()
+        parameters = parameters.strip()
+        params = []
+        failure = False
+        if parameters != "void":
+            for parameter in parameters.split(','):
+                parameter = parameter.strip()
+                m = re_param.match(parameter)
+                if not m:
+                    errors.append("%d: parameter '%s'" % (lineno, parameter))
+                    failure = True
+                    break
+                else:
+                    param_type, param_name = m.groups()
+                    params.append((param_type.strip(), param_name.strip()))
+
+        if not failure:
+            entries.append(Entry(func_name, return_type, params))
+
+    return (entries, prefix_name, verbatim, errors)
+
+
+def gen_functions_header(entries, prefix_name, verbatim, filename, with_args):
+    """Generate a C header containing a macro listing all entry points.
+       |entries| is a list of Entry instances.
+       |prefix_name| is a prefix-name, it will be converted to upper-case.
+       |verbatim| is a list of verbatim lines that must appear before the
+       macro declaration. Useful to insert #include <> statements.
+       |filename| is the name of the original file.
+    """
+    prefix_name = prefix_name.upper()
+
+    print "// Auto-generated with: %s" % banner_command(sys.argv)
+    print "// DO NOT EDIT THIS FILE"
+    print ""
+    print "#ifndef %s_FUNCTIONS_H" % prefix_name
+    print "#define %s_FUNCTIONS_H" % prefix_name
+    print ""
+    for line in verbatim:
+        print line
+
+    print "#define LIST_%s_FUNCTIONS(X) \\" % prefix_name
+    for entry in entries:
+        if with_args:
+            print "  X(%s, %s, (%s), (%s)) \\" % \
+                    (entry.return_type, entry.func_name, entry.parameters,
+                     entry.call)
+        else:
+            print "  X(%s, %s, (%s)) \\" % \
+                    (entry.return_type, entry.func_name, entry.parameters)
+
+    print ""
+    print ""
+    print "#endif  // %s_FUNCTIONS_H" % prefix_name
+
+def gen_dll_wrapper(entries, prefix_name, verbatim, filename):
+    """Generate a C source file that contains functions that act as wrappers
+       for entry points located in another shared library. This allows the
+       code that calls these functions to perform lazy-linking to system
+       libraries.
+       |entries|, |prefix_name|, |verbatim| and |filename| are the same as
+       for gen_functions_header() above.
+    """
+    upper_name = prefix_name.upper()
+
+    ENTRY_PREFIX = "__dll_"
+
+    print "// Auto-generated with: %s" % banner_command(sys.argv)
+    print "// DO NOT EDIT THIS FILE"
+    print ""
+    print "#include <dlfcn.h>"
+    for line in verbatim:
+        print line
+
+    print ""
+    print "///"
+    print "///  W R A P P E R   P O I N T E R S"
+    print "///"
+    print ""
+    for entry in entries:
+        ptr_name = ENTRY_PREFIX + entry.func_name
+        print "static %s (*%s)(%s) = 0;" % \
+                (entry.return_type, ptr_name, entry.parameters)
+
+    print ""
+    print "///"
+    print "///  W R A P P E R   F U N C T I O N S"
+    print "///"
+    print ""
+
+    for entry in entries:
+        print "%s %s(%s) {" % \
+                (entry.return_type, entry.func_name, entry.parameters)
+        ptr_name = ENTRY_PREFIX + entry.func_name
+        if entry.return_type != "void":
+            print "  return %s(%s);" % (ptr_name, entry.call)
+        else:
+            print "  %s(%s);" % (ptr_name, entry.call)
+        print "}\n"
+
+    print ""
+    print "///"
+    print "///  I N I T I A L I Z A T I O N   F U N C T I O N"
+    print "///"
+    print ""
+
+    print "int %s_dynlink_init(void* lib) {" % prefix_name
+    for entry in entries:
+        ptr_name = ENTRY_PREFIX + entry.func_name
+        print "  %s = (%s(*)(%s))dlsym(lib, \"%s\");" % \
+                (ptr_name,
+                 entry.return_type,
+                 entry.parameters,
+                 entry.func_name)
+        print "  if (!%s) return -1;" % ptr_name
+    print "  return 0;"
+    print "}"
+
+
+def gen_windows_def_file(entries):
+    """Generate a windows DLL .def file. |entries| is a list of Entry instances.
+    """
+    print "EXPORTS"
+    for entry in entries:
+        print "    %s" % entry.func_name
+
+
+def gen_unix_sym_file(entries):
+    """Generate an ELF linker version file. |entries| is a list of Entry
+       instances.
+    """
+    print "VERSION {"
+    print "\tglobal:"
+    for entry in entries:
+        print "\t\t%s;" % entry.func_name
+    print "\tlocal:"
+    print "\t\t*;"
+    print "};"
+
+def gen_symbols(entries, underscore):
+    """Generate a list of symbols from |entries|, a list of Entry instances.
+       |underscore| is a boolean. If True, then prepend an underscore to each
+       symbol name.
+    """
+    prefix = ""
+    if underscore:
+        prefix = "_"
+    for entry in entries:
+        print "%s%s" % (prefix, entry.func_name)
+
+def parse_file(filename, lines, mode):
+    """Generate one of possible outputs from |filename|. |lines| must be a list
+       of text lines from the file, and |mode| is one of the --mode option
+       values.
+    """
+    entries, prefix_name, verbatim, errors = parse_entries_file(lines)
+    if errors:
+        for error in errors:
+            print >> sys.stderr, "ERROR: %s:%s" % (filename, error)
+        sys.exit(1)
+
+    if not prefix_name:
+        prefix_name = "unknown"
+
+    if mode == 'def':
+        gen_windows_def_file(entries)
+    elif mode == 'sym':
+        gen_unix_sym_file(entries)
+    elif mode == 'wrapper':
+        gen_dll_wrapper(entries, prefix_name, verbatim, filename)
+    elif mode == 'symbols':
+        gen_symbols(entries, False)
+    elif mode == '_symbols':
+        gen_symbols(entries, True)
+    elif mode == 'functions':
+        gen_functions_header(entries, prefix_name, verbatim, filename, False)
+    elif mode == 'funcargs':
+        gen_functions_header(entries, prefix_name, verbatim, filename, True)
+
+
+# List of valid --mode option values.
+mode_list = [
+    'def', 'sym', 'wrapper', 'symbols', '_symbols', 'functions', 'funcargs'
+]
+
+# Argument parsing.
+parser = argparse.ArgumentParser(
+    formatter_class=argparse.RawDescriptionHelpFormatter,
+    description="""\
+A script used to parse an .entries input file containing a list of function
+declarations, and generate various output files depending on the value of
+the --mode option, which can be:
+
+  def        Generate a windows DLL .def file.
+  sym        Generate a Unix .so linker script.
+  wrapper    Generate a C source file containing wrapper functions.
+  symbols    Generate a simple list of symbols, one per line.
+  _symbols   Generate a simple list of symbols, prefixed with _.
+  functions  Generate a C header containing a macro listing all functions.
+  funcargs   Like 'functions', but adds function call arguments to listing.
+
+""")
+parser.add_argument("--mode", help="Output mode", choices=mode_list)
+parser.add_argument("--output", help="output file")
+parser.add_argument("file", help=".entries file path")
+
+args = parser.parse_args()
+
+if not args.mode:
+    print >> sys.stderr, "ERROR: Please use --mode=<name>, see --help."
+    sys.exit(1)
+
+if args.output:
+    sys.stdout = open(args.output, "w+")
+
+if args.file == '--':
+    parse_file("<stdin>", sys.stdin, args.mode)
+else:
+    parse_file(args.file, open(args.file), args.mode)
diff --git a/host/libs/Android.bp b/host/libs/Android.bp
new file mode 100644
index 0000000000000000000000000000000000000000..65e458da7963ca1b0d701c7f070788cb89a382a5
--- /dev/null
+++ b/host/libs/Android.bp
@@ -0,0 +1,18 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+subdirs = [
+    "virglrenderer",
+]
diff --git a/host/libs/virglrenderer/.clang-format b/host/libs/virglrenderer/.clang-format
new file mode 100644
index 0000000000000000000000000000000000000000..4b84118833995dbfbcc71f82f50b8d8809ac2833
--- /dev/null
+++ b/host/libs/virglrenderer/.clang-format
@@ -0,0 +1,17 @@
+BasedOnStyle: Google
+AccessModifierOffset: -2
+AllowShortBlocksOnASingleLine: false
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: false
+AllowShortIfStatementsOnASingleLine: false
+AllowShortLoopsOnASingleLine: false
+ConstructorInitializerAllOnOneLineOrOnePerLine: false
+ColumnLimit: 100
+CommentPragmas: NOLINT:.*
+Cpp11BracedListStyle: false
+DerivePointerAlignment: false
+IndentWidth: 4
+PointerAlignment: Left
+TabWidth: 4
+UseTab: Never
+PenaltyExcessCharacter: 32
diff --git a/host/libs/virglrenderer/.gitignore b/host/libs/virglrenderer/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..562939a074129f1af8922a855f471d2f913e1ecc
--- /dev/null
+++ b/host/libs/virglrenderer/.gitignore
@@ -0,0 +1,3 @@
+renderControl_dec/renderControl_server_context.cpp
+GLESv1_dec/gles1_server_context.cpp
+GLESv3_dec/gles3_server_context.cpp
diff --git a/host/libs/virglrenderer/AVDVirglRenderer.cpp b/host/libs/virglrenderer/AVDVirglRenderer.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..973e14442ee1da262a82e3694ba670746fd8a7a2
--- /dev/null
+++ b/host/libs/virglrenderer/AVDVirglRenderer.cpp
@@ -0,0 +1,1100 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#undef NDEBUG
+
+extern "C" {
+#include <linux/virtio_gpu.h>
+#include <virglrenderer.h>
+#include <virgl_hw.h>
+}
+
+#include <sys/uio.h>
+
+#include <dlfcn.h>
+#include <algorithm>
+#include <cassert>
+#include <cerrno>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <deque>
+#include <map>
+#include <mutex>
+#include <string>
+#include <vector>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+#include <GLES3/gl31.h>
+#include <GLES3/gl3ext.h>
+
+#include <drm/drm_fourcc.h>
+
+#include <OpenGLESDispatch/EGLDispatch.h>
+#include <OpenGLESDispatch/GLESv1Dispatch.h>
+#include <OpenGLESDispatch/GLESv3Dispatch.h>
+
+#include "OpenglRender/IOStream.h"
+
+#include "Context.h"
+#include "EglConfig.h"
+#include "EglContext.h"
+#include "EglSurface.h"
+#include "EglSync.h"
+#include "Resource.h"
+
+#include <VirtioGpuCmd.h>
+
+// for debug only
+#include <sys/syscall.h>
+#include <unistd.h>
+#define gettid() (int)syscall(__NR_gettid)
+
+#ifndef PAGE_SIZE
+#define PAGE_SIZE 0x1000
+#endif
+
+#define MAX_CMDRESPBUF_SIZE (10 * PAGE_SIZE)
+
+#define ALIGN(A, B) (((A) + (B)-1) / (B) * (B))
+
+// Enable passing scanout buffers as texture names to sdl2 backend
+#define QEMU_HARDWARE_GL_INTEROP
+
+#ifdef QEMU_HARDWARE_GL_INTEROP
+typedef GLenum (*PFNGLGETERROR)(void);
+typedef void (*PFNGLBINDTEXTURE)(GLenum target, GLuint texture);
+typedef void (*PFNGLGENTEXTURES)(GLsizei n, GLuint* textures);
+typedef void (*PFNGLTEXPARAMETERI)(GLenum target, GLenum pname, GLint param);
+typedef void (*PFNGLPIXELSTOREI)(GLenum pname, GLint param);
+typedef void (*PFNGLTEXIMAGE2D)(GLenum target, GLint level, GLint internalformat, GLsizei width,
+                                GLsizei height, GLint border, GLenum format, GLenum type,
+                                const void* pixels);
+static PFNGLBINDTEXTURE g_glBindTexture;
+static PFNGLGENTEXTURES g_glGenTextures;
+static PFNGLTEXPARAMETERI g_glTexParameteri;
+static PFNGLPIXELSTOREI g_glPixelStorei;
+static PFNGLTEXIMAGE2D g_glTexImage2D;
+static virgl_renderer_gl_context g_ctx0_alt;
+#endif
+
+// Global state
+std::map<uint32_t, EglContext*> EglContext::map;
+std::map<uint32_t, EglSurface*> EglSurface::map;
+std::map<uint32_t, EglImage*> EglImage::map;
+std::map<uint32_t, Resource*> Resource::map;
+std::map<uint64_t, EglSync*> EglSync::map;
+std::map<uint32_t, Context*> Context::map;
+std::vector<EglConfig*> EglConfig::vec;
+static virgl_renderer_callbacks* g_cb;
+const EGLint EglConfig::kAttribs[];
+uint32_t EglContext::nextId = 1U;
+uint32_t EglSurface::nextId = 1U;
+uint32_t EglImage::nextId = 1U;
+uint64_t EglSync::nextId = 1U;
+static void* g_cookie;
+
+// Fence queue, must be thread safe
+static std::mutex g_fence_deque_mutex;
+static std::deque<int> g_fence_deque;
+
+// Other GPU context and state
+static EGLSurface g_ctx0_surface;
+static EGLContext g_ctx0_es1;
+static EGLContext g_ctx0_es2;
+static EGLDisplay g_dpy;
+
+// Last context receiving a command. Allows us to find the context a fence is
+// being created for. Works around the poorly designed virgl interface.
+static Context* g_last_submit_cmd_ctx;
+
+#ifdef OPENGL_DEBUG_PRINTOUT
+
+#include "emugl/common/logging.h"
+
+// For logging from the protocol decoders
+
+void default_logger(const char* fmt, ...) {
+    va_list ap;
+    va_start(ap, fmt);
+    vprintf(fmt, ap);
+    va_end(ap);
+}
+
+emugl_logger_t emugl_cxt_logger = default_logger;
+
+#endif
+
+static void dump_global_state(void) {
+    printf("AVDVIRGLRENDERER GLOBAL STATE\n\n");
+
+    printf("Resources:\n");
+    for (auto const& it : Resource::map) {
+        Resource const* res = it.second;
+
+        printf(
+            "  Resource %u: %ux%u 0x%x %p (%zub) t=%u b=%u d=%u a=%u l=%u "
+            "n=%u f=%u\n",
+            res->args.handle, res->args.width, res->args.height, res->args.format,
+            res->iov ? res->iov[0].iov_base : nullptr, res->iov ? res->iov[0].iov_len : 0,
+            res->args.target, res->args.bind, res->args.depth, res->args.array_size,
+            res->args.last_level, res->args.nr_samples, res->args.flags);
+
+        for (auto const& it : res->context_map) {
+            Context const* ctx = it.second;
+
+            printf("    Context %u, pid=%d, tid=%d\n", ctx->handle, ctx->pid, ctx->tid);
+        }
+    }
+
+    printf("Contexts:\n");
+    for (auto const& it : Context::map) {
+        Context const* ctx = it.second;
+
+        printf("  Context %u: %s pid=%u tid=%u\n", ctx->handle, ctx->name.c_str(), ctx->pid,
+               ctx->tid);
+
+        for (auto const& it : ctx->resource_map) {
+            Resource const* res = it.second;
+
+            printf("    Resource %u\n", res->args.handle);
+        }
+    }
+}
+
+static int sync_linear_to_iovec(Resource* res, uint64_t offset, const virgl_box* box) {
+    uint32_t bpp;
+    switch (res->args.format) {
+        case VIRGL_FORMAT_R8_UNORM:
+            bpp = 1U;
+            break;
+        case VIRGL_FORMAT_B5G6R5_UNORM:
+            bpp = 2U;
+            break;
+        default:
+            bpp = 4U;
+            break;
+    }
+
+    if (box->x > res->args.width || box->y > res->args.height)
+        return 0;
+    if (box->w == 0U || box->h == 0U)
+        return 0;
+    uint32_t w = std::min(box->w, res->args.width - box->x);
+    uint32_t h = std::min(box->h, res->args.height - box->y);
+    uint32_t stride = ALIGN(res->args.width * bpp, 16U);
+    offset += box->y * stride + box->x * bpp;
+    size_t length = (h - 1U) * stride + w * bpp;
+    if (offset + length > res->linearSize)
+        return EINVAL;
+
+    if (res->num_iovs > 1) {
+        const char* linear = static_cast<const char*>(res->linear);
+        for (uint32_t i = 0, iovOffset = 0U; length && i < res->num_iovs; i++) {
+            if (iovOffset + res->iov[i].iov_len > offset) {
+                char* iov_base = static_cast<char*>(res->iov[i].iov_base);
+                size_t copyLength = std::min(length, res->iov[i].iov_len);
+                memcpy(iov_base + offset - iovOffset, linear, copyLength);
+                linear += copyLength;
+                offset += copyLength;
+                length -= copyLength;
+            }
+            iovOffset += res->iov[i].iov_len;
+        }
+    }
+
+    return 0;
+}
+
+static int sync_iovec_to_linear(Resource* res, uint64_t offset, const virgl_box* box) {
+    uint32_t bpp;
+    switch (res->args.format) {
+        case VIRGL_FORMAT_R8_UNORM:
+            bpp = 1U;
+            break;
+        case VIRGL_FORMAT_B5G6R5_UNORM:
+            bpp = 2U;
+            break;
+        default:
+            bpp = 4U;
+            break;
+    }
+
+    if (box->x > res->args.width || box->y > res->args.height)
+        return 0;
+    if (box->w == 0U || box->h == 0U)
+        return 0;
+    uint32_t w = std::min(box->w, res->args.width - box->x);
+    uint32_t h = std::min(box->h, res->args.height - box->y);
+    uint32_t stride = ALIGN(res->args.width * bpp, 16U);
+    offset += box->y * stride + box->x * bpp;
+    size_t length = (h - 1U) * stride + w * bpp;
+    if (offset + length > res->linearSize)
+        return EINVAL;
+
+    if (res->num_iovs > 1) {
+        char* linear = static_cast<char*>(res->linear);
+        for (uint32_t i = 0, iovOffset = 0U; length && i < res->num_iovs; i++) {
+            if (iovOffset + res->iov[i].iov_len > offset) {
+                const char* iov_base = static_cast<const char*>(res->iov[i].iov_base);
+                size_t copyLength = std::min(length, res->iov[i].iov_len);
+                memcpy(linear, iov_base + offset - iovOffset, copyLength);
+                linear += copyLength;
+                offset += copyLength;
+                length -= copyLength;
+            }
+            iovOffset += res->iov[i].iov_len;
+        }
+    }
+
+    return 0;
+}
+
+// The below API was defined by virglrenderer 'master', but does not seem to
+// be used by QEMU, so just ignore it for now..
+//
+// virgl_renderer_get_rect
+// virgl_renderer_get_fd_for_texture
+// virgl_renderer_cleanup
+// virgl_renderer_reset
+// virgl_renderer_get_poll_fd
+
+int virgl_renderer_init(void* cookie, int flags, virgl_renderer_callbacks* cb) {
+    if (!cookie || !cb)
+        return EINVAL;
+
+    if (flags != 0)
+        return ENOSYS;
+
+    if (cb->version != 1)
+        return ENOSYS;
+
+#ifdef QEMU_HARDWARE_GL_INTEROP
+    // FIXME: If we just use "libGL.so" here, mesa's interception library returns
+    //        stub dlsyms that do nothing at runtime, even after binding..
+    void* handle = dlopen(
+        "/usr/lib/x86_64-linux-gnu/nvidia/"
+        "current/libGL.so.384.111",
+        RTLD_NOW);
+    assert(handle != nullptr);
+    g_glBindTexture = (PFNGLBINDTEXTURE)dlsym(handle, "glBindTexture");
+    assert(g_glBindTexture != nullptr);
+    g_glGenTextures = (PFNGLGENTEXTURES)dlsym(handle, "glGenTextures");
+    assert(g_glGenTextures != nullptr);
+    g_glTexParameteri = (PFNGLTEXPARAMETERI)dlsym(handle, "glTexParameteri");
+    assert(g_glTexParameteri != nullptr);
+    g_glPixelStorei = (PFNGLPIXELSTOREI)dlsym(handle, "glPixelStorei");
+    assert(g_glPixelStorei != nullptr);
+    g_glTexImage2D = (PFNGLTEXIMAGE2D)dlsym(handle, "glTexImage2D");
+    assert(g_glTexImage2D != nullptr);
+#endif
+
+    if (!egl_dispatch_init())
+        return ENOENT;
+
+    if (!gles1_dispatch_init())
+        return ENOENT;
+
+    if (!gles3_dispatch_init())
+        return ENOENT;
+
+    g_dpy = s_egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
+    if (g_dpy == EGL_NO_DISPLAY) {
+        printf("Failed to open default EGL display\n");
+        return ENOENT;
+    }
+
+    if (!s_egl.eglInitialize(g_dpy, nullptr, nullptr)) {
+        printf("Failed to initialize EGL display\n");
+        g_dpy = EGL_NO_DISPLAY;
+        return ENOENT;
+    }
+
+    EGLint nConfigs;
+    if (!s_egl.eglGetConfigs(g_dpy, nullptr, 0, &nConfigs)) {
+        printf("Failed to retrieve number of EGL configs\n");
+        s_egl.eglTerminate(g_dpy);
+        g_dpy = EGL_NO_DISPLAY;
+        return ENOENT;
+    }
+
+    EGLConfig configs[nConfigs];
+    if (!s_egl.eglGetConfigs(g_dpy, configs, nConfigs, &nConfigs)) {
+        printf("Failed to retrieve EGL configs\n");
+        s_egl.eglTerminate(g_dpy);
+        g_dpy = EGL_NO_DISPLAY;
+        return ENOENT;
+    }
+
+    // Our static analyzer sees the `new`ing of `config` below without any sort
+    // of attempt to free it, and warns about it. Normally, it would catch that
+    // we're pushing it into a vector in the constructor, but it hits an
+    // internal evaluation limit when trying to evaluate the loop inside of the
+    // ctor. So, it never gets to see that we escape our newly-allocated
+    // `config` instance. Silence the warning, since it's incorrect.
+    // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
+    for (EGLint c = 0; c < nConfigs; c++) {
+        EGLint configId;
+        if (!s_egl.eglGetConfigAttrib(g_dpy, configs[c], EGL_CONFIG_ID, &configId)) {
+            printf("Failed to retrieve EGL config ID\n");
+            s_egl.eglTerminate(g_dpy);
+            g_dpy = EGL_NO_DISPLAY;
+            return ENOENT;
+        }
+        EglConfig* config =
+            new (std::nothrow) EglConfig(g_dpy, configs[c], s_egl.eglGetConfigAttrib);
+        if (!config)
+            return ENOMEM;
+    }
+
+    // clang-format off
+    EGLint const attrib_list[] = {
+        EGL_CONFORMANT,   EGL_OPENGL_ES_BIT | EGL_OPENGL_ES3_BIT_KHR,
+        EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
+        EGL_NONE,
+     };
+    // clang-format on
+    EGLint num_config = 0;
+    EGLConfig config;
+    if (!s_egl.eglChooseConfig(g_dpy, attrib_list, &config, 1, &num_config) || num_config != 1) {
+        printf("Failed to select ES1 & ES3 capable EGL config\n");
+        s_egl.eglTerminate(g_dpy);
+        g_dpy = EGL_NO_DISPLAY;
+        return ENOENT;
+    }
+
+    // clang-format off
+    EGLint const pbuffer_attrib_list[] = {
+        EGL_WIDTH,  1,
+        EGL_HEIGHT, 1,
+        EGL_NONE
+    };
+    // clang-format on
+    g_ctx0_surface = s_egl.eglCreatePbufferSurface(g_dpy, config, pbuffer_attrib_list);
+    if (!g_ctx0_surface) {
+        printf("Failed to create pbuffer surface for context 0\n");
+        s_egl.eglTerminate(g_dpy);
+        g_dpy = EGL_NO_DISPLAY;
+        return ENOENT;
+    }
+
+    // clang-format off
+    EGLint const es1_attrib_list[] = {
+        EGL_CONTEXT_CLIENT_VERSION, 1,
+        EGL_NONE
+    };
+    // clang-format on
+    g_ctx0_es1 = s_egl.eglCreateContext(g_dpy, config, EGL_NO_CONTEXT, es1_attrib_list);
+    if (g_ctx0_es1 == EGL_NO_CONTEXT) {
+        printf("Failed to create ES1 context 0\n");
+        s_egl.eglDestroySurface(g_dpy, g_ctx0_surface);
+        s_egl.eglTerminate(g_dpy);
+        g_dpy = EGL_NO_DISPLAY;
+        return ENOENT;
+    }
+
+    // clang-format off
+    EGLint const es2_attrib_list[] = {
+        EGL_CONTEXT_CLIENT_VERSION, 3, // yes, 3
+        EGL_NONE
+    };
+    // clang-format on
+    g_ctx0_es2 = s_egl.eglCreateContext(g_dpy, config, EGL_NO_CONTEXT, es2_attrib_list);
+    if (g_ctx0_es2 == EGL_NO_CONTEXT) {
+        printf("Failed to create ES2 context 0\n");
+        s_egl.eglDestroySurface(g_dpy, g_ctx0_surface);
+        s_egl.eglDestroyContext(g_dpy, g_ctx0_es1);
+        g_ctx0_es1 = EGL_NO_CONTEXT;
+        s_egl.eglTerminate(g_dpy);
+        g_dpy = EGL_NO_DISPLAY;
+    }
+
+#ifdef QEMU_HARDWARE_GL_INTEROP
+    // This is the hardware GPU context. In future, this code should probably
+    // be removed and SwiftShader be used for all presentation blits.
+    virgl_renderer_gl_ctx_param ctx_params = {
+        .major_ver = 3,
+        .minor_ver = 0,
+    };
+    g_ctx0_alt = cb->create_gl_context(cookie, 0, &ctx_params);
+    if (!g_ctx0_alt) {
+        printf("Failed to create hardware GL context 0\n");
+        s_egl.eglDestroySurface(g_dpy, g_ctx0_surface);
+        s_egl.eglDestroyContext(g_dpy, g_ctx0_es1);
+        g_ctx0_es1 = EGL_NO_CONTEXT;
+        s_egl.eglTerminate(g_dpy);
+        g_dpy = EGL_NO_DISPLAY;
+    }
+
+    // Test we can actually make it current; otherwise, bail
+    if (cb->make_current(cookie, 0, g_ctx0_alt)) {
+        printf("Failed to make hardware GL context 0 current\n");
+        cb->destroy_gl_context(cookie, g_ctx0_alt);
+        g_ctx0_alt = nullptr;
+        s_egl.eglDestroySurface(g_dpy, g_ctx0_surface);
+        s_egl.eglDestroyContext(g_dpy, g_ctx0_es1);
+        g_ctx0_es1 = EGL_NO_CONTEXT;
+        s_egl.eglTerminate(g_dpy);
+        g_dpy = EGL_NO_DISPLAY;
+    }
+#endif
+
+    EglContext::nextId = 1U;
+    g_cookie = cookie;
+    g_cb = cb;
+    return 0;
+}
+
+void virgl_renderer_poll(void) {
+    std::lock_guard<std::mutex> lk(g_fence_deque_mutex);
+    for (auto fence : g_fence_deque)
+        g_cb->write_fence(g_cookie, fence);
+    g_fence_deque.clear();
+}
+
+void* virgl_renderer_get_cursor_data(uint32_t resource_id, uint32_t* width, uint32_t* height) {
+    if (!width || !height)
+        return nullptr;
+
+    std::map<uint32_t, Resource*>::iterator it;
+    it = Resource::map.find(resource_id);
+    if (it == Resource::map.end())
+        return nullptr;
+
+    Resource* res = it->second;
+    if (res->args.bind != VIRGL_RES_BIND_CURSOR)
+        return nullptr;
+
+    void* pixels = malloc(res->linearSize);
+    memcpy(pixels, res->linear, res->linearSize);
+    *height = res->args.height;
+    *width = res->args.width;
+    return pixels;
+}
+
+// NOTE: This function is called from thread context. Do not touch anything
+// without a mutex to protect it from concurrent access. Everything else in
+// libvirglrenderer is designed to be single-threaded *only*.
+
+// Hack to serialize all calls into EGL or GLES functions due to bugs in
+// swiftshader. This should be removed as soon as possible.
+static std::mutex swiftshader_wa_mutex;
+
+static void process_cmd(Context* ctx, char* buf, size_t bufSize, int fence) {
+    VirtioGpuCmd* cmd_resp = reinterpret_cast<VirtioGpuCmd*>(ctx->cmd_resp->linear);
+
+    IOStream stream(cmd_resp->buf, MAX_CMDRESPBUF_SIZE - sizeof(*cmd_resp));
+
+    {
+        std::lock_guard<std::mutex> lk(swiftshader_wa_mutex);
+        size_t decodedBytes;
+
+        decodedBytes = ctx->render_control.decode(buf, bufSize, &stream, &ctx->checksum_calc);
+        bufSize -= decodedBytes;
+        buf += decodedBytes;
+
+        decodedBytes = ctx->gles1.decode(buf, bufSize, &stream, &ctx->checksum_calc);
+        bufSize -= decodedBytes;
+        buf += decodedBytes;
+
+        decodedBytes = ctx->gles3.decode(buf, bufSize, &stream, &ctx->checksum_calc);
+        bufSize -= decodedBytes;
+        buf += decodedBytes;
+    }
+
+    assert(bufSize == 0);
+
+    cmd_resp->cmdSize += stream.getFlushSize();
+
+    printf("(tid %d) ctx %d: cmd %u, size %zu, fence %d\n", gettid(), ctx->handle, cmd_resp->op,
+           cmd_resp->cmdSize - sizeof(*cmd_resp), fence);
+    if (cmd_resp->cmdSize - sizeof(*cmd_resp) > 0) {
+        printf("(tid %d) ", gettid());
+        for (size_t i = 0; i < cmd_resp->cmdSize - sizeof(*cmd_resp); i++) {
+            printf("%.2x ", (unsigned char)cmd_resp->buf[i]);
+        }
+        printf("\n");
+    }
+
+    virgl_box box = {
+        .w = cmd_resp->cmdSize,
+        .h = 1,
+    };
+    sync_linear_to_iovec(ctx->cmd_resp, 0, &box);
+
+    {
+        std::lock_guard<std::mutex> lk(g_fence_deque_mutex);
+        g_fence_deque.push_back(fence);
+    }
+}
+
+int virgl_renderer_submit_cmd(void* buffer, int ctx_id, int ndw) {
+    VirtioGpuCmd* cmd = static_cast<VirtioGpuCmd*>(buffer);
+    size_t bufSize = sizeof(uint32_t) * ndw;
+
+    if (bufSize < sizeof(*cmd)) {
+        printf("bad buffer size, bufSize=%zu, ctx=%d\n", bufSize, ctx_id);
+        return -1;
+    }
+
+    printf("ctx %d: cmd %u, size %zu\n", ctx_id, cmd->op, cmd->cmdSize - sizeof(*cmd));
+
+    for (size_t i = 0; i < bufSize - sizeof(*cmd); i++) {
+        printf("%.2x ", (unsigned char)cmd->buf[i]);
+    }
+    printf("\n");
+
+    if (cmd->cmdSize < bufSize) {
+        printf("ignoring short command, cmdSize=%u, bufSize=%zu\n", cmd->cmdSize, bufSize);
+        return 0;
+    }
+
+    if (cmd->cmdSize > bufSize) {
+        printf("command would overflow buffer, cmdSize=%u, bufSize=%zu\n", cmd->cmdSize, bufSize);
+        return -1;
+    }
+
+    std::map<uint32_t, Context*>::iterator it;
+    it = Context::map.find((uint32_t)ctx_id);
+    if (it == Context::map.end()) {
+        printf("command submit from invalid context %d, ignoring\n", ctx_id);
+        return 0;
+    }
+
+    Context* ctx = it->second;
+
+    // When the context is created, the remote side should send a test command
+    // (op == 0) which we use to set up our link to this context's 'response
+    // buffer'. Only apps using EGL or GLES have this. Gralloc contexts will
+    // never hit this path because they do not submit 3D commands.
+    if (cmd->op == 0) {
+        std::map<uint32_t, Resource*>::iterator it;
+        it = Resource::map.find(*(uint32_t*)cmd->buf);
+        if (it != Resource::map.end()) {
+            Resource* res = it->second;
+            size_t cmdRespBufSize = 0U;
+            for (size_t i = 0; i < res->num_iovs; i++)
+                cmdRespBufSize += res->iov[i].iov_len;
+            if (cmdRespBufSize == MAX_CMDRESPBUF_SIZE)
+                ctx->cmd_resp = res;
+        }
+    }
+
+    if (!ctx->cmd_resp) {
+        printf("context command response page not set up, ctx=%d\n", ctx_id);
+        return -1;
+    }
+
+    VirtioGpuCmd* cmd_resp = reinterpret_cast<VirtioGpuCmd*>(ctx->cmd_resp->linear);
+
+    // We can configure bits of the response now. The size, and any message, will
+    // be updated later. This must be done even for the dummy 'op == 0' command.
+    cmd_resp->op = cmd->op;
+    cmd_resp->cmdSize = sizeof(*cmd_resp);
+
+    if (cmd->op == 0) {
+        // Send back a no-op response, just to keep the protocol in check
+        virgl_box box = {
+            .w = cmd_resp->cmdSize,
+            .h = 1,
+        };
+        sync_linear_to_iovec(ctx->cmd_resp, 0, &box);
+    } else {
+        // If the rcSetPuid command was already processed, this command will be
+        // processed by another thread. If not, the command data will be copied
+        // here and responded to when ctx->setFence() is called later.
+        ctx->submitCommand(buffer, bufSize);
+    }
+
+    g_last_submit_cmd_ctx = ctx;
+    return 0;
+}
+
+void virgl_renderer_get_cap_set(uint32_t set, uint32_t* max_ver, uint32_t* max_size) {
+    if (!max_ver || !max_size)
+        return;
+
+    printf("Request for caps version %u\n", set);
+
+    switch (set) {
+        case 1:
+            *max_ver = 1;
+            *max_size = sizeof(virgl_caps_v1);
+            break;
+        case 2:
+            *max_ver = 2;
+            *max_size = sizeof(virgl_caps_v2);
+            break;
+        default:
+            *max_ver = 0;
+            *max_size = 0;
+            break;
+    }
+}
+
+void virgl_renderer_fill_caps(uint32_t set, uint32_t, void* caps_) {
+    union virgl_caps* caps = static_cast<union virgl_caps*>(caps_);
+    EGLSurface old_read_surface, old_draw_surface;
+    GLfloat range[2] = { 0.0f, 0.0f };
+    bool fill_caps_v2 = false;
+    EGLContext old_context;
+    GLint max = 0;
+
+    if (!caps)
+        return;
+
+    // We don't need to handle caps yet, because our guest driver's features
+    // should be as close as possible to the host driver's. But maybe some day
+    // we'll support gallium shaders and the virgl control stream, so it seems
+    // like a good idea to set up the driver caps correctly..
+
+    // If this is broken, nothing will work properly
+    old_read_surface = s_egl.eglGetCurrentSurface(EGL_READ);
+    old_draw_surface = s_egl.eglGetCurrentSurface(EGL_DRAW);
+    old_context = s_egl.eglGetCurrentContext();
+    if (!s_egl.eglMakeCurrent(g_dpy, g_ctx0_surface, g_ctx0_surface, g_ctx0_es1)) {
+        printf("Failed to make ES1 context current\n");
+        return;
+    }
+
+    // Don't validate 'version' because it looks like this was misdesigned
+    // upstream and won't be set; instead, 'set' was bumped from 1->2.
+
+    switch (set) {
+        case 0:
+        case 1:
+            memset(caps, 0, sizeof(virgl_caps_v1));
+            caps->max_version = 1;
+            break;
+        case 2:
+            memset(caps, 0, sizeof(virgl_caps_v2));
+            caps->max_version = 2;
+            fill_caps_v2 = true;
+            break;
+        default:
+            caps->max_version = 0;
+            return;
+    }
+
+    if (fill_caps_v2) {
+        printf("Will probe and fill caps version 2.\n");
+    }
+
+    // Formats supported for textures
+
+    caps->v1.sampler.bitmask[0] = (1 << (VIRGL_FORMAT_B8G8R8A8_UNORM - (0 * 32))) |
+                                  (1 << (VIRGL_FORMAT_B5G6R5_UNORM - (0 * 32)));
+    caps->v1.sampler.bitmask[2] = (1 << (VIRGL_FORMAT_R8G8B8A8_UNORM - (2 * 32)));
+    caps->v1.sampler.bitmask[4] = (1 << (VIRGL_FORMAT_R8G8B8X8_UNORM - (4 * 32)));
+
+    // Formats supported for rendering
+
+    caps->v1.render.bitmask[0] = (1 << (VIRGL_FORMAT_B8G8R8A8_UNORM - (0 * 32))) |
+                                 (1 << (VIRGL_FORMAT_B5G6R5_UNORM - (0 * 32)));
+    caps->v1.render.bitmask[2] = (1 << (VIRGL_FORMAT_R8G8B8A8_UNORM - (2 * 32)));
+    caps->v1.render.bitmask[4] = (1 << (VIRGL_FORMAT_R8G8B8X8_UNORM - (4 * 32)));
+
+    // Could parse s_gles1.glGetString(GL_SHADING_LANGUAGE_VERSION, ...)?
+    caps->v1.glsl_level = 300;  // OpenGL ES GLSL 3.00
+
+    // Call with any API (v1, v3) bound
+
+    caps->v1.max_viewports = 1;
+
+    s_gles1.glGetIntegerv(GL_MAX_DRAW_BUFFERS_EXT, &max);
+    caps->v1.max_render_targets = max;
+
+    s_gles1.glGetIntegerv(GL_MAX_SAMPLES_EXT, &max);
+    caps->v1.max_samples = max;
+
+    if (fill_caps_v2) {
+        s_gles1.glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, range);
+        caps->v2.min_aliased_point_size = range[0];
+        caps->v2.max_aliased_point_size = range[1];
+
+        s_gles1.glGetFloatv(GL_ALIASED_LINE_WIDTH_RANGE, range);
+        caps->v2.min_aliased_line_width = range[0];
+        caps->v2.max_aliased_line_width = range[1];
+
+        // An extension, but everybody has it
+        s_gles1.glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &max);
+        caps->v2.max_vertex_attribs = max;
+
+        // Call with ES 1.0 bound *only*
+
+        s_gles1.glGetFloatv(GL_SMOOTH_POINT_SIZE_RANGE, range);
+        caps->v2.min_smooth_point_size = range[0];
+        caps->v2.max_smooth_point_size = range[1];
+
+        s_gles1.glGetFloatv(GL_SMOOTH_LINE_WIDTH_RANGE, range);
+        caps->v2.min_smooth_line_width = range[0];
+        caps->v2.max_smooth_line_width = range[1];
+    }
+
+    if (!s_egl.eglMakeCurrent(g_dpy, g_ctx0_surface, g_ctx0_surface, g_ctx0_es2)) {
+        s_egl.eglMakeCurrent(g_dpy, old_draw_surface, old_read_surface, old_context);
+        printf("Failed to make ES3 context current\n");
+        return;
+    }
+
+    // Call with ES 3.0 bound *only*
+
+    caps->v1.bset.primitive_restart = 1;
+    caps->v1.bset.seamless_cube_map = 1;
+    caps->v1.bset.occlusion_query = 1;
+    caps->v1.bset.instanceid = 1;
+    caps->v1.bset.ubo = 1;
+
+    s_gles1.glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &max);
+    caps->v1.max_texture_array_layers = max;
+
+    s_gles1.glGetIntegerv(GL_MAX_VERTEX_UNIFORM_BLOCKS, &max);
+    caps->v1.max_uniform_blocks = max + 1;
+
+    if (fill_caps_v2) {
+        s_gles1.glGetFloatv(GL_MAX_TEXTURE_LOD_BIAS, &caps->v2.max_texture_lod_bias);
+
+        s_gles1.glGetIntegerv(GL_MAX_VERTEX_OUTPUT_COMPONENTS, &max);
+        caps->v2.max_vertex_outputs = max / 4;
+
+        s_gles1.glGetIntegerv(GL_MIN_PROGRAM_TEXEL_OFFSET, &caps->v2.min_texel_offset);
+        s_gles1.glGetIntegerv(GL_MAX_PROGRAM_TEXEL_OFFSET, &caps->v2.max_texel_offset);
+
+        s_gles1.glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &max);
+        caps->v2.uniform_buffer_offset_alignment = max;
+    }
+
+    // ES 2.0 extensions (fixme)
+
+    // Gallium compatibility; not usable currently.
+    caps->v1.prim_mask = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6);
+
+    if (!s_egl.eglMakeCurrent(g_dpy, old_draw_surface, old_read_surface, old_context)) {
+        printf("Failed to make no context current\n");
+    }
+}
+
+int virgl_renderer_create_fence(int client_fence_id, uint32_t cmd_type) {
+    switch (cmd_type) {
+        case VIRTIO_GPU_CMD_SUBMIT_3D:
+            if (g_last_submit_cmd_ctx) {
+                g_last_submit_cmd_ctx->setFence(client_fence_id);
+                break;
+            }
+            [[fallthrough]];
+        default: {
+            std::lock_guard<std::mutex> lk(g_fence_deque_mutex);
+            g_fence_deque.push_back(client_fence_id);
+            break;
+        }
+    }
+    return 0;
+}
+
+void virgl_renderer_force_ctx_0(void) {
+#ifdef QEMU_HARDWARE_GL_INTEROP
+    if (!g_ctx0_alt)
+        return;
+
+    if (g_cb->make_current(g_cookie, 0, g_ctx0_alt)) {
+        printf("Failed to make hardware GL context 0 current\n");
+        g_cb->destroy_gl_context(g_cookie, g_ctx0_alt);
+        g_ctx0_alt = nullptr;
+    }
+#endif
+}
+
+int virgl_renderer_resource_create(virgl_renderer_resource_create_args* args, iovec* iov,
+                                   uint32_t num_iovs) {
+    if (!args)
+        return EINVAL;
+
+    if (args->bind == VIRGL_RES_BIND_CURSOR) {
+        // Enforce limitation of current virtio-gpu-3d implementation
+        if (args->width != 64 || args->height != 64 || args->format != VIRGL_FORMAT_B8G8R8A8_UNORM)
+            return EINVAL;
+    }
+
+    assert(!Resource::map.count(args->handle) && "Can't insert same resource twice!");
+
+    Resource* res = new (std::nothrow) Resource(args, num_iovs, iov);
+    if (!res)
+        return ENOMEM;
+
+    printf("Creating Resource %u (num_iovs=%u)\n", args->handle, num_iovs);
+    return 0;
+}
+
+void virgl_renderer_resource_unref(uint32_t res_handle) {
+    std::map<uint32_t, Resource*>::iterator it;
+
+    it = Resource::map.find(res_handle);
+    if (it == Resource::map.end())
+        return;
+
+    Resource* res = it->second;
+
+    for (auto const& it : Context::map) {
+        Context const* ctx = it.second;
+
+        virgl_renderer_ctx_detach_resource(ctx->handle, res->args.handle);
+    }
+
+    assert(res->context_map.empty() && "Deleted resource was associated with contexts");
+
+    printf("Deleting Resource %u\n", res_handle);
+    delete res;
+}
+
+int virgl_renderer_resource_attach_iov(int res_handle, iovec* iov, int num_iovs) {
+    std::map<uint32_t, Resource*>::iterator it;
+
+    it = Resource::map.find((uint32_t)res_handle);
+    if (it == Resource::map.end())
+        return ENOENT;
+
+    Resource* res = it->second;
+
+    if (!res->iov) {
+        printf(
+            "Attaching backing store for Resource %d "
+            "(num_iovs=%d)\n",
+            res_handle, num_iovs);
+
+        res->num_iovs = num_iovs;
+        res->iov = iov;
+
+        res->reallocLinear();
+
+        // Assumes that when resources are attached, they contain junk, and we
+        // don't need to synchronize with the linear buffer
+    }
+
+    return 0;
+}
+
+void virgl_renderer_resource_detach_iov(int res_handle, iovec** iov, int* num_iovs) {
+    std::map<uint32_t, Resource*>::iterator it;
+
+    it = Resource::map.find((uint32_t)res_handle);
+    if (it == Resource::map.end())
+        return;
+
+    Resource* res = it->second;
+
+    printf("Detaching backing store for Resource %d\n", res_handle);
+
+    // Synchronize our linear buffer, if any, with the iovec that we are about
+    // to give up. Most likely this is not required, but it seems cleaner.
+    virgl_box box = {
+        .w = res->args.width,
+        .h = res->args.height,
+    };
+    sync_linear_to_iovec(res, 0, &box);
+
+    if (num_iovs)
+        *num_iovs = res->num_iovs;
+    res->num_iovs = 0U;
+
+    if (iov)
+        *iov = res->iov;
+    res->iov = nullptr;
+
+    res->reallocLinear();
+}
+
+int virgl_renderer_resource_get_info(int res_handle, virgl_renderer_resource_info* info) {
+    if (!info)
+        return EINVAL;
+
+    std::map<uint32_t, Resource*>::iterator it;
+
+    it = Resource::map.find((uint32_t)res_handle);
+    if (it == Resource::map.end())
+        return ENOENT;
+
+    Resource* res = it->second;
+
+    uint32_t bpp = 4U;
+    switch (res->args.format) {
+        case VIRGL_FORMAT_B8G8R8A8_UNORM:
+            info->drm_fourcc = DRM_FORMAT_BGRA8888;
+            break;
+        case VIRGL_FORMAT_B5G6R5_UNORM:
+            info->drm_fourcc = DRM_FORMAT_BGR565;
+            bpp = 2U;
+            break;
+        case VIRGL_FORMAT_R8G8B8A8_UNORM:
+            info->drm_fourcc = DRM_FORMAT_RGBA8888;
+            break;
+        case VIRGL_FORMAT_R8G8B8X8_UNORM:
+            info->drm_fourcc = DRM_FORMAT_RGBX8888;
+            break;
+        default:
+            return EINVAL;
+    }
+
+#ifdef QEMU_HARDWARE_GL_INTEROP
+    GLenum type = GL_UNSIGNED_BYTE;
+    GLenum format = GL_RGBA;
+    switch (res->args.format) {
+        case VIRGL_FORMAT_B8G8R8A8_UNORM:
+            format = 0x80E1;  // GL_BGRA
+            break;
+        case VIRGL_FORMAT_B5G6R5_UNORM:
+            type = GL_UNSIGNED_SHORT_5_6_5;
+            format = GL_RGB;
+            break;
+        case VIRGL_FORMAT_R8G8B8X8_UNORM:
+            format = GL_RGB;
+            break;
+    }
+
+    if (!res->tex_id) {
+        g_glGenTextures(1, &res->tex_id);
+        g_glBindTexture(GL_TEXTURE_2D, res->tex_id);
+        g_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+        g_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+        g_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+        g_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    } else {
+        g_glBindTexture(GL_TEXTURE_2D, res->tex_id);
+    }
+
+    g_glPixelStorei(GL_UNPACK_ROW_LENGTH, ALIGN(res->args.width, 16));
+    g_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, res->args.width, res->args.height, 0, format, type,
+                   res->linear);
+#endif
+
+    info->stride = ALIGN(res->args.width * bpp, 16U);
+    info->virgl_format = res->args.format;
+    info->handle = res->args.handle;
+    info->height = res->args.height;
+    info->width = res->args.width;
+    info->depth = res->args.depth;
+    info->flags = res->args.flags;
+    info->tex_id = res->tex_id;
+
+    printf("Scanning out Resource %d\n", res_handle);
+    dump_global_state();
+
+    return 0;
+}
+
+int virgl_renderer_context_create(uint32_t handle, uint32_t nlen, const char* name) {
+    assert(!Context::map.count(handle) && "Can't insert same context twice!");
+
+    Context* ctx = new (std::nothrow) Context(handle, name, nlen, process_cmd, g_dpy);
+    if (!ctx)
+        return ENOMEM;
+
+    printf("Creating Context %u (%.*s)\n", handle, (int)nlen, name);
+    return 0;
+}
+
+void virgl_renderer_context_destroy(uint32_t handle) {
+    std::map<uint32_t, Context*>::iterator it;
+    it = Context::map.find(handle);
+    if (it == Context::map.end())
+        return;
+
+    Context* ctx = it->second;
+    printf("Destroying Context %u\n", handle);
+    delete ctx;
+}
+
+int virgl_renderer_transfer_read_iov(uint32_t handle, uint32_t, uint32_t, uint32_t, uint32_t,
+                                     virgl_box* box, uint64_t offset, iovec*, int) {
+    // stride, layer_stride and level are not set by minigbm, so don't try to
+    // validate them right now. iov and iovec_cnt are always passed as nullptr
+    // and 0 by qemu, so ignore those too
+
+    std::map<uint32_t, Resource*>::iterator it;
+    it = Resource::map.find((uint32_t)handle);
+    if (it == Resource::map.end())
+        return EINVAL;
+
+    return sync_linear_to_iovec(it->second, offset, box);
+}
+
+int virgl_renderer_transfer_write_iov(uint32_t handle, uint32_t, int, uint32_t, uint32_t,
+                                      virgl_box* box, uint64_t offset, iovec*, unsigned int) {
+    // stride, layer_stride and level are not set by minigbm, so don't try to
+    // validate them right now. iov and iovec_cnt are always passed as nullptr
+    // and 0 by qemu, so ignore those too
+
+    std::map<uint32_t, Resource*>::iterator it;
+    it = Resource::map.find((uint32_t)handle);
+    if (it == Resource::map.end())
+        return EINVAL;
+
+    return sync_iovec_to_linear(it->second, offset, box);
+}
+
+void virgl_renderer_ctx_attach_resource(int ctx_id, int res_handle) {
+    std::map<uint32_t, Context*>::iterator ctx_it;
+
+    ctx_it = Context::map.find((uint32_t)ctx_id);
+    if (ctx_it == Context::map.end())
+        return;
+
+    Context* ctx = ctx_it->second;
+
+    assert(!ctx->resource_map.count((uint32_t)res_handle) &&
+           "Can't attach resource to context twice!");
+
+    std::map<uint32_t, Resource*>::iterator res_it;
+
+    res_it = Resource::map.find((uint32_t)res_handle);
+    if (res_it == Resource::map.end())
+        return;
+
+    Resource* res = res_it->second;
+
+    printf("Attaching Resource %d to Context %d\n", res_handle, ctx_id);
+    res->context_map.emplace((uint32_t)ctx_id, ctx);
+    ctx->resource_map.emplace((uint32_t)res_handle, res);
+}
+
+void virgl_renderer_ctx_detach_resource(int ctx_id, int res_handle) {
+    std::map<uint32_t, Context*>::iterator ctx_it;
+
+    ctx_it = Context::map.find((uint32_t)ctx_id);
+    if (ctx_it == Context::map.end())
+        return;
+
+    Context* ctx = ctx_it->second;
+
+    std::map<uint32_t, Resource*>::iterator res_it;
+
+    res_it = ctx->resource_map.find((uint32_t)res_handle);
+    if (res_it == ctx->resource_map.end())
+        return;
+
+    Resource* res = res_it->second;
+
+    ctx_it = res->context_map.find((uint32_t)ctx_id);
+    if (ctx_it == res->context_map.end())
+        return;
+
+    printf("Detaching Resource %d from Context %d\n", res_handle, ctx_id);
+    if (ctx->cmd_resp && ctx->cmd_resp->args.handle == (uint32_t)res_handle)
+        ctx->cmd_resp = nullptr;
+    ctx->resource_map.erase(res_it);
+    res->context_map.erase(ctx_it);
+}
diff --git a/host/libs/virglrenderer/Android.bp b/host/libs/virglrenderer/Android.bp
new file mode 100644
index 0000000000000000000000000000000000000000..6c31b7a02c087448fcb88c3af58e610949e3d548
--- /dev/null
+++ b/host/libs/virglrenderer/Android.bp
@@ -0,0 +1,208 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+genrule {
+  name: "glesv1_dec_cuttlefish_gensrc",
+  srcs: ["GLESv1_dec/*"],
+  tools: ["emugen_cuttlefish"],
+  cmd: "$(location emugen_cuttlefish) " +
+       "-i device/generic/opengl-transport/host/libs/virglrenderer/GLESv1_dec " +
+       "-D $(genDir) gles1",
+  out: ["gles1_dec.cpp"],
+}
+
+genrule {
+  name: "glesv1_dec_cuttlefish_genhdr",
+  srcs: ["GLESv1_dec/*"],
+  tools: ["emugen_cuttlefish"],
+  cmd: "$(location emugen_cuttlefish) " +
+       "-i device/generic/opengl-transport/host/libs/virglrenderer/GLESv1_dec " +
+       "-D $(genDir) gles1",
+  out: [
+    "gles1_dec.h",
+    "gles1_opcodes.h",
+    "gles1_server_context.h",
+    "gles1_server_proc.h",
+  ],
+}
+
+genrule {
+  name: "glesv3_dec_cuttlefish_gensrc",
+  srcs: ["GLESv3_dec/*"],
+  tools: ["emugen_cuttlefish"],
+  cmd: "$(location emugen_cuttlefish) " +
+       "-i device/generic/opengl-transport/host/libs/virglrenderer/GLESv3_dec " +
+       "-D $(genDir) gles3",
+  out: ["gles3_dec.cpp"],
+}
+
+genrule {
+  name: "glesv3_dec_cuttlefish_genhdr",
+  srcs: ["GLESv3_dec/*"],
+  tools: ["emugen_cuttlefish"],
+  cmd: "$(location emugen_cuttlefish) " +
+       "-i device/generic/opengl-transport/host/libs/virglrenderer/GLESv3_dec " +
+       "-D $(genDir) gles3",
+  out: [
+    "gles3_dec.h",
+    "gles3_opcodes.h",
+    "gles3_server_context.h",
+    "gles3_server_proc.h",
+  ],
+}
+
+genrule {
+  name: "rendercontrol_dec_cuttlefish_gensrc",
+  srcs: ["renderControl_dec/*"],
+  tools: ["emugen_cuttlefish"],
+  cmd: "$(location emugen_cuttlefish) " +
+       "-i device/generic/opengl-transport/host/libs/virglrenderer/renderControl_dec " +
+       "-D $(genDir) renderControl",
+  out: ["renderControl_dec.cpp"],
+}
+
+genrule {
+  name: "rendercontrol_dec_cuttlefish_genhdr",
+  srcs: ["renderControl_dec/*"],
+  tools: ["emugen_cuttlefish"],
+  cmd: "$(location emugen_cuttlefish) " +
+       "-i device/generic/opengl-transport/host/libs/virglrenderer/renderControl_dec " +
+       "-D $(genDir) renderControl",
+  out: [
+    "renderControl_dec.h",
+    "renderControl_opcodes.h",
+    "renderControl_server_context.h",
+    "renderControl_server_proc.h",
+  ],
+}
+
+// out/host/linux-x86/bin/emugen_cuttlefish -i device/generic/opengl-transport/host/libs/virglrenderer/renderControl_dec -D /tmp/foo renderControl
+
+genrule {
+  name: "gles1_core_functions_hdr",
+  tools: ["gen_entries_cuttlefish"],
+  cmd: "$(location gen_entries_cuttlefish) --mode=funcargs $(in) --output $(out)",
+  srcs: ["OpenGLESDispatch/gles1_core.entries"],
+  out: ["gles1_core_functions.h"],
+}
+
+genrule {
+  name: "gles1_extensions_functions_hdr",
+  tools: ["gen_entries_cuttlefish"],
+  cmd: "$(location gen_entries_cuttlefish) --mode=funcargs $(in) --output $(out)",
+  srcs: ["OpenGLESDispatch/gles1_extensions.entries"],
+  out: ["gles1_extensions_functions.h"],
+}
+
+genrule {
+  name: "egl_functions_hdr",
+  tools: ["gen_entries_cuttlefish"],
+  cmd: "$(location gen_entries_cuttlefish) --mode=funcargs $(in) --output $(out)",
+  srcs: ["OpenGLESDispatch/egl.entries"],
+  out: ["egl_functions.h"],
+}
+
+genrule {
+  name: "gles3_only_functions_hdr",
+  tools: ["gen_entries_cuttlefish"],
+  cmd: "$(location gen_entries_cuttlefish) --mode=funcargs $(in) --output $(out)",
+  srcs: ["OpenGLESDispatch/gles3_only.entries"],
+  out: ["gles3_only_functions.h"],
+}
+
+genrule {
+  name: "gles31_only_functions_hdr",
+  tools: ["gen_entries_cuttlefish"],
+  cmd: "$(location gen_entries_cuttlefish) --mode=funcargs $(in) --output $(out)",
+  srcs: ["OpenGLESDispatch/gles31_only.entries"],
+  out: ["gles31_only_functions.h"],
+}
+
+genrule {
+  name: "gles2_extensions_functions_hdr",
+  tools: ["gen_entries_cuttlefish"],
+  cmd: "$(location gen_entries_cuttlefish) --mode=funcargs $(in) --output $(out)",
+  srcs: ["OpenGLESDispatch/gles2_extensions.entries"],
+  out: ["gles2_extensions_functions.h"],
+}
+
+genrule {
+  name: "egl_extensions_functions_hdr",
+  tools: ["gen_entries_cuttlefish"],
+  cmd: "$(location gen_entries_cuttlefish) --mode=funcargs $(in) --output $(out)",
+  srcs: ["OpenGLESDispatch/egl_extensions.entries"],
+  out: ["egl_extensions_functions.h"],
+}
+
+genrule {
+  name: "gles2_core_functions_hdr",
+  tools: ["gen_entries_cuttlefish"],
+  cmd: "$(location gen_entries_cuttlefish) --mode=funcargs $(in) --output $(out)",
+  srcs: ["OpenGLESDispatch/gles2_core.entries"],
+  out: ["gles2_core_functions.h"],
+}
+
+cc_library_host_shared {
+    name: "libvirglrenderer_cuttlefish",
+    include_dirs: [
+        "external/libdrm",
+        "external/libdrm/include",
+        "device/generic/goldfish-opengl/system",
+    ],
+    local_include_dirs: [
+      "GLESv1_dec",
+      "GLESv3_dec",
+      "include",
+      "renderControl_dec",
+    ],
+    srcs: [
+        "AVDVirglRenderer.cpp",
+        "ChecksumCalculator.cpp",
+        "GLESv1.cpp",
+        "GLESv3.cpp",
+        "Gralloc1.cpp",
+        "OpenGLESDispatch/EGLDispatch.cpp",
+        "OpenGLESDispatch/GLESv1Dispatch.cpp",
+        "OpenGLESDispatch/GLESv3Dispatch.cpp",
+        "RenderControl.cpp",
+    ],
+    cflags: ["-Wno-unused-parameter", "-DOPENGL_DEBUG_PRINTOUT"],
+    host_ldlibs: [ "-ldl" ],
+    version_script : "libvirglrenderer.lds",
+    defaults: [ "cuttlefish_host_only" ],
+    generated_sources: [
+      "glesv1_dec_cuttlefish_gensrc",
+      "glesv3_dec_cuttlefish_gensrc",
+      "rendercontrol_dec_cuttlefish_gensrc",
+    ],
+    generated_headers: [
+      "glesv1_dec_cuttlefish_genhdr",
+      "glesv3_dec_cuttlefish_genhdr",
+      "rendercontrol_dec_cuttlefish_genhdr",
+      "gles1_core_functions_hdr",
+      "gles1_extensions_functions_hdr",
+      "egl_functions_hdr",
+      "gles3_only_functions_hdr",
+      "gles31_only_functions_hdr",
+      "gles2_extensions_functions_hdr",
+      "egl_extensions_functions_hdr",
+      "gles2_core_functions_hdr",
+    ],
+    header_libs: [
+      "virtio_gpu_uapi_headers",
+      "virgl_headers"
+    ],
+}
diff --git a/host/libs/virglrenderer/ChecksumCalculator.cpp b/host/libs/virglrenderer/ChecksumCalculator.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b5d11c0cff73b983f045b2abdbebaaf70aefa79a
--- /dev/null
+++ b/host/libs/virglrenderer/ChecksumCalculator.cpp
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ChecksumCalculator.h"
+
+#include <string>
+#include <vector>
+
+#include <assert.h>
+#include <string.h>
+
+// Checklist when implementing new protocol:
+// 1. update CHECKSUMHELPER_MAX_VERSION
+// 2. update checksumByteSize()
+// 3. update addBuffer, writeChecksum, resetChecksum, validate
+
+// change CHECKSUMHELPER_MAX_VERSION when you want to update the protocol version
+#define CHECKSUMHELPER_MAX_VERSION 1
+
+// utility macros to create checksum string at compilation time
+#define CHECKSUMHELPER_VERSION_STR_PREFIX "ANDROID_EMU_CHECKSUM_HELPER_v"
+#define CHECKSUMHELPER_MACRO_TO_STR(x) #x
+#define CHECKSUMHELPER_MACRO_VAL_TO_STR(x) CHECKSUMHELPER_MACRO_TO_STR(x)
+
+static const uint32_t kMaxVersion = CHECKSUMHELPER_MAX_VERSION;
+static const char* kMaxVersionStrPrefix = CHECKSUMHELPER_VERSION_STR_PREFIX;
+static const char* kMaxVersionStr = CHECKSUMHELPER_VERSION_STR_PREFIX CHECKSUMHELPER_MACRO_VAL_TO_STR(CHECKSUMHELPER_MAX_VERSION);
+
+#undef CHECKSUMHELPER_MAX_VERSION
+#undef CHECKSUMHELPER_VERSION_STR_PREFIX
+#undef CHECKSUMHELPER_MACRO_TO_STR
+#undef CHECKSUMHELPER_MACRO_VAL_TO_STR
+
+uint32_t ChecksumCalculator::getMaxVersion() {return kMaxVersion;}
+const char* ChecksumCalculator::getMaxVersionStr() {return kMaxVersionStr;}
+const char* ChecksumCalculator::getMaxVersionStrPrefix() {return kMaxVersionStrPrefix;}
+
+bool ChecksumCalculator::setVersion(uint32_t version) {
+    if (version > kMaxVersion) {  // unsupported version
+        LOG_CHECKSUMHELPER("%s: ChecksumCalculator Set Unsupported version Version %d\n",
+                __FUNCTION__, m_version);
+        return false;
+    }
+    if (m_isEncodingChecksum) { // setVersion is called in the middle of encoding checksums
+        LOG_CHECKSUMHELPER("%s: called between addBuffer and writeChecksum\n",
+                __FUNCTION__);
+        return false;
+    }
+    m_version = version;
+    m_checksumSize = checksumByteSize(version);
+    LOG_CHECKSUMHELPER("%s: ChecksumCalculator Set Version %d\n", __FUNCTION__,
+                m_version);
+    return true;
+}
+
+void ChecksumCalculator::addBuffer(const void* buf, size_t packetLen) {
+    m_isEncodingChecksum = true;
+    switch (m_version) {
+        case 1:
+            m_v1BufferTotalLength += packetLen;
+            break;
+    }
+}
+
+bool ChecksumCalculator::writeChecksum(void* outputChecksum, size_t outputChecksumLen) {
+    if (outputChecksumLen < checksumByteSize()) return false;
+    char *checksumPtr = (char *)outputChecksum;
+    switch (m_version) {
+        case 1: { // protocol v1 is to reverse the packetLen and write it at the end
+            uint32_t val = computeV1Checksum();
+            memcpy(checksumPtr, &val, sizeof(val));
+            memcpy(checksumPtr+sizeof(val), &m_numWrite, sizeof(m_numWrite));
+            break;
+        }
+    }
+    resetChecksum();
+    m_numWrite++;
+    return true;
+}
+
+void ChecksumCalculator::resetChecksum() {
+    switch (m_version) {
+        case 1:
+            m_v1BufferTotalLength = 0;
+            break;
+    }
+    m_isEncodingChecksum = false;
+}
+
+bool ChecksumCalculator::validate(const void* expectedChecksum,
+                                  size_t expectedChecksumLen) {
+    const size_t checksumSize = checksumByteSize();
+    if (expectedChecksumLen != checksumSize) {
+        m_numRead++;
+        resetChecksum();
+        return false;
+    }
+    bool isValid;
+    switch (m_version) {
+        case 1: {
+            const uint32_t val = computeV1Checksum();
+            assert(checksumSize == sizeof(val) + sizeof(m_numRead));
+            isValid = 0 == memcmp(&val, expectedChecksum, sizeof(val)) &&
+                      0 == memcmp(&m_numRead,
+                                  static_cast<const char*>(expectedChecksum) +
+                                          sizeof(val),
+                                  sizeof(m_numRead));
+            break;
+        }
+        default:
+            isValid = true;  // No checksum is a valid checksum.
+            break;
+    }
+    m_numRead++;
+    resetChecksum();
+    return isValid;
+}
+
+uint32_t ChecksumCalculator::computeV1Checksum() const {
+    uint32_t revLen = m_v1BufferTotalLength;
+    revLen = (revLen & 0xffff0000) >> 16 | (revLen & 0x0000ffff) << 16;
+    revLen = (revLen & 0xff00ff00) >> 8 | (revLen & 0x00ff00ff) << 8;
+    revLen = (revLen & 0xf0f0f0f0) >> 4 | (revLen & 0x0f0f0f0f) << 4;
+    revLen = (revLen & 0xcccccccc) >> 2 | (revLen & 0x33333333) << 2;
+    revLen = (revLen & 0xaaaaaaaa) >> 1 | (revLen & 0x55555555) << 1;
+    return revLen;
+}
diff --git a/host/libs/virglrenderer/ChecksumCalculator.h b/host/libs/virglrenderer/ChecksumCalculator.h
new file mode 100644
index 0000000000000000000000000000000000000000..8e8ce952acdf4b1170af86ff85b60099fb099d37
--- /dev/null
+++ b/host/libs/virglrenderer/ChecksumCalculator.h
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <stdlib.h>
+
+// Set TRACE_CHECKSUMHELPER to 1 to debug creation/destruction of GLprotocol
+// instances.
+#define TRACE_CHECKSUMHELPER 0
+
+#if TRACE_CHECKSUMHELPER
+#define LOG_CHECKSUMHELPER(x...) fprintf(stderr, x)
+#else
+#define LOG_CHECKSUMHELPER(x...)
+#endif
+
+namespace android {
+namespace base {
+class Stream;
+}
+}  // namespace android
+
+// ChecksumCalculator adds checksum as an array of bytes to GL pipe communication, which
+// size depends on the protocol version. Each pipe should use one ChecksumCalculator.
+// It can:
+//      (1) take a list of buffers one by one and compute their checksum string,
+//          in this case the checksum should be as the data in those buffers are
+//          concatenated;
+//      (2) compute the checksum of the buffer list, then either write them into
+//          a buffer provided by user, or compare it against a checksum provided
+//          by user
+//      (3) support different checksum version in future.
+//
+// For backward compatibility, checksum version 0 behaves the same as there is
+// no checksum (i.e., checksumByteSize returns 0, validate always returns true,
+// addBuffer and writeCheckSum does nothing).
+//
+// Notice that to detect package lost, ChecksumCalculator also keeps track of how
+// many times it generates/validates checksums, and might use it as part of the
+// checksum.
+//
+// To evaluate checksums from a list of data buffers buf1, buf2... Please call
+// addBuffer(buf1, buf1len), addBuffer(buf2, buf2len) ... in order.
+// Then if the checksum needs to be encoded into a buffer, one needs to allocate
+// a checksum buffer with size checksumByteSize(), and call
+// writeChecksum(checksumBuffer) to write the checksum to the buffer.
+// If the checksum needs to be validated against an existing one, one needs to
+// call validate(existChecksum, existChecksumLen).
+//
+// The checksum generator and validator must be set to the same version, and
+// the validator must check ALL checksums in the order they are generated,
+// otherwise the validation function will return false.
+//
+// It is allowed to change the checksum version between calculating two
+// checksums. This is designed for backward compatibility reason.
+//
+// Example 1, encoding and decoding:
+//
+// bool testChecksum(void* buf, size_t bufLen) {
+//     // encoding message
+//     ChecksumCalculator encoder;
+//     encoder.setVersion(1);
+//     encoder.addBuffer(buf, bufLen);
+//     std::vector<unsigned char> message(bufLen + encoder.checksumByteSize());
+//     memcpy(&message[0], buf, bufLen);
+//     encoder.writeChecksum(&message[0] + bufLen, encoder.checksumByteSize());
+//
+//     // decoding message
+//     ChecksumCalculator decoder;
+//     decoder.setVersion(1);
+//     decoder.addBuffer(&message[0], bufLen);
+//     return decoder.validate(&message[0] + bufLen, decoder.checksumByteSize());
+// }
+// The return value is true.
+//
+// Example 2, decoding will fail if the order of messages is wrong:
+//
+// bool testChecksumOrder(void* buf1, size_t bufLen1,
+//                        void* buf2, size_t bufLen2) {
+//     // encoding messages
+//     ChecksumCalculator encoder;
+//     encoder.setVersion(1);
+//
+//     std::vector<unsigned char> message1(bufLen1 + encoder.checksumByteSize());
+//     std::vector<unsigned char> message2(bufLen2 + encoder.checksumByteSize());
+//
+//     encoder.addBuffer(buf1, bufLen1);
+//     std::vector<unsigned char> message1(bufLen1 + encoder.checksumByteSize());
+//     memcpy(&message1[0], buf1, bufLen1);
+//     encoder.writeChecksum(&message1[0] + bufLen1, encoder.checksumByteSize());
+//
+//     encoder.addBuffer(buf2, bufLen2);
+//     std::vector<unsigned char> message2(bufLen2 + encoder.checksumByteSize());
+//     memcpy(&message2[0], buf2, bufLen2);
+//     encoder.writeChecksum(&message2[0] + bufLen2, encoder.checksumByteSize());
+//
+//     // decoding messages
+//     ChecksumCalculator decoder;
+//     decoder.setVersion(1);
+//     decoder.addBuffer(&message2[0], bufLen2);
+//     // returns false because the decoding order is not consistent with
+//     // encoding order
+//     if (!decoder.validate(&message2[0]+bufLen2, decoder.checksumByteSize())) {
+//         return false;
+//     }
+//
+//     decoder.addBuffer(&message1[0], bufLen1);
+//     if (!decoder.validate(&message1[0]+bufLen1, decoder.checksumByteSize())) {
+//         return false;
+//     }
+//
+//     return false;
+// }
+
+class ChecksumCalculator {
+  public:
+    static constexpr size_t kMaxChecksumLength = 8;
+
+    // Get and set current checksum version
+    uint32_t getVersion() const {
+        return m_version;
+    }
+    // Call setVersion to set a checksum version. It should be called before
+    // addBuffer(), writeChecksum() and validate(). And it should be called
+    // exact once per rendering thread if both host and guest support checksum.
+    // It won't be called if either host or guest does not support checksum.
+    bool setVersion(uint32_t version);
+
+    // Maximum supported checksum version
+    static uint32_t getMaxVersion();
+    // A version string that looks like "ANDROID_EMU_CHECKSUM_HELPER_v1"
+    // Used multiple times when the guest queries the maximum supported version
+    // from the host.
+    // The library owns the returned pointer. The returned pointer will be
+    // deconstructed when unloading library.
+    static const char* getMaxVersionStr();
+    static const char* getMaxVersionStrPrefix();
+
+    // Size of checksum in the current version
+    size_t checksumByteSize() const {
+        return m_checksumSize;
+    }
+
+    // Update the current checksum value from the data
+    // at |buf| of |bufLen| bytes. Once all buffers
+    // have been added, call writeChecksum() to store
+    // the final checksum value and reset its state.
+    void addBuffer(const void* buf, size_t bufLen);
+    // Write the checksum from the list of buffers to outputChecksum
+    // Will reset the list of buffers by calling resetChecksum.
+    // Return false if the buffer is not long enough
+    // Please query buffer size from checksumByteSize()
+    bool writeChecksum(void* outputChecksum, size_t outputChecksumLen);
+    // Restore the states for computing checksums.
+    // Automatically called at the end of writeChecksum and validate.
+    // Can also be used to abandon the current checksum being calculated.
+    // Notes: it doesn't update the internal read / write counter
+    void resetChecksum();
+
+    // Calculate the checksum from the list of buffers and
+    // compare it with the checksum encoded in expectedChecksum
+    // Will reset the list of buffers by calling resetChecksum.
+    bool validate(const void* expectedChecksum, size_t expectedChecksumLen);
+
+  private:
+    static constexpr size_t kVersion1ChecksumSize = 8;  // 2 x uint32_t
+
+    static_assert(kVersion1ChecksumSize <= kMaxChecksumLength,
+                  "Invalid ChecksumCalculator::kMaxChecksumLength value");
+
+    static constexpr size_t checksumByteSize(uint32_t version) {
+        return version == 1 ? kVersion1ChecksumSize : 0;
+    }
+
+    uint32_t m_version = 0;
+    uint32_t m_checksumSize = checksumByteSize(0);
+    // A temporary state used to compute the total length of a list of buffers,
+    // if addBuffer is called.
+    uint32_t m_numRead = 0;
+    uint32_t m_numWrite = 0;
+    // m_isEncodingChecksum is true when between addBuffer and writeChecksum
+    bool m_isEncodingChecksum = false;
+
+    // Compute a 32bit checksum
+    // Used in protocol v1
+    uint32_t computeV1Checksum() const;
+    // The buffer used in protocol version 1 to compute checksum.
+    uint32_t m_v1BufferTotalLength = 0;
+};
diff --git a/host/libs/virglrenderer/ChecksumCalculatorThreadInfo.h b/host/libs/virglrenderer/ChecksumCalculatorThreadInfo.h
new file mode 100644
index 0000000000000000000000000000000000000000..51f8e1c31c84c28ac7cc37d9d6da1e5aea56fa1d
--- /dev/null
+++ b/host/libs/virglrenderer/ChecksumCalculatorThreadInfo.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "ChecksumCalculator.h"
+
+#include <stdio.h>
+
+// NOTE: This fork of ChecksumCalculatorThreadInfo is *not* thread safe
+
+class ChecksumCalculatorThreadInfo {
+  public:
+    static bool writeChecksum(ChecksumCalculator* calc, void* buf, size_t bufLen,
+                              void* outputChecksum, size_t outputChecksumLen) {
+        calc->addBuffer(buf, bufLen);
+        return calc->writeChecksum(outputChecksum, outputChecksumLen);
+    }
+
+    static bool validate(ChecksumCalculator* calc, void* buf, size_t bufLen, void* checksum,
+                         size_t checksumLen) {
+        calc->addBuffer(buf, bufLen);
+        return calc->validate(checksum, checksumLen);
+    }
+
+    static void validOrDie(ChecksumCalculator* calc, void* buf, size_t bufLen, void* checksum,
+                           size_t checksumLen, const char* message) {
+        if (!validate(calc, buf, bufLen, checksum, checksumLen)) {
+            printf("%s\n", message);
+        }
+    }
+};
diff --git a/host/libs/virglrenderer/Context.h b/host/libs/virglrenderer/Context.h
new file mode 100644
index 0000000000000000000000000000000000000000..53c5488cd9d075bc7cb2e95a6faef0a77973a119
--- /dev/null
+++ b/host/libs/virglrenderer/Context.h
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#undef NDEBUG
+
+#include <cassert>
+#include <condition_variable>
+#include <cstdint>
+#include <map>
+#include <mutex>
+#include <string>
+#include <thread>
+
+#include "GLESv1.h"
+#include "GLESv3.h"
+#include "RenderControl.h"
+#include "Resource.h"
+
+struct EglContext;
+struct Context;
+
+typedef void (*PFNSUBMITCMD)(Context*, char*, size_t, int);
+
+struct Context {
+    static std::map<uint32_t, Context*> map;
+
+    Context(uint32_t handle_, const char* name_, uint32_t nlen_, PFNSUBMITCMD pfnProcessCmd_,
+            EGLDisplay dpy_)
+        : render_control(this, dpy_), worker(), name(std::string(name_, nlen_)), handle(handle_),
+          pfnProcessCmd(pfnProcessCmd_) {
+        map.emplace(handle, this);
+        reset();
+    }
+
+    ~Context() {
+        {
+            std::lock_guard<std::mutex> lk(m);
+            killWorker = true;
+        }
+        cv.notify_one();
+        if (worker.joinable())
+            worker.join();
+        map.erase(handle);
+    }
+
+    Context* bind(EglContext* ctx_) {
+        for (auto const& it : Context::map) {
+            Context* ctx = it.second;
+            if (ctx == this)
+                continue;
+            if (ctx->ctx == ctx_)
+                return ctx;
+        }
+        ctx = ctx_;
+        return nullptr;
+    }
+
+    void unbind() {
+        ctx = nullptr;
+    }
+
+    void setPidTid(int pid_, int tid_) {
+        if (pid != pid_ && tid != tid_) {
+            assert(!worker.joinable() && "Changing pid/tid is not allowed");
+            worker = std::thread(&Context::worker_func, this);
+        }
+        pid = pid_;
+        tid = tid_;
+    }
+
+    void submitCommand(void* buf, size_t bufSize) {
+        char* cmdBufCopy = new char[bufSize];
+        memcpy(cmdBufCopy, buf, bufSize);
+        {
+            std::lock_guard<std::mutex> lk(m);
+            cmdBufSize = bufSize;
+            cmdBuf = cmdBufCopy;
+        }
+        cv.notify_one();
+    }
+
+    void setFence(int fence_) {
+        {
+            std::lock_guard<std::mutex> lk(m);
+            fence = fence_;
+            if (!worker.joinable())
+                processCmd();
+        }
+        cv.notify_one();
+    }
+
+    std::map<uint32_t, Resource*> resource_map;
+    ChecksumCalculator checksum_calc;
+    RenderControl render_control;
+    Resource* cmd_resp = nullptr;
+    EglContext* ctx = nullptr;
+    std::thread worker;
+    std::string name;
+    uint32_t handle;
+    GLESv1 gles1;
+    GLESv3 gles3;
+    int pid = 0;
+    int tid = 0;
+
+  private:
+    std::condition_variable cv;
+    PFNSUBMITCMD pfnProcessCmd;
+    bool killWorker = false;
+    size_t cmdBufSize;
+    char* cmdBuf;
+    std::mutex m;
+    int fence;
+
+    void reset() {
+        cmdBuf = nullptr;
+        cmdBufSize = 0U;
+        fence = 0;
+    }
+
+    void worker_func() {
+        while (!killWorker) {
+            std::unique_lock<std::mutex> lk(m);
+            cv.wait(lk, [this] { return killWorker || (cmdBuf && fence); });
+            if (!killWorker)
+                processCmd();
+            lk.unlock();
+        }
+    }
+
+    void processCmd() {
+        pfnProcessCmd(this, cmdBuf, cmdBufSize, fence);
+        delete cmdBuf;
+        reset();
+    }
+};
diff --git a/host/libs/virglrenderer/EglConfig.h b/host/libs/virglrenderer/EglConfig.h
new file mode 100644
index 0000000000000000000000000000000000000000..3b5cd2b49583f097525f4a45aa284081d8da5864
--- /dev/null
+++ b/host/libs/virglrenderer/EglConfig.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cstdint>
+#include <vector>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+typedef EGLBoolean (*PFNEGLGETCONFIGATTRIB)(EGLDisplay, EGLConfig, EGLint, EGLint*);
+
+struct EglConfig {
+    static std::vector<EglConfig*> vec;
+
+    // clang-format off
+    static constexpr EGLint kAttribs[] = {
+        EGL_DEPTH_SIZE,
+        EGL_STENCIL_SIZE,
+        EGL_RENDERABLE_TYPE,
+        EGL_SURFACE_TYPE,
+        EGL_CONFIG_ID,
+        EGL_BUFFER_SIZE,
+        EGL_ALPHA_SIZE,
+        EGL_BLUE_SIZE,
+        EGL_GREEN_SIZE,
+        EGL_RED_SIZE,
+        EGL_CONFIG_CAVEAT,
+        EGL_LEVEL,
+        EGL_MAX_PBUFFER_HEIGHT,
+        EGL_MAX_PBUFFER_PIXELS,
+        EGL_MAX_PBUFFER_WIDTH,
+        EGL_NATIVE_RENDERABLE,
+        EGL_NATIVE_VISUAL_ID,
+        EGL_NATIVE_VISUAL_TYPE,
+        0x3030, // EGL_PRESERVED_RESOURCES
+        EGL_SAMPLES,
+        EGL_SAMPLE_BUFFERS,
+        EGL_TRANSPARENT_TYPE,
+        EGL_TRANSPARENT_BLUE_VALUE,
+        EGL_TRANSPARENT_GREEN_VALUE,
+        EGL_TRANSPARENT_RED_VALUE,
+        EGL_BIND_TO_TEXTURE_RGB,
+        EGL_BIND_TO_TEXTURE_RGBA,
+        EGL_MIN_SWAP_INTERVAL,
+        EGL_MAX_SWAP_INTERVAL,
+        EGL_LUMINANCE_SIZE,
+        EGL_ALPHA_MASK_SIZE,
+        EGL_COLOR_BUFFER_TYPE,
+        //EGL_MATCH_NATIVE_PIXMAP,
+        EGL_RECORDABLE_ANDROID,
+        EGL_CONFORMANT
+    };
+    // clang-format on
+
+    static constexpr size_t kNumAttribs = sizeof(kAttribs) / sizeof(kAttribs[0]);
+
+    EglConfig(EGLDisplay dpy, EGLConfig config_, PFNEGLGETCONFIGATTRIB pfnEglGetConfigAttrib)
+        : config(config_) {
+        for (size_t a = 0; a < kNumAttribs; a++) {
+            if (!pfnEglGetConfigAttrib(dpy, config, kAttribs[a], &attribs[a]))
+                attribs[a] = 0;
+        }
+        vec.push_back(this);
+    }
+
+    ~EglConfig() {
+        for (size_t i = 0; i < EglConfig::vec.size(); i++) {
+            if (vec[i] == this) {
+                vec.erase(vec.begin() + i);
+                break;
+            }
+        }
+    }
+
+    EGLint attribs[kNumAttribs];
+    EGLConfig config;
+};
diff --git a/host/libs/virglrenderer/EglContext.h b/host/libs/virglrenderer/EglContext.h
new file mode 100644
index 0000000000000000000000000000000000000000..7283c08cd209803d630f4f1e4b2227aacb3e6e29
--- /dev/null
+++ b/host/libs/virglrenderer/EglContext.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cstdint>
+#include <map>
+
+#include <EGL/egl.h>
+
+struct EglContext {
+    enum GLESApi {
+        GLESApi_CM = 1,
+        GLESApi_2 = 2,
+        GLESApi_3_0 = 3,
+        GLESApi_3_1 = 4,
+    };
+
+    static std::map<uint32_t, EglContext*> map;
+    static uint32_t nextId;
+
+    EglContext(EGLContext context_, uint32_t ctx_, GLESApi api_)
+        : create_ctx(ctx_), context(context_), api(api_), id(nextId++) {
+        map.emplace(id, this);
+    }
+
+    ~EglContext() {
+        map.erase(id);
+    }
+
+    EglContext* bind(uint32_t ctx_) {
+        for (auto const& it : EglContext::map) {
+            EglContext* ctx = it.second;
+            if (ctx == this)
+                continue;
+            if (ctx->bound_ctx == ctx_)
+                return ctx;
+        }
+        bound_ctx = ctx_;
+        return nullptr;
+    }
+
+    void unbind() {
+        bound_ctx = 0U;
+    }
+
+    bool disposable() {
+        return context == EGL_NO_CONTEXT && bound_ctx == 0U;
+    }
+
+    uint32_t create_ctx;
+    EGLContext context;
+    enum GLESApi api;
+    uint32_t id;
+
+  private:
+    uint32_t bound_ctx = 0U;
+};
diff --git a/host/libs/virglrenderer/EglImage.h b/host/libs/virglrenderer/EglImage.h
new file mode 100644
index 0000000000000000000000000000000000000000..09b968c205a7c90936960b090f19d36a248b4e0c
--- /dev/null
+++ b/host/libs/virglrenderer/EglImage.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cstdint>
+#include <map>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+typedef EGLBoolean (*PFNEGLDESTROYIMAGEKHR)(EGLDisplay, EGLImageKHR);
+
+struct EglImage {
+    static std::map<uint32_t, EglImage*> map;
+    static uint32_t nextId;
+
+    EglImage(EGLDisplay dpy_, EGLImageKHR image_, PFNEGLDESTROYIMAGEKHR pfnEglDestroyImageKHR_)
+        : pfnEglDestroyImageKHR(pfnEglDestroyImageKHR_), image(image_), dpy(dpy_), id(nextId++) {
+        map.emplace(id, this);
+    }
+
+    ~EglImage() {
+        pfnEglDestroyImageKHR(dpy, image);
+        map.erase(id);
+    }
+
+    PFNEGLDESTROYIMAGEKHR pfnEglDestroyImageKHR;
+    EGLImageKHR image;
+    EGLDisplay dpy;
+    uint32_t id;
+};
diff --git a/host/libs/virglrenderer/EglSurface.h b/host/libs/virglrenderer/EglSurface.h
new file mode 100644
index 0000000000000000000000000000000000000000..4bb880dbb0acda986cc9fc7578daf13e83801d86
--- /dev/null
+++ b/host/libs/virglrenderer/EglSurface.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cstdint>
+#include <map>
+
+#include <EGL/egl.h>
+
+struct ANativeWindow;
+
+struct EglSurface {
+    static std::map<uint32_t, EglSurface*> map;
+    static uint32_t nextId;
+
+    EglSurface(EGLConfig config_, uint32_t ctx_, uint32_t width_, uint32_t height_)
+        : create_ctx(ctx_), config(config_), height(height_), width(width_), id(nextId++) {
+        map.emplace(id, this);
+    }
+
+    ~EglSurface() {
+        map.erase(id);
+    }
+
+    EglSurface* bind(uint32_t ctx_, bool read_) {
+        for (auto const& it : EglSurface::map) {
+            EglSurface* sur = it.second;
+            if (sur == this)
+                continue;
+            if (sur->bound_ctx == ctx_) {
+                if (read_ && sur->read)
+                    return sur;
+                if (!read_ && sur->draw)
+                    return sur;
+            }
+        }
+        if (read_) {
+            read = true;
+        } else {
+            draw = true;
+        }
+        bound_ctx = ctx_;
+        return nullptr;
+    }
+
+    void unbind(bool read_) {
+        if (read || draw) {
+            if (read_)
+                read = false;
+            else
+                draw = false;
+            if (read || draw)
+                return;
+            bound_ctx = 0U;
+        }
+        return;
+    }
+
+    bool disposable() {
+        return surface == EGL_NO_SURFACE && bound_ctx == 0U;
+    }
+
+    EGLSurface surface = EGL_NO_SURFACE;
+    ANativeWindow* window = nullptr;
+    uint32_t create_ctx;
+    EGLConfig config;
+    uint32_t height;
+    uint32_t width;
+    uint32_t id;
+
+  private:
+    uint32_t bound_ctx = 0U;
+    bool draw = false;
+    bool read = false;
+};
diff --git a/host/libs/virglrenderer/EglSync.h b/host/libs/virglrenderer/EglSync.h
new file mode 100644
index 0000000000000000000000000000000000000000..8dda71331b70dedfcdc07d02736357f4d9d72426
--- /dev/null
+++ b/host/libs/virglrenderer/EglSync.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cstdint>
+#include <map>
+
+#include <EGL/egl.h>
+
+struct EglSync {
+    static std::map<uint64_t, EglSync*> map;
+    static uint64_t nextId;
+
+    EglSync(EGLSyncKHR sync_) : sync(sync_), id(nextId++) {
+        map.emplace(id, this);
+    }
+
+    ~EglSync() {
+        map.erase(id);
+    }
+
+    EGLSyncKHR sync;
+    uint64_t id;
+};
diff --git a/host/libs/virglrenderer/GLESv1.cpp b/host/libs/virglrenderer/GLESv1.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..17a7ae4b3ed969aebe8fc7d8ab2861b64f2ca46a
--- /dev/null
+++ b/host/libs/virglrenderer/GLESv1.cpp
@@ -0,0 +1,448 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <OpenGLESDispatch/GLESv1Dispatch.h>
+
+#include "GLESv1.h"
+
+// Stubs (common)
+
+static void glDeleteFencesNV(GLsizei, const GLuint*) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glDisableDriverControlQCOM(GLuint) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glDiscardFramebufferEXT(GLenum, GLsizei, const GLenum*) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glEnableDriverControlQCOM(GLuint) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glEndTilingQCOM(GLbitfield) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glExtGetBufferPointervQCOM(GLenum, GLvoid**) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glExtGetBuffersQCOM(GLuint*, GLint, GLint*) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glExtGetFramebuffersQCOM(GLuint*, GLint, GLint*) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glExtGetProgramBinarySourceQCOM(GLuint, GLenum, GLchar*, GLint*) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glExtGetProgramsQCOM(GLuint*, GLint, GLint*) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glExtGetRenderbuffersQCOM(GLuint*, GLint, GLint*) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glExtGetShadersQCOM(GLuint*, GLint, GLint*) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glExtGetTexLevelParameterivQCOM(GLuint, GLenum, GLint, GLenum, GLint*) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glExtGetTexSubImageQCOM(GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei,
+                                    GLenum, GLenum, GLvoid*) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glExtGetTexturesQCOM(GLuint*, GLint, GLint*) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static GLboolean glExtIsProgramBinaryQCOM(GLuint) {
+    printf("%s: not implemented\n", __func__);
+    return GL_FALSE;
+}
+
+static void glExtTexObjectStateOverrideiQCOM(GLenum, GLenum, GLint) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glFinishFenceNV(GLuint) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glFramebufferTexture2DMultisampleIMG(GLenum, GLenum, GLenum, GLuint, GLint, GLsizei) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glGenFencesNV(GLsizei, GLuint*) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glGetDriverControlsQCOM(GLint*, GLsizei, GLuint*) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glGetDriverControlStringQCOM(GLuint, GLsizei, GLsizei*, GLchar*) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glGetFenceivNV(GLuint, GLenum, GLint*) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static GLboolean glIsFenceNV(GLuint) {
+    printf("%s: not implemented\n", __func__);
+    return GL_FALSE;
+}
+
+static void* glMapBufferOES(GLenum, GLenum) {
+    printf("%s: not implemented\n", __func__);
+    return nullptr;
+}
+
+static void glMultiDrawArraysEXT(GLenum, const GLint*, const GLsizei*, GLsizei) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glMultiDrawElementsEXT(GLenum, const GLsizei*, GLenum, const GLvoid* const*, GLsizei) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glRenderbufferStorageMultisampleIMG(GLenum, GLsizei, GLenum, GLsizei, GLsizei) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glSetFenceNV(GLuint, GLenum) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glStartTilingQCOM(GLuint, GLuint, GLuint, GLuint, GLbitfield) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static GLboolean glTestFenceNV(GLuint) {
+    printf("%s: not implemented\n", __func__);
+    return GL_FALSE;
+}
+
+// Stubs (ES 1.1)
+
+static void glBindVertexArrayOES(GLuint) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glCurrentPaletteMatrixOES(GLuint) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glDeleteVertexArraysOES(GLsizei, const GLuint*) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glGenVertexArraysOES(GLsizei, GLuint*) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glGetBufferPointervOES(GLenum, GLenum, GLvoid**) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glGetTexGenfvOES(GLenum, GLenum, GLfloat*) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glGetTexGenivOES(GLenum, GLenum, GLint*) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glGetTexGenxvOES(GLenum, GLenum, GLfixed*) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static GLboolean glIsVertexArrayOES(GLuint) {
+    printf("%s: not implemented\n", __func__);
+    return GL_FALSE;
+}
+
+static void glLoadPaletteFromModelViewMatrixOES() {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glMatrixIndexPointerData(GLint, GLenum, GLsizei, void*, GLuint) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glMatrixIndexPointerOffset(GLint, GLenum, GLsizei, GLuint) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glMultiDrawArraysSUN(GLenum, GLint*, GLsizei*, GLsizei) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glMultiDrawElementsSUN(GLenum, const GLsizei*, GLenum, const GLvoid**, GLsizei) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static GLbitfield glQueryMatrixxOES(GLfixed*, GLint*) {
+    printf("%s: not implemented\n", __func__);
+    return 0;
+}
+
+static void glTexGenfOES(GLenum, GLenum, GLfloat) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glTexGenfvOES(GLenum, GLenum, const GLfloat*) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glTexGeniOES(GLenum, GLenum, GLint) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glTexGenivOES(GLenum, GLenum, const GLint*) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glTexGenxOES(GLenum, GLenum, GLfixed) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glTexGenxvOES(GLenum, GLenum, const GLfixed*) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static GLboolean glUnmapBufferOES(GLenum) {
+    printf("%s: not implemented\n", __func__);
+    return GL_FALSE;
+}
+
+static void glWeightPointerData(GLint, GLenum, GLsizei, void*, GLuint) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glWeightPointerOffset(GLint, GLenum, GLsizei, GLuint) {
+    printf("%s: not implemented\n", __func__);
+}
+
+// Non-stubs (common)
+
+static void glDrawElementsData(GLenum mode, GLsizei count, GLenum type, void* indices, GLuint) {
+    s_gles1.glDrawElements(mode, count, type, indices);
+}
+
+static void glDrawElementsOffset(GLenum mode, GLsizei count, GLenum type, GLuint offset) {
+    s_gles1.glDrawElements(mode, count, type, reinterpret_cast<const GLvoid*>(offset));
+}
+
+static GLint glFinishRoundTrip() {
+    s_gles1.glFinish();
+    return 0;
+}
+
+static void glGetCompressedTextureFormats(int count, GLint* formats) {
+    int nFormats;
+    s_gles1.glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &nFormats);
+    if (nFormats <= count)
+        s_gles1.glGetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, formats);
+}
+
+// Non-stubs (ES 1.1)
+
+static void glColorPointerData(GLint size, GLenum type, GLsizei, void* data, GLuint) {
+    s_gles1.glColorPointer(size, type, 0, data);
+}
+
+static void glColorPointerOffset(GLint size, GLenum type, GLsizei, GLuint offset) {
+    s_gles1.glColorPointer(size, type, 0, reinterpret_cast<GLvoid*>(offset));
+}
+
+static void glNormalPointerData(GLenum type, GLsizei, void* data, GLuint) {
+    s_gles1.glNormalPointer(type, 0, data);
+}
+
+static void glNormalPointerOffset(GLenum type, GLsizei, GLuint offset) {
+    s_gles1.glNormalPointer(type, 0, reinterpret_cast<GLvoid*>(offset));
+}
+
+static void glPointSizePointerData(GLenum type, GLsizei, void* data, GLuint) {
+    s_gles1.glPointSizePointerOES(type, 0, data);
+}
+
+static void glPointSizePointerOffset(GLenum type, GLsizei, GLuint offset) {
+    s_gles1.glPointSizePointerOES(type, 0, reinterpret_cast<GLvoid*>(offset));
+}
+
+static void glTexCoordPointerData(GLint, GLint size, GLenum type, GLsizei, void* data, GLuint) {
+    // FIXME: unit?
+    s_gles1.glTexCoordPointer(size, type, 0, data);
+}
+
+static void glTexCoordPointerOffset(GLint size, GLenum type, GLsizei, GLuint offset) {
+    s_gles1.glTexCoordPointer(size, type, 0, reinterpret_cast<GLvoid*>(offset));
+}
+
+static void glVertexPointerData(GLint size, GLenum type, GLsizei, void* data, GLuint) {
+    s_gles1.glVertexPointer(size, type, 0, data);
+}
+
+static void glVertexPointerOffset(GLint size, GLenum type, GLsizei, GLuint offset) {
+    s_gles1.glVertexPointer(size, type, 0, reinterpret_cast<GLvoid*>(offset));
+}
+
+#define KNIT(return_type, function_name, signature, callargs) function_name = s_gles1.function_name;
+
+GLESv1::GLESv1() {
+    LIST_GLES1_FUNCTIONS(KNIT, KNIT)
+
+    // Remap some ES 1.0 extensions that become core in ES 1.1
+    glAlphaFuncxOES = glAlphaFuncx;
+    glClearColorxOES = glClearColorx;
+    glClearDepthfOES = glClearDepthf;
+    glClearDepthxOES = glClearDepthx;
+    glClipPlanefIMG = glClipPlanef;
+    glClipPlanefOES = glClipPlanef;
+    glClipPlanexIMG = glClipPlanex;
+    glClipPlanexOES = glClipPlanex;
+    glColor4xOES = glColor4x;
+    glDepthRangefOES = glDepthRangef;
+    glDepthRangexOES = glDepthRangex;
+    glFogxOES = glFogx;
+    glFogxvOES = glFogxv;
+    glFrustumfOES = glFrustumf;
+    glFrustumxOES = glFrustumx;
+    glGetClipPlanefOES = glGetClipPlanef;
+    glGetClipPlanexOES = glGetClipPlanex;
+    glGetFixedvOES = glGetFixedv;
+    glGetLightxvOES = glGetLightxv;
+    glGetMaterialxvOES = glGetMaterialxv;
+    glGetTexEnvxvOES = glGetTexEnvxv;
+    glGetTexParameterxvOES = glGetTexParameterxv;
+    glLightModelxOES = glLightModelx;
+    glLightModelxvOES = glLightModelxv;
+    glLightxOES = glLightx;
+    glLightxvOES = glLightxv;
+    glLineWidthxOES = glLineWidthx;
+    glLoadMatrixxOES = glLoadMatrixx;
+    glMaterialxOES = glMaterialx;
+    glMaterialxvOES = glMaterialxv;
+    glMultiTexCoord4xOES = glMultiTexCoord4x;
+    glMultMatrixxOES = glMultMatrixx;
+    glNormal3xOES = glNormal3x;
+    glOrthofOES = glOrthof;
+    glOrthoxOES = glOrthox;
+    glPointParameterxOES = glPointParameterx;
+    glPointParameterxvOES = glPointParameterxv;
+    glPointSizexOES = glPointSizex;
+    glPolygonOffsetxOES = glPolygonOffsetx;
+    glRotatexOES = glRotatex;
+    glSampleCoveragexOES = glSampleCoveragex;
+    glScalexOES = glScalex;
+    glTexEnvxOES = glTexEnvx;
+    glTexEnvxvOES = glTexEnvxv;
+    glTexParameterxOES = glTexParameterx;
+    glTexParameterxvOES = glTexParameterxv;
+    glTranslatexOES = glTranslatex;
+
+    // Entrypoints requiring custom wrappers (common)
+    glDrawElementsData = ::glDrawElementsData;
+    glDrawElementsOffset = ::glDrawElementsOffset;
+    glFinishRoundTrip = ::glFinishRoundTrip;
+    glGetCompressedTextureFormats = ::glGetCompressedTextureFormats;
+
+    // Entrypoints requiring custom wrappers (ES 1.1)
+    glColorPointerData = ::glColorPointerData;
+    glColorPointerOffset = ::glColorPointerOffset;
+    glNormalPointerData = ::glNormalPointerData;
+    glNormalPointerOffset = ::glNormalPointerOffset;
+    glPointSizePointerData = ::glPointSizePointerData;
+    glPointSizePointerOffset = ::glPointSizePointerOffset;
+    glTexCoordPointerData = ::glTexCoordPointerData;
+    glTexCoordPointerOffset = ::glTexCoordPointerOffset;
+    glVertexPointerData = ::glVertexPointerData;
+    glVertexPointerOffset = ::glVertexPointerOffset;
+
+    // Stub some extensions we will never implement (common)
+    glDeleteFencesNV = ::glDeleteFencesNV;
+    glDisableDriverControlQCOM = ::glDisableDriverControlQCOM;
+    glDiscardFramebufferEXT = ::glDiscardFramebufferEXT;
+    glEnableDriverControlQCOM = ::glEnableDriverControlQCOM;
+    glEndTilingQCOM = ::glEndTilingQCOM;
+    glExtGetBufferPointervQCOM = ::glExtGetBufferPointervQCOM;
+    glExtGetBuffersQCOM = ::glExtGetBuffersQCOM;
+    glExtGetFramebuffersQCOM = ::glExtGetFramebuffersQCOM;
+    glExtGetProgramBinarySourceQCOM = ::glExtGetProgramBinarySourceQCOM;
+    glExtGetProgramsQCOM = ::glExtGetProgramsQCOM;
+    glExtGetRenderbuffersQCOM = ::glExtGetRenderbuffersQCOM;
+    glExtGetShadersQCOM = ::glExtGetShadersQCOM;
+    glExtGetTexLevelParameterivQCOM = ::glExtGetTexLevelParameterivQCOM;
+    glExtGetTexSubImageQCOM = ::glExtGetTexSubImageQCOM;
+    glExtGetTexturesQCOM = ::glExtGetTexturesQCOM;
+    glExtIsProgramBinaryQCOM = ::glExtIsProgramBinaryQCOM;
+    glExtTexObjectStateOverrideiQCOM = ::glExtTexObjectStateOverrideiQCOM;
+    glFinishFenceNV = ::glFinishFenceNV;
+    glFramebufferTexture2DMultisampleIMG = ::glFramebufferTexture2DMultisampleIMG;
+    glGenFencesNV = ::glGenFencesNV;
+    glGetDriverControlsQCOM = ::glGetDriverControlsQCOM;
+    glGetDriverControlStringQCOM = ::glGetDriverControlStringQCOM;
+    glGetFenceivNV = ::glGetFenceivNV;
+    glIsFenceNV = ::glIsFenceNV;
+    glMapBufferOES = ::glMapBufferOES;
+    glMultiDrawArraysEXT = ::glMultiDrawArraysEXT;
+    glMultiDrawElementsEXT = ::glMultiDrawElementsEXT;
+    glRenderbufferStorageMultisampleIMG = ::glRenderbufferStorageMultisampleIMG;
+    glSetFenceNV = ::glSetFenceNV;
+    glStartTilingQCOM = ::glStartTilingQCOM;
+    glTestFenceNV = ::glTestFenceNV;
+
+    // Stub some extensions we will never implement (ES 1.1)
+    glBindVertexArrayOES = ::glBindVertexArrayOES;
+    glCurrentPaletteMatrixOES = ::glCurrentPaletteMatrixOES;
+    glDeleteVertexArraysOES = ::glDeleteVertexArraysOES;
+    glGenVertexArraysOES = ::glGenVertexArraysOES;
+    glGetBufferPointervOES = ::glGetBufferPointervOES;
+    glGetTexGenfvOES = ::glGetTexGenfvOES;
+    glGetTexGenivOES = ::glGetTexGenivOES;
+    glGetTexGenxvOES = ::glGetTexGenxvOES;
+    glIsVertexArrayOES = ::glIsVertexArrayOES;
+    glLoadPaletteFromModelViewMatrixOES = ::glLoadPaletteFromModelViewMatrixOES;
+    glMatrixIndexPointerData = ::glMatrixIndexPointerData;
+    glMatrixIndexPointerOffset = ::glMatrixIndexPointerOffset;
+    glMultiDrawArraysSUN = ::glMultiDrawArraysSUN;
+    glMultiDrawElementsSUN = ::glMultiDrawElementsSUN;
+    glQueryMatrixxOES = ::glQueryMatrixxOES;
+    glTexGenfOES = ::glTexGenfOES;
+    glTexGenfvOES = ::glTexGenfvOES;
+    glTexGeniOES = ::glTexGeniOES;
+    glTexGenivOES = ::glTexGenivOES;
+    glTexGenxOES = ::glTexGenxOES;
+    glTexGenxvOES = ::glTexGenxvOES;
+    glUnmapBufferOES = ::glUnmapBufferOES;
+    glWeightPointerData = ::glWeightPointerData;
+    glWeightPointerOffset = ::glWeightPointerOffset;
+}
diff --git a/host/libs/virglrenderer/GLESv1.h b/host/libs/virglrenderer/GLESv1.h
new file mode 100644
index 0000000000000000000000000000000000000000..00c1ec42d52db73021a13c012dd14cc07f3af135
--- /dev/null
+++ b/host/libs/virglrenderer/GLESv1.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "gles1_dec.h"
+
+struct GLESv1 : public gles1_decoder_context_t {
+    GLESv1();
+};
diff --git a/host/libs/virglrenderer/GLESv1_dec/gles1.addon b/host/libs/virglrenderer/GLESv1_dec/gles1.addon
new file mode 100644
index 0000000000000000000000000000000000000000..2331f878c7a532e0ce8b609b04eeee0fdf066803
--- /dev/null
+++ b/host/libs/virglrenderer/GLESv1_dec/gles1.addon
@@ -0,0 +1,15 @@
+GL_ENTRY(void, glVertexPointerOffset, GLint size, GLenum type, GLsizei stride,  GLuint offset)
+GL_ENTRY(void, glColorPointerOffset, GLint size, GLenum type, GLsizei stride,  GLuint offset)
+GL_ENTRY(void, glNormalPointerOffset, GLenum type, GLsizei stride,  GLuint offset)
+GL_ENTRY(void, glPointSizePointerOffset, GLenum type, GLsizei stride,  GLuint offset)
+GL_ENTRY(void, glTexCoordPointerOffset, GLint size, GLenum type, GLsizei stride,  GLuint offset)
+
+GL_ENTRY(void, glVertexPointerData, GLint size, GLenum type, GLsizei stride,  void * data, GLuint datalen)
+GL_ENTRY(void, glColorPointerData, GLint size, GLenum type, GLsizei stride,  void * data, GLuint datalen)
+GL_ENTRY(void, glNormalPointerData, GLenum type, GLsizei stride,  void * data, GLuint datalen)
+GL_ENTRY(void, glTexCoordPointerData, GLint size, GLenum type, GLsizei stride,  void * data, GLuint datalen)
+GL_ENTRY(void, glPointSizePointerData, GLenum type, GLsizei stride,  void * data, GLuint datalen)
+
+GL_ENTRY(void, glDrawElementsOffset, GLenum mode, GLsizei count, GLenum type, GLuint offset);
+GL_ENTRY(void, glDrawElementsData, GLenum mode, GLsizei count, GLenum type, void *data, GLuint datalen);
+
diff --git a/host/libs/virglrenderer/GLESv1_dec/gles1.attrib b/host/libs/virglrenderer/GLESv1_dec/gles1.attrib
new file mode 100644
index 0000000000000000000000000000000000000000..a1f1ee7695480d670f1bf7c1e08247138630d5d2
--- /dev/null
+++ b/host/libs/virglrenderer/GLESv1_dec/gles1.attrib
@@ -0,0 +1,444 @@
+GLOBAL
+    base_opcode 1024
+
+glClipPlanef
+    dir equation in
+    len equation (4 * sizeof(float))
+
+glGetFloatv
+    dir params out
+
+glGetLightfv
+    dir params out
+
+glGetMaterialfv
+    dir params out
+
+glGetTexEnvfv
+    dir params out
+
+glGetTexParameterfv
+    dir params out
+
+glLoadMatrixf
+    len m (16 * sizeof(GLfloat))
+
+glMultMatrixf
+    len m (16 * sizeof(GLfloat))
+
+glBufferData
+    len data size
+    var_flag data nullAllowed
+
+glBufferSubData
+    dir data in
+    len data size
+    var_flag data nullAllowed
+
+glClipPlanex
+    dir eqn in
+    len eqn (4 * sizeof(GLfixed))
+
+glColorPointer
+    len pointer (sizeof(unsigned int))
+    flag unsupported
+
+glCompressedTexImage2D
+    len data imageSize
+    var_flag data nullAllowed
+
+glCompressedTexSubImage2D
+    len data imageSize
+        var_flag data nullAllowed
+
+glDeleteBuffers
+    len buffers (n * sizeof(GLuint))
+    param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; }
+
+glDeleteTextures
+    len textures (n * sizeof(GLuint))
+    param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; }
+
+glDrawElements
+    flag unsupported
+
+glGetBooleanv
+    dir params out
+
+glGetBufferParameteriv
+    len params (sizeof(GLint))
+    dir params out
+
+glGenBuffers
+    len buffers (n * sizeof(GLuint))
+    dir buffers out
+    param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; }
+
+glGenTextures
+    len textures (n * sizeof(GLuint))
+    dir textures out
+    param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; }
+
+glGetFixedv
+    dir params out
+
+glGetIntegerv
+    dir params out
+
+glGetLightxv
+    dir params out
+
+glGetMaterialxv
+    dir params out
+
+glGetPointerv
+    flag unsupported
+
+glGetString
+    flag unsupported
+
+glGetTexEnviv
+    dir params out
+
+glGetTexEnvxv
+    dir params out
+
+glGetTexParameteriv
+    dir params out
+    len params (sizeof(GLint))
+
+glGetTexParameterxv
+    dir params out
+    len params (sizeof(GLfixed))
+
+glLoadMatrixx
+    len m (16 * sizeof(GLfixed))
+
+glMultMatrixx
+    len m (16 * sizeof(GLfixed))
+
+glNormalPointer
+    len pointer (sizeof(unsigned int))
+    flag unsupported
+
+glReadPixels
+    dir pixels out
+    len pixels glesv1_enc::pixelDataSize(self, width, height, format, type, 1)
+
+glTexCoordPointer
+    len pointer (sizeof(unsigned int))
+    flag unsupported
+
+glTexImage2D
+    dir pixels in
+    len pixels glesv1_enc::pixelDataSize(self, width, height, format, type, 0)
+    var_flag pixels nullAllowed isLarge
+
+glTexSubImage2D
+    len pixels glesv1_enc::pixelDataSize(self, width, height, format, type, 0)
+    var_flag pixels nullAllowed isLarge
+
+glVertexPointer
+    flag unsupported
+
+glPointSizePointerOES
+    len pointer (sizeof(unsigned int))
+    flag unsupported
+
+glGetClipPlanef
+    dir eqn out
+    len eqn (4 * sizeof(GLfloat))
+
+glVertexPointerData
+    len data datalen
+    flag not_api
+
+glColorPointerData
+    len data datalen
+    flag not_api
+
+glNormalPointerData
+    len data datalen
+    flag not_api
+
+glPointSizePointerData
+    len data datalen
+    flag not_api
+
+glTexCoordPointerData
+    len data datalen
+    flag not_api
+
+glWeightPointerData
+    len data datalen
+    flag not_api
+
+glMatrixIndexPointerData
+    len data datalen
+    flag not_api
+
+glVertexPointerOffset
+    flag not_api
+
+glNormalPointerOffset
+    flag not_api
+
+glTexCoordPointerOffset
+    flag not_api
+
+glPointSizePointerOffset
+    flag not_api
+
+glColorPointerOffset
+    flag not_api
+
+glWeightPointerOffset
+    flag not_api
+
+glMatrixIndexPointerOffset
+    flag not_api
+
+glDrawElementsData
+    len data datalen
+    flag not_api
+
+glDrawElementsOffset
+    flag not_api
+
+glGetCompressedTextureFormats
+    dir formats out
+    len formats (count * sizeof(GLint))
+    flag not_api
+
+glFinishRoundTrip
+    flag not_api
+
+glDrawTexsvOES
+    len coords (5 * sizeof(GLshort))
+
+glDrawTexivOES
+    len coords (5 * sizeof(GLint))
+
+glDrawTexxvOES
+    len coords (5 * sizeof(GLfixed))
+
+glDrawTexfvOES
+    len coords (5 * sizeof(GLfloat))
+
+glClipPlanexOES
+    dir equation in
+    len equation (4 * sizeof(GLfixed))
+
+glClipPlanexIMG
+    dir equation in
+    len equation (4 * sizeof(GLfixed))
+
+glFogxvOES
+    dir params in
+
+glGetClipPlanexOES
+    dir eqn out
+    len eqn (4 * sizeof(GLfixed))
+
+glGetClipPlanex
+    dir eqn out
+    len eqn (4 * sizeof(GLfixed))
+
+glGetFixedvOES
+    dir params out
+
+glGetLightxvOES
+    dir params out
+
+glGetMaterialxvOES
+    dir params out
+
+glGetTexEnvxvOES
+    dir params out
+
+glGetTexParameterxvOES
+    dir params out
+
+glLightModelxvOES
+    dir params in
+
+glLightxvOES
+    dir params in
+
+glLoadMatrixxOES
+    dir m in
+    len m (16 * sizeof(GLfixed))
+
+glMaterialxvOES
+    dir params in
+
+glMultMatrixxOES
+    dir m in
+    len m (16 * sizeof(GLfixed))
+
+glPointParameterxvOES
+    dir params in
+
+glTexEnvxvOES
+    dir params in
+
+glTexParameterxvOES
+    dir params in
+
+glDeleteRenderbuffersOES
+    dir renderbuffers in
+    len renderbuffers (n * sizeof(GLuint))
+    param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; }
+
+glGenRenderbuffersOES
+    dir renderbuffers out
+    len renderbuffers (n * sizeof(GLuint))
+    param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; }
+
+glGetRenderbufferParameterivOES
+    dir params out
+
+glDeleteFramebuffersOES
+    dir framebuffers in
+    len framebuffers (n * sizeof(GLuint))
+    param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; }
+
+glGenFramebuffersOES
+    dir framebuffers out
+    len framebuffers (n * sizeof(GLuint))
+    param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; }
+
+glGetFramebufferAttachmentParameterivOES
+    dir params out
+
+glMapBufferOES
+    flag unsupported
+
+glGetBufferPointervOES
+    flag unsupported
+
+glMatrixIndexPointerOES
+    len pointer (sizeof(unsigned int))
+    flag unsupported
+
+glWeightPointerOES
+    len pointer (sizeof(unsigned int))
+    flag unsupported
+
+glQueryMatrixxOES
+    dir mantissa out
+    len mantissa (16 * sizeof(GLfixed))
+    dir exponent out
+    len exponent (16 * sizeof(GLfixed))
+
+glClipPlanefOES
+    dir equation in
+    len equation (4 * sizeof(GLfloat))
+
+glClipPlanefIMG
+    dir equation in
+    len equation (4 * sizeof(GLfloat))
+
+glGetClipPlanefOES
+    dir eqn out
+    len eqn (4 * sizeof(GLfloat))
+
+glDeleteVertexArraysOES
+    dir arrays in
+    len arrays (n * sizeof(GLuint))
+    param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; }
+
+glGenVertexArraysOES
+    dir arrays out
+    len arrays (n * sizeof(GLuint))
+    param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; }
+
+glDiscardFramebufferEXT
+    dir attachments in
+    len attachments (numAttachments * sizeof(const GLenum))
+
+glMultiDrawArraysEXT
+    flag unsupported
+
+glMultiDrawElementsEXT
+    flag unsupported
+
+glMultiDrawArraysSUN
+    flag unsupported
+
+glMultiDrawElementsSUN
+    flag unsupported
+
+glDeleteFencesNV
+    dir fences in
+    len fences (n * sizeof(GLuint))
+    param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; }
+
+glGenFencesNV
+    dir fences in
+    len fences (n * sizeof(GLuint))
+    param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; }
+
+glGetFenceivNV
+    dir params out
+
+glGetDriverControlsQCOM
+    dir num out
+    len num (1 * sizeof(GLint))
+    dir driverControls out
+    len driverControls (size * sizeof(GLuint))
+
+glGetDriverControlStringQCOM
+    dir length out
+    len length (1 * sizeof(GLsizei))
+    dir driverControlString out
+    len driverControlString (1 * sizeof(GLchar))
+
+glExtGetTexturesQCOM
+    dir textures out
+    len textures (maxTextures * sizeof(GLuint))
+    dir numTextures out
+    len numTextures (1 * sizeof(GLint))
+
+glExtGetBuffersQCOM
+    dir buffers out
+    len buffers (maxBuffers * sizeof(GLuint))
+    dir numBuffers out
+    len numBuffers (1 * sizeof(GLint))
+
+glExtGetRenderbuffersQCOM
+    dir renderbuffers out
+    len renderbuffers (maxRenderbuffers * sizeof(GLuint))
+    dir numRenderbuffers out
+    len numRenderbuffers (1 * sizeof(GLint))
+
+glExtGetFramebuffersQCOM
+    dir framebuffers out
+    len framebuffers (maxFramebuffers * sizeof(GLuint))
+    dir numFramebuffers out
+    len numFramebuffers (1 * sizeof(GLint))
+
+glExtGetTexLevelParameterivQCOM
+    dir params out
+
+glExtGetTexSubImageQCOM
+    dir texels out
+    len texels (depth * glesv1_enc::pixelDataSize(self, width, height, format, type, 0))
+
+glExtGetBufferPointervQCOM
+    flag unsupported
+
+glExtGetShadersQCOM
+    dir shaders out
+    len shaders (maxShaders * sizeof(GLuint))
+    dir numShaders out
+    len numShaders (1 * sizeof(GLint))
+
+glExtGetProgramsQCOM
+    dir programs out
+    len programs (maxPrograms * sizeof(GLuint))
+    dir numPrograms out
+    len numPrograms (1 * sizeof(GLint))
+
+glExtGetProgramBinarySourceQCOM
+    flag unsupported
diff --git a/host/libs/virglrenderer/GLESv1_dec/gles1.in b/host/libs/virglrenderer/GLESv1_dec/gles1.in
new file mode 100644
index 0000000000000000000000000000000000000000..74d5454d38b77913d5238fef56957eabc89ebebe
--- /dev/null
+++ b/host/libs/virglrenderer/GLESv1_dec/gles1.in
@@ -0,0 +1,298 @@
+GL_ENTRY(void, glAlphaFunc, GLenum func, GLclampf ref)
+GL_ENTRY(void, glClearColor, GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
+GL_ENTRY(void, glClearDepthf, GLclampf depth)
+GL_ENTRY(void, glClipPlanef, GLenum plane, const GLfloat *equation)
+GL_ENTRY(void, glColor4f, GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
+GL_ENTRY(void, glDepthRangef, GLclampf zNear, GLclampf zFar)
+GL_ENTRY(void, glFogf, GLenum pname, GLfloat param)
+GL_ENTRY(void, glFogfv, GLenum pname, const GLfloat *params)
+GL_ENTRY(void, glFrustumf, GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar)
+GL_ENTRY(void, glGetClipPlanef, GLenum pname, GLfloat* eqn)
+GL_ENTRY(void, glGetFloatv, GLenum pname, GLfloat *params)
+GL_ENTRY(void, glGetLightfv, GLenum light, GLenum pname, GLfloat *params)
+GL_ENTRY(void, glGetMaterialfv, GLenum face, GLenum pname, GLfloat *params)
+GL_ENTRY(void, glGetTexEnvfv, GLenum env, GLenum pname, GLfloat *params)
+GL_ENTRY(void, glGetTexParameterfv, GLenum target, GLenum pname, GLfloat *params)
+GL_ENTRY(void, glLightModelf, GLenum pname, GLfloat param)
+GL_ENTRY(void, glLightModelfv, GLenum pname, const GLfloat *params)
+GL_ENTRY(void, glLightf, GLenum light, GLenum pname, GLfloat param)
+GL_ENTRY(void, glLightfv, GLenum light, GLenum pname, const GLfloat *params)
+GL_ENTRY(void, glLineWidth, GLfloat width)
+GL_ENTRY(void, glLoadMatrixf, const GLfloat *m)
+GL_ENTRY(void, glMaterialf, GLenum face, GLenum pname, GLfloat param)
+GL_ENTRY(void, glMaterialfv, GLenum face, GLenum pname, const GLfloat *params)
+GL_ENTRY(void, glMultMatrixf, const GLfloat *m)
+GL_ENTRY(void, glMultiTexCoord4f, GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q)
+GL_ENTRY(void, glNormal3f, GLfloat nx, GLfloat ny, GLfloat nz)
+GL_ENTRY(void, glOrthof, GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar)
+GL_ENTRY(void, glPointParameterf, GLenum pname, GLfloat param)
+GL_ENTRY(void, glPointParameterfv, GLenum pname, const GLfloat *params)
+GL_ENTRY(void, glPointSize, GLfloat size)
+GL_ENTRY(void, glPolygonOffset, GLfloat factor, GLfloat units)
+GL_ENTRY(void, glRotatef, GLfloat angle, GLfloat x, GLfloat y, GLfloat z)
+GL_ENTRY(void, glScalef, GLfloat x, GLfloat y, GLfloat z)
+GL_ENTRY(void, glTexEnvf, GLenum target, GLenum pname, GLfloat param)
+GL_ENTRY(void, glTexEnvfv, GLenum target, GLenum pname, const GLfloat *params)
+GL_ENTRY(void, glTexParameterf, GLenum target, GLenum pname, GLfloat param)
+GL_ENTRY(void, glTexParameterfv, GLenum target, GLenum pname, const GLfloat *params)
+GL_ENTRY(void, glTranslatef, GLfloat x, GLfloat y, GLfloat z)
+GL_ENTRY(void, glActiveTexture, GLenum texture)
+GL_ENTRY(void, glAlphaFuncx, GLenum func, GLclampx ref)
+GL_ENTRY(void, glBindBuffer, GLenum target, GLuint buffer)
+GL_ENTRY(void, glBindTexture, GLenum target, GLuint texture)
+GL_ENTRY(void, glBlendFunc, GLenum sfactor, GLenum dfactor)
+GL_ENTRY(void, glBufferData, GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage)
+GL_ENTRY(void, glBufferSubData, GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data)
+GL_ENTRY(void, glClear, GLbitfield mask)
+GL_ENTRY(void, glClearColorx, GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha)
+GL_ENTRY(void, glClearDepthx, GLclampx depth)
+GL_ENTRY(void, glClearStencil, GLint s)
+GL_ENTRY(void, glClientActiveTexture, GLenum texture)
+GL_ENTRY(void, glColor4ub, GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha)
+GL_ENTRY(void, glColor4x, GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha)
+GL_ENTRY(void, glColorMask, GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)
+GL_ENTRY(void, glColorPointer, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
+GL_ENTRY(void, glCompressedTexImage2D, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data)
+GL_ENTRY(void, glCompressedTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data)
+GL_ENTRY(void, glCopyTexImage2D, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
+GL_ENTRY(void, glCopyTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)
+GL_ENTRY(void, glCullFace, GLenum mode)
+GL_ENTRY(void, glDeleteBuffers, GLsizei n, const GLuint *buffers)
+GL_ENTRY(void, glDeleteTextures, GLsizei n, const GLuint *textures)
+GL_ENTRY(void, glDepthFunc, GLenum func)
+GL_ENTRY(void, glDepthMask, GLboolean flag)
+GL_ENTRY(void, glDepthRangex, GLclampx zNear, GLclampx zFar)
+GL_ENTRY(void, glDisable, GLenum cap)
+GL_ENTRY(void, glDisableClientState, GLenum array)
+GL_ENTRY(void, glDrawArrays, GLenum mode, GLint first, GLsizei count)
+GL_ENTRY(void, glDrawElements, GLenum mode, GLsizei count, GLenum type, const GLvoid *indices)
+GL_ENTRY(void, glEnable, GLenum cap)
+GL_ENTRY(void, glEnableClientState, GLenum array)
+GL_ENTRY(void, glFinish, void)
+GL_ENTRY(void, glFlush, void)
+GL_ENTRY(void, glFogx, GLenum pname, GLfixed param)
+GL_ENTRY(void, glFogxv, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glFrontFace, GLenum mode)
+GL_ENTRY(void, glFrustumx, GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar)
+GL_ENTRY(void, glGetBooleanv, GLenum pname, GLboolean *params)
+GL_ENTRY(void, glGetBufferParameteriv, GLenum target, GLenum pname, GLint *params)
+GL_ENTRY(void, glClipPlanex, GLenum pname, const GLfixed * eqn)
+GL_ENTRY(void, glGenBuffers, GLsizei n, GLuint *buffers)
+GL_ENTRY(void, glGenTextures, GLsizei n, GLuint *textures)
+GL_ENTRY(GLenum, glGetError, void)
+GL_ENTRY(void, glGetFixedv, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetIntegerv, GLenum pname, GLint *params)
+GL_ENTRY(void, glGetLightxv, GLenum light, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetMaterialxv, GLenum face, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetPointerv, GLenum pname, GLvoid **params)
+GL_ENTRY(const GLubyte *, glGetString, GLenum name)
+GL_ENTRY(void, glGetTexEnviv, GLenum env, GLenum pname, GLint *params)
+GL_ENTRY(void, glGetTexEnvxv, GLenum env, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetTexParameteriv, GLenum target, GLenum pname, GLint *params)
+GL_ENTRY(void, glGetTexParameterxv, GLenum target, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glHint, GLenum target, GLenum mode)
+GL_ENTRY(GLboolean, glIsBuffer, GLuint buffer)
+GL_ENTRY(GLboolean, glIsEnabled, GLenum cap)
+GL_ENTRY(GLboolean, glIsTexture, GLuint texture)
+GL_ENTRY(void, glLightModelx, GLenum pname, GLfixed param)
+GL_ENTRY(void, glLightModelxv, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glLightx, GLenum light, GLenum pname, GLfixed param)
+GL_ENTRY(void, glLightxv, GLenum light, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glLineWidthx, GLfixed width)
+GL_ENTRY(void, glLoadIdentity, void)
+GL_ENTRY(void, glLoadMatrixx, const GLfixed *m)
+GL_ENTRY(void, glLogicOp, GLenum opcode)
+GL_ENTRY(void, glMaterialx, GLenum face, GLenum pname, GLfixed param)
+GL_ENTRY(void, glMaterialxv, GLenum face, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glMatrixMode, GLenum mode)
+GL_ENTRY(void, glMultMatrixx, const GLfixed *m)
+GL_ENTRY(void, glMultiTexCoord4x, GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q)
+GL_ENTRY(void, glNormal3x, GLfixed nx, GLfixed ny, GLfixed nz)
+GL_ENTRY(void, glNormalPointer, GLenum type, GLsizei stride, const GLvoid *pointer)
+GL_ENTRY(void, glOrthox, GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar)
+GL_ENTRY(void, glPixelStorei, GLenum pname, GLint param)
+GL_ENTRY(void, glPointParameterx, GLenum pname, GLfixed param)
+GL_ENTRY(void, glPointParameterxv, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glPointSizex, GLfixed size)
+GL_ENTRY(void, glPolygonOffsetx, GLfixed factor, GLfixed units)
+GL_ENTRY(void, glPopMatrix, void)
+GL_ENTRY(void, glPushMatrix, void)
+GL_ENTRY(void, glReadPixels, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels)
+GL_ENTRY(void, glRotatex, GLfixed angle, GLfixed x, GLfixed y, GLfixed z)
+GL_ENTRY(void, glSampleCoverage, GLclampf value, GLboolean invert)
+GL_ENTRY(void, glSampleCoveragex, GLclampx value, GLboolean invert)
+GL_ENTRY(void, glScalex, GLfixed x, GLfixed y, GLfixed z)
+GL_ENTRY(void, glScissor, GLint x, GLint y, GLsizei width, GLsizei height)
+GL_ENTRY(void, glShadeModel, GLenum mode)
+GL_ENTRY(void, glStencilFunc, GLenum func, GLint ref, GLuint mask)
+GL_ENTRY(void, glStencilMask, GLuint mask)
+GL_ENTRY(void, glStencilOp, GLenum fail, GLenum zfail, GLenum zpass)
+GL_ENTRY(void, glTexCoordPointer, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
+GL_ENTRY(void, glTexEnvi, GLenum target, GLenum pname, GLint param)
+GL_ENTRY(void, glTexEnvx, GLenum target, GLenum pname, GLfixed param)
+GL_ENTRY(void, glTexEnviv, GLenum target, GLenum pname, const GLint *params)
+GL_ENTRY(void, glTexEnvxv, GLenum target, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glTexImage2D, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels)
+GL_ENTRY(void, glTexParameteri, GLenum target, GLenum pname, GLint param)
+GL_ENTRY(void, glTexParameterx, GLenum target, GLenum pname, GLfixed param)
+GL_ENTRY(void, glTexParameteriv, GLenum target, GLenum pname, const GLint *params)
+GL_ENTRY(void, glTexParameterxv, GLenum target, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels)
+GL_ENTRY(void, glTranslatex, GLfixed x, GLfixed y, GLfixed z)
+GL_ENTRY(void, glVertexPointer, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
+GL_ENTRY(void, glViewport, GLint x, GLint y, GLsizei width, GLsizei height)
+GL_ENTRY(void, glPointSizePointerOES, GLenum type, GLsizei stride, const GLvoid *pointer)
+
+GL_ENTRY(void, glVertexPointerOffset, GLint size, GLenum type, GLsizei stride,  GLuint offset)
+GL_ENTRY(void, glColorPointerOffset, GLint size, GLenum type, GLsizei stride,  GLuint offset)
+GL_ENTRY(void, glNormalPointerOffset, GLenum type, GLsizei stride,  GLuint offset)
+GL_ENTRY(void, glPointSizePointerOffset, GLenum type, GLsizei stride,  GLuint offset)
+GL_ENTRY(void, glTexCoordPointerOffset, GLint size, GLenum type, GLsizei stride,  GLuint offset)
+GL_ENTRY(void, glWeightPointerOffset, GLint size, GLenum type, GLsizei stride,  GLuint offset)
+GL_ENTRY(void, glMatrixIndexPointerOffset, GLint size, GLenum type, GLsizei stride,  GLuint offset)
+
+GL_ENTRY(void, glVertexPointerData, GLint size, GLenum type, GLsizei stride,  void * data, GLuint datalen)
+GL_ENTRY(void, glColorPointerData, GLint size, GLenum type, GLsizei stride,  void * data, GLuint datalen)
+GL_ENTRY(void, glNormalPointerData, GLenum type, GLsizei stride,  void * data, GLuint datalen)
+GL_ENTRY(void, glTexCoordPointerData, GLint unit, GLint size, GLenum type, GLsizei stride,  void * data, GLuint datalen)
+GL_ENTRY(void, glPointSizePointerData, GLenum type, GLsizei stride,  void * data, GLuint datalen)
+GL_ENTRY(void, glWeightPointerData, GLint size, GLenum type, GLsizei stride,  void * data, GLuint datalen)
+GL_ENTRY(void, glMatrixIndexPointerData, GLint size, GLenum type, GLsizei stride,  void * data, GLuint datalen)
+
+GL_ENTRY(void, glDrawElementsOffset, GLenum mode, GLsizei count, GLenum type, GLuint offset)
+GL_ENTRY(void, glDrawElementsData, GLenum mode, GLsizei count, GLenum type, void *data, GLuint datalen)
+GL_ENTRY(void, glGetCompressedTextureFormats, int count, GLint *formats);
+
+GL_ENTRY(int, glFinishRoundTrip, void)
+
+#opengl extensions
+
+GL_ENTRY(void, glBlendEquationSeparateOES, GLenum modeRGB, GLenum modeAlpha)
+GL_ENTRY(void, glBlendFuncSeparateOES, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)
+GL_ENTRY(void, glBlendEquationOES, GLenum mode)
+GL_ENTRY(void, glDrawTexsOES, GLshort x, GLshort y, GLshort z, GLshort width, GLshort height)
+GL_ENTRY(void, glDrawTexiOES, GLint x, GLint y, GLint z, GLint width, GLint height)
+GL_ENTRY(void, glDrawTexxOES, GLfixed x, GLfixed y, GLfixed z, GLfixed width, GLfixed height)
+GL_ENTRY(void, glDrawTexsvOES, const GLshort *coords)
+GL_ENTRY(void, glDrawTexivOES, const GLint *coords)
+GL_ENTRY(void, glDrawTexxvOES, const GLfixed *coords)
+GL_ENTRY(void, glDrawTexfOES, GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height)
+GL_ENTRY(void, glDrawTexfvOES, const GLfloat *coords)
+GL_ENTRY(void, glEGLImageTargetTexture2DOES, GLenum target, GLeglImageOES image)
+GL_ENTRY(void, glEGLImageTargetRenderbufferStorageOES, GLenum target, GLeglImageOES image)
+GL_ENTRY(void, glAlphaFuncxOES, GLenum func, GLclampx ref)
+GL_ENTRY(void, glClearColorxOES, GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha)
+GL_ENTRY(void, glClearDepthxOES, GLclampx depth)
+GL_ENTRY(void, glClipPlanexOES, GLenum plane, const GLfixed * equation)
+GL_ENTRY(void, glClipPlanexIMG, GLenum plane, const GLfixed * equation)
+GL_ENTRY(void, glColor4xOES, GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha)
+GL_ENTRY(void, glDepthRangexOES, GLclampx zNear, GLclampx zFar)
+GL_ENTRY(void, glFogxOES, GLenum pname, GLfixed param)
+GL_ENTRY(void, glFogxvOES, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glFrustumxOES, GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar)
+GL_ENTRY(void, glGetClipPlanexOES, GLenum pname, GLfixed* eqn)
+GL_ENTRY(void, glGetClipPlanex, GLenum pname, GLfixed* eqn)
+GL_ENTRY(void, glGetFixedvOES, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetLightxvOES, GLenum light, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetMaterialxvOES, GLenum face, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetTexEnvxvOES, GLenum env, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetTexParameterxvOES, GLenum target, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glLightModelxOES, GLenum pname, GLfixed param)
+GL_ENTRY(void, glLightModelxvOES, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glLightxOES, GLenum light, GLenum pname, GLfixed param)
+GL_ENTRY(void, glLightxvOES, GLenum light, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glLineWidthxOES, GLfixed width)
+GL_ENTRY(void, glLoadMatrixxOES, const GLfixed *m)
+GL_ENTRY(void, glMaterialxOES, GLenum face, GLenum pname, GLfixed param)
+GL_ENTRY(void, glMaterialxvOES, GLenum face, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glMultMatrixxOES, const GLfixed *m)
+GL_ENTRY(void, glMultiTexCoord4xOES, GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q)
+GL_ENTRY(void, glNormal3xOES, GLfixed nx, GLfixed ny, GLfixed nz)
+GL_ENTRY(void, glOrthoxOES, GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar)
+GL_ENTRY(void, glPointParameterxOES, GLenum pname, GLfixed param)
+GL_ENTRY(void, glPointParameterxvOES, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glPointSizexOES, GLfixed size)
+GL_ENTRY(void, glPolygonOffsetxOES, GLfixed factor, GLfixed units)
+GL_ENTRY(void, glRotatexOES, GLfixed angle, GLfixed x, GLfixed y, GLfixed z)
+GL_ENTRY(void, glSampleCoveragexOES, GLclampx value, GLboolean invert)
+GL_ENTRY(void, glScalexOES, GLfixed x, GLfixed y, GLfixed z)
+GL_ENTRY(void, glTexEnvxOES, GLenum target, GLenum pname, GLfixed param)
+GL_ENTRY(void, glTexEnvxvOES, GLenum target, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glTexParameterxOES, GLenum target, GLenum pname, GLfixed param)
+GL_ENTRY(void, glTexParameterxvOES, GLenum target, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glTranslatexOES, GLfixed x, GLfixed y, GLfixed z)
+GL_ENTRY(GLboolean, glIsRenderbufferOES, GLuint renderbuffer)
+GL_ENTRY(void, glBindRenderbufferOES, GLenum target, GLuint renderbuffer)
+GL_ENTRY(void, glDeleteRenderbuffersOES, GLsizei n, const GLuint* renderbuffers)
+GL_ENTRY(void, glGenRenderbuffersOES, GLsizei n, GLuint* renderbuffers)
+GL_ENTRY(void, glRenderbufferStorageOES, GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
+GL_ENTRY(void, glGetRenderbufferParameterivOES, GLenum target, GLenum pname, GLint* params)
+GL_ENTRY(GLboolean, glIsFramebufferOES, GLuint framebuffer)
+GL_ENTRY(void, glBindFramebufferOES, GLenum target, GLuint framebuffer)
+GL_ENTRY(void, glDeleteFramebuffersOES, GLsizei n, const GLuint* framebuffers)
+GL_ENTRY(void, glGenFramebuffersOES, GLsizei n, GLuint* framebuffers)
+GL_ENTRY(GLenum, glCheckFramebufferStatusOES, GLenum target)
+GL_ENTRY(void, glFramebufferRenderbufferOES, GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
+GL_ENTRY(void, glFramebufferTexture2DOES, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
+GL_ENTRY(void, glGetFramebufferAttachmentParameterivOES, GLenum target, GLenum attachment, GLenum pname, GLint* params)
+GL_ENTRY(void, glGenerateMipmapOES, GLenum target)
+GL_ENTRY(void*, glMapBufferOES, GLenum target, GLenum access)
+GL_ENTRY(GLboolean, glUnmapBufferOES, GLenum target)
+GL_ENTRY(void, glGetBufferPointervOES, GLenum target, GLenum pname, GLvoid* *params)
+GL_ENTRY(void, glCurrentPaletteMatrixOES, GLuint matrixpaletteindex)
+GL_ENTRY(void, glLoadPaletteFromModelViewMatrixOES, void)
+GL_ENTRY(void, glMatrixIndexPointerOES, GLint size, GLenum type, GLsizei stride, const GLvoid * pointer)
+GL_ENTRY(void, glWeightPointerOES, GLint size, GLenum type, GLsizei stride, const GLvoid * pointer)
+GL_ENTRY(GLbitfield, glQueryMatrixxOES, GLfixed * mantissa, GLint * exponent)
+GL_ENTRY(void, glDepthRangefOES, GLclampf zNear, GLclampf zFar)
+GL_ENTRY(void, glFrustumfOES, GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar)
+GL_ENTRY(void, glOrthofOES, GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar)
+GL_ENTRY(void, glClipPlanefOES, GLenum plane, const GLfloat *equation)
+GL_ENTRY(void, glClipPlanefIMG, GLenum plane, const GLfloat *equation)
+GL_ENTRY(void, glGetClipPlanefOES, GLenum pname, GLfloat * eqn)
+GL_ENTRY(void, glClearDepthfOES, GLclampf depth)
+GL_ENTRY(void, glTexGenfOES, GLenum coord, GLenum pname, GLfloat param)
+GL_ENTRY(void, glTexGenfvOES, GLenum coord, GLenum pname, const GLfloat *params)
+GL_ENTRY(void, glTexGeniOES, GLenum coord, GLenum pname, GLint param)
+GL_ENTRY(void, glTexGenivOES, GLenum coord, GLenum pname, const GLint *params)
+GL_ENTRY(void, glTexGenxOES, GLenum coord, GLenum pname, GLfixed param)
+GL_ENTRY(void, glTexGenxvOES, GLenum coord, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glGetTexGenfvOES, GLenum coord, GLenum pname, GLfloat *params)
+GL_ENTRY(void, glGetTexGenivOES, GLenum coord, GLenum pname, GLint *params)
+GL_ENTRY(void, glGetTexGenxvOES, GLenum coord, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glBindVertexArrayOES, GLuint array)
+GL_ENTRY(void, glDeleteVertexArraysOES, GLsizei n, const GLuint *arrays)
+GL_ENTRY(void, glGenVertexArraysOES, GLsizei n, GLuint *arrays)
+GL_ENTRY(GLboolean, glIsVertexArrayOES, GLuint array)
+GL_ENTRY(void, glDiscardFramebufferEXT, GLenum target, GLsizei numAttachments, const GLenum *attachments)
+GL_ENTRY(void, glMultiDrawArraysEXT, GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount)
+GL_ENTRY(void, glMultiDrawElementsEXT, GLenum mode, const GLsizei *count, GLenum type, const GLvoid*const *indices, GLsizei primcount)
+GL_ENTRY(void, glMultiDrawArraysSUN, GLenum mode, GLint *first, GLsizei *count, GLsizei primcount)
+GL_ENTRY(void, glMultiDrawElementsSUN, GLenum mode, const GLsizei *count, GLenum type, const GLvoid **indices, GLsizei primcount)
+GL_ENTRY(void, glRenderbufferStorageMultisampleIMG, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height)
+GL_ENTRY(void, glFramebufferTexture2DMultisampleIMG, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples)
+GL_ENTRY(void, glDeleteFencesNV, GLsizei n, const GLuint *fences)
+GL_ENTRY(void, glGenFencesNV, GLsizei n, GLuint *fences)
+GL_ENTRY(GLboolean, glIsFenceNV, GLuint fence)
+GL_ENTRY(GLboolean, glTestFenceNV, GLuint fence)
+GL_ENTRY(void, glGetFenceivNV, GLuint fence, GLenum pname, GLint *params)
+GL_ENTRY(void, glFinishFenceNV, GLuint fence)
+GL_ENTRY(void, glSetFenceNV, GLuint fence, GLenum condition)
+GL_ENTRY(void, glGetDriverControlsQCOM, GLint *num, GLsizei size, GLuint *driverControls)
+GL_ENTRY(void, glGetDriverControlStringQCOM, GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString)
+GL_ENTRY(void, glEnableDriverControlQCOM, GLuint driverControl)
+GL_ENTRY(void, glDisableDriverControlQCOM, GLuint driverControl)
+GL_ENTRY(void, glExtGetTexturesQCOM, GLuint *textures, GLint maxTextures, GLint *numTextures)
+GL_ENTRY(void, glExtGetBuffersQCOM, GLuint *buffers, GLint maxBuffers, GLint *numBuffers)
+GL_ENTRY(void, glExtGetRenderbuffersQCOM, GLuint * renderbuffers, GLint maxRenderbuffers, GLint * numRenderbuffers)
+GL_ENTRY(void, glExtGetFramebuffersQCOM, GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers)
+GL_ENTRY(void, glExtGetTexLevelParameterivQCOM, GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params)
+GL_ENTRY(void, glExtTexObjectStateOverrideiQCOM, GLenum target, GLenum pname, GLint param)
+GL_ENTRY(void, glExtGetTexSubImageQCOM, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLvoid *texels)
+GL_ENTRY(void, glExtGetBufferPointervQCOM, GLenum target, GLvoid* *params)
+GL_ENTRY(void, glExtGetShadersQCOM, GLuint *shaders, GLint maxShaders, GLint *numShaders)
+GL_ENTRY(void, glExtGetProgramsQCOM, GLuint *programs, GLint maxPrograms, GLint *numPrograms)
+GL_ENTRY(GLboolean, glExtIsProgramBinaryQCOM, GLuint program)
+GL_ENTRY(void, glExtGetProgramBinarySourceQCOM, GLuint program, GLenum shadertype, GLchar *source, GLint *length)
+GL_ENTRY(void, glStartTilingQCOM, GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask)
+GL_ENTRY(void, glEndTilingQCOM, GLbitfield preserveMask)
diff --git a/host/libs/virglrenderer/GLESv1_dec/gles1.types b/host/libs/virglrenderer/GLESv1_dec/gles1.types
new file mode 100644
index 0000000000000000000000000000000000000000..05be29e5e4f9f9f54abbaf9ea593b22a7b09cfa5
--- /dev/null
+++ b/host/libs/virglrenderer/GLESv1_dec/gles1.types
@@ -0,0 +1,34 @@
+GLbitfield 32 0x%08x
+GLboolean 8 %d
+GLclampf 32 %f
+GLclampx 32 0x%08x
+GLeglImageOES 32 %p
+GLenum 32 0x%08x
+GLfixed 32 0x%08x
+GLfloat 32 %f
+GLint 32 %d
+GLintptr 32 0x%08lx
+GLshort 16 %d
+GLsizei 32 %d
+GLsizeiptr 32 0x%08lx
+GLubyte 8 0x%02x
+GLuint 32 %u
+GLvoid 0 %x
+GLchar 8 %d
+GLenum* 32 0x%08x
+GLboolean* 32 0x%08x
+GLclampf* 32 0x%08x
+GLclampx* 32 0x%08x
+GLeglImageOES* 32 0x%08x
+GLfixed* 32 0x%08x
+GLfloat* 32 0x%08x
+GLint* 32 0x%08x
+GLshort* 32 0x%08x
+GLsizei* 32 0x%08x
+GLubyte* 32 0x%08x
+GLuint* 32 0x%08x
+GLvoid* 32 0x%08x
+GLchar* 32 0x%08x
+GLvoid** 32 0x%08x
+void* 32 0x%08x
+GLvoid*const* 32 0x%08x
diff --git a/host/libs/virglrenderer/GLESv1_dec/gles1_types.h b/host/libs/virglrenderer/GLESv1_dec/gles1_types.h
new file mode 100644
index 0000000000000000000000000000000000000000..097e03f71086e527caa16c6bea45bf4b9380a76f
--- /dev/null
+++ b/host/libs/virglrenderer/GLESv1_dec/gles1_types.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
diff --git a/host/libs/virglrenderer/GLESv3.cpp b/host/libs/virglrenderer/GLESv3.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..dd2707d17c213f6b674517c2eba7c7ee690ea832
--- /dev/null
+++ b/host/libs/virglrenderer/GLESv3.cpp
@@ -0,0 +1,642 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <OpenGLESDispatch/GLESv3Dispatch.h>
+
+#include "GLESv3.h"
+
+#include <string>
+#include <vector>
+
+// Stubs (common)
+
+static void glDeleteFencesNV(GLsizei, const GLuint*) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glDisableDriverControlQCOM(GLuint) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glDiscardFramebufferEXT(GLenum, GLsizei, const GLenum*) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glEnableDriverControlQCOM(GLuint) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glEndTilingQCOM(GLbitfield) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glExtGetBufferPointervQCOM(GLenum, GLvoid**) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glExtGetBuffersQCOM(GLuint*, GLint, GLint*) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glExtGetFramebuffersQCOM(GLuint*, GLint, GLint*) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glExtGetProgramBinarySourceQCOM(GLuint, GLenum, GLchar*, GLint*) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glExtGetProgramsQCOM(GLuint*, GLint, GLint*) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glExtGetRenderbuffersQCOM(GLuint*, GLint, GLint*) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glExtGetShadersQCOM(GLuint*, GLint, GLint*) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glExtGetTexLevelParameterivQCOM(GLuint, GLenum, GLint, GLenum, GLint*) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glExtGetTexSubImageQCOM(GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei,
+                                    GLenum, GLenum, GLvoid*) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glExtGetTexturesQCOM(GLuint*, GLint, GLint*) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static GLboolean glExtIsProgramBinaryQCOM(GLuint) {
+    printf("%s: not implemented\n", __func__);
+    return GL_FALSE;
+}
+
+static void glExtTexObjectStateOverrideiQCOM(GLenum, GLenum, GLint) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glFinishFenceNV(GLuint) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glFramebufferTexture2DMultisampleIMG(GLenum, GLenum, GLenum, GLuint, GLint, GLsizei) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glGenFencesNV(GLsizei, GLuint*) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glGetDriverControlsQCOM(GLint*, GLsizei, GLuint*) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glGetDriverControlStringQCOM(GLuint, GLsizei, GLsizei*, GLchar*) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glGetFenceivNV(GLuint, GLenum, GLint*) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static GLboolean glIsFenceNV(GLuint) {
+    printf("%s: not implemented\n", __func__);
+    return GL_FALSE;
+}
+
+static void* glMapBufferOES(GLenum, GLenum) {
+    printf("%s: not implemented\n", __func__);
+    return nullptr;
+}
+
+static void glMultiDrawArraysEXT(GLenum, const GLint*, const GLsizei*, GLsizei) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glMultiDrawElementsEXT(GLenum, const GLsizei*, GLenum, const GLvoid* const*, GLsizei) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glRenderbufferStorageMultisampleIMG(GLenum, GLsizei, GLenum, GLsizei, GLsizei) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glSetFenceNV(GLuint, GLenum) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glStartTilingQCOM(GLuint, GLuint, GLuint, GLuint, GLbitfield) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static GLboolean glTestFenceNV(GLuint) {
+    printf("%s: not implemented\n", __func__);
+    return GL_FALSE;
+}
+
+// Stubs (ES 3.1)
+
+static void glBeginPerfMonitorAMD(GLuint) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glCoverageMaskNV(GLboolean) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glCoverageOperationNV(GLenum) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glDeletePerfMonitorsAMD(GLsizei, GLuint*) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glEndPerfMonitorAMD(GLuint) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glGenPerfMonitorsAMD(GLsizei, GLuint*) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glGetPerfMonitorCounterDataAMD(GLuint, GLenum, GLsizei, GLuint*, GLint*) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glGetPerfMonitorCounterInfoAMD(GLuint, GLuint, GLenum, GLvoid*) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glGetPerfMonitorCountersAMD(GLuint, GLint*, GLint*, GLsizei, GLuint*) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glGetPerfMonitorCounterStringAMD(GLuint, GLuint, GLsizei, GLsizei*, GLchar*) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glGetPerfMonitorGroupsAMD(GLint*, GLsizei, GLuint*) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glGetPerfMonitorGroupStringAMD(GLuint, GLsizei, GLsizei*, GLchar*) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void glSelectPerfMonitorCountersAMD(GLuint, GLboolean, GLuint, GLint, GLuint*) {
+    printf("%s: not implemented\n", __func__);
+}
+
+// Non-stubs (common)
+
+static void glDrawElementsData(GLenum mode, GLsizei count, GLenum type, void* indices, GLuint) {
+    s_gles3.glDrawElements(mode, count, type, indices);
+}
+
+static void glDrawElementsOffset(GLenum mode, GLsizei count, GLenum type, GLuint offset) {
+    s_gles3.glDrawElements(mode, count, type, reinterpret_cast<const GLvoid*>(offset));
+}
+
+static GLint glFinishRoundTrip() {
+    s_gles3.glFinish();
+    return 0;
+}
+
+static void glGetCompressedTextureFormats(int count, GLint* formats) {
+    int nFormats;
+    s_gles3.glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &nFormats);
+    if (nFormats <= count)
+        s_gles3.glGetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, formats);
+}
+
+// Non-stubs (ES 3.1)
+
+struct GlSync {
+    GlSync(GLESv3* ctx_, GLsync sync_) : sync(sync_), id(ctx_->sync_nextId++), ctx(ctx_) {
+        ctx->sync_map.emplace(id, this);
+    }
+
+    ~GlSync() {
+        ctx->sync_map.erase(id);
+    }
+
+    GLsync sync;
+    uint64_t id;
+
+  private:
+    GLESv3* ctx;
+};
+
+static GLenum glClientWaitSyncAEMU(void* ctx_, uint64_t wait_on, GLbitfield flags,
+                                   GLuint64 timeout) {
+    GLESv3* ctx = static_cast<GLESv3*>(ctx_);
+
+    std::map<uint64_t, GlSync*>::iterator it;
+    it = ctx->sync_map.find(wait_on);
+    if (it == ctx->sync_map.end())
+        return GL_INVALID_VALUE;
+
+    GlSync* sync = it->second;
+    return s_gles3.glClientWaitSync(sync->sync, flags, timeout);
+}
+
+static void glCompressedTexImage2DOffsetAEMU(GLenum target, GLint level, GLenum internalformat,
+                                             GLsizei width, GLsizei height, GLint border,
+                                             GLsizei imageSize, GLuint offset) {
+    s_gles3.glCompressedTexImage2D(target, level, internalformat, width, height, border, imageSize,
+                                   reinterpret_cast<const GLvoid*>(offset));
+}
+
+static void glCompressedTexImage3DOffsetAEMU(GLenum target, GLint level, GLenum internalformat,
+                                             GLsizei width, GLsizei height, GLsizei depth,
+                                             GLint border, GLsizei imageSize, GLuint offset) {
+    s_gles3.glCompressedTexImage3D(target, level, internalformat, width, height, depth, border,
+                                   imageSize, reinterpret_cast<const GLvoid*>(offset));
+}
+
+static void glCompressedTexSubImage2DOffsetAEMU(GLenum target, GLint level, GLint xoffset,
+                                                GLint yoffset, GLsizei width, GLsizei height,
+                                                GLenum format, GLsizei imageSize, GLuint offset) {
+    s_gles3.glCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format,
+                                      imageSize, reinterpret_cast<const GLvoid*>(offset));
+}
+
+static void glCompressedTexSubImage3DOffsetAEMU(GLenum target, GLint level, GLint xoffset,
+                                                GLint yoffset, GLint zoffset, GLsizei width,
+                                                GLsizei height, GLsizei depth, GLenum format,
+                                                GLsizei imageSize, GLuint offset) {
+    s_gles3.glCompressedTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth,
+                                      format, imageSize, reinterpret_cast<const GLvoid*>(offset));
+}
+
+static GLuint glCreateShaderProgramvAEMU(GLenum type, GLsizei, const char* packedStrings, GLuint) {
+    return s_gles3.glCreateShaderProgramv(type, 1, &packedStrings);
+}
+
+static void glDeleteSyncAEMU(void* ctx_, uint64_t to_delete) {
+    GLESv3* ctx = static_cast<GLESv3*>(ctx_);
+
+    std::map<uint64_t, GlSync*>::iterator it;
+    it = ctx->sync_map.find(to_delete);
+    if (it == ctx->sync_map.end())
+        return;
+
+    GlSync* sync = it->second;
+    s_gles3.glDeleteSync(sync->sync);
+    delete sync;
+}
+
+static void glDrawArraysIndirectDataAEMU(GLenum mode, const void* indirect, GLuint) {
+    s_gles3.glDrawArraysIndirect(mode, indirect);
+}
+
+static void glDrawArraysIndirectOffsetAEMU(GLenum mode, GLuint offset) {
+    s_gles3.glDrawArraysIndirect(mode, reinterpret_cast<const void*>(offset));
+}
+
+static void glDrawElementsIndirectDataAEMU(GLenum mode, GLenum type, const void* indirect, GLuint) {
+    s_gles3.glDrawElementsIndirect(mode, type, indirect);
+}
+
+static void glDrawElementsIndirectOffsetAEMU(GLenum mode, GLenum type, GLuint offset) {
+    s_gles3.glDrawElementsIndirect(mode, type, reinterpret_cast<const void*>(offset));
+}
+
+static void glDrawElementsInstancedDataAEMU(GLenum mode, GLsizei count, GLenum type,
+                                            const void* indices, GLsizei primcount, GLsizei) {
+    s_gles3.glDrawElementsInstanced(mode, count, type, indices, primcount);
+}
+
+static void glDrawElementsInstancedOffsetAEMU(GLenum mode, GLsizei count, GLenum type,
+                                              GLuint offset, GLsizei primcount) {
+    s_gles3.glDrawElementsInstanced(mode, count, type, reinterpret_cast<const void*>(offset),
+                                    primcount);
+}
+
+static void glDrawRangeElementsDataAEMU(GLenum mode, GLuint start, GLuint end, GLsizei count,
+                                        GLenum type, const GLvoid* indices, GLsizei) {
+    s_gles3.glDrawRangeElements(mode, start, end, count, type, indices);
+}
+
+static void glDrawRangeElementsOffsetAEMU(GLenum mode, GLuint start, GLuint end, GLsizei count,
+                                          GLenum type, GLuint offset) {
+    s_gles3.glDrawRangeElements(mode, start, end, count, type,
+                                reinterpret_cast<const GLvoid*>(offset));
+}
+
+static uint64_t glFenceSyncAEMU(void* ctx_, GLenum condition, GLbitfield flags) {
+    GLsync sync_ = s_gles3.glFenceSync(condition, flags);
+    if (sync_ == 0)
+        return 0U;
+
+    GLESv3* ctx = static_cast<GLESv3*>(ctx_);
+    GlSync* sync = new (std::nothrow) GlSync(ctx, sync_);
+    if (!sync) {
+        s_gles3.glDeleteSync(sync_);
+        return 0U;
+    }
+
+    return sync->id;
+}
+
+static void glFlushMappedBufferRangeAEMU(GLenum target, GLintptr offset, GLsizeiptr length,
+                                         GLbitfield access, void* guest_buffer) {
+    if (guest_buffer && length) {
+        void* gpuPtr = s_gles3.glMapBufferRange(target, offset, length, access);
+        if (gpuPtr) {
+            memcpy(gpuPtr, guest_buffer, length);
+            s_gles3.glFlushMappedBufferRange(target, 0, length);
+            s_gles3.glUnmapBuffer(target);
+        }
+    }
+}
+
+static void glGetSyncivAEMU(void* ctx_, uint64_t sync_, GLenum pname, GLsizei bufSize,
+                            GLsizei* length, GLint* values) {
+    GLESv3* ctx = static_cast<GLESv3*>(ctx_);
+
+    std::map<uint64_t, GlSync*>::iterator it;
+    it = ctx->sync_map.find(sync_);
+    if (it == ctx->sync_map.end())
+        return;
+
+    GlSync* sync = it->second;
+    s_gles3.glGetSynciv(sync->sync, pname, bufSize, length, values);
+}
+
+static std::vector<std::string> sUnpackVarNames(GLsizei count, const char* packedNames) {
+    std::vector<std::string> unpacked;
+    GLsizei current = 0;
+
+    while (current < count) {
+        const char* delimPos = strstr(packedNames, ";");
+        size_t nameLen = delimPos - packedNames;
+        std::string next;
+        next.resize(nameLen);
+        memcpy(&next[0], packedNames, nameLen);
+        unpacked.push_back(next);
+        packedNames = delimPos + 1;
+        current++;
+    }
+
+    return unpacked;
+}
+
+static void glGetUniformIndicesAEMU(GLuint program, GLsizei uniformCount, const GLchar* packedNames,
+                                    GLsizei packedLen, GLuint* uniformIndices) {
+    std::vector<std::string> unpacked = sUnpackVarNames(uniformCount, packedNames);
+    GLchar** unpackedArray = new GLchar*[unpacked.size()];
+    GLsizei i = 0;
+    for (auto& elt : unpacked) {
+        unpackedArray[i] = (GLchar*)&elt[0];
+        i++;
+    }
+
+    s_gles3.glGetUniformIndices(program, uniformCount, const_cast<const GLchar**>(unpackedArray),
+                                uniformIndices);
+    delete[] unpackedArray;
+}
+
+static GLboolean glIsSyncAEMU(void* ctx_, uint64_t sync) {
+    GLESv3* ctx = static_cast<GLESv3*>(ctx_);
+    return ctx->sync_map.count(sync) ? GL_TRUE : GL_FALSE;
+}
+
+static void glMapBufferRangeAEMU(GLenum target, GLintptr offset, GLsizeiptr length,
+                                 GLbitfield access, void* mapped) {
+    if ((access & GL_MAP_READ_BIT) ||
+        ((access & GL_MAP_WRITE_BIT) &&
+         (!(access & GL_MAP_INVALIDATE_RANGE_BIT) && !(access & GL_MAP_INVALIDATE_BUFFER_BIT)))) {
+        void* gpuPtr = s_gles3.glMapBufferRange(target, offset, length, access);
+        if (gpuPtr) {
+            if (mapped)
+                memcpy(mapped, gpuPtr, length);
+            s_gles3.glUnmapBuffer(target);
+        }
+    }
+}
+
+static void glReadPixelsOffsetAEMU(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format,
+                                   GLenum type, GLuint offset) {
+    s_gles3.glReadPixels(x, y, width, height, format, type, reinterpret_cast<GLvoid*>(offset));
+}
+
+static void glShaderString(GLuint shader, const GLchar* string, GLsizei) {
+    s_gles3.glShaderSource(shader, 1, &string, NULL);
+}
+
+static void glTexImage2DOffsetAEMU(GLenum target, GLint level, GLint internalformat, GLsizei width,
+                                   GLsizei height, GLint border, GLenum format, GLenum type,
+                                   GLuint offset) {
+    s_gles3.glTexImage2D(target, level, internalformat, width, height, border, format, type,
+                         reinterpret_cast<const GLvoid*>(offset));
+}
+
+static void glTexImage3DOffsetAEMU(GLenum target, GLint level, GLint internalFormat, GLsizei width,
+                                   GLsizei height, GLsizei depth, GLint border, GLenum format,
+                                   GLenum type, GLuint offset) {
+    s_gles3.glTexImage3D(target, level, internalFormat, width, height, depth, border, format, type,
+                         reinterpret_cast<const GLvoid*>(offset));
+}
+
+static void glTexSubImage2DOffsetAEMU(GLenum target, GLint level, GLint xoffset, GLint yoffset,
+                                      GLsizei width, GLsizei height, GLenum format, GLenum type,
+                                      GLuint offset) {
+    s_gles3.glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type,
+                            reinterpret_cast<const GLvoid*>(offset));
+}
+
+static void glTexSubImage3DOffsetAEMU(GLenum target, GLint level, GLint xoffset, GLint yoffset,
+                                      GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
+                                      GLenum format, GLenum type, GLuint offset) {
+    s_gles3.glTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format,
+                            type, reinterpret_cast<const GLvoid*>(offset));
+}
+
+static void glTransformFeedbackVaryingsAEMU(GLuint program, GLsizei count,
+                                            const char* packedVaryings, GLuint packedVaryingsLen,
+                                            GLenum bufferMode) {
+    std::vector<std::string> unpacked = sUnpackVarNames(count, packedVaryings);
+    char** unpackedArray = new char*[unpacked.size()];
+    GLsizei i = 0;
+    for (auto& elt : unpacked) {
+        unpackedArray[i] = &elt[0];
+        i++;
+    }
+
+    s_gles3.glTransformFeedbackVaryings(program, count, const_cast<const char**>(unpackedArray),
+                                        bufferMode);
+    delete[] unpackedArray;
+}
+
+static void glUnmapBufferAEMU(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access,
+                              void* guest_buffer, GLboolean* out_res) {
+    *out_res = GL_TRUE;
+
+    if (access & GL_MAP_WRITE_BIT) {
+        if (guest_buffer) {
+            void* gpuPtr = s_gles3.glMapBufferRange(target, offset, length, access);
+            if (gpuPtr)
+                memcpy(gpuPtr, guest_buffer, length);
+        }
+
+        *out_res = s_gles3.glUnmapBuffer(target);
+    }
+}
+
+static void glVertexAttribIPointerDataAEMU(GLuint index, GLint size, GLenum type, GLsizei,
+                                           void* data, GLuint) {
+    s_gles3.glVertexAttribIPointer(index, size, type, 0, data);
+}
+
+static void glVertexAttribIPointerOffsetAEMU(GLuint index, GLint size, GLenum type, GLsizei,
+                                             GLuint offset) {
+    s_gles3.glVertexAttribIPointer(index, size, type, 0, reinterpret_cast<const GLvoid*>(offset));
+}
+
+static void glVertexAttribPointerData(GLuint indx, GLint size, GLenum type, GLboolean normalized,
+                                      GLsizei, void* data, GLuint) {
+    s_gles3.glVertexAttribPointer(indx, size, type, normalized, 0, data);
+}
+
+static void glVertexAttribPointerOffset(GLuint indx, GLint size, GLenum type, GLboolean normalized,
+                                        GLsizei, GLuint offset) {
+    s_gles3.glVertexAttribPointer(indx, size, type, normalized, 0,
+                                  reinterpret_cast<const GLvoid*>(offset));
+}
+
+static void glWaitSyncAEMU(void* ctx_, uint64_t wait_on, GLbitfield flags, GLuint64 timeout) {
+    GLESv3* ctx = static_cast<GLESv3*>(ctx_);
+
+    std::map<uint64_t, GlSync*>::iterator it;
+    it = ctx->sync_map.find(wait_on);
+    if (it == ctx->sync_map.end())
+        return;
+
+    GlSync* sync = it->second;
+    s_gles3.glWaitSync(sync->sync, flags, timeout);
+}
+
+#define KNIT(return_type, function_name, signature, callargs) function_name = s_gles3.function_name;
+
+GLESv3::GLESv3() {
+    LIST_GLES3_FUNCTIONS(KNIT, KNIT)
+
+    // Remap some ES 2.0 extensions that become core in ES 3.1
+    glBindVertexArrayOES = glBindVertexArray;
+    glDeleteVertexArraysOES = glDeleteVertexArrays;
+    glGenVertexArraysOES = glGenVertexArrays;
+    glGetProgramBinaryOES = glGetProgramBinary;
+    glIsVertexArrayOES = glIsVertexArray;
+    glProgramBinaryOES = glProgramBinary;
+    glUnmapBufferOES = glUnmapBuffer;
+
+    // Entrypoints requiring custom wrappers (common)
+    glDrawElementsData = ::glDrawElementsData;
+    glDrawElementsOffset = ::glDrawElementsOffset;
+    glFinishRoundTrip = ::glFinishRoundTrip;
+    glGetCompressedTextureFormats = ::glGetCompressedTextureFormats;
+
+    // Entrypoints requiring custom wrappers (ES 3.1)
+    glClientWaitSyncAEMU = ::glClientWaitSyncAEMU;
+    glCompressedTexImage2DOffsetAEMU = ::glCompressedTexImage2DOffsetAEMU;
+    glCompressedTexImage3DOffsetAEMU = ::glCompressedTexImage3DOffsetAEMU;
+    glCompressedTexSubImage2DOffsetAEMU = ::glCompressedTexSubImage2DOffsetAEMU;
+    glCompressedTexSubImage3DOffsetAEMU = ::glCompressedTexSubImage3DOffsetAEMU;
+    glCreateShaderProgramvAEMU = ::glCreateShaderProgramvAEMU;
+    glDeleteSyncAEMU = ::glDeleteSyncAEMU;
+    glDrawArraysIndirectDataAEMU = ::glDrawArraysIndirectDataAEMU;
+    glDrawArraysIndirectOffsetAEMU = ::glDrawArraysIndirectOffsetAEMU;
+    glDrawElementsIndirectDataAEMU = ::glDrawElementsIndirectDataAEMU;
+    glDrawElementsIndirectOffsetAEMU = ::glDrawElementsIndirectOffsetAEMU;
+    glDrawElementsInstancedDataAEMU = ::glDrawElementsInstancedDataAEMU;
+    glDrawElementsInstancedOffsetAEMU = ::glDrawElementsInstancedOffsetAEMU;
+    glDrawRangeElementsDataAEMU = ::glDrawRangeElementsDataAEMU;
+    glDrawRangeElementsOffsetAEMU = ::glDrawRangeElementsOffsetAEMU;
+    glFenceSyncAEMU = ::glFenceSyncAEMU;
+    glFlushMappedBufferRangeAEMU = ::glFlushMappedBufferRangeAEMU;
+    glGetSyncivAEMU = ::glGetSyncivAEMU;
+    glGetUniformIndicesAEMU = ::glGetUniformIndicesAEMU;
+    glIsSyncAEMU = ::glIsSyncAEMU;
+    glMapBufferRangeAEMU = ::glMapBufferRangeAEMU;
+    glReadPixelsOffsetAEMU = ::glReadPixelsOffsetAEMU;
+    glShaderString = ::glShaderString;
+    glTexImage2DOffsetAEMU = ::glTexImage2DOffsetAEMU;
+    glTexImage3DOffsetAEMU = ::glTexImage3DOffsetAEMU;
+    glTexSubImage2DOffsetAEMU = ::glTexSubImage2DOffsetAEMU;
+    glTexSubImage3DOffsetAEMU = ::glTexSubImage3DOffsetAEMU;
+    glTransformFeedbackVaryingsAEMU = ::glTransformFeedbackVaryingsAEMU;
+    glUnmapBufferAEMU = ::glUnmapBufferAEMU;
+    glVertexAttribIPointerDataAEMU = ::glVertexAttribIPointerDataAEMU;
+    glVertexAttribIPointerOffsetAEMU = ::glVertexAttribIPointerOffsetAEMU;
+    glVertexAttribPointerData = ::glVertexAttribPointerData;
+    glVertexAttribPointerOffset = ::glVertexAttribPointerOffset;
+    glWaitSyncAEMU = ::glWaitSyncAEMU;
+
+    // Stub some extensions we will never implement (common)
+    glDeleteFencesNV = ::glDeleteFencesNV;
+    glDisableDriverControlQCOM = ::glDisableDriverControlQCOM;
+    glDiscardFramebufferEXT = ::glDiscardFramebufferEXT;
+    glEnableDriverControlQCOM = ::glEnableDriverControlQCOM;
+    glEndTilingQCOM = ::glEndTilingQCOM;
+    glExtGetBufferPointervQCOM = ::glExtGetBufferPointervQCOM;
+    glExtGetBuffersQCOM = ::glExtGetBuffersQCOM;
+    glExtGetFramebuffersQCOM = ::glExtGetFramebuffersQCOM;
+    glExtGetProgramBinarySourceQCOM = ::glExtGetProgramBinarySourceQCOM;
+    glExtGetProgramsQCOM = ::glExtGetProgramsQCOM;
+    glExtGetRenderbuffersQCOM = ::glExtGetRenderbuffersQCOM;
+    glExtGetShadersQCOM = ::glExtGetShadersQCOM;
+    glExtGetTexLevelParameterivQCOM = ::glExtGetTexLevelParameterivQCOM;
+    glExtGetTexSubImageQCOM = ::glExtGetTexSubImageQCOM;
+    glExtGetTexturesQCOM = ::glExtGetTexturesQCOM;
+    glExtIsProgramBinaryQCOM = ::glExtIsProgramBinaryQCOM;
+    glExtTexObjectStateOverrideiQCOM = ::glExtTexObjectStateOverrideiQCOM;
+    glFinishFenceNV = ::glFinishFenceNV;
+    glFramebufferTexture2DMultisampleIMG = ::glFramebufferTexture2DMultisampleIMG;
+    glGenFencesNV = ::glGenFencesNV;
+    glGetDriverControlsQCOM = ::glGetDriverControlsQCOM;
+    glGetDriverControlStringQCOM = ::glGetDriverControlStringQCOM;
+    glGetFenceivNV = ::glGetFenceivNV;
+    glIsFenceNV = ::glIsFenceNV;
+    glMapBufferOES = ::glMapBufferOES;
+    glMultiDrawArraysEXT = ::glMultiDrawArraysEXT;
+    glMultiDrawElementsEXT = ::glMultiDrawElementsEXT;
+    glRenderbufferStorageMultisampleIMG = ::glRenderbufferStorageMultisampleIMG;
+    glSetFenceNV = ::glSetFenceNV;
+    glStartTilingQCOM = ::glStartTilingQCOM;
+    glTestFenceNV = ::glTestFenceNV;
+
+    // Stub some extensions we will never implement (ES 3.1)
+    glBeginPerfMonitorAMD = ::glBeginPerfMonitorAMD;
+    glCoverageMaskNV = ::glCoverageMaskNV;
+    glCoverageOperationNV = ::glCoverageOperationNV;
+    glDeletePerfMonitorsAMD = ::glDeletePerfMonitorsAMD;
+    glEndPerfMonitorAMD = ::glEndPerfMonitorAMD;
+    glGenPerfMonitorsAMD = ::glGenPerfMonitorsAMD;
+    glGetPerfMonitorCounterDataAMD = ::glGetPerfMonitorCounterDataAMD;
+    glGetPerfMonitorCounterInfoAMD = ::glGetPerfMonitorCounterInfoAMD;
+    glGetPerfMonitorCountersAMD = ::glGetPerfMonitorCountersAMD;
+    glGetPerfMonitorCounterStringAMD = ::glGetPerfMonitorCounterStringAMD;
+    glGetPerfMonitorGroupsAMD = ::glGetPerfMonitorGroupsAMD;
+    glGetPerfMonitorGroupStringAMD = ::glGetPerfMonitorGroupStringAMD;
+    glSelectPerfMonitorCountersAMD = ::glSelectPerfMonitorCountersAMD;
+}
diff --git a/host/libs/virglrenderer/GLESv3.h b/host/libs/virglrenderer/GLESv3.h
new file mode 100644
index 0000000000000000000000000000000000000000..a0778533c1760dc10dd173c1464ac56515dc7883
--- /dev/null
+++ b/host/libs/virglrenderer/GLESv3.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "gles3_dec.h"
+
+#include <map>
+
+struct GlSync;
+
+struct GLESv3 : public gles3_decoder_context_t {
+    GLESv3();
+
+    glDrawBuffers_server_proc_t glDrawBuffersEXT;
+
+    glDrawArraysInstanced_server_proc_t glDrawArraysInstancedEXT;
+    glDrawElementsInstanced_server_proc_t glDrawElementsInstancedEXT;
+
+    glVertexAttribDivisor_server_proc_t glVertexAttribDivisorEXT;
+
+    std::map<uint64_t, GlSync*> sync_map;
+
+  private:
+    uint64_t sync_nextId = 1U;
+    friend struct GlSync;
+};
diff --git a/host/libs/virglrenderer/GLESv3_dec/gles3.attrib b/host/libs/virglrenderer/GLESv3_dec/gles3.attrib
new file mode 100644
index 0000000000000000000000000000000000000000..d5d8d18360b1b76afec83a497ba8b977f2c6b9cf
--- /dev/null
+++ b/host/libs/virglrenderer/GLESv3_dec/gles3.attrib
@@ -0,0 +1,967 @@
+GLOBAL
+    base_opcode 2048
+
+glBindAttribLocation
+    len name (strlen(name) + 1)
+
+glBufferData
+    len data size
+    var_flag data nullAllowed isLarge
+
+glBufferSubData
+    len data size
+    var_flag data nullAllowed isLarge
+
+glCompressedTexImage2D
+    len data imageSize
+    param_check imageSize if(imageSize<0){ ctx->setError(GL_INVALID_VALUE); return; }
+    var_flag data nullAllowed isLarge
+    param_check imageSize if(imageSize<0){ ctx->setError(GL_INVALID_VALUE); return; }
+
+glCompressedTexSubImage2D
+    len data imageSize
+    param_check imageSize if(imageSize<0){ ctx->setError(GL_INVALID_VALUE); return; }
+    var_flag data nullAllowed isLarge
+    param_check imageSize if(imageSize<0){ ctx->setError(GL_INVALID_VALUE); return; }
+
+glDeleteBuffers
+    len buffers (n * sizeof(GLuint))
+    param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; }
+
+glDeleteFramebuffers
+    len framebuffers (n * sizeof(GLuint))
+    param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; }
+
+glDeleteRenderbuffers
+    len renderbuffers (n * sizeof(GLuint))
+    param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; }
+
+glDeleteTextures
+    len textures (n * sizeof(GLuint))
+    param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; }
+
+glDrawElements
+    flag unsupported
+
+glGenBuffers
+    len buffers (n * sizeof(GLuint))
+    dir buffers out
+    param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; }
+
+glGenFramebuffers
+    len framebuffers (n * sizeof(GLuint))
+    dir framebuffers out
+    param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; }
+
+glGenRenderbuffers
+    len renderbuffers (n * sizeof(GLuint))
+    dir renderbuffers out
+    param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; }
+
+glGenTextures
+    len textures (n * sizeof(GLuint))
+    dir textures out
+    param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; }
+
+glGetActiveAttrib
+    param_check bufsize if(bufsize<0){ ctx->setError(GL_INVALID_VALUE); return; }
+    len name bufsize
+    dir name out
+    var_flag name nullAllowed
+    dir length out
+    len length (sizeof(GLsizei))
+    var_flag length nullAllowed
+    dir size out
+    len size (sizeof(GLint))
+    var_flag size nullAllowed
+    dir type out
+    len type (sizeof(GLenum))
+    var_flag type nullAllowed
+
+glGetActiveUniform
+    param_check bufsize if(bufsize<0){ ctx->setError(GL_INVALID_VALUE); return; }
+    len name bufsize
+    dir name out
+    var_flag name nullAllowed
+    dir length out
+    len length (sizeof(GLsizei))
+    var_flag length nullAllowed
+    dir size out
+    len size (sizeof(GLint))
+    var_flag size nullAllowed
+    dir type out
+    len type (sizeof(GLenum))
+    var_flag type nullAllowed
+
+glGetAttachedShaders
+    len shaders (maxcount*sizeof(GLuint))
+    dir shaders out
+    dir count out
+    var_flag count nullAllowed
+    len count (sizeof(GLsizei))
+
+glGetAttribLocation
+    len name (strlen(name) + 1)
+
+glGetBooleanv
+    dir params out
+
+glGetBufferParameteriv
+    len params (sizeof(GLint))
+    dir params out
+
+glGetFloatv
+    dir params out
+
+glGetFramebufferAttachmentParameteriv
+    dir params out
+    len params (sizeof(GLint))
+
+glGetIntegerv
+    dir params out
+
+glGetProgramiv
+    dir params out
+
+glGetProgramInfoLog
+    dir infolog out
+    len infolog bufsize
+    param_check bufsize if(bufsize<0){ ctx->setError(GL_INVALID_VALUE); return; }
+    dir length out
+    len length sizeof(GLsizei)
+    var_flag length nullAllowed
+
+glGetRenderbufferParameteriv
+    dir params out
+    len params sizeof(GLint)
+
+glGetShaderiv
+    dir params out
+    len params sizeof(GLint)
+
+glGetShaderInfoLog
+    dir length out
+    len length (sizeof(GLsizei))
+    var_flag length nullAllowed
+    dir infolog out
+    len infolog bufsize
+    param_check bufsize if(bufsize<0){ ctx->setError(GL_INVALID_VALUE); return; }
+
+glGetShaderPrecisionFormat
+    dir range out
+    len range (2 * sizeof(GLint))
+    dir precision out
+    len precision (sizeof(GLint))
+
+glGetShaderSource
+    dir length out
+    len length (sizeof(GLsizei))
+    var_flag length nullAllowed
+    dir source out
+    len source bufsize
+    param_check bufsize if(bufsize<0){ ctx->setError(GL_INVALID_VALUE); return; }
+
+glGetString
+    flag unsupported
+
+glGetTexParameterfv
+    dir params out
+
+glGetTexParameteriv
+    dir params out
+
+glGetUniformfv
+    dir params out
+    len params glSizeof(glesv2_enc::uniformType(self, program, location))
+
+glGetUniformiv
+    dir params out
+    len params glSizeof(glesv2_enc::uniformType(self, program, location))
+
+glGetUniformLocation
+    len name (strlen(name) + 1)
+
+glGetVertexAttribfv
+    dir params out
+
+glGetVertexAttribiv
+    dir params out
+
+glReadPixels
+    dir pixels out
+    len pixels glesv2_enc::pixelDataSize(self, width, height, format, type, 1)
+
+glReadPixelsOffsetAEMU
+    flag not_api
+
+glShaderBinary
+    flag unsupported
+
+glTexImage2D
+    dir pixels in
+    len pixels glesv2_enc::pixelDataSize(self, width, height, format, type, 0)
+    var_flag pixels nullAllowed isLarge
+
+glTexSubImage2D
+    len pixels glesv2_enc::pixelDataSize(self, width, height, format, type, 0)
+    var_flag pixels nullAllowed isLarge
+
+glUniform1fv
+    len v (count * sizeof(GLfloat))
+
+glUniform1iv
+    len v (count * sizeof(GLint))
+
+glUniform2fv
+    len v (count * 2 * sizeof(GLfloat))
+
+glUniform2iv
+    len v (count * 2 * sizeof(GLint))
+
+glUniform3fv
+    len v (count * 3 * sizeof(GLfloat))
+
+glUniform3iv
+    len v (3 * count * sizeof(GLint))
+
+glUniform4fv
+    len v (4 * count * sizeof(GLfloat))
+
+glUniform4iv
+    len v (4 * count * sizeof(GLint))
+
+glUniformMatrix2fv
+    len value (count * 4 * sizeof(GLfloat))
+
+glUniformMatrix3fv
+    len value (count * 9 * sizeof(GLfloat))
+
+glUniformMatrix4fv
+    len value (count * 16 * sizeof(GLfloat))
+
+glVertexAttrib1fv
+    len values (sizeof(GLfloat))
+glVertexAttrib2fv
+    len values (2 * sizeof(GLfloat))
+
+glVertexAttrib3fv
+    len values (3 * sizeof(GLfloat))
+
+glVertexAttrib4fv
+    len values (4 * sizeof(GLfloat))
+
+glVertexAttribPointer
+    flag unsupported
+
+glGetProgramBinaryOES
+    flag unsupported
+
+glProgramBinaryOES
+    flag unsupported
+
+glMapBufferOES
+    flag unsupported
+
+glTexImage3DOES
+    len pixels glesv2_enc::pixelDataSize3D(self, width, height, depth, format, type, 0)
+    var_flag pixels nullAllowed isLarge
+
+glTexSubImage3DOES
+    len pixels glesv2_enc::pixelDataSize3D(self, width, height, depth, format, type, 0)
+    var_flag pixels nullAllowed isLarge
+
+glCompressedTexImage3DOES
+    len data imageSize
+    param_check imageSize if(imageSize<0){ ctx->setError(GL_INVALID_VALUE); return; }
+    var_flag data nullAllowed isLarge
+
+glCompressedTexSubImage3DOES
+    len data imageSize
+    param_check imageSize if(imageSize<0){ ctx->setError(GL_INVALID_VALUE); return; }
+    var_flag data nullAllowed isLarge
+
+glDeleteVertexArraysOES
+    len arrays (n * sizeof(GLuint))
+    param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; }
+
+glGenVertexArraysOES
+    len arrays (n * sizeof(GLuint))
+    dir arrays out
+    param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; }
+
+glDiscardFramebufferEXT
+    len attachments (numAttachments * sizeof(GLenum))
+
+glMultiDrawArraysEXT
+    flag unsupported
+
+glMultiDrawElementsEXT
+    flag unsupported
+
+glShaderSource
+    flag unsupported
+
+glGetPerfMonitorGroupsAMD
+    flag unsupported
+
+glGetPerfMonitorCountersAMD
+    flag unsupported
+
+glGetPerfMonitorGroupStringAMD
+    flag unsupported
+
+glGetPerfMonitorCounterStringAMD
+    flag unsupported
+
+glGetPerfMonitorCounterInfoAMD
+    flag unsupported
+
+glGenPerfMonitorsAMD
+    flag unsupported
+
+glDeletePerfMonitorsAMD
+    flag unsupported
+
+glSelectPerfMonitorCountersAMD
+    flag unsupported
+
+glBeginPerfMonitorAMD
+    flag unsupported
+
+glEndPerfMonitorAMD
+    flag unsupported
+
+glGetPerfMonitorCounterDataAMD
+    flag unsupported
+
+glRenderbufferStorageMultisampleIMG
+    flag unsupported
+
+glFramebufferTexture2DMultisampleIMG
+    flag unsupported
+
+glDeleteFencesNV
+    flag unsupported
+
+glGenFencesNV
+    flag unsupported
+
+glIsFenceNV
+    flag unsupported
+
+glTestFenceNV
+    flag unsupported
+
+glGetFenceivNV
+    flag unsupported
+
+glFinishFenceNV
+    flag unsupported
+
+glSetFenceNV
+    flag unsupported
+
+glCoverageMaskNV
+    flag unsupported
+
+glCoverageOperationNV
+    flag unsupported
+
+glGetDriverControlsQCOM
+    flag unsupported
+
+glGetDriverControlStringQCOM
+    flag unsupported
+
+glEnableDriverControlQCOM
+    flag unsupported
+
+glDisableDriverControlQCOM
+    flag unsupported
+
+glExtGetTexturesQCOM
+    flag unsupported
+
+glExtGetBuffersQCOM
+    flag unsupported
+
+glExtGetRenderbuffersQCOM
+    flag unsupported
+
+glExtGetFramebuffersQCOM
+    flag unsupported
+
+glExtGetTexLevelParameterivQCOM
+    flag unsupported
+
+glExtTexObjectStateOverrideiQCOM
+    flag unsupported
+
+glExtGetTexSubImageQCOM
+    flag unsupported
+
+glExtGetBufferPointervQCOM
+    flag unsupported
+
+glExtGetShadersQCOM
+    flag unsupported
+
+glExtGetProgramsQCOM
+    flag unsupported
+
+glExtIsProgramBinaryQCOM
+    flag unsupported
+
+glExtGetProgramBinarySourceQCOM
+    flag unsupported
+
+glStartTilingQCOM
+    flag unsupported
+
+glEndTilingQCOM
+    flag unsupported
+
+glVertexAttribPointerData
+    len data datalen
+    flag not_api
+
+glVertexAttribPointerOffset
+    flag not_api
+
+glGetVertexAttribPointerv
+    flag unsupported
+
+glDrawElementsData
+    len data datalen
+    flag not_api
+
+glDrawElementsOffset
+    flag not_api
+
+glGetCompressedTextureFormats
+    dir formats out
+    len formats (count * sizeof(GLint))
+    flag not_api
+
+glShaderString
+    len string len
+    flag not_api
+
+glFinishRoundTrip
+    flag not_api
+
+glGenVertexArrays
+    len arrays (n * sizeof(GLuint))
+    dir arrays out
+    param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; }
+
+glDeleteVertexArrays
+    len arrays (n * sizeof(GLuint))
+    param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; }
+
+glMapBufferRange
+    flag unsupported
+
+glUnmapBuffer
+    flag unsupported
+
+glFlushMappedBufferRange
+    flag unsupported
+
+glMapBufferRangeAEMU
+    dir mapped out
+    len mapped length
+    var_flag mapped nullAllowed
+    flag not_api
+
+glUnmapBufferAEMU
+    dir guest_buffer in
+    len guest_buffer length
+    var_flag guest_buffer nullAllowed
+    dir out_res out
+    len out_res (sizeof(GLboolean))
+    flag not_api
+
+glFlushMappedBufferRangeAEMU
+    dir guest_buffer in
+    len guest_buffer length
+    var_flag guest_buffer nullAllowed
+    flag not_api
+
+glReadPixelsOffsetAEMU
+    flag not_api
+
+glCompressedTexImage2DOffsetAEMU
+    flag not_api
+
+glCompressedTexSubImage2DOffsetAEMU
+    flag not_api
+
+glTexImage2DOffsetAEMU
+    flag not_api
+
+glTexSubImage2DOffsetAEMU
+    flag not_api
+
+glCopyBufferSubData
+    flag flushOnEncode
+
+glClearBufferiv
+    dir value in
+    len value (sizeof(GLint) * glesv2_enc::clearBufferNumElts(self, buffer))
+
+glClearBufferuiv
+    dir value in
+    len value (sizeof(GLuint) * glesv2_enc::clearBufferNumElts(self, buffer))
+
+glClearBufferfv
+    dir value in
+    len value (sizeof(GLfloat) * glesv2_enc::clearBufferNumElts(self, buffer))
+
+glGetBufferParameteri64v
+    flag unsupported
+
+glGetBufferPointerv
+    flag unsupported
+
+glGetUniformBlockIndex
+    len uniformBlockName (strlen(uniformBlockName) + 1)
+
+glGetUniformIndices
+    flag unsupported
+
+glGetUniformIndicesAEMU
+    dir packedUniformNames in
+    len packedUniformNames packedLen
+    dir uniformIndices out
+    len uniformIndices (uniformCount * sizeof(GLuint))
+    flag not_api
+
+glGetActiveUniformBlockiv
+    dir params out
+    len params (glesv2_enc::glActiveUniformBlockivParamSize(self, program, uniformBlockIndex, pname) * sizeof(GLint))
+
+glGetActiveUniformBlockName
+    dir uniformBlockName out
+    len uniformBlockName bufSize
+    param_check bufSize if(bufSize<0){ ctx->setError(GL_INVALID_VALUE); return; }
+    var_flag uniformBlockName nullAllowed
+    dir length out
+    len length (sizeof(GLsizei))
+    var_flag length nullAllowed
+
+glUniform1uiv
+    len value (count * sizeof(GLuint))
+
+glUniform2uiv
+    len value (count * 2 * sizeof(GLuint))
+
+glUniform3uiv
+    len value (count * 3 * sizeof(GLuint))
+
+glUniform4uiv
+    len value (count * 4 * sizeof(GLuint))
+
+glUniformMatrix2x3fv
+    len value (count * 6 * sizeof(GLfloat))
+
+glUniformMatrix3x2fv
+    len value (count * 6 * sizeof(GLfloat))
+
+glUniformMatrix2x4fv
+    len value (count * 8 * sizeof(GLfloat))
+
+glUniformMatrix4x2fv
+    len value (count * 8 * sizeof(GLfloat))
+
+glUniformMatrix3x4fv
+    len value (count * 12 * sizeof(GLfloat))
+
+glUniformMatrix4x3fv
+    len value (count * 12 * sizeof(GLfloat))
+
+glGetUniformuiv
+    dir params out
+    len params glSizeof(glesv2_enc::uniformType(self, program, location))
+
+glGetActiveUniformsiv
+    len uniformIndices (uniformCount * sizeof(GLuint))
+    dir params out
+    len params (uniformCount * sizeof(GLint))
+
+glVertexAttribI4iv
+    len v (4 * sizeof(GLint))
+
+glVertexAttribI4uiv
+    len v (4 * sizeof(GLuint))
+
+glVertexAttribIPointer
+    flag unsupported
+
+glVertexAttribIPointerOffsetAEMU
+    flag not_api
+
+glVertexAttribIPointerDataAEMU
+    len data datalen
+    flag not_api
+
+glGetVertexAttribIiv
+    dir params out
+
+glGetVertexAttribIuiv
+    dir params out
+
+glDrawElementsInstanced
+    flag unsupported
+
+glDrawElementsInstancedDataAEMU
+    len indices datalen
+    flag not_api
+
+glDrawElementsInstancedOffsetAEMU
+    flag not_api
+
+glDrawRangeElements
+    flag unsupported
+
+glDrawRangeElementsDataAEMU
+    len indices datalen
+    flag not_api
+
+glDrawRangeElementsOffsetAEMU
+    flag not_api
+
+glFenceSync
+    flag unsupported
+
+glClientWaitSync
+    flag unsupported
+
+glWaitSync
+    flag unsupported
+
+glDeleteSync
+    flag unsupported
+
+glIsSync
+    flag unsupported
+
+glGetSynciv
+    flag unsupported
+
+glFenceSyncAEMU
+    flag custom_decoder
+    flag not_api
+
+glClientWaitSyncAEMU
+    flag custom_decoder
+    flag not_api
+
+glWaitSyncAEMU
+    flag custom_decoder
+    flag not_api
+
+glDeleteSyncAEMU
+    flag custom_decoder
+    flag not_api
+
+glIsSyncAEMU
+    flag custom_decoder
+    flag not_api
+
+glGetSyncivAEMU
+    flag custom_decoder
+    flag not_api
+    param_check bufSize if(bufSize<0){ ctx->setError(GL_INVALID_VALUE); return; }
+    dir length out
+    len length (sizeof(GLsizei))
+    var_flag length nullAllowed
+    dir values out
+    len values (bufSize * sizeof(GLint))
+
+glGetInternalformativ
+    dir params out
+    len params (sizeof(GLint) * bufSize)
+
+glDrawBuffers
+    len bufs (n * sizeof(GLenum))
+
+glInvalidateFramebuffer
+    len attachments (numAttachments * sizeof(GLenum))
+
+glInvalidateSubFramebuffer
+    len attachments (numAttachments * sizeof(GLenum))
+
+glGenTransformFeedbacks
+    dir ids out
+    len ids (n * sizeof(GLuint))
+    param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; }
+
+glDeleteTransformFeedbacks
+    len ids (n * sizeof(GLuint))
+    param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; }
+
+glTransformFeedbackVaryings
+    flag unsupported
+
+glTransformFeedbackVaryingsAEMU
+    dir packedVaryings in
+    len packedVaryings packedVaryingsLen
+    flag not_api
+
+glGetTransformFeedbackVarying
+    dir name out
+    len name bufSize
+    param_check bufSize if(bufSize<0){ ctx->setError(GL_INVALID_VALUE); return; }
+    var_flag name nullAllowed
+    dir length out
+    len length (sizeof(GLsizei))
+    var_flag length nullAllowed
+    dir size out
+    len size (sizeof(GLsizei))
+    var_flag type nullAllowed
+    dir type out
+    len type (sizeof(GLenum))
+    var_flag type nullAllowed
+
+glGenSamplers
+    dir samplers out
+    len samplers (n * sizeof(GLuint))
+    param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; }
+
+glDeleteSamplers
+    len samplers (n * sizeof(GLuint))
+    param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; }
+
+glGetSamplerParameterfv
+    dir params out
+
+glGetSamplerParameteriv
+    dir params out
+
+glGenQueries
+    dir queries out
+    len queries (n * sizeof(GLuint))
+    param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; }
+
+glDeleteQueries
+    len queries (n * sizeof(GLuint))
+    param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; }
+
+glGetQueryiv
+    dir params out
+
+glGetQueryObjectuiv
+    dir params out
+
+glProgramBinary
+    len binary length
+
+glGetProgramBinary
+    param_check bufSize if(bufSize<0){ ctx->setError(GL_INVALID_VALUE); return; }
+    dir binary out
+    len binary bufSize
+    dir binaryFormat out
+    len binaryFormat (sizeof(GLenum))
+    var_flag length nullAllowed
+    dir length out
+    len length (sizeof(GLsizei))
+
+glGetFragDataLocation
+    len name (strlen(name) + 1)
+
+glGetInteger64v
+    dir data out
+
+glGetIntegeri_v
+    dir data out
+    len data (sizeof(GLint))
+
+glGetInteger64i_v
+    dir data out
+    len data (sizeof(GLint64))
+
+glTexImage3D
+    dir data in
+    len data glesv2_enc::pixelDataSize3D(self, width, height, depth, format, type, 0)
+    var_flag data nullAllowed isLarge
+
+glTexImage3DOffsetAEMU
+    flag not_api
+
+glTexSubImage3D
+    len data glesv2_enc::pixelDataSize3D(self, width, height, depth, format, type, 0)
+    var_flag data nullAllowed isLarge
+
+glTexSubImage3DOffsetAEMU
+    flag not_api
+
+glCompressedTexImage3D
+    len data imageSize
+    param_check imageSize if(imageSize<0){ ctx->setError(GL_INVALID_VALUE); return; }
+    var_flag data nullAllowed isLarge
+
+glCompressedTexImage3DOffsetAEMU
+    flag not_api
+
+glCompressedTexSubImage3D
+    param_check imageSize if(imageSize<0){ ctx->setError(GL_INVALID_VALUE); return; }
+    len data imageSize
+    var_flag data nullAllowed isLarge
+
+glCompressedTexSubImage3DOffsetAEMU
+    flag not_api
+
+glGetStringi
+    flag unsupported
+
+glGetBooleani_v
+    dir data out
+    len data (sizeof(GLboolean))
+
+glGenProgramPipelines
+    dir pipelines out
+    len pipelines (n * sizeof(GLuint))
+
+glDeleteProgramPipelines
+    len pipelines (n * sizeof(GLuint))
+    param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; }
+
+glGetProgramPipelineiv
+    dir params out
+
+glGetProgramPipelineInfoLog
+    dir infoLog out
+    len infoLog bufSize
+    param_check bufSize if(bufSize<0){ ctx->setError(GL_INVALID_VALUE); return; }
+    dir length out
+    len length sizeof(GLsizei)
+    var_flag length nullAllowed
+
+glCreateShaderProgramv
+    flag unsupported
+
+glCreateShaderProgramvAEMU
+    len packedStrings packedLen
+    flag not_api
+
+glProgramUniform1fv
+    len value (count * sizeof(GLfloat))
+
+glProgramUniform2fv
+    len value (count * 2 * sizeof(GLfloat))
+
+glProgramUniform3fv
+    len value (count * 3 * sizeof(GLfloat))
+
+glProgramUniform4fv
+    len value (count * 4 * sizeof(GLfloat))
+
+glProgramUniform1iv
+    len value (count * sizeof(GLint))
+
+glProgramUniform2iv
+    len value (count * 2 * sizeof(GLint))
+
+glProgramUniform3iv
+    len value (count * 3 * sizeof(GLint))
+
+glProgramUniform4iv
+    len value (count * 4 * sizeof(GLint))
+
+glProgramUniform1uiv
+    len value (count * sizeof(GLuint))
+
+glProgramUniform2uiv
+    len value (count * 2 * sizeof(GLuint))
+
+glProgramUniform3uiv
+    len value (count * 3 * sizeof(GLuint))
+
+glProgramUniform4uiv
+    len value (count * 4 * sizeof(GLuint))
+
+glProgramUniformMatrix2fv
+    len value (count * 4 * sizeof(GLfloat))
+
+glProgramUniformMatrix3fv
+    len value (count * 9 * sizeof(GLfloat))
+
+glProgramUniformMatrix4fv
+    len value (count * 16 * sizeof(GLfloat))
+
+glProgramUniformMatrix2x3fv
+    len value (count * 6 * sizeof(GLfloat))
+
+glProgramUniformMatrix3x2fv
+    len value (count * 6 * sizeof(GLfloat))
+
+glProgramUniformMatrix2x4fv
+    len value (count * 8 * sizeof(GLfloat))
+
+glProgramUniformMatrix4x2fv
+    len value (count * 8 * sizeof(GLfloat))
+
+glProgramUniformMatrix3x4fv
+    len value (count * 12 * sizeof(GLfloat))
+
+glProgramUniformMatrix4x3fv
+    len value (count * 12 * sizeof(GLfloat))
+
+glGetProgramInterfaceiv
+    dir params out
+
+glGetProgramResourceiv
+    dir params out
+    len params (bufSize * sizeof(GLint))
+    param_check bufSize if(bufSize<0){ ctx->setError(GL_INVALID_VALUE); return; }
+    var_flag length nullAllowed
+    dir length out
+    len length (sizeof(GLsizei))
+    len props (propCount * sizeof(GLenum))
+
+glGetProgramResourceIndex
+    len name (strlen(name) + 1)
+
+glGetProgramResourceLocation
+    len name (strlen(name) + 1)
+
+glGetProgramResourceName
+    dir name out
+    len name bufSize
+    param_check bufSize if(bufSize<0){ ctx->setError(GL_INVALID_VALUE); return; }
+    var_flag length nullAllowed
+    dir length out
+    len length (sizeof(GLsizei))
+
+glDrawArraysIndirect
+    flag unsupported
+
+glDrawArraysIndirectDataAEMU
+    len indirect datalen
+    flag not_api
+
+glDrawArraysIndirectOffsetAEMU
+    flag not_api
+
+glDrawElementsIndirect
+    flag unsupported
+
+glDrawElementsIndirectDataAEMU
+    len indirect datalen
+    flag not_api
+
+glDrawElementsIndirectOffsetAEMU
+    flag not_api
+
+glGetMultisamplefv
+    dir val out
+
+glGetFramebufferParameteriv
+    dir params out
+
+glGetTexLevelParameterfv
+    dir params out
+
+glGetTexLevelParameteriv
+    dir params out
diff --git a/host/libs/virglrenderer/GLESv3_dec/gles3.in b/host/libs/virglrenderer/GLESv3_dec/gles3.in
new file mode 100644
index 0000000000000000000000000000000000000000..33eb3b3961f5954925278bc03bd8e170505e9af9
--- /dev/null
+++ b/host/libs/virglrenderer/GLESv3_dec/gles3.in
@@ -0,0 +1,559 @@
+GL_ENTRY(void, glActiveTexture, GLenum texture)
+GL_ENTRY(void, glAttachShader, GLuint program, GLuint shader)
+GL_ENTRY(void, glBindAttribLocation, GLuint program, GLuint index, const GLchar* name)
+GL_ENTRY(void, glBindBuffer, GLenum target, GLuint buffer)
+GL_ENTRY(void, glBindFramebuffer, GLenum target, GLuint framebuffer)
+GL_ENTRY(void, glBindRenderbuffer, GLenum target, GLuint renderbuffer)
+GL_ENTRY(void, glBindTexture, GLenum target, GLuint texture)
+GL_ENTRY(void, glBlendColor, GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
+GL_ENTRY(void, glBlendEquation,  GLenum mode )
+GL_ENTRY(void, glBlendEquationSeparate, GLenum modeRGB, GLenum modeAlpha)
+GL_ENTRY(void, glBlendFunc, GLenum sfactor, GLenum dfactor)
+GL_ENTRY(void, glBlendFuncSeparate, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)
+GL_ENTRY(void, glBufferData, GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage)
+GL_ENTRY(void, glBufferSubData, GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data)
+GL_ENTRY(GLenum, glCheckFramebufferStatus, GLenum target)
+GL_ENTRY(void, glClear, GLbitfield mask)
+GL_ENTRY(void, glClearColor, GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
+GL_ENTRY(void, glClearDepthf, GLclampf depth)
+GL_ENTRY(void, glClearStencil, GLint s)
+GL_ENTRY(void, glColorMask, GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)
+GL_ENTRY(void, glCompileShader, GLuint shader)
+GL_ENTRY(void, glCompressedTexImage2D, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data)
+GL_ENTRY(void, glCompressedTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data)
+GL_ENTRY(void, glCopyTexImage2D, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
+GL_ENTRY(void, glCopyTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)
+GL_ENTRY(GLuint, glCreateProgram, void)
+GL_ENTRY(GLuint, glCreateShader, GLenum type)
+GL_ENTRY(void, glCullFace, GLenum mode)
+GL_ENTRY(void, glDeleteBuffers, GLsizei n, const GLuint* buffers)
+GL_ENTRY(void, glDeleteFramebuffers, GLsizei n, const GLuint* framebuffers)
+GL_ENTRY(void, glDeleteProgram, GLuint program)
+GL_ENTRY(void, glDeleteRenderbuffers, GLsizei n, const GLuint* renderbuffers)
+GL_ENTRY(void, glDeleteShader, GLuint shader)
+GL_ENTRY(void, glDeleteTextures, GLsizei n, const GLuint* textures)
+GL_ENTRY(void, glDepthFunc, GLenum func)
+GL_ENTRY(void, glDepthMask, GLboolean flag)
+GL_ENTRY(void, glDepthRangef, GLclampf zNear, GLclampf zFar)
+GL_ENTRY(void, glDetachShader, GLuint program, GLuint shader)
+GL_ENTRY(void, glDisable, GLenum cap)
+GL_ENTRY(void, glDisableVertexAttribArray, GLuint index)
+GL_ENTRY(void, glDrawArrays, GLenum mode, GLint first, GLsizei count)
+GL_ENTRY(void, glDrawElements, GLenum mode, GLsizei count, GLenum type, const GLvoid* indices)
+GL_ENTRY(void, glEnable, GLenum cap)
+GL_ENTRY(void, glEnableVertexAttribArray, GLuint index)
+GL_ENTRY(void, glFinish, void)
+GL_ENTRY(void, glFlush, void)
+GL_ENTRY(void, glFramebufferRenderbuffer, GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
+GL_ENTRY(void, glFramebufferTexture2D, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
+GL_ENTRY(void, glFrontFace, GLenum mode)
+GL_ENTRY(void, glGenBuffers, GLsizei n, GLuint* buffers)
+GL_ENTRY(void, glGenerateMipmap, GLenum target)
+GL_ENTRY(void, glGenFramebuffers, GLsizei n, GLuint* framebuffers)
+GL_ENTRY(void, glGenRenderbuffers, GLsizei n, GLuint* renderbuffers)
+GL_ENTRY(void, glGenTextures, GLsizei n, GLuint* textures)
+GL_ENTRY(void, glGetActiveAttrib, GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name)
+GL_ENTRY(void, glGetActiveUniform, GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name)
+GL_ENTRY(void, glGetAttachedShaders, GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders)
+GL_ENTRY(int, glGetAttribLocation, GLuint program, const GLchar* name)
+GL_ENTRY(void, glGetBooleanv, GLenum pname, GLboolean* params)
+GL_ENTRY(void, glGetBufferParameteriv, GLenum target, GLenum pname, GLint* params)
+GL_ENTRY(GLenum, glGetError, void)
+GL_ENTRY(void, glGetFloatv, GLenum pname, GLfloat* params)
+GL_ENTRY(void, glGetFramebufferAttachmentParameteriv, GLenum target, GLenum attachment, GLenum pname, GLint* params)
+GL_ENTRY(void, glGetIntegerv, GLenum pname, GLint* params)
+GL_ENTRY(void, glGetProgramiv, GLuint program, GLenum pname, GLint* params)
+GL_ENTRY(void, glGetProgramInfoLog, GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog)
+GL_ENTRY(void, glGetRenderbufferParameteriv, GLenum target, GLenum pname, GLint* params)
+GL_ENTRY(void, glGetShaderiv, GLuint shader, GLenum pname, GLint* params)
+GL_ENTRY(void, glGetShaderInfoLog, GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog)
+GL_ENTRY(void, glGetShaderPrecisionFormat, GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision)
+GL_ENTRY(void, glGetShaderSource, GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source)
+GL_ENTRY(const GLubyte*, glGetString, GLenum name)
+GL_ENTRY(void, glGetTexParameterfv, GLenum target, GLenum pname, GLfloat* params)
+GL_ENTRY(void, glGetTexParameteriv, GLenum target, GLenum pname, GLint* params)
+GL_ENTRY(void, glGetUniformfv, GLuint program, GLint location, GLfloat* params)
+GL_ENTRY(void, glGetUniformiv, GLuint program, GLint location, GLint* params)
+GL_ENTRY(int, glGetUniformLocation, GLuint program, const GLchar* name)
+GL_ENTRY(void, glGetVertexAttribfv, GLuint index, GLenum pname, GLfloat* params)
+GL_ENTRY(void, glGetVertexAttribiv, GLuint index, GLenum pname, GLint* params)
+GL_ENTRY(void, glGetVertexAttribPointerv, GLuint index, GLenum pname, GLvoid** pointer)
+GL_ENTRY(void, glHint, GLenum target, GLenum mode)
+GL_ENTRY(GLboolean, glIsBuffer, GLuint buffer)
+GL_ENTRY(GLboolean, glIsEnabled, GLenum cap)
+GL_ENTRY(GLboolean, glIsFramebuffer, GLuint framebuffer)
+GL_ENTRY(GLboolean, glIsProgram, GLuint program)
+GL_ENTRY(GLboolean, glIsRenderbuffer, GLuint renderbuffer)
+GL_ENTRY(GLboolean, glIsShader, GLuint shader)
+GL_ENTRY(GLboolean, glIsTexture, GLuint texture)
+GL_ENTRY(void, glLineWidth, GLfloat width)
+GL_ENTRY(void, glLinkProgram, GLuint program)
+GL_ENTRY(void, glPixelStorei, GLenum pname, GLint param)
+GL_ENTRY(void, glPolygonOffset, GLfloat factor, GLfloat units)
+GL_ENTRY(void, glReadPixels, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels)
+GL_ENTRY(void, glReleaseShaderCompiler, void)
+GL_ENTRY(void, glRenderbufferStorage, GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
+GL_ENTRY(void, glSampleCoverage, GLclampf value, GLboolean invert)
+GL_ENTRY(void, glScissor, GLint x, GLint y, GLsizei width, GLsizei height)
+GL_ENTRY(void, glShaderBinary, GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length)
+GL_ENTRY(void, glShaderSource, GLuint shader, GLsizei count, const GLchar*const* string, const GLint* length)
+GL_ENTRY(void, glStencilFunc, GLenum func, GLint ref, GLuint mask)
+GL_ENTRY(void, glStencilFuncSeparate, GLenum face, GLenum func, GLint ref, GLuint mask)
+GL_ENTRY(void, glStencilMask, GLuint mask)
+GL_ENTRY(void, glStencilMaskSeparate, GLenum face, GLuint mask)
+GL_ENTRY(void, glStencilOp, GLenum fail, GLenum zfail, GLenum zpass)
+GL_ENTRY(void, glStencilOpSeparate, GLenum face, GLenum fail, GLenum zfail, GLenum zpass)
+GL_ENTRY(void, glTexImage2D, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels)
+GL_ENTRY(void, glTexParameterf, GLenum target, GLenum pname, GLfloat param)
+GL_ENTRY(void, glTexParameterfv, GLenum target, GLenum pname, const GLfloat* params)
+GL_ENTRY(void, glTexParameteri, GLenum target, GLenum pname, GLint param)
+GL_ENTRY(void, glTexParameteriv, GLenum target, GLenum pname, const GLint* params)
+GL_ENTRY(void, glTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels)
+GL_ENTRY(void, glUniform1f, GLint location, GLfloat x)
+GL_ENTRY(void, glUniform1fv, GLint location, GLsizei count, const GLfloat* v)
+GL_ENTRY(void, glUniform1i, GLint location, GLint x)
+GL_ENTRY(void, glUniform1iv, GLint location, GLsizei count, const GLint* v)
+GL_ENTRY(void, glUniform2f, GLint location, GLfloat x, GLfloat y)
+GL_ENTRY(void, glUniform2fv, GLint location, GLsizei count, const GLfloat* v)
+GL_ENTRY(void, glUniform2i, GLint location, GLint x, GLint y)
+GL_ENTRY(void, glUniform2iv, GLint location, GLsizei count, const GLint* v)
+GL_ENTRY(void, glUniform3f, GLint location, GLfloat x, GLfloat y, GLfloat z)
+GL_ENTRY(void, glUniform3fv, GLint location, GLsizei count, const GLfloat* v)
+GL_ENTRY(void, glUniform3i, GLint location, GLint x, GLint y, GLint z)
+GL_ENTRY(void, glUniform3iv, GLint location, GLsizei count, const GLint* v)
+GL_ENTRY(void, glUniform4f, GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+GL_ENTRY(void, glUniform4fv, GLint location, GLsizei count, const GLfloat* v)
+GL_ENTRY(void, glUniform4i, GLint location, GLint x, GLint y, GLint z, GLint w)
+GL_ENTRY(void, glUniform4iv, GLint location, GLsizei count, const GLint* v)
+GL_ENTRY(void, glUniformMatrix2fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+GL_ENTRY(void, glUniformMatrix3fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+GL_ENTRY(void, glUniformMatrix4fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+GL_ENTRY(void, glUseProgram, GLuint program)
+GL_ENTRY(void, glValidateProgram, GLuint program)
+GL_ENTRY(void, glVertexAttrib1f, GLuint indx, GLfloat x)
+GL_ENTRY(void, glVertexAttrib1fv, GLuint indx, const GLfloat* values)
+GL_ENTRY(void, glVertexAttrib2f, GLuint indx, GLfloat x, GLfloat y)
+GL_ENTRY(void, glVertexAttrib2fv, GLuint indx, const GLfloat* values)
+GL_ENTRY(void, glVertexAttrib3f, GLuint indx, GLfloat x, GLfloat y, GLfloat z)
+GL_ENTRY(void, glVertexAttrib3fv, GLuint indx, const GLfloat* values)
+GL_ENTRY(void, glVertexAttrib4f, GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+GL_ENTRY(void, glVertexAttrib4fv, GLuint indx, const GLfloat* values)
+GL_ENTRY(void, glVertexAttribPointer, GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr)
+GL_ENTRY(void, glViewport, GLint x, GLint y, GLsizei width, GLsizei height)
+GL_ENTRY(void, glEGLImageTargetTexture2DOES, GLenum target, GLeglImageOES image)
+GL_ENTRY(void, glEGLImageTargetRenderbufferStorageOES, GLenum target, GLeglImageOES image)
+GL_ENTRY(void, glGetProgramBinaryOES, GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary)
+GL_ENTRY(void, glProgramBinaryOES, GLuint program, GLenum binaryFormat, const GLvoid *binary, GLint length)
+GL_ENTRY(void*, glMapBufferOES, GLenum target, GLenum access)
+GL_ENTRY(GLboolean, glUnmapBufferOES, GLenum target)
+#GL_ENTRY(void, glGetBufferPointervOES, GLenum target, GLenum pname, GLvoid** params)
+GL_ENTRY(void, glTexImage3DOES, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels)
+GL_ENTRY(void, glTexSubImage3DOES, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels)
+GL_ENTRY(void, glCopyTexSubImage3DOES, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height)
+GL_ENTRY(void, glCompressedTexImage3DOES, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data)
+GL_ENTRY(void, glCompressedTexSubImage3DOES, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data)
+GL_ENTRY(void, glFramebufferTexture3DOES, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset)
+GL_ENTRY(void, glBindVertexArrayOES, GLuint array)
+GL_ENTRY(void, glDeleteVertexArraysOES, GLsizei n, const GLuint *arrays)
+GL_ENTRY(void, glGenVertexArraysOES, GLsizei n, GLuint *arrays)
+GL_ENTRY(GLboolean, glIsVertexArrayOES, GLuint array)
+GL_ENTRY(void, glDiscardFramebufferEXT, GLenum target, GLsizei numAttachments, const GLenum *attachments)
+GL_ENTRY(void, glMultiDrawArraysEXT, GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount)
+GL_ENTRY(void, glMultiDrawElementsEXT, GLenum mode, const GLsizei *count, GLenum type, const GLvoid*const* indices, GLsizei primcount)
+
+#not supported
+GL_ENTRY(void, glGetPerfMonitorGroupsAMD, GLint *numGroups, GLsizei groupsSize, GLuint *groups)
+GL_ENTRY(void, glGetPerfMonitorCountersAMD, GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters)
+GL_ENTRY(void, glGetPerfMonitorGroupStringAMD, GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString)
+GL_ENTRY(void, glGetPerfMonitorCounterStringAMD, GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString)
+GL_ENTRY(void, glGetPerfMonitorCounterInfoAMD, GLuint group, GLuint counter, GLenum pname, GLvoid *data)
+GL_ENTRY(void, glGenPerfMonitorsAMD, GLsizei n, GLuint *monitors)
+GL_ENTRY(void, glDeletePerfMonitorsAMD, GLsizei n, GLuint *monitors)
+GL_ENTRY(void, glSelectPerfMonitorCountersAMD, GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *countersList)
+GL_ENTRY(void, glBeginPerfMonitorAMD, GLuint monitor)
+GL_ENTRY(void, glEndPerfMonitorAMD, GLuint monitor)
+GL_ENTRY(void, glGetPerfMonitorCounterDataAMD, GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten)
+
+GL_ENTRY(void, glRenderbufferStorageMultisampleIMG, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height)
+GL_ENTRY(void, glFramebufferTexture2DMultisampleIMG, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples)
+GL_ENTRY(void, glDeleteFencesNV, GLsizei n, const GLuint *fences)
+GL_ENTRY(void, glGenFencesNV, GLsizei n, GLuint *fences)
+GL_ENTRY(GLboolean, glIsFenceNV, GLuint fence)
+GL_ENTRY(GLboolean, glTestFenceNV, GLuint fence)
+GL_ENTRY(void, glGetFenceivNV, GLuint fence, GLenum pname, GLint *params)
+GL_ENTRY(void, glFinishFenceNV, GLuint fence)
+GL_ENTRY(void, glSetFenceNV, GLuint fence, GLenum condition)
+GL_ENTRY(void, glCoverageMaskNV, GLboolean mask)
+GL_ENTRY(void, glCoverageOperationNV, GLenum operation)
+GL_ENTRY(void, glGetDriverControlsQCOM, GLint *num, GLsizei size, GLuint *driverControls)
+GL_ENTRY(void, glGetDriverControlStringQCOM, GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString)
+GL_ENTRY(void, glEnableDriverControlQCOM, GLuint driverControl)
+GL_ENTRY(void, glDisableDriverControlQCOM, GLuint driverControl)
+GL_ENTRY(void, glExtGetTexturesQCOM, GLuint *textures, GLint maxTextures, GLint *numTextures)
+GL_ENTRY(void, glExtGetBuffersQCOM, GLuint *buffers, GLint maxBuffers, GLint *numBuffers)
+GL_ENTRY(void, glExtGetRenderbuffersQCOM, GLuint *renderbuffers, GLint maxRenderbuffers, GLint *numRenderbuffers)
+GL_ENTRY(void, glExtGetFramebuffersQCOM, GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers)
+GL_ENTRY(void, glExtGetTexLevelParameterivQCOM, GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params)
+GL_ENTRY(void, glExtTexObjectStateOverrideiQCOM, GLenum target, GLenum pname, GLint param)
+GL_ENTRY(void, glExtGetTexSubImageQCOM, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLvoid *texels)
+GL_ENTRY(void, glExtGetBufferPointervQCOM, GLenum target, GLvoid** params)
+GL_ENTRY(void, glExtGetShadersQCOM, GLuint *shaders, GLint maxShaders, GLint *numShaders)
+GL_ENTRY(void, glExtGetProgramsQCOM, GLuint *programs, GLint maxPrograms, GLint *numPrograms)
+GL_ENTRY(GLboolean, glExtIsProgramBinaryQCOM, GLuint program)
+GL_ENTRY(void, glExtGetProgramBinarySourceQCOM, GLuint program, GLenum shadertype, GLchar *source, GLint *length)
+GL_ENTRY(void, glStartTilingQCOM, GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask)
+GL_ENTRY(void, glEndTilingQCOM, GLbitfield preserveMask)
+
+# add-ons for GLES 2
+GL_ENTRY(void, glVertexAttribPointerData, GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride,  void * data, GLuint datalen)
+GL_ENTRY(void, glVertexAttribPointerOffset, GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride,  GLuint offset)
+GL_ENTRY(void, glDrawElementsOffset, GLenum mode, GLsizei count, GLenum type, GLuint offset)
+GL_ENTRY(void, glDrawElementsData, GLenum mode, GLsizei count, GLenum type, void *data, GLuint datalen)
+GL_ENTRY(void, glGetCompressedTextureFormats, int count, GLint *formats)
+GL_ENTRY(void, glShaderString, GLuint shader, const GLchar* string, GLsizei len)
+GL_ENTRY(int, glFinishRoundTrip, void)
+
+# GLES 3.0 ApiGen .in
+
+# Changes to existing API:
+
+## New formats: Need to update all validation code to handle GLES 3.x-specific formats.
+## Primitive restart (close to already implemented in guest encoder, but can be tricky to validate in the middle of all the other draw validation going on)
+## Texture compression with ETC2 (already implemented)
+
+# New API calls - listed in approximate decreasing order of complexity
+
+# Vertex Array Objects
+## Before anything else, move GL calls out of sendVertexAttributes() in encoder,
+## or we will get this wrong, as we currently delay glEnableVertexAttribArray/ glVertexAttribPointer
+## until right before glDrawElements/Arrays.
+## This means moving those attribpointer calls out,
+## AND preserving the index range validation behavior that happens
+## just before glDrawElements/Arrays.
+GL_ENTRY(void, glGenVertexArrays, GLsizei n, GLuint* arrays)
+GL_ENTRY(void, glBindVertexArray, GLuint array)
+GL_ENTRY(void, glDeleteVertexArrays, GLsizei n, const GLuint *arrays)
+GL_ENTRY(GLboolean, glIsVertexArray, GLuint array)
+
+# New buffer operationarrays Mapping needs different encoding interface: copy from host on map, and copy to host (and host GPU pointer) on unmap or flush.
+## Proposed:
+GL_ENTRY(void*, glMapBufferRange, GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access)
+GL_ENTRY(GLboolean, glUnmapBuffer, GLenum target)
+GL_ENTRY(void, glFlushMappedBufferRange, GLenum target, GLintptr offset, GLsizeiptr length)
+GL_ENTRY(void, glMapBufferRangeAEMU, GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, void* mapped)
+GL_ENTRY(void, glUnmapBufferAEMU, GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, void* guest_buffer, GLboolean* out_res)
+GL_ENTRY(void, glFlushMappedBufferRangeAEMU, GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, void* guest_buffer)
+## It seems we can use glUnmapBuffer and glFlushMappedBufferRange as synchronization points
+## to update the host with the new buffer contents:
+## glMapBufferRange / glUnmapBuffer:
+## Guest:                    | Encoder:                           | Host:
+## void* x = glMapBuffer...  |                                    |          
+##                           | glMapBufferRangeAEMU_enc...        |                                             
+##                           |                                    | void* hostptr = glMapBufferRange...
+##                           |                                    | memcpy(mapped, hostptr, sz)
+##                           | stream->readback(mapped, sz)       |                            
+##                           | glMapBufferRangeAEMU_enc exit      |                            
+## x holds host GPU contents |                                    |          
+## <operations on x>         |                                    |           
+## glUnmapBuffer...          |                                    |           
+##                           | glUnmapBufferAEMU_enc...           |           
+##                           | stream->writeFully(x, sz)          |           
+##                           |                                    | memcpy(hostptr, x, sz)
+##                           |                                    | glUnmapBuffer
+## glMapBufferRange / glFlushMappedBufferRange:
+## Guest:                    | Encoder:                           | Host:
+## void* x = glMapBuffer...  |                                    |          
+##                           | glMapBufferRangeAEMU_enc...        |                                             
+##                           |                                    | void* hostptr = glMapBufferRange...
+##                           |                                    | memcpy(mapped, hostptr, sz)
+##                           | stream->readback(mapped, sz)       |                            
+##                           | glMapBufferRangeAEMU_enc exit      |                            
+## x holds host GPU contents |                                    |          
+## <operations on x>         |                                    |           
+## glFlushMappedBufferRange..|                                    |           
+##                           | glFlushMappedBufferRangeAEMU...    |           
+##                           | stream->writeFully(flushedrange... |           
+##                           |                                    | memcpy(hostptr + offset, flushedrange, length)
+##                           |                                    | glFlushMappedBufferRange
+## Make sure to store the binded range when mapped, I bet there is some dEQP test that checks this sort of thing :)
+
+## PBOs need to be delivered differently to the host.
+GL_ENTRY(void, glReadPixelsOffsetAEMU, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLuint offset)
+GL_ENTRY(void, glCompressedTexImage2DOffsetAEMU, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, GLuint offset)
+GL_ENTRY(void, glCompressedTexSubImage2DOffsetAEMU, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, GLuint offset)
+GL_ENTRY(void, glTexImage2DOffsetAEMU, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, GLuint offset)
+GL_ENTRY(void, glTexSubImage2DOffsetAEMU, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLuint offset)
+
+GL_ENTRY(void, glBindBufferRange, GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size)
+GL_ENTRY(void, glBindBufferBase, GLenum target, GLuint index, GLuint buffer)
+## No need to consider mapped buffers here as that is a GL_INVALID_OPERATION :)
+GL_ENTRY(void, glCopyBufferSubData, GLenum readtarget, GLenum writetarget, GLintptr readoffset, GLintptr writeoffset, GLsizeiptr size);
+
+## These buffer clears don't involve anything that can be mapped, so we are OK.
+GL_ENTRY(void, glClearBufferiv, GLenum buffer, GLint drawBuffer, const GLint * value)
+GL_ENTRY(void, glClearBufferuiv, GLenum buffer, GLint drawBuffer, const GLuint * value)
+GL_ENTRY(void, glClearBufferfv, GLenum buffer, GLint drawBuffer, const GLfloat * value)
+GL_ENTRY(void, glClearBufferfi, GLenum buffer, GLint drawBuffer, GLfloat depth, GLint stencil)
+
+## Reads (not writes) mapped state only, so shouldn't be sent to host.
+GL_ENTRY(void, glGetBufferParameteri64v, GLenum target, GLenum value, GLint64 * data)
+
+# Get current mapped buffer pointer. Shouldn't be sent to host.
+GL_ENTRY(void, glGetBufferPointerv, GLenum target, GLenum pname, GLvoid** params)
+
+# UBOs
+## Share group processing needed for all of these, as the program is an argument.
+## Validation is bound (heh) to be tricky
+GL_ENTRY(void, glUniformBlockBinding, GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding)
+
+GL_ENTRY(GLuint, glGetUniformBlockIndex, GLuint program, const GLchar *uniformBlockName)
+
+# Assume uniformNames packed into 1 buffer on the guest.
+GL_ENTRY(void, glGetUniformIndices, GLuint program, GLsizei uniformCount, const GLchar*const* uniformNames, GLuint* uniformIndices)
+GL_ENTRY(void, glGetUniformIndicesAEMU, GLuint program, GLsizei uniformCount, const GLchar *packedUniformNames, GLsizei packedLen, GLuint *uniformIndices)
+
+GL_ENTRY(void, glGetActiveUniformBlockiv, GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params)
+GL_ENTRY(void, glGetActiveUniformBlockName, GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName)
+
+# More uniform setters
+GL_ENTRY(void, glUniform1ui, GLint location, GLuint v0)
+GL_ENTRY(void, glUniform2ui, GLint location, GLuint v0, GLuint v1)
+GL_ENTRY(void, glUniform3ui, GLint location, GLuint v0, GLuint v1, GLuint v2)
+GL_ENTRY(void, glUniform4ui, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3)
+GL_ENTRY(void, glUniform1uiv, GLint location, GLsizei count, const GLuint *value)
+GL_ENTRY(void, glUniform2uiv, GLint location, GLsizei count, const GLuint *value)
+GL_ENTRY(void, glUniform3uiv, GLint location, GLsizei count, const GLuint *value)
+GL_ENTRY(void, glUniform4uiv, GLint location, GLsizei count, const GLuint *value)
+GL_ENTRY(void, glUniformMatrix2x3fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+GL_ENTRY(void, glUniformMatrix3x2fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+GL_ENTRY(void, glUniformMatrix2x4fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+GL_ENTRY(void, glUniformMatrix4x2fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+GL_ENTRY(void, glUniformMatrix3x4fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+GL_ENTRY(void, glUniformMatrix4x3fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+
+# Need share group processing for these gets
+GL_ENTRY(void, glGetUniformuiv, GLuint program, GLint location, GLuint *params)
+GL_ENTRY(void, glGetActiveUniformsiv, GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params)
+
+# More vertex attribute setters / queries
+GL_ENTRY(void, glVertexAttribI4i, GLuint index, GLint v0, GLint v1, GLint v2, GLint v3)
+GL_ENTRY(void, glVertexAttribI4ui, GLuint index, GLuint v0, GLuint v1, GLuint v2, GLuint v3)
+GL_ENTRY(void, glVertexAttribI4iv, GLuint index, const GLint *v)
+GL_ENTRY(void, glVertexAttribI4uiv, GLuint index, const GLuint *v)
+GL_ENTRY(void, glVertexAttribIPointer, GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid* pointer)
+GL_ENTRY(void, glVertexAttribIPointerOffsetAEMU, GLuint index, GLint size, GLenum type, GLsizei stride, GLuint offset)
+GL_ENTRY(void, glVertexAttribIPointerDataAEMU, GLuint index, GLint size, GLenum type, GLsizei stride, void* data, GLuint datalen)
+GL_ENTRY(void, glGetVertexAttribIiv, GLuint index, GLenum pname, GLint *params)
+GL_ENTRY(void, glGetVertexAttribIuiv, GLuint index, GLenum pname, GLuint *params)
+
+# Instanced draws
+GL_ENTRY(void, glVertexAttribDivisor, GLuint index, GLuint divisor)
+GL_ENTRY(void, glDrawArraysInstanced, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
+
+GL_ENTRY(void, glDrawElementsInstanced, GLenum mode, GLsizei count, GLenum type, const void * indices, GLsizei primcount)
+GL_ENTRY(void, glDrawElementsInstancedDataAEMU, GLenum mode, GLsizei count, GLenum type, const void * indices, GLsizei primcount, GLsizei datalen)
+GL_ENTRY(void, glDrawElementsInstancedOffsetAEMU, GLenum mode, GLsizei count, GLenum type, GLuint offset, GLsizei primcount)
+
+
+# Draw with known index range
+GL_ENTRY(void, glDrawRangeElements, GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid * indices)
+GL_ENTRY(void, glDrawRangeElementsDataAEMU, GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid * indices, GLsizei datalen)
+GL_ENTRY(void, glDrawRangeElementsOffsetAEMU, GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, GLuint offset)
+
+# Sync - mostly implemented on host, just need encoder part
+GL_ENTRY(GLsync, glFenceSync, GLenum condition, GLbitfield flags)
+GL_ENTRY(GLenum, glClientWaitSync, GLsync wait_on, GLbitfield flags, GLuint64 timeout)
+GL_ENTRY(void, glWaitSync, GLsync wait_on, GLbitfield flags, GLuint64 timeout)
+GL_ENTRY(void, glDeleteSync, GLsync to_delete)
+GL_ENTRY(GLboolean, glIsSync, GLsync sync)
+GL_ENTRY(void, glGetSynciv, GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values)
+
+GL_ENTRY(uint64_t, glFenceSyncAEMU, GLenum condition, GLbitfield flags)
+GL_ENTRY(GLenum, glClientWaitSyncAEMU, uint64_t wait_on, GLbitfield flags, GLuint64 timeout)
+GL_ENTRY(void, glWaitSyncAEMU, uint64_t wait_on, GLbitfield flags, GLuint64 timeout)
+GL_ENTRY(void, glDeleteSyncAEMU, uint64_t to_delete)
+GL_ENTRY(GLboolean, glIsSyncAEMU, uint64_t sync)
+GL_ENTRY(void, glGetSyncivAEMU, uint64_t sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values)
+
+# MRT / MSAA render buffer
+GL_ENTRY(void, glDrawBuffers, GLsizei n, const GLenum *bufs);
+GL_ENTRY(void, glReadBuffer, GLenum src);
+GL_ENTRY(void, glBlitFramebuffer, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+
+# Not even implemented in host driver if < OpenGL 4.3.
+# But we should call this anyway if the function is available.
+GL_ENTRY(void, glInvalidateFramebuffer, GLenum target, GLsizei numAttachments, const GLenum *attachments)
+GL_ENTRY(void, glInvalidateSubFramebuffer, GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height)
+
+GL_ENTRY(void, glFramebufferTextureLayer, GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
+GL_ENTRY(void, glRenderbufferStorageMultisample, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+GL_ENTRY(void, glTexStorage2D, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+GL_ENTRY(void, glGetInternalformativ, GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params)
+
+# Transform feedback - share group processing in the last two
+GL_ENTRY(void, glBeginTransformFeedback, GLenum primitiveMode)
+GL_ENTRY(void, glEndTransformFeedback, void)
+GL_ENTRY(void, glGenTransformFeedbacks, GLsizei n, GLuint *ids)
+GL_ENTRY(void, glDeleteTransformFeedbacks, GLsizei n, const GLuint *ids)
+GL_ENTRY(void, glBindTransformFeedback, GLenum target, GLuint id)
+GL_ENTRY(void, glPauseTransformFeedback, void)
+GL_ENTRY(void, glResumeTransformFeedback, void)
+GL_ENTRY(GLboolean, glIsTransformFeedback, GLuint id)
+GL_ENTRY(void, glTransformFeedbackVaryings, GLuint program, GLsizei count, const GLchar*const* varyings, GLenum bufferMode)
+GL_ENTRY(void, glTransformFeedbackVaryingsAEMU, GLuint program, GLsizei count, const char* packedVaryings, GLuint packedVaryingsLen, GLenum bufferMode)
+GL_ENTRY(void, glGetTransformFeedbackVarying, GLuint program, GLuint index, GLsizei bufSize, GLsizei * length, GLsizei * size, GLenum * type, char * name)
+
+# Sampler objects
+GL_ENTRY(void, glGenSamplers, GLsizei n, GLuint *samplers)
+GL_ENTRY(void, glDeleteSamplers, GLsizei n, const GLuint * samplers)
+GL_ENTRY(void, glBindSampler, GLuint unit, GLuint sampler)
+GL_ENTRY(void, glSamplerParameterf, GLuint sampler, GLenum pname, GLfloat param)
+GL_ENTRY(void, glSamplerParameteri, GLuint sampler, GLenum pname, GLint param)
+GL_ENTRY(void, glSamplerParameterfv, GLuint sampler, GLenum pname, const GLfloat * params)
+GL_ENTRY(void, glSamplerParameteriv, GLuint sampler, GLenum pname, const GLint * params)
+GL_ENTRY(void, glGetSamplerParameterfv, GLuint sampler, GLenum pname, GLfloat * params)
+GL_ENTRY(void, glGetSamplerParameteriv, GLuint sampler, GLenum pname, GLint * params)
+GL_ENTRY(GLboolean, glIsSampler, GLuint sampler)
+
+# Query objects
+GL_ENTRY(void, glGenQueries, GLsizei n, GLuint * queries)
+GL_ENTRY(void, glDeleteQueries, GLsizei n, const GLuint * queries)
+GL_ENTRY(void, glBeginQuery, GLenum target, GLuint query)
+GL_ENTRY(void, glEndQuery, GLenum target)
+GL_ENTRY(void, glGetQueryiv, GLenum target, GLenum pname, GLint * params)
+GL_ENTRY(void, glGetQueryObjectuiv, GLuint query, GLenum pname, GLuint * params)
+GL_ENTRY(GLboolean, glIsQuery, GLuint query)
+
+# Shader binary objects - need share group processing
+GL_ENTRY(void, glProgramParameteri, GLuint program, GLenum pname, GLint value)
+GL_ENTRY(void, glProgramBinary, GLuint program, GLenum binaryFormat, const void *binary, GLsizei length)
+GL_ENTRY(void, glGetProgramBinary, GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary)
+
+# New glGets - need share group processing for program object
+GL_ENTRY(GLint, glGetFragDataLocation, GLuint program, const char * name)
+GL_ENTRY(void, glGetInteger64v, GLenum pname, GLint64 * data)
+GL_ENTRY(void, glGetIntegeri_v, GLenum target, GLuint index, GLint * data)
+GL_ENTRY(void, glGetInteger64i_v, GLenum target, GLuint index, GLint64 * data)
+
+# Array/3D textures
+GL_ENTRY(void, glTexImage3D, GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid * data)
+GL_ENTRY(void, glTexImage3DOffsetAEMU, GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, GLuint offset)
+GL_ENTRY(void, glTexStorage3D, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+GL_ENTRY(void, glTexSubImage3D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid * data);
+GL_ENTRY(void, glTexSubImage3DOffsetAEMU, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLuint offset);
+GL_ENTRY(void, glCompressedTexImage3D, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid * data)
+GL_ENTRY(void, glCompressedTexImage3DOffsetAEMU, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, GLuint offset)
+GL_ENTRY(void, glCompressedTexSubImage3D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid * data);
+GL_ENTRY(void, glCompressedTexSubImage3DOffsetAEMU, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, GLuint data);
+GL_ENTRY(void, glCopyTexSubImage3D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height)
+
+# glGetStringi
+GL_ENTRY(const GLubyte*, glGetStringi, GLenum name, GLuint index);
+
+# GLES 3.1:
+
+# New get
+GL_ENTRY(void, glGetBooleani_v, GLenum target, GLuint index, GLboolean * data)
+
+# Memory barriers
+GL_ENTRY(void, glMemoryBarrier, GLbitfield barriers);
+GL_ENTRY(void, glMemoryBarrierByRegion, GLbitfield barriers);
+
+# Program pipelines - may require adding a new shared object type!
+GL_ENTRY(void, glGenProgramPipelines, GLsizei n, GLuint *pipelines)
+GL_ENTRY(void, glDeleteProgramPipelines, GLsizei n, const GLuint *pipelines)
+GL_ENTRY(void, glBindProgramPipeline, GLuint pipeline)
+
+GL_ENTRY(void, glGetProgramPipelineiv, GLuint pipeline, GLenum pname, GLint *params)
+GL_ENTRY(void, glGetProgramPipelineInfoLog, GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog)
+
+GL_ENTRY(void, glValidateProgramPipeline, GLuint pipeline)
+GL_ENTRY(GLboolean, glIsProgramPipeline, GLuint pipeline);
+GL_ENTRY(void, glUseProgramStages, GLuint pipeline, GLbitfield stages, GLuint program)
+
+# Separable shader programs - may need to change how program objects are represented and shared!
+GL_ENTRY(void, glActiveShaderProgram, GLuint pipeline, GLuint program);
+GL_ENTRY(GLuint, glCreateShaderProgramv, GLenum type, GLsizei count, const GLchar*const* strings)
+GL_ENTRY(GLuint, glCreateShaderProgramvAEMU, GLenum type, GLsizei count, const char *packedStrings, GLuint packedLen)
+# Uniforms should work easily if any program object representation problems are solved.
+GL_ENTRY(void, glProgramUniform1f, GLuint program, GLint location, GLfloat v0)
+GL_ENTRY(void, glProgramUniform2f, GLuint program, GLint location, GLfloat v0, GLfloat v1)
+GL_ENTRY(void, glProgramUniform3f, GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2)
+GL_ENTRY(void, glProgramUniform4f, GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3)
+GL_ENTRY(void, glProgramUniform1i, GLuint program, GLint location, GLint v0)
+GL_ENTRY(void, glProgramUniform2i, GLuint program, GLint location, GLint v0, GLint v1)
+GL_ENTRY(void, glProgramUniform3i, GLuint program, GLint location, GLint v0, GLint v1, GLint v2)
+GL_ENTRY(void, glProgramUniform4i, GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3)
+GL_ENTRY(void, glProgramUniform1ui, GLuint program, GLint location, GLuint v0)
+GL_ENTRY(void, glProgramUniform2ui, GLuint program, GLint location, GLuint v0, GLuint v1)
+GL_ENTRY(void, glProgramUniform3ui, GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2)
+GL_ENTRY(void, glProgramUniform4ui, GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3)
+GL_ENTRY(void, glProgramUniform1fv, GLuint program, GLint location, GLsizei count, const GLfloat *value)
+GL_ENTRY(void, glProgramUniform2fv, GLuint program, GLint location, GLsizei count, const GLfloat *value)
+GL_ENTRY(void, glProgramUniform3fv, GLuint program, GLint location, GLsizei count, const GLfloat *value)
+GL_ENTRY(void, glProgramUniform4fv, GLuint program, GLint location, GLsizei count, const GLfloat *value)
+GL_ENTRY(void, glProgramUniform1iv, GLuint program, GLint location, GLsizei count, const GLint *value)
+GL_ENTRY(void, glProgramUniform2iv, GLuint program, GLint location, GLsizei count, const GLint *value)
+GL_ENTRY(void, glProgramUniform3iv, GLuint program, GLint location, GLsizei count, const GLint *value)
+GL_ENTRY(void, glProgramUniform4iv, GLuint program, GLint location, GLsizei count, const GLint *value)
+GL_ENTRY(void, glProgramUniform1uiv, GLuint program, GLint location, GLsizei count, const GLuint *value)
+GL_ENTRY(void, glProgramUniform2uiv, GLuint program, GLint location, GLsizei count, const GLuint *value)
+GL_ENTRY(void, glProgramUniform3uiv, GLuint program, GLint location, GLsizei count, const GLuint *value)
+GL_ENTRY(void, glProgramUniform4uiv, GLuint program, GLint location, GLsizei count, const GLuint *value)
+GL_ENTRY(void, glProgramUniformMatrix2fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+GL_ENTRY(void, glProgramUniformMatrix3fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+GL_ENTRY(void, glProgramUniformMatrix4fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+GL_ENTRY(void, glProgramUniformMatrix2x3fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+GL_ENTRY(void, glProgramUniformMatrix3x2fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+GL_ENTRY(void, glProgramUniformMatrix2x4fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+GL_ENTRY(void, glProgramUniformMatrix4x2fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+GL_ENTRY(void, glProgramUniformMatrix3x4fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+GL_ENTRY(void, glProgramUniformMatrix4x3fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+
+# Depending on whether ANGLE shader translator supports ES 3.1, this might require us to enhance the ANGLE shader translator by a LOT.
+GL_ENTRY(void, glGetProgramInterfaceiv, GLuint program, GLenum programInterface, GLenum pname, GLint * params)
+GL_ENTRY(void, glGetProgramResourceiv, GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum * props, GLsizei bufSize, GLsizei * length, GLint * params)
+GL_ENTRY(GLuint, glGetProgramResourceIndex, GLuint program, GLenum programInterface, const char * name)
+GL_ENTRY(GLint, glGetProgramResourceLocation, GLuint program, GLenum programInterface, const char * name)
+GL_ENTRY(void, glGetProgramResourceName, GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei * length, char * name)
+ 
+# Compute shaders. Should just work if everything else does.
+GL_ENTRY(void, glBindImageTexture, GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format)
+GL_ENTRY(void, glDispatchCompute, GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z)
+
+### This is an indirect call and the |indirect| field could be a GPU pointer.
+### We will need to make sure that |indirect| is updated to the latest version if so,
+### and probably manage a running set of GPU pointers on the host
+### that the guest is using.
+GL_ENTRY(void, glDispatchComputeIndirect, GLintptr indirect)
+
+# Separate vertex format / buffer binding
+### Requires us tp really clean up how draws work in the encoder currently.
+GL_ENTRY(void, glBindVertexBuffer, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride)
+GL_ENTRY(void, glVertexAttribBinding, GLuint attribindex, GLuint bindingindex);
+GL_ENTRY(void, glVertexAttribFormat, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset)
+GL_ENTRY(void, glVertexAttribIFormat, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset)
+GL_ENTRY(void, glVertexBindingDivisor, GLuint bindingindex, GLuint divisor)
+
+# Indirect draws
+### Again, if |indirect| is a GPU pointer, we need to synchronize it before calling.
+GL_ENTRY(void, glDrawArraysIndirect, GLenum mode, const void * indirect)
+GL_ENTRY(void, glDrawArraysIndirectDataAEMU, GLenum mode, const void *indirect, GLuint datalen)
+GL_ENTRY(void, glDrawArraysIndirectOffsetAEMU, GLenum mode, GLuint offset)
+GL_ENTRY(void, glDrawElementsIndirect, GLenum mode, GLenum type, const void * indirect)
+GL_ENTRY(void, glDrawElementsIndirectDataAEMU, GLenum mode, GLenum type, const void *indirect, GLuint datalen)
+GL_ENTRY(void, glDrawElementsIndirectOffsetAEMU, GLenum mode, GLenum type, GLuint offset)
+
+# Multisampling
+GL_ENTRY(void, glTexStorage2DMultisample, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations)
+GL_ENTRY(void, glSampleMaski, GLuint maskNumber, GLbitfield mask)
+GL_ENTRY(void, glGetMultisamplefv, GLenum pname, GLuint index, GLfloat *val)
+
+# New framebuffer parameters
+GL_ENTRY(void, glFramebufferParameteri, GLenum target, GLenum pname, GLint param)
+GL_ENTRY(void, glGetFramebufferParameteriv, GLenum target, GLenum pname, GLint * params)
+
+# Texture LOD queries    
+# Already used in Translator's validations, just need encoder.
+GL_ENTRY(void, glGetTexLevelParameterfv, GLenum target, GLint level, GLenum pname, GLfloat * params)
+GL_ENTRY(void, glGetTexLevelParameteriv, GLenum target, GLint level, GLenum pname, GLint * params)
diff --git a/host/libs/virglrenderer/GLESv3_dec/gles3.types b/host/libs/virglrenderer/GLESv3_dec/gles3.types
new file mode 100644
index 0000000000000000000000000000000000000000..2b39b29dc4916f3f4753d140646f6a7d84d67161
--- /dev/null
+++ b/host/libs/virglrenderer/GLESv3_dec/gles3.types
@@ -0,0 +1,50 @@
+GLbitfield 32 0x%08x
+GLboolean 8 %d
+GLclampf 32 %f
+GLclampx 32 0x%08x
+GLeglImageOES 32 %p
+GLenum 32 0x%08x
+GLfixed 32 0x%08x
+GLfloat 32 %f
+GLint 32 %d
+GLintptr 32 0x%08lx
+GLshort 16 %d
+GLsizei 32 %d
+GLsizeiptr 32 0x%08lx
+GLubyte 8 0x%02x
+GLuint 32 %u
+GLvoid 0 %x
+GLchar 8 %d
+GLenum* 32 0x%08x
+GLboolean* 32 0x%08x
+GLclampf* 32 0x%08x
+GLclampx* 32 0x%08x
+GLeglImageOES* 32 0x%08x
+GLfixed* 32 0x%08x
+GLfloat* 32 0x%08x
+GLint* 32 0x%08x
+GLshort* 32 0x%08x
+GLsizei* 32 0x%08x
+GLubyte* 32 0x%08x
+GLuint* 32 0x%08x
+GLvoid* 32 0x%08x
+GLchar* 32 0x%08x
+GLchar** 32 0x%08x
+GLvoid** 32 0x%08x
+void* 32 0x%08x
+GLstr* 32 0x%08x
+GLvoidptr* 32 0x%08x
+GLchar*const* 32 0x%08x
+GLvoid*const* 32 0x%08x
+GLsync 64 %p
+uint64_t 64 0x%016lx
+GLint32 32 0x%08x
+GLint32* 32 %p
+GLint64 64 0x%016lx
+GLint64* 32 %p
+GLuint32 32 0x%08x
+GLuint32* 32 %p
+GLuint64 64 0x%016lx
+GLuint64* 32 %p
+char* 32 0x%08x
+char** 32 0x%08x
diff --git a/host/libs/virglrenderer/GLESv3_dec/gles3_types.h b/host/libs/virglrenderer/GLESv3_dec/gles3_types.h
new file mode 100644
index 0000000000000000000000000000000000000000..3347b99238b46586c281833e6e3ba8c30987e9e4
--- /dev/null
+++ b/host/libs/virglrenderer/GLESv3_dec/gles3_types.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <GLES3/gl31.h>
+#include <GLES2/gl2ext.h>
diff --git a/host/libs/virglrenderer/Gralloc1.cpp b/host/libs/virglrenderer/Gralloc1.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a2fcd8147bb78e47470d7129ab7c4092112b94fb
--- /dev/null
+++ b/host/libs/virglrenderer/Gralloc1.cpp
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cstdint>
+
+extern "C" {
+#include "virgl_hw.h"
+}
+
+#include "Resource.h"
+
+#include <android/sync.h>
+#include <hardware/gralloc1.h>
+
+#include <cerrno>
+
+#define ALIGN(A, B) (((A) + (B)-1) / (B) * (B))
+
+static int gralloc1_device_open(const hw_module_t*, const char*, hw_device_t**);
+
+static hw_module_methods_t g_gralloc1_methods = {
+    .open = gralloc1_device_open,
+};
+
+static hw_module_t g_gralloc1_module = {
+    .tag = HARDWARE_MODULE_TAG,
+    .module_api_version = GRALLOC_MODULE_API_VERSION_1_0,
+    .hal_api_version = HARDWARE_HAL_API_VERSION,
+    .id = GRALLOC_HARDWARE_MODULE_ID,
+    .name = "AVDVirglRenderer",
+    .author = "Google",
+    .methods = &g_gralloc1_methods,
+};
+
+static int gralloc1_device_close(hw_device_t*) {
+    // No-op
+    return 0;
+}
+
+static void gralloc1_getCapabilities(gralloc1_device_t*, uint32_t* outCount, int32_t*) {
+    *outCount = 0U;
+}
+
+static int32_t gralloc1_lock(gralloc1_device_t*, buffer_handle_t buffer, uint64_t producerUsage,
+                             uint64_t consumerUsage, const gralloc1_rect_t* rect, void** outData,
+                             int32_t) {
+    uint32_t resource_id = (uint32_t) reinterpret_cast<uintptr_t>(buffer);
+    std::map<uint32_t, Resource*>::iterator it;
+    it = Resource::map.find(resource_id);
+    if (it == Resource::map.end())
+        return GRALLOC1_ERROR_BAD_HANDLE;
+
+    Resource* res = it->second;
+
+    // validate the lock rectangle
+    if (rect->width < 0 || rect->height < 0 || rect->left < 0 || rect->top < 0 ||
+        (uint32_t)rect->width + (uint32_t)rect->left > res->args.width ||
+        (uint32_t)rect->height + (uint32_t)rect->top > res->args.height) {
+        return GRALLOC1_ERROR_BAD_VALUE;
+    }
+
+    uint32_t bpp;
+    switch (res->args.format) {
+        case VIRGL_FORMAT_R8_UNORM:
+            bpp = 1U;
+            break;
+        case VIRGL_FORMAT_B5G6R5_UNORM:
+            bpp = 2U;
+            break;
+        default:
+            bpp = 4U;
+            break;
+    }
+    uint32_t stride = ALIGN(res->args.width * bpp, 16U);
+    *outData = (char*)res->linear + rect->top * stride + rect->left * bpp;
+    return GRALLOC1_ERROR_NONE;
+}
+
+static int32_t gralloc1_unlock(gralloc1_device_t*, buffer_handle_t buffer,
+                               int32_t* outReleaseFence) {
+    uint32_t resource_id = (uint32_t) reinterpret_cast<uintptr_t>(buffer);
+    std::map<uint32_t, Resource*>::iterator it;
+    it = Resource::map.find(resource_id);
+    if (it == Resource::map.end())
+        return GRALLOC1_ERROR_BAD_HANDLE;
+    if (outReleaseFence)
+        *outReleaseFence = -1;
+
+    return GRALLOC1_ERROR_NONE;
+}
+
+static gralloc1_function_pointer_t gralloc1_getFunction(gralloc1_device_t*, int32_t descriptor) {
+    switch (descriptor) {
+        case GRALLOC1_FUNCTION_LOCK:
+            return reinterpret_cast<gralloc1_function_pointer_t>(&gralloc1_lock);
+        case GRALLOC1_FUNCTION_UNLOCK:
+            return reinterpret_cast<gralloc1_function_pointer_t>(&gralloc1_unlock);
+        default:
+            return nullptr;
+    }
+}
+
+static gralloc1_device_t g_gralloc1_device = {
+    .common =
+        {
+            .tag = HARDWARE_DEVICE_TAG,
+            .module = &g_gralloc1_module,
+            .close = gralloc1_device_close,
+        },
+    .getCapabilities = gralloc1_getCapabilities,
+    .getFunction = gralloc1_getFunction,
+};
+
+static int gralloc1_device_open(const hw_module_t* module, const char* id, hw_device_t** device) {
+    if (module != &g_gralloc1_module)
+        return -EINVAL;
+    if (strcmp(id, g_gralloc1_module.id))
+        return -EINVAL;
+    *device = &g_gralloc1_device.common;
+    return 0;
+}
+
+int hw_get_module(const char* id, const hw_module_t** module) {
+    if (strcmp(id, g_gralloc1_module.id))
+        return -EINVAL;
+    *module = const_cast<const hw_module_t*>(&g_gralloc1_module);
+    return 0;
+}
+
+int sync_wait(int, int) {
+    return 0;
+}
diff --git a/host/libs/virglrenderer/OpenGLESDispatch/EGLDispatch.cpp b/host/libs/virglrenderer/OpenGLESDispatch/EGLDispatch.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..40cf7fc37fe0b46763500ada6ca9721ff6017ac4
--- /dev/null
+++ b/host/libs/virglrenderer/OpenGLESDispatch/EGLDispatch.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <OpenGLESDispatch/EGLDispatch.h>
+
+#include <dlfcn.h>
+#include <stdio.h>
+
+EGLDispatch s_egl;
+
+#define DEFAULT_EGL_LIB "libEGL_swiftshader.so"
+
+#define EGL_LOAD_FIELD(return_type, function_name, signature, callargs) \
+    s_egl.function_name = (function_name##_t)dlsym(handle, #function_name);
+
+#define EGL_LOAD_FIELD_WITH_EGL(return_type, function_name, signature, callargs) \
+    if ((!s_egl.function_name) && s_egl.eglGetProcAddress)                       \
+        s_egl.function_name = (function_name##_t)s_egl.eglGetProcAddress(#function_name);
+
+#define EGL_LOAD_OPTIONAL_FIELD(return_type, function_name, signature, callargs)          \
+    if (s_egl.eglGetProcAddress)                                                          \
+        s_egl.function_name = (function_name##_t)s_egl.eglGetProcAddress(#function_name); \
+    if (!s_egl.function_name || !s_egl.eglGetProcAddress)                                 \
+    EGL_LOAD_FIELD(return_type, function_name, signature, callargs)
+
+bool egl_dispatch_init() {
+    void* handle = dlopen(DEFAULT_EGL_LIB, RTLD_NOW);
+    if (!handle) {
+        printf("Failed to open %s\n", dlerror());
+        return false;
+    }
+
+    LIST_EGL_FUNCTIONS(EGL_LOAD_FIELD)
+    LIST_EGL_FUNCTIONS(EGL_LOAD_FIELD_WITH_EGL)
+    LIST_EGL_EXTENSIONS_FUNCTIONS(EGL_LOAD_OPTIONAL_FIELD)
+
+    return true;
+}
diff --git a/host/libs/virglrenderer/OpenGLESDispatch/EGLDispatch.h b/host/libs/virglrenderer/OpenGLESDispatch/EGLDispatch.h
new file mode 100644
index 0000000000000000000000000000000000000000..13c60787370a749ba1adbc2610e3352313e9b656
--- /dev/null
+++ b/host/libs/virglrenderer/OpenGLESDispatch/EGLDispatch.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include <egl_functions.h>
+#include <egl_extensions_functions.h>
+
+#define EGL_DEFINE_TYPE(return_type, function_name, signature, callargs) \
+    typedef return_type(EGLAPIENTRY* function_name##_t) signature;
+
+#define EGL_DECLARE_MEMBER(return_type, function_name, signature, callargs) \
+    function_name##_t function_name;
+
+LIST_EGL_FUNCTIONS(EGL_DEFINE_TYPE)
+LIST_EGL_EXTENSIONS_FUNCTIONS(EGL_DEFINE_TYPE)
+
+struct EGLDispatch {
+    LIST_EGL_FUNCTIONS(EGL_DECLARE_MEMBER)
+    LIST_EGL_EXTENSIONS_FUNCTIONS(EGL_DECLARE_MEMBER)
+};
+
+bool egl_dispatch_init();
+
+extern EGLDispatch s_egl;
diff --git a/host/libs/virglrenderer/OpenGLESDispatch/GLESv1Dispatch.cpp b/host/libs/virglrenderer/OpenGLESDispatch/GLESv1Dispatch.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..fd25afc5d28a544dcf50b7a08f1f8c5c9e30417b
--- /dev/null
+++ b/host/libs/virglrenderer/OpenGLESDispatch/GLESv1Dispatch.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <OpenGLESDispatch/EGLDispatch.h>
+#include <OpenGLESDispatch/GLESv1Dispatch.h>
+
+#include <dlfcn.h>
+#include <stdio.h>
+
+#define DEFAULT_GLES_CM_LIB "libGLES_CM_swiftshader.so"
+
+GLESv1Dispatch s_gles1;
+
+#define LOOKUP_SYMBOL(return_type, function_name, signature, callargs)        \
+    s_gles1.function_name = (function_name##_t)dlsym(handle, #function_name); \
+    if ((!s_gles1.function_name) && s_egl.eglGetProcAddress)                  \
+        s_gles1.function_name = (function_name##_t)s_egl.eglGetProcAddress(#function_name);
+
+bool gles1_dispatch_init() {
+    void* handle = dlopen(DEFAULT_GLES_CM_LIB, RTLD_NOW);
+    if (!handle) {
+        printf("Failed to open %s\n", dlerror());
+        return false;
+    }
+
+    LIST_GLES1_FUNCTIONS(LOOKUP_SYMBOL, LOOKUP_SYMBOL)
+
+    return true;
+}
diff --git a/host/libs/virglrenderer/OpenGLESDispatch/GLESv1Dispatch.h b/host/libs/virglrenderer/OpenGLESDispatch/GLESv1Dispatch.h
new file mode 100644
index 0000000000000000000000000000000000000000..b65b83cdcb8fb27df2293cb5b6134d1d0010eeba
--- /dev/null
+++ b/host/libs/virglrenderer/OpenGLESDispatch/GLESv1Dispatch.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <GLES/gl.h>
+
+#include <OpenGLESDispatch/gles_functions.h>
+
+#define GLES1_DISPATCH_DEFINE_TYPE(return_type, func_name, signature, callargs) \
+    typedef return_type(KHRONOS_APIENTRY* func_name##_t) signature;
+
+#define GLES1_DISPATCH_DECLARE_POINTER(return_type, func_name, signature, callargs) \
+    func_name##_t func_name;
+
+LIST_GLES1_FUNCTIONS(GLES1_DISPATCH_DEFINE_TYPE, GLES1_DISPATCH_DEFINE_TYPE)
+
+struct GLESv1Dispatch {
+    LIST_GLES1_FUNCTIONS(GLES1_DISPATCH_DECLARE_POINTER, GLES1_DISPATCH_DECLARE_POINTER)
+};
+
+#undef GLES1_DISPATCH_DEFINE_TYPE
+#undef GLES1_DISPATCH_DECLARE_POINTER
+
+bool gles1_dispatch_init();
+
+extern GLESv1Dispatch s_gles1;
diff --git a/host/libs/virglrenderer/OpenGLESDispatch/GLESv3Dispatch.cpp b/host/libs/virglrenderer/OpenGLESDispatch/GLESv3Dispatch.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4aaa5180c45d35602a5f099d70f1e59cb6a7a19e
--- /dev/null
+++ b/host/libs/virglrenderer/OpenGLESDispatch/GLESv3Dispatch.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <OpenGLESDispatch/EGLDispatch.h>
+#include <OpenGLESDispatch/GLESv3Dispatch.h>
+
+#include <dlfcn.h>
+#include <stdio.h>
+
+#define DEFAULT_GLESv2_LIB "libGLESv2_swiftshader.so"
+
+GLESv3Dispatch s_gles3;
+
+#define LOOKUP_SYMBOL(return_type, function_name, signature, callargs)        \
+    s_gles3.function_name = (function_name##_t)dlsym(handle, #function_name); \
+    if ((!s_gles3.function_name) && s_egl.eglGetProcAddress)                  \
+        s_gles3.function_name = (function_name##_t)s_egl.eglGetProcAddress(#function_name);
+
+bool gles3_dispatch_init() {
+    void* handle = dlopen(DEFAULT_GLESv2_LIB, RTLD_NOW);
+    if (!handle) {
+        printf("Failed to open %s\n", dlerror());
+        return false;
+    }
+
+    LIST_GLES3_FUNCTIONS(LOOKUP_SYMBOL, LOOKUP_SYMBOL)
+
+    return true;
+}
diff --git a/host/libs/virglrenderer/OpenGLESDispatch/GLESv3Dispatch.h b/host/libs/virglrenderer/OpenGLESDispatch/GLESv3Dispatch.h
new file mode 100644
index 0000000000000000000000000000000000000000..afdd0007d4bcec527998926cccb9fb42184a5c00
--- /dev/null
+++ b/host/libs/virglrenderer/OpenGLESDispatch/GLESv3Dispatch.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <GLES3/gl31.h>
+
+#include <OpenGLESDispatch/gles_functions.h>
+
+// Define function pointer types.
+#define GLES3_DISPATCH_DEFINE_TYPE(return_type, func_name, signature, callargs) \
+    typedef return_type(KHRONOS_APIENTRY* func_name##_t) signature;
+
+#define GLES3_DISPATCH_DECLARE_POINTER(return_type, func_name, signature, callargs) \
+    func_name##_t func_name;
+
+LIST_GLES3_FUNCTIONS(GLES3_DISPATCH_DEFINE_TYPE, GLES3_DISPATCH_DEFINE_TYPE)
+
+struct GLESv3Dispatch {
+    LIST_GLES3_FUNCTIONS(GLES3_DISPATCH_DECLARE_POINTER, GLES3_DISPATCH_DECLARE_POINTER)
+};
+
+#undef GLES3_DISPATCH_DEFINE_TYPE
+#undef GLES3_DISPATCH_DECLARE_POINTER
+
+bool gles3_dispatch_init();
+
+extern GLESv3Dispatch s_gles3;
diff --git a/host/libs/virglrenderer/OpenGLESDispatch/egl.entries b/host/libs/virglrenderer/OpenGLESDispatch/egl.entries
new file mode 100644
index 0000000000000000000000000000000000000000..46d4c0dd8bb9ecbe24fdabcdc7d234839bfa5265
--- /dev/null
+++ b/host/libs/virglrenderer/OpenGLESDispatch/egl.entries
@@ -0,0 +1,44 @@
+!egl
+
+%#include <EGL/egl.h>
+
+%// Return types must be single words, see GLDispatch.cpp
+%typedef const char* EGLconstcharptr;
+
+EGLBoolean eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config);
+EGLBoolean eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target);
+EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list);
+EGLSurface eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list);
+EGLSurface eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list);
+EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list);
+EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx);
+EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface);
+EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value);
+EGLBoolean eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config);
+EGLDisplay eglGetCurrentDisplay(void);
+EGLSurface eglGetCurrentSurface(EGLint readdraw);
+EGLDisplay eglGetDisplay(EGLNativeDisplayType display_id);
+EGLint eglGetError(void);
+void* eglGetProcAddress(const char *procname);
+EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor);
+EGLBoolean eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);
+EGLBoolean eglQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value);
+EGLconstcharptr eglQueryString(EGLDisplay dpy, EGLint name);
+EGLBoolean eglQuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value);
+EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface surface);
+EGLBoolean eglTerminate(EGLDisplay dpy);
+EGLBoolean eglWaitGL(void);
+EGLBoolean eglWaitNative(EGLint engine);
+
+EGLBoolean eglBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer);
+EGLBoolean eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer);
+EGLBoolean eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value);
+EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval);
+
+EGLBoolean eglBindAPI(EGLenum api);
+EGLenum eglQueryAPI(void);
+EGLSurface eglCreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list);
+EGLBoolean eglReleaseThread(void);
+EGLBoolean eglWaitClient(void);
+
+EGLContext eglGetCurrentContext(void);
diff --git a/host/libs/virglrenderer/OpenGLESDispatch/egl_extensions.entries b/host/libs/virglrenderer/OpenGLESDispatch/egl_extensions.entries
new file mode 100644
index 0000000000000000000000000000000000000000..e1e0bc7ded4c98e7adf257f1f512d0b216177d65
--- /dev/null
+++ b/host/libs/virglrenderer/OpenGLESDispatch/egl_extensions.entries
@@ -0,0 +1,11 @@
+!egl_extensions
+
+%#include <EGL/eglext.h>
+
+EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list);
+EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync);
+EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout);
+EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value);
+
+EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
+EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR image);
diff --git a/host/libs/virglrenderer/OpenGLESDispatch/gles1_core.entries b/host/libs/virglrenderer/OpenGLESDispatch/gles1_core.entries
new file mode 100644
index 0000000000000000000000000000000000000000..8c7f95376499fddfafdc084d2512eea1f5e188a1
--- /dev/null
+++ b/host/libs/virglrenderer/OpenGLESDispatch/gles1_core.entries
@@ -0,0 +1,153 @@
+!gles1_core
+
+%#include <GLES/gl.h>
+
+%// Return types must be single words, see GLDispatch.cpp
+%typedef const GLubyte* GL1constubyteptr;
+
+void glAlphaFunc(GLenum func, GLclampf ref);
+void glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+void glClearDepthf(GLclampf depth);
+void glClipPlanef(GLenum plane, const GLfloat *equation);
+void glColor4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
+void glDepthRangef(GLclampf zNear, GLclampf zFar);
+void glFogf(GLenum pname, GLfloat param);
+void glFogfv(GLenum pname, const GLfloat *params);
+void glFrustumf(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar);
+void glGetClipPlanef(GLenum pname, GLfloat *eqn);
+void glGetFloatv(GLenum pname, GLfloat *params);
+void glGetLightfv(GLenum light, GLenum pname, GLfloat *params);
+void glGetMaterialfv(GLenum face, GLenum pname, GLfloat *params);
+void glGetTexEnvfv(GLenum env, GLenum pname, GLfloat *params);
+void glGetTexParameterfv(GLenum target, GLenum pname, GLfloat *params);
+void glLightModelf(GLenum pname, GLfloat param);
+void glLightModelfv(GLenum pname, const GLfloat *params);
+void glLightf(GLenum light, GLenum pname, GLfloat param);
+void glLightfv(GLenum light, GLenum pname, const GLfloat *params);
+void glLineWidth(GLfloat width);
+void glLoadMatrixf(const GLfloat *m);
+void glMaterialf(GLenum face, GLenum pname, GLfloat param);
+void glMaterialfv(GLenum face, GLenum pname, const GLfloat *params);
+void glMultMatrixf(const GLfloat *m);
+void glMultiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);
+void glNormal3f(GLfloat nx, GLfloat ny, GLfloat nz);
+void glOrthof(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar);
+void glPointParameterf(GLenum pname, GLfloat param);
+void glPointParameterfv(GLenum pname, const GLfloat *params);
+void glPointSize(GLfloat size);
+void glPolygonOffset(GLfloat factor, GLfloat units);
+void glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z);
+void glScalef(GLfloat x, GLfloat y, GLfloat z);
+void glTexEnvf(GLenum target, GLenum pname, GLfloat param);
+void glTexEnvfv(GLenum target, GLenum pname, const GLfloat *params);
+void glTexParameterf(GLenum target, GLenum pname, GLfloat param);
+void glTexParameterfv(GLenum target, GLenum pname, const GLfloat *params);
+void glTranslatef(GLfloat x, GLfloat y, GLfloat z);
+void glActiveTexture(GLenum texture);
+void glAlphaFuncx(GLenum func, GLclampx ref);
+void glBindBuffer(GLenum target, GLuint buffer);
+void glBindTexture(GLenum target, GLuint texture);
+void glBlendFunc(GLenum sfactor, GLenum dfactor);
+void glBufferData(GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage);
+void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data);
+void glClear(GLbitfield mask);
+void glClearColorx(GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha);
+void glClearDepthx(GLclampx depth);
+void glClearStencil(GLint s);
+void glClientActiveTexture(GLenum texture);
+void glClipPlanex(GLenum plane, const GLfixed *equation);
+void glColor4ub(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha);
+void glColor4x(GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);
+void glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
+void glColorPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+void glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data);
+void glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data);
+void glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+void glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+void glCullFace(GLenum mode);
+void glDeleteBuffers(GLsizei n, const GLuint *buffers);
+void glDeleteTextures(GLsizei n, const GLuint *textures);
+void glDepthFunc(GLenum func);
+void glDepthMask(GLboolean flag);
+void glDepthRangex(GLclampx zNear, GLclampx zFar);
+void glDisable(GLenum cap);
+void glDisableClientState(GLenum array);
+void glDrawArrays(GLenum mode, GLint first, GLsizei count);
+void glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices);
+void glEnable(GLenum cap);
+void glEnableClientState(GLenum array);
+void glFinish(void);
+void glFlush(void);
+void glFogx(GLenum pname, GLfixed param);
+void glFogxv(GLenum pname, const GLfixed *params);
+void glFrontFace(GLenum mode);
+void glFrustumx(GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar);
+void glGetBooleanv(GLenum pname, GLboolean *params);
+void glGetBufferParameteriv(GLenum target, GLenum pname, GLint *params);
+void glGetClipPlanex(GLenum pname, GLfixed *eqn);
+void glGenBuffers(GLsizei n, GLuint *buffers);
+void glGenTextures(GLsizei n, GLuint *textures);
+GLenum glGetError(void);
+void glGetFixedv(GLenum pname, GLfixed *params);
+void glGetIntegerv(GLenum pname, GLint *params);
+void glGetLightxv(GLenum light, GLenum pname, GLfixed *params);
+void glGetMaterialxv(GLenum face, GLenum pname, GLfixed *params);
+void glGetPointerv(GLenum pname, GLvoid **params);
+GL1constubyteptr glGetString(GLenum name);
+void glGetTexEnviv(GLenum env, GLenum pname, GLint *params);
+void glGetTexEnvxv(GLenum env, GLenum pname, GLfixed *params);
+void glGetTexParameteriv(GLenum target, GLenum pname, GLint *params);
+void glGetTexParameterxv(GLenum target, GLenum pname, GLfixed *params);
+void glHint(GLenum target, GLenum mode);
+GLboolean glIsBuffer(GLuint buffer);
+GLboolean glIsEnabled(GLenum cap);
+GLboolean glIsTexture(GLuint texture);
+void glLightModelx(GLenum pname, GLfixed param);
+void glLightModelxv(GLenum pname, const GLfixed *params);
+void glLightx(GLenum light, GLenum pname, GLfixed param);
+void glLightxv(GLenum light, GLenum pname, const GLfixed *params);
+void glLineWidthx(GLfixed width);
+void glLoadIdentity(void);
+void glLoadMatrixx(const GLfixed *m);
+void glLogicOp(GLenum opcode);
+void glMaterialx(GLenum face, GLenum pname, GLfixed param);
+void glMaterialxv(GLenum face, GLenum pname, const GLfixed *params);
+void glMatrixMode(GLenum mode);
+void glMultMatrixx(const GLfixed *m);
+void glMultiTexCoord4x(GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q);
+void glNormal3x(GLfixed nx, GLfixed ny, GLfixed nz);
+void glNormalPointer(GLenum type, GLsizei stride, const GLvoid *pointer);
+void glOrthox(GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar);
+void glPixelStorei(GLenum pname, GLint param);
+void glPointParameterx(GLenum pname, GLfixed param);
+void glPointParameterxv(GLenum pname, const GLfixed *params);
+void glPointSizex(GLfixed size);
+void glPolygonOffsetx(GLfixed factor, GLfixed units);
+void glPopMatrix(void);
+void glPushMatrix(void);
+void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels);
+void glRotatex(GLfixed angle, GLfixed x, GLfixed y, GLfixed z);
+void glSampleCoverage(GLclampf value, GLboolean invert);
+void glSampleCoveragex(GLclampx value, GLboolean invert);
+void glScalex(GLfixed x, GLfixed y, GLfixed z);
+void glScissor(GLint x, GLint y, GLsizei width, GLsizei height);
+void glShadeModel(GLenum mode);
+void glStencilFunc(GLenum func, GLint ref, GLuint mask);
+void glStencilMask(GLuint mask);
+void glStencilOp(GLenum fail, GLenum zfail, GLenum zpass);
+void glTexCoordPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+void glTexEnvi(GLenum target, GLenum pname, GLint param);
+void glTexEnvx(GLenum target, GLenum pname, GLfixed param);
+void glTexEnviv(GLenum target, GLenum pname, const GLint *params);
+void glTexEnvxv(GLenum target, GLenum pname, const GLfixed *params);
+void glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
+void glTexParameteri(GLenum target, GLenum pname, GLint param);
+void glTexParameterx(GLenum target, GLenum pname, GLfixed param);
+void glTexParameteriv(GLenum target, GLenum pname, const GLint *params);
+void glTexParameterxv(GLenum target, GLenum pname, const GLfixed *params);
+void glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
+void glTranslatex(GLfixed x, GLfixed y, GLfixed z);
+void glVertexPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+void glViewport(GLint x, GLint y, GLsizei width, GLsizei height);
+
+void glPointSizePointerOES(GLenum type, GLsizei stride, const GLvoid *pointer);
diff --git a/host/libs/virglrenderer/OpenGLESDispatch/gles1_extensions.entries b/host/libs/virglrenderer/OpenGLESDispatch/gles1_extensions.entries
new file mode 100644
index 0000000000000000000000000000000000000000..a2e990acf2798089525b6f4a7090092c03179bf5
--- /dev/null
+++ b/host/libs/virglrenderer/OpenGLESDispatch/gles1_extensions.entries
@@ -0,0 +1,35 @@
+!gles1_extensions
+
+%#include <GLES/glext.h>
+
+void glBlendEquationSeparateOES(GLenum modeRGB, GLenum modeAlpha);
+void glBlendFuncSeparateOES(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
+void glBlendEquationOES(GLenum mode);
+
+void glDrawTexsOES(GLshort x, GLshort y, GLshort z, GLshort width, GLshort height);
+void glDrawTexiOES(GLint x, GLint y, GLint z, GLint width, GLint height);
+void glDrawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed width, GLfixed height);
+void glDrawTexsvOES(const GLshort *coords);
+void glDrawTexivOES(const GLint *coords);
+void glDrawTexxvOES(const GLfixed *coords);
+void glDrawTexfOES(GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height);
+void glDrawTexfvOES(const GLfloat *coords);
+
+void glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image);
+void glEGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image);
+
+GLboolean glIsRenderbufferOES(GLuint renderbuffer);
+void glBindRenderbufferOES(GLenum target, GLuint renderbuffer);
+void glDeleteRenderbuffersOES(GLsizei n, const GLuint* renderbuffers);
+void glGenRenderbuffersOES(GLsizei n, GLuint* renderbuffers);
+void glRenderbufferStorageOES(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+void glGetRenderbufferParameterivOES(GLenum target, GLenum pname, GLint* params);
+GLboolean glIsFramebufferOES(GLuint framebuffer);
+void glBindFramebufferOES(GLenum target, GLuint framebuffer);
+void glDeleteFramebuffersOES(GLsizei n, const GLuint* framebuffers);
+void glGenFramebuffersOES(GLsizei n, GLuint* framebuffers);
+GLenum glCheckFramebufferStatusOES(GLenum target);
+void glFramebufferRenderbufferOES(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+void glFramebufferTexture2DOES(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+void glGetFramebufferAttachmentParameterivOES(GLenum target, GLenum attachment, GLenum pname, GLint* params);
+void glGenerateMipmapOES(GLenum target);
diff --git a/host/libs/virglrenderer/OpenGLESDispatch/gles2_core.entries b/host/libs/virglrenderer/OpenGLESDispatch/gles2_core.entries
new file mode 100644
index 0000000000000000000000000000000000000000..6cab5f8fa1d26598ba4a2150ac0903e7b990b63a
--- /dev/null
+++ b/host/libs/virglrenderer/OpenGLESDispatch/gles2_core.entries
@@ -0,0 +1,146 @@
+!gles2_core
+
+%#include <GLES3/gl31.h>
+
+void glActiveTexture(GLenum texture);
+void glAttachShader(GLuint program, GLuint shader);
+void glBindAttribLocation(GLuint program, GLuint index, const GLchar *name);
+void glBindBuffer(GLenum target, GLuint buffer);
+void glBindFramebuffer(GLenum target, GLuint framebuffer);
+void glBindRenderbuffer(GLenum target, GLuint renderbuffer);
+void glBindTexture(GLenum target, GLuint texture);
+void glBlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
+void glBlendEquation(GLenum mode);
+void glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha);
+void glBlendFunc(GLenum sfactor, GLenum dfactor);
+void glBlendFuncSeparate(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
+void glBufferData(GLenum target, GLsizeiptr size, const void *data, GLenum usage);
+void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const void *data);
+GLenum glCheckFramebufferStatus(GLenum target);
+void glClear(GLbitfield mask);
+void glClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
+void glClearDepthf(GLfloat d);
+void glClearStencil(GLint s);
+void glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
+void glCompileShader(GLuint shader);
+void glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data);
+void glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data);
+void glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+void glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+GLuint glCreateProgram(void);
+GLuint glCreateShader(GLenum type);
+void glCullFace(GLenum mode);
+void glDeleteBuffers(GLsizei n, const GLuint *buffers);
+void glDeleteFramebuffers(GLsizei n, const GLuint *framebuffers);
+void glDeleteProgram(GLuint program);
+void glDeleteRenderbuffers(GLsizei n, const GLuint *renderbuffers);
+void glDeleteShader(GLuint shader);
+void glDeleteTextures(GLsizei n, const GLuint *textures);
+void glDepthFunc(GLenum func);
+void glDepthMask(GLboolean flag);
+void glDepthRangef(GLfloat n, GLfloat f);
+void glDetachShader(GLuint program, GLuint shader);
+void glDisable(GLenum cap);
+void glDisableVertexAttribArray(GLuint index);
+void glDrawArrays(GLenum mode, GLint first, GLsizei count);
+void glDrawElements(GLenum mode, GLsizei count, GLenum type, const void *indices);
+void glEnable(GLenum cap);
+void glEnableVertexAttribArray(GLuint index);
+void glFinish(void);
+void glFlush(void);
+void glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+void glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+void glFrontFace(GLenum mode);
+void glGenBuffers(GLsizei n, GLuint *buffers);
+void glGenerateMipmap(GLenum target);
+void glGenFramebuffers(GLsizei n, GLuint *framebuffers);
+void glGenRenderbuffers(GLsizei n, GLuint *renderbuffers);
+void glGenTextures(GLsizei n, GLuint *textures);
+void glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);
+void glGetActiveUniform(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);
+void glGetAttachedShaders(GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders);
+GLint glGetAttribLocation(GLuint program, const GLchar *name);
+void glGetBooleanv(GLenum pname, GLboolean *data);
+void glGetBufferParameteriv(GLenum target, GLenum pname, GLint *params);
+GLenum glGetError(void);
+void glGetFloatv(GLenum pname, GLfloat *data);
+void glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint *params);
+void glGetIntegerv(GLenum pname, GLint *data);
+void glGetProgramiv(GLuint program, GLenum pname, GLint *params);
+void glGetProgramInfoLog(GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+void glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint *params);
+void glGetShaderiv(GLuint shader, GLenum pname, GLint *params);
+void glGetShaderInfoLog(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+void glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision);
+void glGetShaderSource(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source);
+const GLubyte *glGetString(GLenum name);
+void glGetTexParameterfv(GLenum target, GLenum pname, GLfloat *params);
+void glGetTexParameteriv(GLenum target, GLenum pname, GLint *params);
+void glGetUniformfv(GLuint program, GLint location, GLfloat *params);
+void glGetUniformiv(GLuint program, GLint location, GLint *params);
+GLint glGetUniformLocation(GLuint program, const GLchar *name);
+void glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat *params);
+void glGetVertexAttribiv(GLuint index, GLenum pname, GLint *params);
+void glGetVertexAttribPointerv(GLuint index, GLenum pname, void **pointer);
+void glHint(GLenum target, GLenum mode);
+GLboolean glIsBuffer(GLuint buffer);
+GLboolean glIsEnabled(GLenum cap);
+GLboolean glIsFramebuffer(GLuint framebuffer);
+GLboolean glIsProgram(GLuint program);
+GLboolean glIsRenderbuffer(GLuint renderbuffer);
+GLboolean glIsShader(GLuint shader);
+GLboolean glIsTexture(GLuint texture);
+void glLineWidth(GLfloat width);
+void glLinkProgram(GLuint program);
+void glPixelStorei(GLenum pname, GLint param);
+void glPolygonOffset(GLfloat factor, GLfloat units);
+void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels);
+void glReleaseShaderCompiler(void);
+void glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+void glSampleCoverage(GLfloat value, GLboolean invert);
+void glScissor(GLint x, GLint y, GLsizei width, GLsizei height);
+void glShaderBinary(GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length);
+void glShaderSource(GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length);
+void glStencilFunc(GLenum func, GLint ref, GLuint mask);
+void glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask);
+void glStencilMask(GLuint mask);
+void glStencilMaskSeparate(GLenum face, GLuint mask);
+void glStencilOp(GLenum fail, GLenum zfail, GLenum zpass);
+void glStencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);
+void glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels);
+void glTexParameterf(GLenum target, GLenum pname, GLfloat param);
+void glTexParameterfv(GLenum target, GLenum pname, const GLfloat *params);
+void glTexParameteri(GLenum target, GLenum pname, GLint param);
+void glTexParameteriv(GLenum target, GLenum pname, const GLint *params);
+void glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);
+void glUniform1f(GLint location, GLfloat v0);
+void glUniform1fv(GLint location, GLsizei count, const GLfloat *value);
+void glUniform1i(GLint location, GLint v0);
+void glUniform1iv(GLint location, GLsizei count, const GLint *value);
+void glUniform2f(GLint location, GLfloat v0, GLfloat v1);
+void glUniform2fv(GLint location, GLsizei count, const GLfloat *value);
+void glUniform2i(GLint location, GLint v0, GLint v1);
+void glUniform2iv(GLint location, GLsizei count, const GLint *value);
+void glUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
+void glUniform3fv(GLint location, GLsizei count, const GLfloat *value);
+void glUniform3i(GLint location, GLint v0, GLint v1, GLint v2);
+void glUniform3iv(GLint location, GLsizei count, const GLint *value);
+void glUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
+void glUniform4fv(GLint location, GLsizei count, const GLfloat *value);
+void glUniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
+void glUniform4iv(GLint location, GLsizei count, const GLint *value);
+void glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+void glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+void glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+void glUseProgram(GLuint program);
+void glValidateProgram(GLuint program);
+void glVertexAttrib1f(GLuint index, GLfloat x);
+void glVertexAttrib1fv(GLuint index, const GLfloat *v);
+void glVertexAttrib2f(GLuint index, GLfloat x, GLfloat y);
+void glVertexAttrib2fv(GLuint index, const GLfloat *v);
+void glVertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z);
+void glVertexAttrib3fv(GLuint index, const GLfloat *v);
+void glVertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+void glVertexAttrib4fv(GLuint index, const GLfloat *v);
+void glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
+void glViewport(GLint x, GLint y, GLsizei width, GLsizei height);
diff --git a/host/libs/virglrenderer/OpenGLESDispatch/gles2_extensions.entries b/host/libs/virglrenderer/OpenGLESDispatch/gles2_extensions.entries
new file mode 100644
index 0000000000000000000000000000000000000000..1453e874400eb5167f32fbca2e052643d66bb4da
--- /dev/null
+++ b/host/libs/virglrenderer/OpenGLESDispatch/gles2_extensions.entries
@@ -0,0 +1,20 @@
+!gles2_extensions
+
+%#include <GLES2/gl2ext.h>
+
+void glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image);
+void glEGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image);
+
+void glTexImage3DOES(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels);
+void glTexSubImage3DOES(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels);
+void glCopyTexSubImage3DOES(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+void glCompressedTexImage3DOES(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data);
+void glCompressedTexSubImage3DOES(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data);
+void glFramebufferTexture3DOES(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
+
+void glDrawBuffersEXT(GLsizei n, const GLenum *bufs);
+
+void glDrawArraysInstancedEXT(GLenum mode, GLint start, GLsizei count, GLsizei primcount);
+void glDrawElementsInstancedEXT(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount);
+
+void glVertexAttribDivisorEXT(GLuint index, GLuint divisor);
diff --git a/host/libs/virglrenderer/OpenGLESDispatch/gles31_only.entries b/host/libs/virglrenderer/OpenGLESDispatch/gles31_only.entries
new file mode 100644
index 0000000000000000000000000000000000000000..53cc1e1991783012e60d63f7af4bc58ef9ccee20
--- /dev/null
+++ b/host/libs/virglrenderer/OpenGLESDispatch/gles31_only.entries
@@ -0,0 +1,72 @@
+!gles31_only
+
+%#include <GLES3/gl31.h>
+
+void glDispatchCompute(GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z);
+void glDispatchComputeIndirect(GLintptr indirect);
+void glDrawArraysIndirect(GLenum mode, const void *indirect);
+void glDrawElementsIndirect(GLenum mode, GLenum type, const void *indirect);
+void glFramebufferParameteri(GLenum target, GLenum pname, GLint param);
+void glGetFramebufferParameteriv(GLenum target, GLenum pname, GLint *params);
+void glGetProgramInterfaceiv(GLuint program, GLenum programInterface, GLenum pname, GLint *params);
+GLuint glGetProgramResourceIndex(GLuint program, GLenum programInterface, const GLchar *name);
+void glGetProgramResourceName(GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name);
+void glGetProgramResourceiv(GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLint *params);
+GLint glGetProgramResourceLocation(GLuint program, GLenum programInterface, const GLchar *name);
+void glUseProgramStages(GLuint pipeline, GLbitfield stages, GLuint program);
+void glActiveShaderProgram(GLuint pipeline, GLuint program);
+GLuint glCreateShaderProgramv(GLenum type, GLsizei count, const GLchar *const*strings);
+void glBindProgramPipeline(GLuint pipeline);
+void glDeleteProgramPipelines(GLsizei n, const GLuint *pipelines);
+void glGenProgramPipelines(GLsizei n, GLuint *pipelines);
+GLboolean glIsProgramPipeline(GLuint pipeline);
+void glGetProgramPipelineiv(GLuint pipeline, GLenum pname, GLint *params);
+void glProgramUniform1i(GLuint program, GLint location, GLint v0);
+void glProgramUniform2i(GLuint program, GLint location, GLint v0, GLint v1);
+void glProgramUniform3i(GLuint program, GLint location, GLint v0, GLint v1, GLint v2);
+void glProgramUniform4i(GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
+void glProgramUniform1ui(GLuint program, GLint location, GLuint v0);
+void glProgramUniform2ui(GLuint program, GLint location, GLuint v0, GLuint v1);
+void glProgramUniform3ui(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2);
+void glProgramUniform4ui(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
+void glProgramUniform1f(GLuint program, GLint location, GLfloat v0);
+void glProgramUniform2f(GLuint program, GLint location, GLfloat v0, GLfloat v1);
+void glProgramUniform3f(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
+void glProgramUniform4f(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
+void glProgramUniform1iv(GLuint program, GLint location, GLsizei count, const GLint *value);
+void glProgramUniform2iv(GLuint program, GLint location, GLsizei count, const GLint *value);
+void glProgramUniform3iv(GLuint program, GLint location, GLsizei count, const GLint *value);
+void glProgramUniform4iv(GLuint program, GLint location, GLsizei count, const GLint *value);
+void glProgramUniform1uiv(GLuint program, GLint location, GLsizei count, const GLuint *value);
+void glProgramUniform2uiv(GLuint program, GLint location, GLsizei count, const GLuint *value);
+void glProgramUniform3uiv(GLuint program, GLint location, GLsizei count, const GLuint *value);
+void glProgramUniform4uiv(GLuint program, GLint location, GLsizei count, const GLuint *value);
+void glProgramUniform1fv(GLuint program, GLint location, GLsizei count, const GLfloat *value);
+void glProgramUniform2fv(GLuint program, GLint location, GLsizei count, const GLfloat *value);
+void glProgramUniform3fv(GLuint program, GLint location, GLsizei count, const GLfloat *value);
+void glProgramUniform4fv(GLuint program, GLint location, GLsizei count, const GLfloat *value);
+void glProgramUniformMatrix2fv(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+void glProgramUniformMatrix3fv(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+void glProgramUniformMatrix4fv(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+void glProgramUniformMatrix2x3fv(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+void glProgramUniformMatrix3x2fv(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+void glProgramUniformMatrix2x4fv(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+void glProgramUniformMatrix4x2fv(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+void glProgramUniformMatrix3x4fv(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+void glProgramUniformMatrix4x3fv(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+void glValidateProgramPipeline(GLuint pipeline);
+void glGetProgramPipelineInfoLog(GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+void glBindImageTexture(GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format);
+void glGetBooleani_v(GLenum target, GLuint index, GLboolean *data);
+void glMemoryBarrier(GLbitfield barriers);
+void glMemoryBarrierByRegion(GLbitfield barriers);
+void glTexStorage2DMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);
+void glGetMultisamplefv(GLenum pname, GLuint index, GLfloat *val);
+void glSampleMaski(GLuint maskNumber, GLbitfield mask);
+void glGetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint *params);
+void glGetTexLevelParameterfv(GLenum target, GLint level, GLenum pname, GLfloat *params);
+void glBindVertexBuffer(GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride);
+void glVertexAttribFormat(GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset);
+void glVertexAttribIFormat(GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
+void glVertexAttribBinding(GLuint attribindex, GLuint bindingindex);
+void glVertexBindingDivisor(GLuint bindingindex, GLuint divisor);
diff --git a/host/libs/virglrenderer/OpenGLESDispatch/gles3_only.entries b/host/libs/virglrenderer/OpenGLESDispatch/gles3_only.entries
new file mode 100644
index 0000000000000000000000000000000000000000..9742d382e56e40c02363f7c85dee21a67c7c24ce
--- /dev/null
+++ b/host/libs/virglrenderer/OpenGLESDispatch/gles3_only.entries
@@ -0,0 +1,111 @@
+!gles3_only
+
+%#include <GLES3/gl31.h>
+
+%// Return types must be single words, see GLDispatch.cpp
+%typedef const GLubyte* GL3constubyteptr;
+
+void glReadBuffer(GLenum src);
+void glDrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices);
+void glTexImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels);
+void glTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels);
+void glCopyTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+void glCompressedTexImage3D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data);
+void glCompressedTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data);
+void glGenQueries(GLsizei n, GLuint *ids);
+void glDeleteQueries(GLsizei n, const GLuint *ids);
+GLboolean glIsQuery(GLuint id);
+void glBeginQuery(GLenum target, GLuint id);
+void glEndQuery(GLenum target);
+void glGetQueryiv(GLenum target, GLenum pname, GLint *params);
+void glGetQueryObjectuiv(GLuint id, GLenum pname, GLuint *params);
+GLboolean glUnmapBuffer(GLenum target);
+void glGetBufferPointerv(GLenum target, GLenum pname, void **params);
+void glDrawBuffers(GLsizei n, const GLenum *bufs);
+void glUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+void glUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+void glUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+void glUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+void glUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+void glUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+void glBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+void glRenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+void glFramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
+void* glMapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
+void glFlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length);
+void glBindVertexArray(GLuint array);
+void glDeleteVertexArrays(GLsizei n, const GLuint *arrays);
+void glGenVertexArrays(GLsizei n, GLuint *arrays);
+GLboolean glIsVertexArray(GLuint array);
+void glGetIntegeri_v(GLenum target, GLuint index, GLint *data);
+void glBeginTransformFeedback(GLenum primitiveMode);
+void glEndTransformFeedback(void);
+void glBindBufferRange(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);
+void glBindBufferBase(GLenum target, GLuint index, GLuint buffer);
+void glTransformFeedbackVaryings(GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode);
+void glGetTransformFeedbackVarying(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name);
+void glVertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer);
+void glGetVertexAttribIiv(GLuint index, GLenum pname, GLint *params);
+void glGetVertexAttribIuiv(GLuint index, GLenum pname, GLuint *params);
+void glVertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w);
+void glVertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
+void glVertexAttribI4iv(GLuint index, const GLint *v);
+void glVertexAttribI4uiv(GLuint index, const GLuint *v);
+void glGetUniformuiv(GLuint program, GLint location, GLuint *params);
+GLint glGetFragDataLocation(GLuint program, const GLchar *name);
+void glUniform1ui(GLint location, GLuint v0);
+void glUniform2ui(GLint location, GLuint v0, GLuint v1);
+void glUniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2);
+void glUniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
+void glUniform1uiv(GLint location, GLsizei count, const GLuint *value);
+void glUniform2uiv(GLint location, GLsizei count, const GLuint *value);
+void glUniform3uiv(GLint location, GLsizei count, const GLuint *value);
+void glUniform4uiv(GLint location, GLsizei count, const GLuint *value);
+void glClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint *value);
+void glClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint *value);
+void glClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat *value);
+void glClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
+GL3constubyteptr glGetStringi(GLenum name, GLuint index);
+void glCopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
+void glGetUniformIndices(GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices);
+void glGetActiveUniformsiv(GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params);
+GLuint glGetUniformBlockIndex(GLuint program, const GLchar *uniformBlockName);
+void glGetActiveUniformBlockiv(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params);
+void glGetActiveUniformBlockName(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName);
+void glUniformBlockBinding(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding);
+void glDrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instancecount);
+void glDrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount);
+GLsync glFenceSync(GLenum condition, GLbitfield flags);
+GLboolean glIsSync(GLsync sync);
+void glDeleteSync(GLsync sync);
+GLenum glClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout);
+void glWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout);
+void glGetInteger64v(GLenum pname, GLint64 *data);
+void glGetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values);
+void glGetInteger64i_v(GLenum target, GLuint index, GLint64 *data);
+void glGetBufferParameteri64v(GLenum target, GLenum pname, GLint64 *params);
+void glGenSamplers(GLsizei count, GLuint *samplers);
+void glDeleteSamplers(GLsizei count, const GLuint *samplers);
+GLboolean glIsSampler(GLuint sampler);
+void glBindSampler(GLuint unit, GLuint sampler);
+void glSamplerParameteri(GLuint sampler, GLenum pname, GLint param);
+void glSamplerParameteriv(GLuint sampler, GLenum pname, const GLint *param);
+void glSamplerParameterf(GLuint sampler, GLenum pname, GLfloat param);
+void glSamplerParameterfv(GLuint sampler, GLenum pname, const GLfloat *param);
+void glGetSamplerParameteriv(GLuint sampler, GLenum pname, GLint *params);
+void glGetSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat *params);
+void glVertexAttribDivisor(GLuint index, GLuint divisor);
+void glBindTransformFeedback(GLenum target, GLuint id);
+void glDeleteTransformFeedbacks(GLsizei n, const GLuint *ids);
+void glGenTransformFeedbacks(GLsizei n, GLuint *ids);
+GLboolean glIsTransformFeedback(GLuint id);
+void glPauseTransformFeedback(void);
+void glResumeTransformFeedback(void);
+void glGetProgramBinary(GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary);
+void glProgramBinary(GLuint program, GLenum binaryFormat, const void *binary, GLsizei length);
+void glProgramParameteri(GLuint program, GLenum pname, GLint value);
+void glInvalidateFramebuffer(GLenum target, GLsizei numAttachments, const GLenum *attachments);
+void glInvalidateSubFramebuffer(GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height);
+void glTexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+void glTexStorage3D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+void glGetInternalformativ(GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params);
diff --git a/host/libs/virglrenderer/OpenGLESDispatch/gles_functions.h b/host/libs/virglrenderer/OpenGLESDispatch/gles_functions.h
new file mode 100644
index 0000000000000000000000000000000000000000..1219391ce6c113d22a81536e92c7ed7183d34b55
--- /dev/null
+++ b/host/libs/virglrenderer/OpenGLESDispatch/gles_functions.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "gles1_core_functions.h"
+#include "gles1_extensions_functions.h"
+#include "gles2_core_functions.h"
+#include "gles2_extensions_functions.h"
+#include "gles3_only_functions.h"
+#include "gles31_only_functions.h"
+
+#define LIST_GLES1_FUNCTIONS(X, Y) \
+    LIST_GLES1_CORE_FUNCTIONS(X) \
+    LIST_GLES1_EXTENSIONS_FUNCTIONS(Y) \
+
+#define LIST_GLES3_FUNCTIONS(X, Y) \
+    LIST_GLES2_CORE_FUNCTIONS(X) \
+    LIST_GLES2_EXTENSIONS_FUNCTIONS(Y) \
+    LIST_GLES3_ONLY_FUNCTIONS(X) \
+    LIST_GLES31_ONLY_FUNCTIONS(X)
diff --git a/host/libs/virglrenderer/OpenglRender/IOStream.h b/host/libs/virglrenderer/OpenglRender/IOStream.h
new file mode 100644
index 0000000000000000000000000000000000000000..82e5bdea5a81116cb4a377d5308dbb2e80ae7097
--- /dev/null
+++ b/host/libs/virglrenderer/OpenglRender/IOStream.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+
+class IOStream {
+  public:
+    IOStream(unsigned char* buf, size_t bufSize) : m_buf(buf), m_bufSize(bufSize) {
+    }
+
+    unsigned char* alloc(size_t len) {
+        if (m_allocSize + len > m_bufSize) {
+            printf("Command response is too large.\n");
+            return nullptr;
+        }
+        unsigned char* buf = m_buf + m_allocSize;
+        m_allocSize += len;
+        return buf;
+    }
+
+    int flush() {
+        m_flushSize = m_allocSize;
+        return 0;
+    }
+
+    void* getDmaForReading(uint64_t guest_paddr) {
+        // GLDMA is not supported, so we don't have to implement this. Just keep
+        // a stub here to keep the generated decoder stubs happy
+        return nullptr;
+    }
+
+    void unlockDma(uint64_t guest_paddr) {
+        // GLDMA is not supported, so we don't have to implement this. Just keep
+        // a stub here to keep the generated decoder stubs happy
+    }
+
+    size_t getFlushSize() {
+        return m_flushSize;
+    }
+
+  private:
+    size_t m_allocSize = 0U;
+    size_t m_flushSize = 0U;
+    unsigned char* m_buf;
+    size_t m_bufSize;
+};
diff --git a/host/libs/virglrenderer/ProtocolUtils.h b/host/libs/virglrenderer/ProtocolUtils.h
new file mode 100644
index 0000000000000000000000000000000000000000..fd0bebef3e5ac08df4482bba62dc9c8d43b8d9d5
--- /dev/null
+++ b/host/libs/virglrenderer/ProtocolUtils.h
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+namespace emugl {
+
+// A helper template to extract values form the wire protocol stream
+// and convert them to appropriate host values.
+//
+// The wire protocol uses 32-bit exclusively when transferring
+// GLintptr or GLsizei values, as well as opaque handles like GLeglImage,
+// from the guest (even when the guest is 64-bit).
+//
+// The corresponding host definitions depend on the host bitness. For
+// example, GLintptr is 64-bit on linux-x86_64. The following is a set
+// of templates that can simplify the conversion of protocol values
+// into host ones.
+//
+// The most important one is:
+//
+//     unpack<HOST_TYPE,SIZE_TYPE>(const void* ptr)
+//
+// Which reads bytes from |ptr|, using |SIZE_TYPE| as the underlying
+// sized-integer specifier (e.g. 'uint32_t'), and converting the result
+// into a |HOST_TYPE| value. For example:
+//
+//     unpack<EGLImage,uint32_t>(ptr + 12);
+//
+// will read a 4-byte value from |ptr + 12| and convert it into
+// an EGLImage, which is a host void*. The template detects host
+// pointer types to perform proper type casting.
+//
+// TODO(digit): Add custom unpackers to handle generic opaque void* values.
+//              and map them to unique 32-bit values.
+
+template <typename T, typename S>
+struct UnpackerT {
+    static T unpack(const void* ptr) {
+        static_assert(sizeof(T) == sizeof(S),
+                      "Bad input arguments, have to be of the same size");
+        return *(const T*)ptr;
+    }
+};
+
+template <typename T, typename S>
+struct UnpackerT<T*, S> {
+    static T* unpack(const void* ptr) {
+        return (T*)(uintptr_t)(*(const S*)ptr);
+    }
+};
+
+template <>
+struct UnpackerT<ssize_t, uint32_t> {
+    static ssize_t unpack(const void* ptr) {
+        return (ssize_t)*(const int32_t*)ptr;
+    }
+};
+
+template <typename T, typename S>
+inline T Unpack(const void* ptr) {
+    return UnpackerT<T, S>::unpack(ptr);
+}
+
+// Helper classes GenericInputBuffer and GenericOutputBuffer used to ensure
+// input and output buffers passed to EGL/GL functions are properly aligned
+// (preventing crashes with some backends).
+//
+// Usage example:
+//
+//    GenericInputBuffer<> inputBuffer(ptrIn, sizeIn);
+//    GenericOutputBuffer<> outputBuffer(ptrOut, sizeOut);
+//    glDoGetStuff(inputBuffer.get(), outputBuffer.get());
+//    outputBuffer.flush();
+//
+// get() will return the original value of |ptr| if it was aligned on the
+// configured boundary (8 bytes by default). Otherwise, it will return the
+// address of an aligned copy of the original |size| bytes starting from |ptr|.
+//
+// Allowed alignment values are 1, 2, 4, 8.
+//
+// outputBuffer.flush() copies the content of the copy back to |ptr| explictly,
+// if needed. It is a no-op if |ptr| was aligned.
+//
+// Both classes try to minimize heap usage as much as possible - the first
+// template argument defines the size of an internal array Generic*Buffer-s use
+// if the |ptr|'s |size| is small enough. If it doesn't fit into the internal
+// array, an aligned copy is allocated on the heap and freed in the dtor.
+
+template <size_t StackSize = 1024, size_t Align = 8>
+class GenericInputBuffer {
+    static_assert(Align == 1 || Align == 2 || Align == 4 || Align == 8,
+                  "Bad alignment parameter");
+
+public:
+    GenericInputBuffer(const void* input, size_t size) : mOrigBuff(input) {
+        if (((uintptr_t)input & (Align - 1U)) == 0) {
+            mPtr = const_cast<void*>(input);
+        } else {
+            if (size <= StackSize) {
+                mPtr = &mArray[0];
+            } else {
+                mPtr = malloc(size);
+            }
+            memcpy(mPtr, input, size);
+        }
+    }
+
+    ~GenericInputBuffer() {
+        if (mPtr != mOrigBuff && mPtr != &mArray[0]) {
+            free(mPtr);
+        }
+    }
+
+    const void* get() const { return mPtr; }
+
+private:
+    // A pointer to the aligned buffer, might point either to mOrgBuf, to mArray
+    // start or to a heap-allocated chunk of data.
+    void* mPtr;
+    // Original buffer.
+    const void* mOrigBuff;
+    // Inplace aligned array for small enough buffers.
+    char __attribute__((__aligned__(Align))) mArray[StackSize];
+};
+
+template <size_t StackSize = 1024, size_t Align = 8>
+class GenericOutputBuffer {
+    static_assert(Align == 1 || Align == 2 || Align == 4 || Align == 8,
+                  "Bad alignment parameter");
+
+public:
+    GenericOutputBuffer(unsigned char* ptr, size_t size) :
+            mOrigBuff(ptr), mSize(size) {
+        if (((uintptr_t)ptr & (Align - 1U)) == 0) {
+            mPtr = ptr;
+        } else {
+            if (size <= StackSize) {
+                mPtr = &mArray[0];
+            } else {
+                mPtr = calloc(1, size);
+            }
+        }
+    }
+
+    ~GenericOutputBuffer() {
+        if (mPtr != mOrigBuff && mPtr != &mArray[0]) {
+            free(mPtr);
+        }
+    }
+
+    void* get() const { return mPtr; }
+
+    void flush() {
+        if (mPtr != mOrigBuff) {
+            memcpy(mOrigBuff, mPtr, mSize);
+        }
+    }
+
+private:
+    // A pointer to the aligned buffer, might point either to mOrgBuf, to mArray
+    // start or to a heap-allocated chunk of data.
+    void* mPtr;
+    // Original buffer.
+    unsigned char* mOrigBuff;
+    // Original buffer size.
+    size_t mSize;
+    // Inplace array for small enough buffers.
+    unsigned char __attribute__((__aligned__(Align))) mArray[StackSize];
+};
+
+// Pin the defaults for the commonly used type names
+using InputBuffer = GenericInputBuffer<>;
+using OutputBuffer = GenericOutputBuffer<>;
+
+}  // namespace emugl
diff --git a/host/libs/virglrenderer/README.md b/host/libs/virglrenderer/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..e9b13789cce489e25ada2be8cfc4d1ab367689cc
--- /dev/null
+++ b/host/libs/virglrenderer/README.md
@@ -0,0 +1,112 @@
+# AVDVirglRenderer
+
+This project implements an alternative for 'virglrenderer', a part of the
+Virgil 3D GPU project that normally implements the translation from the
+virtio-gpu-3d command stream & tgsi/gallium shaders, to desktop OpenGL.
+
+This version of the library keeps translation to a minimum and only works with
+a true EGL/GLES driver implementation on the host. It won't intercept and
+translate shaders, and no part of the GL state machine is processed in the
+emulated guest.
+
+The wire protocol used between the virtio-gpu DRM driver and QEMU's
+virtio-gpu-3d device is the same as that used by goldfish (the classic Android
+emulator). Submits (writes) are made with an `DRM_VIRTGPU_EXECBUFFER` call; the
+response comes back through a separate memory mapped buffer. Responses are very
+expensive and are minimized where possible, as they involve a pipeline flush and
+roundtrip to the host.
+
+## Structure
+
+### [`AVDVirglRenderer`](AVDVirglRenderer.cpp)[](#AVDVirglRenderer)
+
+Provides the entrypoints expected by QEMU for its libvirglrenderer integration.
+
+This is where contexts, resources and fences are monitored.
+
+### [`RenderControl`](RenderControl.cpp) [`Header`](RenderControl.h) [`Decoder`](renderControl_dec)[](#RenderControl)
+
+The RenderControl is analogous to EGL on the guest side. It has a similar API to
+EGL, except that not every EGL function can be implemented as one API call, and
+instead multiple RenderControl calls are made. The RenderControl architecture
+was precipitated by goldfish's requirement that EGL window surfaces and images
+would be directly mapped to GL texture names, but in AVDVirglRenderer we
+preserve them as EGL objects on the host side.
+
+This component contains a decoder for the wire protocol, and stubs for any
+functions that we do not need to implement. The wire protocol is completely
+unmodified.
+
+### [`GLESv1`](GLESv1.cpp) [`Header`](GLESv1.h) [`Decoder`](GLESv1_dec)[](#GLESv1)
+
+This component contains a decoder for the wire protocol, and stubs for any
+functions that we do not need to implement. Only the GL ES 1.1 extensions
+implemented by SwiftShader are implemented, and only if they are needed by
+Android. Any extensions provided by the wire protocol that are not supported by
+either are intentionally stubbed.
+
+### [`GLESv3`](GLESv3.cpp) [`Header`](GLESv3.h) [`Decoder`](GLESv3_dec)[](#GLESv3)
+
+This component contains a decoder for the wire protocol, and stubs for any
+functions that we do not need to implement. Only the core GL ES 3.0 API is
+implemented; no ES 2.0 extensions are supported, unless they are remappable to
+GL ES 3.0 features. GL ES 3.1 is not currently supported. Any extensions
+provided by the wire protocol that are not supported by either Android or
+SwiftShader are intentionally stubbed.
+
+Note that we are *not* stubbing ES 3.1 functions; these will crash if called.
+
+### [`ChecksumCalculator`](OpenglRenderer/ChecksumCalculator.cpp)[`Header`](ChecksumCalculator.h)[](#ChecksumCalculator)
+
+This code was taken from the Android emulator. The header has been slightly
+trimmed but its functionality has not been changed.
+
+### [`ChecksumCalculatorThreadInfo`](ChecksumCalculatorThreadInfo.h)[](#ChecksumCalculatorThreadInfo)
+
+This header has been added for compatibility with the decoder code generated by
+the `emugen_cuttlefish` tool. Unlike the original implementation, it is not
+thread safe. We do not require thread safety because no decoder state is shared
+between threads in AVDVirglRenderer without its own locking.
+
+### [`Context`](Context.h)[](#Context)
+
+The Context structure represents a virglrenderer context assigned by QEMU. Each
+time the driver's device node is opened by the guest, a new context is created.
+In the design of AVDVirglRenderer, there are two kinds of context. The first
+kind of context is for `gralloc`, and there is one of these contexts per guest
+process. The second kind of context is per-thread, used by the EGL/GLES
+implementation. This second kind of context can receive 3D commands, which are
+processed in their own thread by AVDVirglRenderer so as to minimize the number
+of synthetic calls we have to make (such as eglMakeCurrent()).
+
+### [`Resource`](Resource.h)[](#Resource)
+
+The Resource structure represents a virglrenderer resource assigned by QEMU.
+Each time the driver allocates memory through the device driver's interface, a
+new resource is created. Resources can be owned by the kernel (for example, the
+primary framebuffer surfaces), Gralloc (EGL window surfaces or images), or used
+for other purposes such as the Context response buffer and fencing.
+
+### [`EglConfig`](EglConfig.h)[](EglConfig)
+
+The EglConfig structure maintains a list of available EGLConfigs.
+
+### [`EglContext`](EglContext.h)[](EglContext)
+
+The EglContext structure maintains a list of active EGLContexts, and decides
+when they can be disposed of.
+
+### [`EglImage`](EglImage.h)[](EglImage)
+
+The EglImage structure maintains a list of active EGLImageKHRs, and decides
+when they can be disposed of.
+
+### [`EglSurface`](EglSurface.h)[](EglSurface)
+
+The EglSurface structure maintains a list of active EGLSurfaces, and decides
+when they can be disposed of.
+
+### [`EglSync`](EglSync.h)[](EglSync)
+
+The EglSync structure maintains a list of active EGLSyncKHRs, and decides
+when they can be disposed of.
diff --git a/host/libs/virglrenderer/RenderControl.cpp b/host/libs/virglrenderer/RenderControl.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..fd84eb5485cc74d91386d7db3cbc5c7078a5c94e
--- /dev/null
+++ b/host/libs/virglrenderer/RenderControl.cpp
@@ -0,0 +1,868 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#undef NDEBUG
+
+#include "Context.h"
+#include "EglConfig.h"
+#include "EglContext.h"
+#include "EglImage.h"
+#include "EglSurface.h"
+#include "EglSync.h"
+
+#include <cassert>
+#include <cerrno>
+#include <cstring>
+#include <string>
+
+#include <unistd.h>
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include <OpenGLESDispatch/EGLDispatch.h>
+#include <OpenGLESDispatch/GLESv1Dispatch.h>
+#include <OpenGLESDispatch/GLESv3Dispatch.h>
+
+#include "virgl_hw.h"
+
+#include "RenderControl.h"
+
+#include <hardware/gralloc.h>
+#include <hardware/gralloc1.h>
+#include <nativebase/nativebase.h>
+#include <system/window.h>
+
+static void incRefANWB(android_native_base_t* base) {
+    ANativeWindowBuffer* anwb = reinterpret_cast<ANativeWindowBuffer*>(base);
+    anwb->layerCount++;
+}
+
+static void decRefANWB(android_native_base_t* base) {
+    ANativeWindowBuffer* anwb = reinterpret_cast<ANativeWindowBuffer*>(base);
+    if (anwb->layerCount > 0) {
+        anwb->layerCount--;
+        if (anwb->layerCount == 0)
+            delete anwb;
+    }
+}
+struct FakeANativeWindowBuffer : public ANativeWindowBuffer {
+    FakeANativeWindowBuffer() {
+        ANativeWindowBuffer();
+
+        common.incRef = incRefANWB;
+        common.decRef = decRefANWB;
+        layerCount = 0U;
+    }
+};
+
+static void incRefANW(android_native_base_t* base) {
+    ANativeWindow* anw = reinterpret_cast<ANativeWindow*>(base);
+    anw->oem[0]++;
+}
+
+static void decRefANW(android_native_base_t* base) {
+    ANativeWindow* anw = reinterpret_cast<ANativeWindow*>(base);
+    if (anw->oem[0] > 0) {
+        anw->oem[0]--;
+        if (anw->oem[0] == 0)
+            delete anw;
+    }
+}
+
+static int setSwapInterval(ANativeWindow*, int) {
+    printf("%s: not implemented\n", __func__);
+    return 0;
+}
+
+static int dequeueBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer** buffer) {
+    if (!window->oem[1])
+        return -EINVAL;
+    *buffer = reinterpret_cast<ANativeWindowBuffer*>(window->oem[1]);
+    window->oem[1] = 0;
+    return 0;
+}
+
+static int lockBuffer_DEPRECATED(ANativeWindow*, ANativeWindowBuffer*) {
+    printf("%s: not implemented\n", __func__);
+    return 0;
+}
+
+static int queueBuffer_DEPRECATED(ANativeWindow*, ANativeWindowBuffer*) {
+    printf("%s: not implemented\n", __func__);
+    return 0;
+}
+
+static int query(const ANativeWindow* window, int what, int* value) {
+    switch (what) {
+        case NATIVE_WINDOW_WIDTH:
+            return static_cast<int>(window->oem[2]);
+        case NATIVE_WINDOW_HEIGHT:
+            return static_cast<int>(window->oem[3]);
+        default:
+            return -EINVAL;
+    }
+}
+
+static int perform(ANativeWindow*, int, ...) {
+    printf("%s: not implemented\n", __func__);
+    return 0;
+}
+
+static int cancelBuffer_DEPRECATED(ANativeWindow*, ANativeWindowBuffer*) {
+    printf("%s: not implemented\n", __func__);
+    return 0;
+}
+
+static int dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer, int* fenceFd) {
+    *fenceFd = -1;
+    return dequeueBuffer_DEPRECATED(window, buffer);
+}
+
+static int queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd) {
+    if (fenceFd >= 0)
+        close(fenceFd);
+    return queueBuffer_DEPRECATED(window, buffer);
+}
+
+static int cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd) {
+    if (fenceFd >= 0)
+        close(fenceFd);
+    return cancelBuffer_DEPRECATED(window, buffer);
+}
+
+struct FakeANativeWindow : public ANativeWindow {
+    FakeANativeWindow(uint32_t width, uint32_t height) {
+        ANativeWindow();
+
+        common.incRef = incRefANW;
+        common.decRef = decRefANW;
+        oem[0] = 0;
+        oem[2] = static_cast<intptr_t>(width);
+        oem[3] = static_cast<intptr_t>(height);
+
+        this->setSwapInterval = ::setSwapInterval;
+        this->dequeueBuffer_DEPRECATED = ::dequeueBuffer_DEPRECATED;
+        this->lockBuffer_DEPRECATED = ::lockBuffer_DEPRECATED;
+        this->queueBuffer_DEPRECATED = ::queueBuffer_DEPRECATED;
+        this->query = ::query;
+        this->perform = ::perform;
+        this->cancelBuffer_DEPRECATED = ::cancelBuffer_DEPRECATED;
+        this->dequeueBuffer = ::dequeueBuffer;
+        this->queueBuffer = ::queueBuffer;
+        this->cancelBuffer = ::cancelBuffer;
+    }
+};
+
+// Helpers
+
+static ANativeWindowBuffer* resourceToANWB(Resource* res) {
+    ANativeWindowBuffer* buffer = new (std::nothrow) FakeANativeWindowBuffer();
+    if (!buffer)
+        return nullptr;
+
+    buffer->width = res->args.width;
+    buffer->height = res->args.height;
+    buffer->stride = res->args.width;
+    buffer->handle = reinterpret_cast<const native_handle_t*>(res->args.handle);
+    buffer->usage_deprecated = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
+                               GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_RENDER;
+    buffer->usage =
+        GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN | GRALLOC1_CONSUMER_USAGE_CPU_WRITE_OFTEN |
+        GRALLOC1_CONSUMER_USAGE_GPU_TEXTURE | GRALLOC1_PRODUCER_USAGE_CPU_READ_OFTEN |
+        GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN | GRALLOC1_PRODUCER_USAGE_GPU_RENDER_TARGET;
+
+    switch (res->args.format) {
+        case VIRGL_FORMAT_B8G8R8A8_UNORM:
+            buffer->format = HAL_PIXEL_FORMAT_BGRA_8888;
+            break;
+        case VIRGL_FORMAT_B5G6R5_UNORM:
+            buffer->format = HAL_PIXEL_FORMAT_RGB_565;
+            break;
+        case VIRGL_FORMAT_R8G8B8A8_UNORM:
+            buffer->format = HAL_PIXEL_FORMAT_RGBA_8888;
+            break;
+        case VIRGL_FORMAT_R8G8B8X8_UNORM:
+            buffer->format = HAL_PIXEL_FORMAT_RGBX_8888;
+            break;
+        default:
+            delete buffer;
+            return nullptr;
+    }
+
+    return buffer;
+}
+
+// RenderControl
+
+static GLint rcGetRendererVersion() {
+    return 1;  // seems to be hard-coded
+}
+
+static EGLint rcGetEGLVersion(void* ctx_, EGLint* major, EGLint* minor) {
+    RenderControl* rc = static_cast<RenderControl*>(ctx_);
+    return s_egl.eglInitialize(rc->dpy, major, minor);
+}
+
+static EGLint rcQueryEGLString(void* ctx_, EGLenum name, void* buffer, EGLint bufferSize) {
+    RenderControl* rc = static_cast<RenderControl*>(ctx_);
+    const char* str = s_egl.eglQueryString(rc->dpy, name);
+    if (!str)
+        str = "";
+
+    if (strlen(str) > (size_t)bufferSize) {
+        memset(buffer, 0, bufferSize);
+        return -strlen(str);
+    }
+
+    char* strOut = static_cast<char*>(buffer);
+    strncpy(strOut, str, bufferSize - 1);
+    strOut[bufferSize - 1] = 0;
+
+    return strlen(strOut) + 1U;
+}
+
+static std::string replaceESVersionString(const std::string& prev, const char* const newver) {
+    // Do not touch ES 1.x contexts (they will all be 1.1 anyway)
+    if (prev.find("ES-CM") != std::string::npos)
+        return prev;
+
+    size_t esStart = prev.find("ES ");
+    size_t esEnd = prev.find(" ", esStart + 3);
+
+    // Do not change out-of-spec version strings.
+    if (esStart == std::string::npos || esEnd == std::string::npos)
+        return prev;
+
+    std::string res = prev.substr(0, esStart + 3);
+    res += newver;
+    res += prev.substr(esEnd);
+    return res;
+}
+
+static EGLint rcGetGLString(void* ctx_, EGLenum name, void* buffer, EGLint bufferSize) {
+    std::string glStr;
+
+    RenderControl* rc = static_cast<RenderControl*>(ctx_);
+    if (rc->ctx->ctx) {
+        const char* str = nullptr;
+        switch (rc->ctx->ctx->api) {
+            case EglContext::GLESApi::GLESApi_CM:
+                str = reinterpret_cast<const char*>(s_gles1.glGetString(name));
+                break;
+            default:
+                str = reinterpret_cast<const char*>(s_gles3.glGetString(name));
+                break;
+        }
+        if (str)
+            glStr += str;
+    }
+
+    // FIXME: Should probably filter the extensions list like the emulator
+    //        does. We need to handle ES2 on ES3 compatibility for older
+    //        Android versions, as well as filter out unsupported features.
+
+    if (name == GL_EXTENSIONS) {
+        glStr += ChecksumCalculator::getMaxVersionStr();
+        glStr += " ";
+
+        // FIXME: Hard-coded to 3.0 for now. We should attempt to detect 3.1.
+        glStr += "ANDROID_EMU_gles_max_version_3_0";
+        glStr += " ";
+    }
+
+    // FIXME: Add support for async swap and the fence_sync extensions
+
+    // We don't support GLDMA; use VIRTGPU_RESOURCE_CREATE and a combination of
+    // VIRTGPU_TRANSFER_TO_HOST and VIRTGPU_TRANSFER_FROM_HOST.
+
+    // FIXME: Add support for 'no host error'
+
+    if (name == GL_VERSION)
+        glStr = replaceESVersionString(glStr, "3.0");
+
+    int nextBufferSize = glStr.size() + 1;
+
+    if (!buffer || nextBufferSize > bufferSize)
+        return -nextBufferSize;
+
+    snprintf((char*)buffer, nextBufferSize, "%s", glStr.c_str());
+    return nextBufferSize;
+}
+
+static EGLint rcGetNumConfigs(uint32_t* numAttribs) {
+    *numAttribs = EglConfig::kNumAttribs;
+    return EglConfig::vec.size();
+}
+
+static EGLint rcGetConfigs(uint32_t bufSize, GLuint* buffer) {
+    size_t configAttribBytes = sizeof(EglConfig::kAttribs);
+    size_t nConfigs = EglConfig::vec.size();
+    size_t sizeNeeded = configAttribBytes + nConfigs * configAttribBytes;
+
+    if (bufSize < sizeNeeded)
+        return -sizeNeeded;
+
+    memcpy(buffer, &EglConfig::kAttribs, configAttribBytes);
+    size_t offset = EglConfig::kNumAttribs;
+    for (auto const& config : EglConfig::vec) {
+        memcpy(&buffer[offset], config->attribs, configAttribBytes);
+        offset += EglConfig::kNumAttribs;
+    }
+
+    return nConfigs;
+}
+
+static EGLint rcChooseConfig(void* ctx_, EGLint* attribs, uint32_t, uint32_t* config_ints,
+                             uint32_t configs_size) {
+    EGLint num_config;
+    EGLConfig configs[configs_size];
+    RenderControl* rc = static_cast<RenderControl*>(ctx_);
+    EGLBoolean ret = s_egl.eglChooseConfig(rc->dpy, attribs, configs, configs_size, &num_config);
+    if (!ret)
+        num_config = 0;
+
+    if (configs_size) {
+        for (EGLint i = 0; i < num_config; i++) {
+            config_ints[i] = ~0U;
+            EGLint config_id;
+            if (s_egl.eglGetConfigAttrib(rc->dpy, configs[i], EGL_CONFIG_ID, &config_id)) {
+                for (size_t i = 0; i < EglConfig::vec.size(); i++) {
+                    if (EglConfig::vec[i]->attribs[4] == config_id)
+                        config_ints[i] = i;
+                }
+            }
+            if (config_ints[i] == ~0U) {
+                num_config = 0;
+                break;
+            }
+        }
+        if (!num_config)
+            memset(config_ints, 0, configs_size * sizeof(uint32_t));
+    }
+
+    return num_config;
+}
+
+static EGLint rcGetFBParam(EGLint) {
+    printf("%s: not implemented\n", __func__);
+    return 0;
+}
+
+static uint32_t rcCreateContext(void* ctx_, uint32_t config_, uint32_t share_, uint32_t glVersion) {
+    // clang-format off
+    EGLint attrib_list[] = {
+        EGL_CONTEXT_CLIENT_VERSION,    0,
+        EGL_CONTEXT_MINOR_VERSION_KHR, 0,
+        EGL_NONE
+    };
+    // clang-format on
+    switch (glVersion) {
+        case EglContext::GLESApi::GLESApi_CM:
+            attrib_list[1] = 1;
+            attrib_list[3] = 1;
+            break;
+        case EglContext::GLESApi::GLESApi_2:
+            attrib_list[1] = 2;
+            break;
+        case EglContext::GLESApi::GLESApi_3_0:
+            attrib_list[1] = 3;
+            break;
+        case EglContext::GLESApi::GLESApi_3_1:
+            attrib_list[1] = 3;
+            attrib_list[3] = 1;
+            break;
+    }
+    if (!attrib_list[1])
+        return 0U;
+
+    if (config_ > EglConfig::vec.size())
+        return 0U;
+    EglConfig const* config = EglConfig::vec[config_];
+
+    EGLContext share_context = EGL_NO_CONTEXT;
+    if (share_ > 0) {
+        std::map<uint32_t, EglContext*>::iterator context_it;
+        context_it = EglContext::map.find(share_);
+        if (context_it == EglContext::map.end())
+            return 0U;
+
+        EglContext const* share = context_it->second;
+        share_context = share->context;
+    }
+
+    RenderControl* rc = static_cast<RenderControl*>(ctx_);
+    EGLContext context_ =
+        s_egl.eglCreateContext(rc->dpy, config->config, share_context, attrib_list);
+    if (context_ == EGL_NO_CONTEXT)
+        return 0U;
+
+    EglContext* context = new (std::nothrow)
+        EglContext(context_, rc->ctx->handle, (enum EglContext::GLESApi)glVersion);
+    if (!context) {
+        s_egl.eglDestroyContext(rc->dpy, context_);
+        return 0U;
+    }
+
+    return context->id;
+}
+
+static void rcDestroyContext(void* ctx_, uint32_t ctx) {
+    std::map<uint32_t, EglContext*>::iterator it;
+    it = EglContext::map.find(ctx);
+    if (it == EglContext::map.end())
+        return;
+
+    EglContext* context = it->second;
+
+    RenderControl* rc = static_cast<RenderControl*>(ctx_);
+    s_egl.eglDestroyContext(rc->dpy, context->context);
+    context->context = EGL_NO_CONTEXT;
+    if (context->disposable())
+        delete context;
+}
+
+static uint32_t rcCreateWindowSurface(void* ctx_, uint32_t config_, uint32_t width,
+                                      uint32_t height) {
+    if (config_ > EglConfig::vec.size())
+        return 0U;
+
+    EglConfig const* config = EglConfig::vec[config_];
+
+    RenderControl* rc = static_cast<RenderControl*>(ctx_);
+    EglSurface* surface =
+        new (std::nothrow) EglSurface(config->config, rc->ctx->handle, width, height);
+    if (!surface)
+        return 0U;
+
+    return surface->id;
+}
+
+static void rcDestroyWindowSurface(void* ctx_, uint32_t surface_) {
+    std::map<uint32_t, EglSurface*>::iterator it;
+    it = EglSurface::map.find(surface_);
+    if (it == EglSurface::map.end())
+        return;
+
+    EglSurface* surface = it->second;
+
+    RenderControl* rc = static_cast<RenderControl*>(ctx_);
+    s_egl.eglDestroySurface(rc->dpy, surface->surface);
+    surface->surface = EGL_NO_SURFACE;
+    if (surface->disposable()) {
+        delete surface->window;
+        delete surface;
+    }
+}
+
+static uint32_t rcCreateColorBuffer(uint32_t, uint32_t, GLenum) {
+    // NOTE: This CreateColorBuffer implementation is a no-op which returns a
+    //       special surface ID to indicate that a pbuffer surface should be
+    //       created. This is necessary because the emulator does not create a
+    //       true pbuffer, it always creates a fake one. We don't want this.
+    return ~1U;
+}
+
+static void rcOpenColorBuffer(uint32_t) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void rcCloseColorBuffer(uint32_t) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void rcSetWindowColorBuffer(void* ctx_, uint32_t windowSurface, uint32_t colorBuffer) {
+    std::map<uint32_t, EglSurface*>::iterator surface_it;
+    surface_it = EglSurface::map.find(windowSurface);
+    if (surface_it == EglSurface::map.end())
+        return;
+
+    EglSurface* surface = surface_it->second;
+
+    RenderControl* rc = static_cast<RenderControl*>(ctx_);
+
+    if (colorBuffer == ~1U) {
+        EGLint const attrib_list[] = { EGL_WIDTH, (EGLint)surface->width, EGL_HEIGHT,
+                                       (EGLint)surface->height, EGL_NONE };
+        assert(surface->surface == EGL_NO_SURFACE && "Pbuffer set twice");
+        surface->surface = s_egl.eglCreatePbufferSurface(rc->dpy, surface->config, attrib_list);
+    } else {
+        std::map<uint32_t, Resource*>::iterator resource_it;
+        resource_it = Resource::map.find(colorBuffer);
+        if (resource_it == Resource::map.end())
+            return;
+
+        Resource* res = resource_it->second;
+        ANativeWindowBuffer* buffer = resourceToANWB(res);
+        if (!buffer)
+            return;
+
+        if (surface->surface == EGL_NO_SURFACE) {
+            surface->window =
+                new (std::nothrow) FakeANativeWindow(res->args.width, res->args.height);
+            if (!surface->window)
+                return;
+
+            NativeWindowType native_window = reinterpret_cast<NativeWindowType>(surface->window);
+            surface->window->oem[1] = (intptr_t)buffer;
+            surface->surface =
+                s_egl.eglCreateWindowSurface(rc->dpy, surface->config, native_window, nullptr);
+        } else {
+            surface->window->oem[1] = (intptr_t)buffer;
+            s_egl.eglSwapBuffers(rc->dpy, surface->surface);
+        }
+    }
+}
+
+static int rcFlushWindowColorBuffer(uint32_t windowSurface) {
+    std::map<uint32_t, EglSurface*>::iterator it;
+    it = EglSurface::map.find(windowSurface);
+    return it == EglSurface::map.end() ? -1 : 0;
+}
+
+static EGLint rcMakeCurrent(void* ctx_, uint32_t context_, uint32_t drawSurf, uint32_t readSurf) {
+    std::map<uint32_t, EglContext*>::iterator context_it;
+    context_it = EglContext::map.find(context_);
+    if (context_it == EglContext::map.end())
+        return EGL_FALSE;
+
+    EglContext* context = context_it->second;
+
+    std::map<uint32_t, EglSurface*>::iterator surface_it;
+    surface_it = EglSurface::map.find(drawSurf);
+    if (surface_it == EglSurface::map.end())
+        return EGL_FALSE;
+
+    EglSurface* draw_surface = surface_it->second;
+
+    surface_it = EglSurface::map.find(readSurf);
+    if (surface_it == EglSurface::map.end())
+        return EGL_FALSE;
+
+    EglSurface* read_surface = surface_it->second;
+
+    RenderControl* rc = static_cast<RenderControl*>(ctx_);
+
+    EglSurface* old_draw_surface = draw_surface->bind(rc->ctx->handle, false);
+    if (old_draw_surface)
+        old_draw_surface->unbind(false);
+
+    EglSurface* old_read_surface = read_surface->bind(rc->ctx->handle, true);
+    if (old_read_surface)
+        old_read_surface->unbind(true);
+
+    EglContext* old_context = context->bind(rc->ctx->handle);
+    if (old_context)
+        old_context->unbind();
+
+    EGLBoolean ret = s_egl.eglMakeCurrent(rc->dpy, draw_surface->surface, read_surface->surface,
+                                          context->context);
+    if (!ret) {
+        // If eglMakeCurrent fails, it's specified *not* to have unbound the
+        // previous contexts or surfaces, but many implementations do. This bug
+        // isn't worked around here, and we just assume the implementations obey
+        // the spec.
+        context->unbind();
+        if (old_context)
+            old_context->bind(rc->ctx->handle);
+        read_surface->unbind(true);
+        if (old_read_surface)
+            old_read_surface->bind(rc->ctx->handle, true);
+        draw_surface->unbind(false);
+        if (old_draw_surface)
+            old_draw_surface->bind(rc->ctx->handle, false);
+    } else {
+        if (old_context && old_context->disposable())
+            delete old_context;
+        if (old_read_surface && old_read_surface->disposable())
+            delete old_read_surface;
+        if (old_draw_surface && old_draw_surface->disposable())
+            delete old_draw_surface;
+        rc->ctx->unbind();
+        rc->ctx->bind(context);
+    }
+
+    return (EGLint)ret;
+}
+
+static void rcFBPost(uint32_t) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static void rcFBSetSwapInterval(void* ctx_, EGLint interval) {
+    RenderControl* rc = static_cast<RenderControl*>(ctx_);
+    s_egl.eglSwapInterval(rc->dpy, interval);
+}
+
+static void rcBindTexture(void* ctx_, uint32_t colorBuffer) {
+    std::map<uint32_t, Resource*>::iterator it;
+    it = Resource::map.find(colorBuffer);
+    if (it == Resource::map.end())
+        return;
+
+    RenderControl* rc = static_cast<RenderControl*>(ctx_);
+    Resource* res = it->second;
+    if (!res->image) {
+        ANativeWindowBuffer* buffer = resourceToANWB(res);
+        if (!buffer)
+            return;
+
+        EGLClientBuffer client_buffer = static_cast<EGLClientBuffer>(buffer);
+        EGLImageKHR image = s_egl.eglCreateImageKHR(
+            rc->dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, client_buffer, nullptr);
+        if (image == EGL_NO_IMAGE_KHR)
+            return;
+
+        EglImage* img = new (std::nothrow) EglImage(rc->dpy, image, s_egl.eglDestroyImageKHR);
+        if (!img) {
+            s_egl.eglDestroyImageKHR(rc->dpy, image);
+            return;
+        }
+
+        // FIXME: House keeping, because we won't get asked to delete the image
+        //        object otherwise, so we need to keep a reference to it..
+        res->image = img;
+    }
+
+    if (rc->ctx->ctx->api == EglContext::GLESApi::GLESApi_CM) {
+        // FIXME: Unconditional use of GL_TEXTURE_2D here is wrong
+        s_gles1.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, res->image->image);
+    } else {
+        // FIXME: Unconditional use of GL_TEXTURE_2D here is wrong
+        s_gles3.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, res->image->image);
+    }
+}
+
+static void rcBindRenderbuffer(void* ctx_, uint32_t colorBuffer) {
+    std::map<uint32_t, Resource*>::iterator it;
+    it = Resource::map.find(colorBuffer);
+    if (it == Resource::map.end())
+        return;
+
+    RenderControl* rc = static_cast<RenderControl*>(ctx_);
+    Resource* res = it->second;
+    if (!res->image) {
+        ANativeWindowBuffer* buffer = resourceToANWB(res);
+        if (!buffer)
+            return;
+
+        EGLClientBuffer client_buffer = static_cast<EGLClientBuffer>(buffer);
+        EGLImageKHR image = s_egl.eglCreateImageKHR(
+            rc->dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, client_buffer, nullptr);
+        if (image == EGL_NO_IMAGE_KHR)
+            return;
+
+        EglImage* img = new (std::nothrow) EglImage(rc->dpy, image, s_egl.eglDestroyImageKHR);
+        if (!img) {
+            s_egl.eglDestroyImageKHR(rc->dpy, image);
+            return;
+        }
+
+        // FIXME: House keeping, because we won't get asked to delete the image
+        //        object otherwise, so we need to keep a reference to it..
+        res->image = img;
+    }
+
+    if (rc->ctx->ctx->api == EglContext::GLESApi::GLESApi_CM) {
+        s_gles1.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER_OES, res->image->image);
+    } else {
+        s_gles3.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER_OES, res->image->image);
+    }
+}
+
+static EGLint rcColorBufferCacheFlush(uint32_t, EGLint, int) {
+    printf("%s: not implemented\n", __func__);
+    return 0;
+}
+
+static void rcReadColorBuffer(uint32_t, GLint, GLint, GLint, GLint, GLenum, GLenum, void*) {
+    printf("%s: not implemented\n", __func__);
+}
+
+static int rcUpdateColorBuffer(uint32_t, GLint, GLint, GLint, GLint, GLenum, GLenum, void*) {
+    printf("%s: not implemented\n", __func__);
+    return 0;
+}
+
+static int rcOpenColorBuffer2(uint32_t) {
+    printf("%s: not implemented\n", __func__);
+    return 0;
+}
+
+static uint32_t rcCreateClientImage(void* ctx_, uint32_t context_, EGLenum target, GLuint buffer_) {
+    std::map<uint32_t, EglContext*>::iterator it;
+    it = EglContext::map.find(context_);
+    if (it == EglContext::map.end())
+        return 0U;
+
+    EglContext* context = it->second;
+
+    RenderControl* rc = static_cast<RenderControl*>(ctx_);
+    EGLClientBuffer buffer = reinterpret_cast<EGLClientBuffer>(buffer_);
+    EGLImageKHR image = s_egl.eglCreateImageKHR(rc->dpy, context, target, buffer, nullptr);
+    EglImage* img = new (std::nothrow) EglImage(rc->dpy, image, s_egl.eglDestroyImageKHR);
+    if (!img) {
+        s_egl.eglDestroyImageKHR(rc->dpy, image);
+        return 0U;
+    }
+
+    return img->id;
+}
+
+static int rcDestroyClientImage(uint32_t image_) {
+    std::map<uint32_t, EglImage*>::iterator it;
+    it = EglImage::map.find(image_);
+    if (it == EglImage::map.end())
+        return EGL_FALSE;
+
+    EglImage* image = it->second;
+
+    delete image;
+    return EGL_TRUE;
+}
+
+static void rcSelectChecksumHelper(void* ctx_, uint32_t protocol, uint32_t) {
+    RenderControl* rc = static_cast<RenderControl*>(ctx_);
+    rc->ctx->checksum_calc.setVersion(protocol);
+}
+
+static void rcCreateSyncKHR(void* ctx_, EGLenum type, EGLint* attribs, uint32_t, int,
+                            uint64_t* glsync_out, uint64_t* syncthread_out) {
+    *syncthread_out = 0ULL;
+
+    RenderControl* rc = static_cast<RenderControl*>(ctx_);
+    EGLSyncKHR sync = s_egl.eglCreateSyncKHR(rc->dpy, type, attribs);
+    if (sync == EGL_NO_SYNC_KHR) {
+        *glsync_out = 0ULL;
+        return;
+    }
+
+    EglSync* syn = new (std::nothrow) EglSync(sync);
+    if (!syn) {
+        s_egl.eglDestroySyncKHR(rc->dpy, sync);
+        *glsync_out = 0ULL;
+        return;
+    }
+
+    *glsync_out = syn->id;
+}
+
+static EGLint rcClientWaitSyncKHR(void* ctx_, uint64_t sync_, EGLint flags, uint64_t timeout) {
+    std::map<uint64_t, EglSync*>::iterator it;
+    it = EglSync::map.find(sync_);
+    if (it == EglSync::map.end())
+        return EGL_CONDITION_SATISFIED_KHR;
+
+    EglSync* sync = it->second;
+    RenderControl* rc = static_cast<RenderControl*>(ctx_);
+    return s_egl.eglClientWaitSyncKHR(rc->dpy, sync->sync, flags, timeout);
+}
+
+static void rcFlushWindowColorBufferAsync(uint32_t windowSurface) {
+    // No-op
+}
+
+static int rcDestroySyncKHR(void* ctx_, uint64_t sync_) {
+    std::map<uint64_t, EglSync*>::iterator it;
+    it = EglSync::map.find(sync_);
+    if (it == EglSync::map.end())
+        return EGL_FALSE;
+
+    EglSync* sync = it->second;
+    RenderControl* rc = static_cast<RenderControl*>(ctx_);
+    return s_egl.eglDestroySyncKHR(rc->dpy, sync->sync);
+}
+
+static void rcSetPuid(void* ctx_, uint64_t proto) {
+    union {
+        uint64_t proto;
+        struct {
+            int pid;
+            int tid;
+        } id;
+    } puid;
+
+    puid.proto = proto;
+
+    RenderControl* rc = static_cast<RenderControl*>(ctx_);
+    rc->ctx->setPidTid(puid.id.pid, puid.id.tid);
+}
+
+static int rcUpdateColorBufferDMA(uint32_t, GLint, GLint, GLint, GLint, GLenum, GLenum, void*,
+                                  uint32_t) {
+    printf("%s: not implemented\n", __func__);
+    return 0;
+}
+
+static uint32_t rcCreateColorBufferDMA(uint32_t, uint32_t, GLenum, int) {
+    printf("%s: not implemented\n", __func__);
+    return 0U;
+}
+
+static void rcWaitSyncKHR(void* ctx_, uint64_t sync_, EGLint flags) {
+    std::map<uint64_t, EglSync*>::iterator it;
+    it = EglSync::map.find(sync_);
+    if (it == EglSync::map.end())
+        return;
+
+    EglSync* sync = it->second;
+    RenderControl* rc = static_cast<RenderControl*>(ctx_);
+    // FIXME: No eglWaitSyncKHR support in SwiftShader
+    //        This call will BLOCK when it should be asynchronous!
+    s_egl.eglClientWaitSyncKHR(rc->dpy, sync->sync, flags, EGL_FOREVER_KHR);
+}
+
+RenderControl::RenderControl(Context* ctx_, EGLDisplay dpy_) {
+    rcGetRendererVersion = ::rcGetRendererVersion;
+    rcGetEGLVersion_dec = ::rcGetEGLVersion;
+    rcQueryEGLString_dec = ::rcQueryEGLString;
+    rcGetGLString_dec = ::rcGetGLString;
+    rcGetNumConfigs = ::rcGetNumConfigs;
+    rcGetConfigs = ::rcGetConfigs;
+    rcChooseConfig_dec = ::rcChooseConfig;
+    rcGetFBParam = ::rcGetFBParam;
+    rcCreateContext_dec = ::rcCreateContext;
+    rcDestroyContext_dec = ::rcDestroyContext;
+    rcCreateWindowSurface_dec = ::rcCreateWindowSurface;
+    rcDestroyWindowSurface_dec = ::rcDestroyWindowSurface;
+    rcCreateColorBuffer = ::rcCreateColorBuffer;
+    rcOpenColorBuffer = ::rcOpenColorBuffer;
+    rcCloseColorBuffer = ::rcCloseColorBuffer;
+    rcSetWindowColorBuffer_dec = ::rcSetWindowColorBuffer;
+    rcFlushWindowColorBuffer = ::rcFlushWindowColorBuffer;
+    rcMakeCurrent_dec = ::rcMakeCurrent;
+    rcFBPost = ::rcFBPost;
+    rcFBSetSwapInterval_dec = ::rcFBSetSwapInterval;
+    rcBindTexture_dec = ::rcBindTexture;
+    rcBindRenderbuffer_dec = ::rcBindRenderbuffer;
+    rcColorBufferCacheFlush = ::rcColorBufferCacheFlush;
+    rcReadColorBuffer = ::rcReadColorBuffer;
+    rcUpdateColorBuffer = ::rcUpdateColorBuffer;
+    rcOpenColorBuffer2 = ::rcOpenColorBuffer2;
+    rcCreateClientImage_dec = ::rcCreateClientImage;
+    rcDestroyClientImage = ::rcDestroyClientImage;
+    rcSelectChecksumHelper_dec = ::rcSelectChecksumHelper;
+    rcCreateSyncKHR_dec = ::rcCreateSyncKHR;
+    rcClientWaitSyncKHR_dec = ::rcClientWaitSyncKHR;
+    rcFlushWindowColorBufferAsync = ::rcFlushWindowColorBufferAsync;
+    rcDestroySyncKHR_dec = ::rcDestroySyncKHR;
+    rcSetPuid_dec = ::rcSetPuid;
+    rcUpdateColorBufferDMA = ::rcUpdateColorBufferDMA;
+    rcCreateColorBufferDMA = ::rcCreateColorBufferDMA;
+    rcWaitSyncKHR_dec = ::rcWaitSyncKHR;
+
+    dpy = dpy_;
+    ctx = ctx_;
+}
diff --git a/host/libs/virglrenderer/RenderControl.h b/host/libs/virglrenderer/RenderControl.h
new file mode 100644
index 0000000000000000000000000000000000000000..88734e5684ecc8c0469d7f7510aa32741fb58864
--- /dev/null
+++ b/host/libs/virglrenderer/RenderControl.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "renderControl_dec.h"
+
+typedef void* EGLDisplay;
+
+struct Context;
+
+struct RenderControl : public renderControl_decoder_context_t {
+    RenderControl(Context* ctx_, EGLDisplay dpy_);
+    EGLDisplay dpy;
+    Context* ctx;
+};
diff --git a/host/libs/virglrenderer/Resource.h b/host/libs/virglrenderer/Resource.h
new file mode 100644
index 0000000000000000000000000000000000000000..9fd462e712d53e8ff2658a843e3e1dc0206fb7de
--- /dev/null
+++ b/host/libs/virglrenderer/Resource.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+extern "C" {
+#include <virglrenderer.h>
+}
+
+#include <cstdint>
+#include <cstdlib>
+#include <map>
+
+#include <GLES/gl.h>
+
+#include <sys/uio.h>
+
+#include "EglImage.h"
+
+struct Context;
+
+struct Resource {
+    static std::map<uint32_t, Resource*> map;
+
+    Resource(virgl_renderer_resource_create_args* args_, uint32_t num_iovs_, iovec* iov_)
+        : args(*args_), num_iovs(num_iovs_), tex_id(0U), iov(iov_) {
+        reallocLinear();
+        map.emplace(args.handle, this);
+    }
+
+    ~Resource() {
+        map.erase(args.handle);
+        delete image;
+    }
+
+    void reallocLinear() {
+        if (linearShadow && num_iovs <= 1)
+            free(linear);
+        linearShadow = num_iovs > 1 ? true : false;
+        if (linearShadow) {
+            uint32_t i;
+            for (i = 0, linearSize = 0U; i < num_iovs; i++)
+                linearSize += iov[i].iov_len;
+            linear = realloc(linear, linearSize);
+        } else if (num_iovs == 1) {
+            linearSize = iov[0].iov_len;
+            linear = iov[0].iov_base;
+        } else {
+            linearSize = 0U;
+            linear = nullptr;
+        }
+    }
+
+    std::map<uint32_t, Context*> context_map;
+    virgl_renderer_resource_create_args args;
+    EglImage* image = nullptr;
+    size_t linearSize = 0U;
+    void* linear = nullptr;
+    uint32_t num_iovs;
+    GLuint tex_id;
+    iovec* iov;
+
+  private:
+    bool linearShadow = false;
+};
diff --git a/host/libs/virglrenderer/emugl/common/dma_device.cpp b/host/libs/virglrenderer/emugl/common/dma_device.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..880d559cd130fd5176d3fbd8266a1b79d8b077c3
--- /dev/null
+++ b/host/libs/virglrenderer/emugl/common/dma_device.cpp
@@ -0,0 +1,38 @@
+
+#include "android/emulation/GoldfishDma.h"
+#include "emugl/common/dma_device.h"
+
+static void defaultDmaAddBuffer(void* pipe, uint64_t guest_paddr, uint64_t size) { }
+static void defaultDmaRemoveBuffer(uint64_t guest_paddr) { }
+static void* defaultDmaGetHostAddr(uint64_t guest_paddr) {
+    return nullptr;
+}
+static void defaultDmaInvalidateHostMappings() { }
+
+static void defaultDmaUnlock(uint64_t addr) { }
+
+emugl_dma_add_buffer_t g_emugl_dma_add_buffer = defaultDmaAddBuffer;
+emugl_dma_remove_buffer_t g_emugl_dma_remove_buffer = defaultDmaRemoveBuffer;
+emugl_dma_get_host_addr_t g_emugl_dma_get_host_addr = defaultDmaGetHostAddr;
+emugl_dma_invalidate_host_mappings_t g_emugl_dma_invalidate_host_mappings = defaultDmaInvalidateHostMappings;
+emugl_dma_unlock_t g_emugl_dma_unlock = defaultDmaUnlock;
+
+void set_emugl_dma_add_buffer(emugl_dma_add_buffer_t f) {
+    g_emugl_dma_add_buffer = f;
+}
+
+void set_emugl_dma_remove_buffer(emugl_dma_remove_buffer_t f) {
+    g_emugl_dma_remove_buffer = f;
+}
+
+void set_emugl_dma_get_host_addr(emugl_dma_get_host_addr_t f) {
+    g_emugl_dma_get_host_addr = f;
+}
+
+void set_emugl_dma_invalidate_host_mappings(emugl_dma_invalidate_host_mappings_t f) {
+    g_emugl_dma_invalidate_host_mappings = f;
+}
+
+void set_emugl_dma_unlock(emugl_dma_unlock_t f) {
+    g_emugl_dma_unlock = f;
+}
diff --git a/host/libs/virglrenderer/emugl/common/dma_device.h b/host/libs/virglrenderer/emugl/common/dma_device.h
new file mode 100644
index 0000000000000000000000000000000000000000..a76c4345b2e612c785e34c6e087fa82272722611
--- /dev/null
+++ b/host/libs/virglrenderer/emugl/common/dma_device.h
@@ -0,0 +1,30 @@
+/*
+* Copyright (C) 2016 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#pragma once
+
+#include "OpenglRender/render_api_types.h"
+
+extern emugl_dma_add_buffer_t g_emugl_dma_add_buffer;
+extern emugl_dma_remove_buffer_t g_emugl_dma_remove_buffer;
+extern emugl_dma_get_host_addr_t g_emugl_dma_get_host_addr;
+extern emugl_dma_unlock_t g_emugl_dma_unlock;
+
+void set_emugl_dma_add_buffer(emugl_dma_add_buffer_t);
+void set_emugl_dma_remove_buffer(emugl_dma_remove_buffer_t);
+void set_emugl_dma_get_host_addr(emugl_dma_get_host_addr_t);
+void set_emugl_dma_invalidate_host_mappings(emugl_dma_invalidate_host_mappings_t);
+void set_emugl_dma_unlock(emugl_dma_unlock_t);
diff --git a/host/libs/virglrenderer/emugl/common/logging.h b/host/libs/virglrenderer/emugl/common/logging.h
new file mode 100644
index 0000000000000000000000000000000000000000..081df6132daab62a3c741ca0dc718cbf3d152320
--- /dev/null
+++ b/host/libs/virglrenderer/emugl/common/logging.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+typedef void (*emugl_logger_t)(const char* fmt, ...);
+
+extern emugl_logger_t emugl_logger;
+extern emugl_logger_t emugl_cxt_logger;
+void set_emugl_logger(emugl_logger_t f);
+void set_emugl_cxt_logger(emugl_logger_t f);
+
+#define GL_LOGGING 1
+
+#if GL_LOGGING
+
+#define GL_LOG(...) do { \
+    emugl_logger(__VA_ARGS__); \
+} while (0)
+
+#define GL_CXT_LOG(...) do { \
+    emugl_cxt_logger(__VA_ARGS__); \
+} while (0)
+
+#else
+#define GL_LOG(...) 0
+#endif
diff --git a/host/libs/virglrenderer/include/VirtioGpuCmd.h b/host/libs/virglrenderer/include/VirtioGpuCmd.h
new file mode 100644
index 0000000000000000000000000000000000000000..6ffacd3fc6a708083261b4a8b3e0441d04da20db
--- /dev/null
+++ b/host/libs/virglrenderer/include/VirtioGpuCmd.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+struct VirtioGpuCmd {
+    uint32_t op;
+    uint32_t cmdSize;
+    unsigned char buf[0];
+} __attribute__((packed));
diff --git a/host/libs/virglrenderer/include/android/api-level.h b/host/libs/virglrenderer/include/android/api-level.h
new file mode 100644
index 0000000000000000000000000000000000000000..2d2f0968c4e9d4527778c2ba13c640b916206f22
--- /dev/null
+++ b/host/libs/virglrenderer/include/android/api-level.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef ANDROID_API_LEVEL_H
+#define ANDROID_API_LEVEL_H
+
+/*
+ * Magic version number for a current development build, which has
+ * not yet turned into an official release.
+ */
+#define __ANDROID_API__ 10000
+
+#endif /* ANDROID_API_LEVEL_H */
diff --git a/host/libs/virglrenderer/include/android/sync.h b/host/libs/virglrenderer/include/android/sync.h
new file mode 100644
index 0000000000000000000000000000000000000000..1ae728a5a892b65496fe576b280256b71dfa2989
--- /dev/null
+++ b/host/libs/virglrenderer/include/android/sync.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+extern "C" {
+int sync_wait(int fd, int timeout);
+};
diff --git a/host/libs/virglrenderer/include/cutils/native_handle.h b/host/libs/virglrenderer/include/cutils/native_handle.h
new file mode 100644
index 0000000000000000000000000000000000000000..b92a66385245e6fa6994912665374bce6299d4b3
--- /dev/null
+++ b/host/libs/virglrenderer/include/cutils/native_handle.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+struct native_handle_t;
+
+typedef const struct native_handle_t* buffer_handle_t;
diff --git a/host/libs/virglrenderer/include/hardware/gralloc.h b/host/libs/virglrenderer/include/hardware/gralloc.h
new file mode 100644
index 0000000000000000000000000000000000000000..8446ba4ea803941cb6a64e7651b44825a5b3d71e
--- /dev/null
+++ b/host/libs/virglrenderer/include/hardware/gralloc.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cutils/native_handle.h>
+
+#include <hardware/hardware.h>
+
+struct android_ycbcr;
+
+enum {
+    GRALLOC_USAGE_SW_READ_OFTEN = 0x00000003U,
+    GRALLOC_USAGE_SW_WRITE_OFTEN = 0x00000030U,
+    GRALLOC_USAGE_HW_TEXTURE = 0x00000100U,
+    GRALLOC_USAGE_HW_RENDER = 0x00000200U,
+};
+
+struct gralloc_module_t {
+    hw_module_t common;
+    int (*registerBuffer)(gralloc_module_t const*, buffer_handle_t);
+    int (*unregisterBuffer)(gralloc_module_t const*, buffer_handle_t);
+    int (*lock)(gralloc_module_t const*, buffer_handle_t, int, int, int, int, int, void**);
+    int (*unlock)(gralloc_module_t const*, buffer_handle_t);
+    int (*perform)(gralloc_module_t const*, int, ...);
+    int (*lock_ycbcr)(gralloc_module_t const*, buffer_handle_t, int, int, int, int, int,
+                      android_ycbcr*);
+    int (*lockAsync)(gralloc_module_t const*, buffer_handle_t, int, int, int, int, int, void**, int);
+    int (*unlockAsync)(gralloc_module_t const*, buffer_handle_t, int*);
+    int (*lockAsync_ycbcr)(gralloc_module_t const*, buffer_handle_t, int, int, int, int, int,
+                           android_ycbcr*, int);
+    void* reserved_proc[3];
+};
diff --git a/host/libs/virglrenderer/include/hardware/gralloc1.h b/host/libs/virglrenderer/include/hardware/gralloc1.h
new file mode 100644
index 0000000000000000000000000000000000000000..b02decfa031a124d1825d62cf5ff1871d02e8195
--- /dev/null
+++ b/host/libs/virglrenderer/include/hardware/gralloc1.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <hardware/hardware.h>
+
+#include <cutils/native_handle.h>
+
+#define GRALLOC_MODULE_API_VERSION_1_0 HARDWARE_MAKE_API_VERSION(1, 0)
+
+#define GRALLOC_HARDWARE_MODULE_ID "gralloc"
+
+enum {
+    GRALLOC1_ERROR_NONE = 0,
+    GRALLOC1_ERROR_BAD_HANDLE = 2,
+    GRALLOC1_ERROR_BAD_VALUE = 3,
+    GRALLOC1_ERROR_UNDEFINED = 6,
+};
+
+enum {
+    GRALLOC1_FUNCTION_LOCK = 18,
+    GRALLOC1_FUNCTION_UNLOCK = 20,
+};
+
+enum {
+    GRALLOC1_CONSUMER_USAGE_CPU_READ = 1ULL << 1,
+    GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN = 1ULL << 2 | GRALLOC1_CONSUMER_USAGE_CPU_READ,
+    GRALLOC1_CONSUMER_USAGE_CPU_WRITE = 1ULL << 5,
+    GRALLOC1_CONSUMER_USAGE_CPU_WRITE_OFTEN = 1ULL << 6 | GRALLOC1_CONSUMER_USAGE_CPU_WRITE,
+    GRALLOC1_CONSUMER_USAGE_GPU_TEXTURE = 1ULL << 8,
+};
+
+enum {
+    GRALLOC1_PRODUCER_USAGE_CPU_READ = 1ULL << 1,
+    GRALLOC1_PRODUCER_USAGE_CPU_READ_OFTEN = 1ULL << 2 | GRALLOC1_PRODUCER_USAGE_CPU_READ,
+    GRALLOC1_PRODUCER_USAGE_CPU_WRITE = 1ULL << 5,
+    GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN = 1ULL << 6 | GRALLOC1_PRODUCER_USAGE_CPU_WRITE,
+    GRALLOC1_PRODUCER_USAGE_GPU_RENDER_TARGET = 1ULL << 9,
+};
+
+typedef void (*gralloc1_function_pointer_t)();
+
+struct gralloc1_rect_t {
+    int32_t left;
+    int32_t top;
+    int32_t width;
+    int32_t height;
+};
+
+struct gralloc1_device_t {
+    hw_device_t common;
+    void (*getCapabilities)(gralloc1_device_t*, uint32_t*, int32_t*);
+    gralloc1_function_pointer_t (*getFunction)(gralloc1_device_t*, int32_t);
+};
+
+typedef int32_t (*GRALLOC1_PFN_LOCK)(gralloc1_device_t*, buffer_handle_t, uint64_t, uint64_t,
+                                     const gralloc1_rect_t*, void**, int32_t);
+typedef int32_t (*GRALLOC1_PFN_UNLOCK)(gralloc1_device_t*, buffer_handle_t, int32_t*);
+
+static inline int gralloc1_open(const hw_module_t* module, gralloc1_device_t** device) {
+    return module->methods->open(module, GRALLOC_HARDWARE_MODULE_ID,
+                                 reinterpret_cast<hw_device_t**>(device));
+}
diff --git a/host/libs/virglrenderer/include/hardware/hardware.h b/host/libs/virglrenderer/include/hardware/hardware.h
new file mode 100644
index 0000000000000000000000000000000000000000..21d6dc4ab58e35bb4681cb6b92f8549617cdd7de
--- /dev/null
+++ b/host/libs/virglrenderer/include/hardware/hardware.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cstdint>
+
+#define MAKE_TAG_CONSTANT(A, B, C, D) (((A) << 24) | ((B) << 16) | ((C) << 8) | (D))
+
+#define HARDWARE_MODULE_TAG MAKE_TAG_CONSTANT('H', 'W', 'M', 'T')
+#define HARDWARE_DEVICE_TAG MAKE_TAG_CONSTANT('H', 'W', 'D', 'T')
+
+#define HARDWARE_MAKE_API_VERSION(maj, min) ((((maj)&0xff) << 8) | ((min)&0xff))
+
+#define HARDWARE_HAL_API_VERSION HARDWARE_MAKE_API_VERSION(1, 0)
+
+struct hw_module_methods_t;
+
+struct hw_module_t {
+    uint32_t tag;
+    uint16_t module_api_version;
+    uint16_t hal_api_version;
+    const char* id;
+    const char* name;
+    const char* author;
+    hw_module_methods_t* methods;
+    void* dso;
+#ifdef __LP64__
+    uint64_t reserved[32 - 7];
+#else
+    uint32_t reserved[32 - 7];
+#endif
+};
+
+struct hw_device_t {
+    uint32_t tag;
+    uint32_t version;
+    struct hw_module_t* module;
+#ifdef __LP64__
+    uint64_t reserved[12];
+#else
+    uint32_t reserved[12];
+#endif
+    int (*close)(hw_device_t* device);
+};
+
+struct hw_module_methods_t {
+    int (*open)(const hw_module_t*, const char*, hw_device_t**);
+};
+
+extern "C" {
+int hw_get_module(const char* id, const hw_module_t** module);
+};
diff --git a/host/libs/virglrenderer/include/nativebase/nativebase.h b/host/libs/virglrenderer/include/nativebase/nativebase.h
new file mode 100644
index 0000000000000000000000000000000000000000..c2e84d79a7750eab6a0fcb20a781c367627c27de
--- /dev/null
+++ b/host/libs/virglrenderer/include/nativebase/nativebase.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cutils/native_handle.h>
+
+#include <cstdint>
+#include <cstring>
+
+// clang-format off
+#define ANDROID_NATIVE_MAKE_CONSTANT(a, b, c, d) \
+    ((static_cast<unsigned int>(a) << 24) | \
+     (static_cast<unsigned int>(b) << 16) | \
+     (static_cast<unsigned int>(c) <<  8) | \
+     (static_cast<unsigned int>(d) <<  0))
+// clang-format on
+
+struct android_native_base_t {
+    int magic;
+    int version;
+    void* reserved[4];
+    void (*incRef)(android_native_base_t*);
+    void (*decRef)(android_native_base_t*);
+};
+
+#define ANDROID_NATIVE_BUFFER_MAGIC ANDROID_NATIVE_MAKE_CONSTANT('_', 'b', 'f', 'r')
+
+struct ANativeWindowBuffer {
+    ANativeWindowBuffer() {
+        common.magic = ANDROID_NATIVE_BUFFER_MAGIC;
+        common.version = sizeof(ANativeWindowBuffer);
+        memset(common.reserved, 0, sizeof(common.reserved));
+    }
+
+    android_native_base_t common;
+
+    int width;
+    int height;
+    int stride;
+    int format;
+    int usage_deprecated;
+    uintptr_t layerCount;
+
+    void* reserved[1];
+
+    const native_handle_t* handle;
+    uint64_t usage;
+
+    void* reserved_proc[8 - (sizeof(uint64_t) / sizeof(void*))];
+};
diff --git a/host/libs/virglrenderer/include/sync/sync.h b/host/libs/virglrenderer/include/sync/sync.h
new file mode 100644
index 0000000000000000000000000000000000000000..1ae728a5a892b65496fe576b280256b71dfa2989
--- /dev/null
+++ b/host/libs/virglrenderer/include/sync/sync.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+extern "C" {
+int sync_wait(int fd, int timeout);
+};
diff --git a/host/libs/virglrenderer/include/system/graphics.h b/host/libs/virglrenderer/include/system/graphics.h
new file mode 100644
index 0000000000000000000000000000000000000000..884db9cc2639804cc53824b12947f25d0beee99c
--- /dev/null
+++ b/host/libs/virglrenderer/include/system/graphics.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+enum {
+    HAL_PIXEL_FORMAT_RGBA_8888 = 1,
+    HAL_PIXEL_FORMAT_RGBX_8888 = 2,
+    HAL_PIXEL_FORMAT_RGB_888 = 3,
+    HAL_PIXEL_FORMAT_RGB_565 = 4,
+    HAL_PIXEL_FORMAT_BGRA_8888 = 5,
+    HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 34,
+    HAL_PIXEL_FORMAT_YV12 = 842094169,
+};
diff --git a/host/libs/virglrenderer/include/system/window.h b/host/libs/virglrenderer/include/system/window.h
new file mode 100644
index 0000000000000000000000000000000000000000..f986274c1ae1103fd6e69323d48c8ef19a6f56fa
--- /dev/null
+++ b/host/libs/virglrenderer/include/system/window.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <nativebase/nativebase.h>
+#include <system/graphics.h>
+
+#define ANDROID_NATIVE_WINDOW_MAGIC ANDROID_NATIVE_MAKE_CONSTANT('_', 'w', 'n', 'd')
+
+enum {
+    NATIVE_WINDOW_WIDTH = 0,
+    NATIVE_WINDOW_HEIGHT = 1,
+};
+
+struct ANativeWindow {
+    ANativeWindow() : flags(0), minSwapInterval(0), maxSwapInterval(0), xdpi(0), ydpi(0) {
+        common.magic = ANDROID_NATIVE_BUFFER_MAGIC;
+        common.version = sizeof(ANativeWindowBuffer);
+        memset(common.reserved, 0, sizeof(common.reserved));
+    }
+
+    android_native_base_t common;
+
+    const uint32_t flags;
+    const int minSwapInterval;
+    const int maxSwapInterval;
+    const float xdpi;
+    const float ydpi;
+    intptr_t oem[4];
+
+    int (*setSwapInterval)(ANativeWindow*, int);
+    int (*dequeueBuffer_DEPRECATED)(ANativeWindow*, ANativeWindowBuffer**);
+    int (*lockBuffer_DEPRECATED)(ANativeWindow*, ANativeWindowBuffer*);
+    int (*queueBuffer_DEPRECATED)(ANativeWindow*, ANativeWindowBuffer*);
+    int (*query)(const ANativeWindow*, int, int*);
+    int (*perform)(ANativeWindow*, int, ...);
+    int (*cancelBuffer_DEPRECATED)(ANativeWindow*, ANativeWindowBuffer*);
+    int (*dequeueBuffer)(ANativeWindow*, ANativeWindowBuffer**, int*);
+    int (*queueBuffer)(ANativeWindow*, ANativeWindowBuffer*, int);
+    int (*cancelBuffer)(ANativeWindow*, ANativeWindowBuffer*, int);
+};
+
+static inline int native_window_set_usage(ANativeWindow*, uint64_t) {
+    // No-op
+    return 0;
+}
+
+static inline int native_window_dequeue_buffer_and_wait(ANativeWindow* anw,
+                                                        ANativeWindowBuffer** anwb) {
+    return anw->dequeueBuffer_DEPRECATED(anw, anwb);
+}
diff --git a/host/libs/virglrenderer/libOpenglRender/FrameworkFormats.h b/host/libs/virglrenderer/libOpenglRender/FrameworkFormats.h
new file mode 100644
index 0000000000000000000000000000000000000000..c6f1f3719dbdcb057d6c863dc8a5db4bd0313a56
--- /dev/null
+++ b/host/libs/virglrenderer/libOpenglRender/FrameworkFormats.h
@@ -0,0 +1,19 @@
+#pragma once
+
+// Android system might want to allocate some color buffers with formats
+// that are not compatible with most OpenGL implementations,
+// such as YV12.
+// In this situation, we need to convert to some OpenGL format such as
+// RGB888 that actually works.
+// While we can do some of this conversion in the guest gralloc driver itself
+// (which would make ColorBuffer see only the OpenGL formatted pixels),
+// it may be advantageous to do the conversion on the host as well.
+// FrameworkFormat tracks whether the incoming color buffer from the guest
+// can be directly used as a GL texture (FRAMEWORK_FORMAT_GL_COMPATIBLE).
+// Otherwise, we need to know which format it is (e.g., FRAMEWORK_FORMAT_YV12)
+// and convert on the host.
+enum FrameworkFormat {
+    FRAMEWORK_FORMAT_GL_COMPATIBLE = 0,
+    FRAMEWORK_FORMAT_YV12 = 1,
+    FRAMEWORK_FORMAT_YUV_420_888 = 2,
+};
diff --git a/host/libs/virglrenderer/libOpenglRender/GLESVersionDetector.cpp b/host/libs/virglrenderer/libOpenglRender/GLESVersionDetector.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..57a3b50274ce5e327ad8ba872341df6837df3efd
--- /dev/null
+++ b/host/libs/virglrenderer/libOpenglRender/GLESVersionDetector.cpp
@@ -0,0 +1,47 @@
+/*
+* Copyright (C) 2016 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#include "GLESVersionDetector.h"
+
+#include "DispatchTables.h"
+
+#include "emugl/common/feature_control.h"
+
+#include <algorithm>
+
+GLESDispatchMaxVersion calcMaxVersionFromDispatch() {
+    // Detect the proper OpenGL ES version to advertise to the system.
+    //
+    // If the underlying glesv2 library also is on top of system OpenGL,
+    // we assume existence of a function called "gl_dispatch_get_max_version"
+    // which matches the return type of gles2_dispatch_get_max_version,
+    // and allows us to scale back if the underlying host machine
+    // doesn't actually suppport a particular GLES version.
+    if (!emugl_feature_is_enabled(android::featurecontrol::GLESDynamicVersion))
+        return GLES_DISPATCH_MAX_VERSION_2;
+
+    GLESDispatchMaxVersion underlying_gles2_lib_max =
+        gles2_dispatch_get_max_version();
+    if (s_gles2.gl_dispatch_get_max_version) {
+        GLESDispatchMaxVersion underlying_gl_lib_max =
+            (GLESDispatchMaxVersion)s_gles2.gl_dispatch_get_max_version();
+        return std::min(underlying_gl_lib_max, underlying_gles2_lib_max);
+    } else {
+        return underlying_gles2_lib_max;
+    }
+
+    return GLES_DISPATCH_MAX_VERSION_2;
+}
diff --git a/host/libs/virglrenderer/libOpenglRender/GLESVersionDetector.h b/host/libs/virglrenderer/libOpenglRender/GLESVersionDetector.h
new file mode 100644
index 0000000000000000000000000000000000000000..82532ff1614cf9ddc1b7a37a0bd8497a1d31b950
--- /dev/null
+++ b/host/libs/virglrenderer/libOpenglRender/GLESVersionDetector.h
@@ -0,0 +1,22 @@
+/*
+* Copyright (C) 2016 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#pragma once
+
+#include "OpenGLESDispatch/GLESv2Dispatch.h"
+
+// Used to determine maximum supported GLES version.
+GLESDispatchMaxVersion calcMaxVersionFromDispatch();
diff --git a/host/libs/virglrenderer/libOpenglRender/YUVConverter.cpp b/host/libs/virglrenderer/libOpenglRender/YUVConverter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..74a229f8e2f4045c3c7c956c4202f5c57294f771
--- /dev/null
+++ b/host/libs/virglrenderer/libOpenglRender/YUVConverter.cpp
@@ -0,0 +1,475 @@
+/*
+* Copyright (C) 2016 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#include "YUVConverter.h"
+
+#include "DispatchTables.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#define FATAL(fmt,...) do { \
+    fprintf(stderr, "%s: FATAL: " fmt "\n", __func__, ##__VA_ARGS__); \
+    assert(false); \
+} while(0)
+
+static void getPlanarYUVSizes(int width, int height,
+                              FrameworkFormat format,
+                              uint32_t* nBytes_out,
+                              uint32_t* yStride_out,
+                              uint32_t* cStride_out,
+                              uint32_t* cHeight_out) {
+    assert(nBytes_out);
+    assert(yStride_out);
+    assert(cStride_out);
+    assert(cHeight_out);
+
+    uint32_t align;
+    switch (format) {
+    case FRAMEWORK_FORMAT_YV12:
+        align = 16;
+        break;
+    case FRAMEWORK_FORMAT_YUV_420_888:
+        align = 1;
+        break;
+    case FRAMEWORK_FORMAT_GL_COMPATIBLE:
+        FATAL("Input not a YUV format!");
+    }
+
+    // 16-alignment means we need to get the
+    // smallest multiple of 16 pixels that is
+    // greater than or equal to |width| for |yStride| and
+    // greater than or equal to |width / 2| for |cStride|
+    uint32_t yStride = (width + (align - 1)) & ~(align - 1);
+    uint32_t cStride = (yStride / 2 + (align - 1)) & ~(align - 1);
+    uint32_t cHeight = height / 2;
+
+    *nBytes_out = yStride * height + 2 * (cStride * cHeight);
+    *yStride_out = yStride;
+    *cStride_out = cStride;
+    *cHeight_out = cHeight;
+}
+
+// getYUVSizes(): given |width| and |height|, return
+// the total number of bytes of the YUV-formatted buffer
+// in |nBytes_out|, and store aligned width and C height
+// in |yStride_out|/|cStride_out| and |cHeight_out|.
+static void getYUVSizes(int width, int height,
+                        FrameworkFormat format,
+                        uint32_t* nBytes_out,
+                        uint32_t* yStride_out,
+                        uint32_t* cStride_out,
+                        uint32_t* cHeight_out) {
+    switch (format) {
+    case FRAMEWORK_FORMAT_YV12:
+    case FRAMEWORK_FORMAT_YUV_420_888:
+        getPlanarYUVSizes(width, height, format,
+                          nBytes_out,
+                          yStride_out,
+                          cStride_out,
+                          cHeight_out);
+        break;
+    case FRAMEWORK_FORMAT_GL_COMPATIBLE:
+        FATAL("Input not a YUV format!");
+    }
+}
+
+static void getPlanarYUVOffsets(int width, int height, FrameworkFormat format,
+                                uint32_t* yoff, uint32_t* uoff, uint32_t* voff,
+                                uint32_t* alignwidth, uint32_t* alignwidthc) {
+    uint32_t totalSize, yStride, cStride, cHeight;
+    cStride = 0;
+    yStride = 0;
+    totalSize = 0;
+    getYUVSizes(width, height, format, &totalSize, &yStride, &cStride, &cHeight);
+    int cSize = cStride * height / 2;
+
+    switch (format) {
+    case FRAMEWORK_FORMAT_YV12:
+        // In our use cases (so far), the buffer should
+        // always begin with Y.
+        *yoff = 0;
+        // The U and V planes are switched around so physically
+        // YV12 is more of a "YVU" format
+        *voff = (*yoff) + yStride * height;
+        *uoff = (*voff) + cSize;
+        *alignwidth = yStride;
+        *alignwidthc = cStride;
+        break;
+    case FRAMEWORK_FORMAT_YUV_420_888:
+        *yoff = 0;
+        *uoff = (*yoff) + yStride * height;
+        *voff = (*uoff) + cSize;
+        *alignwidth = yStride;
+        *alignwidthc = cStride;
+        break;
+    case FRAMEWORK_FORMAT_GL_COMPATIBLE:
+        FATAL("Input not a YUV format!");
+    }
+}
+
+// getYUVOffsets(), given a YUV-formatted buffer that is arranged
+// according to the spec
+// https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV
+// In particular, Android YUV widths are aligned to 16 pixels.
+// Inputs:
+// |yv12|: the YUV-formatted buffer
+// Outputs:
+// |yoff|: offset into |yv12| of the start of the Y component
+// |uoff|: offset into |yv12| of the start of the U component
+// |voff|: offset into |yv12| of the start of the V component
+static void getYUVOffsets(int width, int height, FrameworkFormat format,
+                          uint32_t* yoff, uint32_t* uoff, uint32_t* voff,
+                          uint32_t* alignwidth, uint32_t* alignwidthc) {
+    switch (format) {
+    case FRAMEWORK_FORMAT_YV12:
+    case FRAMEWORK_FORMAT_YUV_420_888:
+        getPlanarYUVOffsets(width, height, format,
+                            yoff, uoff, voff,
+                            alignwidth, alignwidthc);
+        break;
+    case FRAMEWORK_FORMAT_GL_COMPATIBLE:
+        FATAL("Input not a YUV format!");
+    }
+}
+
+// createYUVGLTex() allocates GPU memory that is enough
+// to hold the raw data of the YV12 buffer.
+// The memory is in the form of an OpenGL texture
+// with one component (GL_LUMINANCE) and
+// of type GL_UNSIGNED_BYTE.
+// In order to process all Y, U, V components
+// simultaneously in conversion, the simple thing to do
+// is to use multiple texture units, hence
+// the |texture_unit| argument.
+// Returns a new OpenGL texture object in |texName_out|
+// that is to be cleaned up by the caller.
+static void createYUVGLTex(GLenum texture_unit,
+                           GLsizei width,
+                           GLsizei height,
+                           GLuint* texName_out) {
+    assert(texName_out);
+
+    s_gles2.glActiveTexture(texture_unit);
+    s_gles2.glGenTextures(1, texName_out);
+    s_gles2.glBindTexture(GL_TEXTURE_2D, *texName_out);
+    s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    s_gles2.glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE,
+                         width, height, 0,
+                         GL_LUMINANCE, GL_UNSIGNED_BYTE,
+                         NULL);
+    s_gles2.glActiveTexture(GL_TEXTURE0);
+}
+
+// subUpdateYUVGLTex() updates a given YUV texture
+// at the coordinates (x, y, width, height),
+// with the raw YUV data in |pixels|.
+// We cannot view the result properly until
+// after conversion; this is to be used only
+// as input to the conversion shader.
+static void subUpdateYUVGLTex(GLenum texture_unit,
+                              GLuint tex,
+                              int x, int y, int width, int height,
+                              void* pixels) {
+    s_gles2.glActiveTexture(texture_unit);
+    s_gles2.glBindTexture(GL_TEXTURE_2D, tex);
+    s_gles2.glTexSubImage2D(GL_TEXTURE_2D, 0,
+                            x, y, width, height,
+                            GL_LUMINANCE, GL_UNSIGNED_BYTE,
+                            pixels);
+    s_gles2.glActiveTexture(GL_TEXTURE0);
+}
+
+// createYUVGLShader() defines the vertex/fragment
+// shader that does the actual work of converting
+// YUV to RGB. The resulting shaders and program
+// are stored in |vshader_out|, |fshader_out|,
+// and |program_out|.
+static void createYUVGLShader(GLuint* vshader_out,
+                              GLuint* fshader_out,
+                              GLuint* program_out,
+                              GLint* ywidthcutoffloc_out,
+                              GLint* cwidthcutoffloc_out,
+                              GLint* ysamplerloc_out,
+                              GLint* usamplerloc_out,
+                              GLint* vsamplerloc_out) {
+    assert(vshader_out);
+    assert(fshader_out);
+    assert(program_out);
+
+    static const char kVShader[] = R"(
+precision highp float;
+attribute mediump vec4 position;
+attribute highp vec2 inCoord;
+varying highp vec2 outCoord;
+void main(void) {
+  gl_Position = position;
+  outCoord = inCoord;
+}
+    )";
+    const GLchar* const kVShaders =
+        static_cast<const GLchar*>(kVShader);
+
+    // Based on:
+    // http://stackoverflow.com/questions/11093061/yv12-to-rgb-using-glsl-in-ios-result-image-attached
+    // + account for 16-pixel alignment using |yWidthCutoff| / |cWidthCutoff|
+    // + use conversion matrix in
+    // frameworks/av/media/libstagefright/colorconversion/ColorConverter.cpp (YUV420p)
+    // + more precision from
+    // https://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.601_conversion
+    static const char kFShader[] = R"(
+precision highp float;
+varying highp vec2 outCoord;
+uniform highp float yWidthCutoff;
+uniform highp float cWidthCutoff;
+uniform sampler2D ysampler;
+uniform sampler2D usampler;
+uniform sampler2D vsampler;
+void main(void) {
+    highp vec2 cutoffCoordsY;
+    highp vec2 cutoffCoordsC;
+    highp vec3 yuv;
+    highp vec3 rgb;
+    cutoffCoordsY.x = outCoord.x * yWidthCutoff;
+    cutoffCoordsY.y = outCoord.y;
+    cutoffCoordsC.x = outCoord.x * cWidthCutoff;
+    cutoffCoordsC.y = outCoord.y;
+    yuv[0] = texture2D(ysampler, cutoffCoordsY).r - 0.0625;
+    yuv[1] = texture2D(usampler, cutoffCoordsC).r - 0.5;
+    yuv[2] = texture2D(vsampler, cutoffCoordsC).r - 0.5;
+    highp float yscale = 1.1643835616438356;
+    rgb = mat3(yscale,                           yscale,            yscale,
+               0,                  -0.39176229009491365, 2.017232142857143,
+               1.5960267857142856, -0.8129676472377708,                  0) * yuv;
+    gl_FragColor = vec4(rgb, 1);
+}
+    )";
+
+    const GLchar* const kFShaders =
+        static_cast<const GLchar*>(kFShader);
+
+    *vshader_out = s_gles2.glCreateShader(GL_VERTEX_SHADER);
+    *fshader_out = s_gles2.glCreateShader(GL_FRAGMENT_SHADER);
+
+    const GLint vtextLen = strlen(kVShader);
+    const GLint ftextLen = strlen(kFShader);
+    s_gles2.glShaderSource(*vshader_out, 1, &kVShaders, &vtextLen);
+    s_gles2.glShaderSource(*fshader_out, 1, &kFShaders, &ftextLen);
+    s_gles2.glCompileShader(*vshader_out);
+    s_gles2.glCompileShader(*fshader_out);
+
+    *program_out = s_gles2.glCreateProgram();
+    s_gles2.glAttachShader(*program_out, *vshader_out);
+    s_gles2.glAttachShader(*program_out, *fshader_out);
+    s_gles2.glLinkProgram(*program_out);
+
+    s_gles2.glUseProgram(*program_out);
+    *ywidthcutoffloc_out = s_gles2.glGetUniformLocation(*program_out, "yWidthCutoff");
+    *cwidthcutoffloc_out = s_gles2.glGetUniformLocation(*program_out, "cWidthCutoff");
+    *ysamplerloc_out = s_gles2.glGetUniformLocation(*program_out, "ysampler");
+    *usamplerloc_out = s_gles2.glGetUniformLocation(*program_out, "usampler");
+    *vsamplerloc_out = s_gles2.glGetUniformLocation(*program_out, "vsampler");
+    s_gles2.glUseProgram(0);
+}
+
+// When converting YUV to RGB with shaders,
+// we are using the OpenGL graphics pipeline to do compute,
+// so we need to express the place to store the result
+// with triangles and draw calls.
+// createYUVGLFullscreenQuad() defines a fullscreen quad
+// with position and texture coordinates.
+// The quad will be textured with the resulting RGB colors,
+// and we will read back the pixels from the framebuffer
+// to retrieve our RGB result.
+static void createYUVGLFullscreenQuad(GLuint* vbuf_out,
+                                      GLuint* ibuf_out,
+                                      int picture_width,
+                                      int aligned_width) {
+    assert(vbuf_out);
+    assert(ibuf_out);
+
+    s_gles2.glGenBuffers(1, vbuf_out);
+    s_gles2.glGenBuffers(1, ibuf_out);
+
+    static const float kVertices[] = {
+        +1, -1, +0, +1, +0,
+        +1, +1, +0, +1, +1,
+        -1, +1, +0, +0, +1,
+        -1, -1, +0, +0, +0,
+    };
+
+    static const GLubyte kIndices[] = { 0, 1, 2, 2, 3, 0 };
+
+    s_gles2.glBindBuffer(GL_ARRAY_BUFFER, *vbuf_out);
+    s_gles2.glBufferData(GL_ARRAY_BUFFER, sizeof(kVertices), kVertices,
+                         GL_STATIC_DRAW);
+    s_gles2.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, *ibuf_out);
+    s_gles2.glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(kIndices), kIndices,
+                         GL_STATIC_DRAW);
+}
+
+// doYUVConversionDraw() does the actual work of setting up
+// and submitting draw commands to the GPU.
+// It uses the textures, shaders, and fullscreen quad defined above
+// and executes the pipeline on them.
+// Note, however, that it is up to the caller to dig out
+// the result of the draw.
+static void doYUVConversionDraw(GLuint program,
+                                GLint yWidthCutoffLoc,
+                                GLint cWidthCutoffLoc,
+                                GLint ySamplerLoc,
+                                GLint uSamplerLoc,
+                                GLint vSamplerLoc,
+                                GLuint vbuf, GLuint ibuf,
+                                int width, int ywidth,
+                                int halfwidth, int cwidth,
+                                float yWidthCutoff,
+                                float cWidthCutoff) {
+
+    const GLsizei kVertexAttribStride = 5 * sizeof(GL_FLOAT);
+    const GLvoid* kVertexAttribPosOffset = (GLvoid*)0;
+    const GLvoid* kVertexAttribCoordOffset = (GLvoid*)(3 * sizeof(GL_FLOAT));
+
+    s_gles2.glUseProgram(program);
+
+    GLint posLoc = s_gles2.glGetAttribLocation(program, "position");
+    GLint coordLoc = s_gles2.glGetAttribLocation(program, "inCoord");
+
+    s_gles2.glUniform1f(yWidthCutoffLoc, yWidthCutoff);
+    s_gles2.glUniform1f(cWidthCutoffLoc, cWidthCutoff);
+
+    s_gles2.glUniform1i(ySamplerLoc, 0);
+    s_gles2.glUniform1i(uSamplerLoc, 1);
+    s_gles2.glUniform1i(vSamplerLoc, 2);
+
+    s_gles2.glBindBuffer(GL_ARRAY_BUFFER, vbuf);
+    s_gles2.glEnableVertexAttribArray(posLoc);
+    s_gles2.glEnableVertexAttribArray(coordLoc);
+
+    s_gles2.glVertexAttribPointer(posLoc, 3, GL_FLOAT, false,
+                                  kVertexAttribStride,
+                                  kVertexAttribPosOffset);
+    s_gles2.glVertexAttribPointer(coordLoc, 2, GL_FLOAT, false,
+                                  kVertexAttribStride,
+                                  kVertexAttribCoordOffset);
+
+    s_gles2.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibuf);
+    s_gles2.glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, 0);
+
+    s_gles2.glDisableVertexAttribArray(posLoc);
+    s_gles2.glDisableVertexAttribArray(coordLoc);
+}
+
+// initialize(): allocate GPU memory for YUV components,
+// and create shaders and vertex data.
+YUVConverter::YUVConverter(int width, int height, FrameworkFormat format) : mFormat(format){
+
+    uint32_t totalSize, yStride, cStride, cHeight;
+    totalSize = 0;
+    getYUVSizes(width, height, mFormat, &totalSize, &yStride, &cStride, &cHeight);
+
+    uint32_t yoff, uoff, voff,
+             ywidth, cwidth, cheight;
+    getYUVOffsets(width, height, mFormat,
+                  &yoff, &uoff, &voff,
+                  &ywidth, &cwidth);
+    cheight = height / 2;
+
+    createYUVGLTex(GL_TEXTURE0, ywidth, height, &mYtex);
+    createYUVGLTex(GL_TEXTURE1, cwidth, cheight, &mUtex);
+    createYUVGLTex(GL_TEXTURE2, cwidth, cheight, &mVtex);
+
+    createYUVGLShader(&mVshader, &mFshader,
+                      &mProgram,
+                      &mYWidthCutoffLoc,
+                      &mCWidthCutoffLoc,
+                      &mYSamplerLoc,
+                      &mUSamplerLoc,
+                      &mVSamplerLoc);
+
+    createYUVGLFullscreenQuad(&mVbuf, &mIbuf, width, ywidth);
+}
+
+// drawConvert: per-frame updates.
+// Update YUV textures, then draw the fullscreen
+// quad set up above, which results in a framebuffer
+// with the RGB colors.
+void YUVConverter::drawConvert(int x, int y,
+                               int width, int height,
+                               char* pixels) {
+    s_gles2.glViewport(x, y, width, height);
+
+    uint32_t yoff, uoff, voff,
+             ywidth, cwidth, cheight;
+    getYUVOffsets(width, height, mFormat,
+                  &yoff, &uoff, &voff,
+                  &ywidth, &cwidth);
+    cheight = height / 2;
+
+    subUpdateYUVGLTex(GL_TEXTURE0, mYtex,
+                      x, y, ywidth, height,
+                      pixels + yoff);
+    subUpdateYUVGLTex(GL_TEXTURE1, mUtex,
+                      x, y, cwidth, cheight,
+                      pixels + uoff);
+    subUpdateYUVGLTex(GL_TEXTURE2, mVtex,
+                      x, y, cwidth, cheight,
+                      pixels + voff);
+
+
+    updateCutoffs(width, ywidth, width / 2, cwidth);
+
+    doYUVConversionDraw(mProgram,
+                        mYWidthCutoffLoc,
+                        mCWidthCutoffLoc,
+                        mYSamplerLoc,
+                        mUSamplerLoc,
+                        mVSamplerLoc,
+                        mVbuf, mIbuf,
+                        width, ywidth,
+                        width / 2, cwidth,
+                        mYWidthCutoff,
+                        mCWidthCutoff);
+}
+
+void YUVConverter::updateCutoffs(float width, float ywidth,
+                                 float halfwidth, float cwidth) {
+    switch (mFormat) {
+    case FRAMEWORK_FORMAT_YV12:
+        mYWidthCutoff = ((float)width) / ((float)ywidth);
+        mCWidthCutoff = ((float)halfwidth) / ((float)cwidth);
+        break;
+    case FRAMEWORK_FORMAT_YUV_420_888:
+        mYWidthCutoff = 1.0f;
+        mCWidthCutoff = 1.0f;
+        break;
+    case FRAMEWORK_FORMAT_GL_COMPATIBLE:
+        FATAL("Input not a YUV format!");
+    } 
+}
+
+YUVConverter::~YUVConverter() {
+    if (mIbuf) s_gles2.glDeleteBuffers(1, &mIbuf);
+    if (mVbuf) s_gles2.glDeleteBuffers(1, &mVbuf);
+    if (mProgram) s_gles2.glDeleteProgram(mProgram);
+    if (mFshader) s_gles2.glDeleteShader(mFshader);
+    if (mVshader) s_gles2.glDeleteShader(mVshader);
+    if (mYtex) s_gles2.glDeleteTextures(1, &mYtex);
+    if (mUtex) s_gles2.glDeleteTextures(1, &mUtex);
+    if (mVtex) s_gles2.glDeleteTextures(1, &mVtex);
+}
diff --git a/host/libs/virglrenderer/libOpenglRender/YUVConverter.h b/host/libs/virglrenderer/libOpenglRender/YUVConverter.h
new file mode 100644
index 0000000000000000000000000000000000000000..6d773a1b382028911e4839b62a6b8a6a3044f766
--- /dev/null
+++ b/host/libs/virglrenderer/libOpenglRender/YUVConverter.h
@@ -0,0 +1,77 @@
+/*
+* Copyright (C) 2016 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#pragma once
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include "FrameworkFormats.h"
+
+// The purpose of YUVConverter is to use
+// OpenGL shaders to convert YUV images to RGB
+// images that can be displayed on screen.
+// Doing this on the GPU can be much faster than
+// on the CPU.
+
+// Usage:
+// 0. Have a current OpenGL context working.
+// 1. Constructing the YUVConverter object will allocate
+//    OpenGL resources needed to convert, given the desired
+//    |width| and |height| of the buffer.
+// 2. To convert a given YUV buffer of |pixels|, call
+//    the drawConvert method (with x, y, width, and height
+//    arguments depicting the region to convert).
+//    The RGB version of the YUV buffer will be drawn
+//    to the current framebuffer. To retrieve
+//    the result, if the user of the result is an OpenGL texture,
+//    it suffices to have that texture be the color attachment
+//    of the framebuffer object. Or, if you want the results
+//    on the CPU, call glReadPixels() after the call to drawConvert().
+class YUVConverter {
+public:
+    // call ctor when creating a gralloc buffer
+    // with YUV format
+    YUVConverter(int width, int height, FrameworkFormat format);
+    // destroy when ColorBuffer is destroyed
+    ~YUVConverter();
+    // call when gralloc_unlock updates
+    // the host color buffer
+    // (rcUpdateColorBuffer)
+    void drawConvert(int x, int y, int width, int height, char* pixels);
+private:
+    // For dealing with n-pixel-aligned buffers
+    void updateCutoffs(float width, float ywidth, float halfwidth, float cwidth);
+    FrameworkFormat mFormat;
+    // We need the following GL objects:
+    GLuint mVshader = 0;
+    GLuint mFshader = 0; // Fragment shader (does actual conversion)
+    GLuint mProgram = 0;
+    GLuint mVbuf = 0;
+    GLuint mIbuf = 0;
+    GLuint mYtex = 0;
+    GLuint mUtex = 0;
+    GLuint mVtex = 0;
+
+    // shader uniform locations
+    GLint mYWidthCutoffLoc = -1;
+    GLint mCWidthCutoffLoc = -1;
+    GLint mYSamplerLoc = -1;
+    GLint mUSamplerLoc = -1;
+    GLint mVSamplerLoc = -1;
+    float mYWidthCutoff = 1.0;
+    float mCWidthCutoff = 1.0;
+};
diff --git a/host/libs/virglrenderer/libvirglrenderer.lds b/host/libs/virglrenderer/libvirglrenderer.lds
new file mode 100644
index 0000000000000000000000000000000000000000..9fc62d540a64b44409954e30aa7a1fd917a939cf
--- /dev/null
+++ b/host/libs/virglrenderer/libvirglrenderer.lds
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+{
+global:
+	# virglrenderer API
+	virgl_renderer_init;
+	virgl_renderer_poll;
+	virgl_renderer_get_cursor_data;
+	virgl_renderer_resource_create;
+	virgl_renderer_resource_unref;
+	virgl_renderer_context_create;
+	virgl_renderer_context_destroy;
+	virgl_renderer_submit_cmd;
+	virgl_renderer_transfer_read_iov;
+	virgl_renderer_transfer_write_iov;
+	virgl_renderer_get_cap_set;
+	virgl_renderer_fill_caps;
+	virgl_renderer_resource_attach_iov;
+	virgl_renderer_resource_detach_iov;
+	virgl_renderer_create_fence;
+	virgl_renderer_force_ctx_0;
+	virgl_renderer_ctx_attach_resource;
+	virgl_renderer_ctx_detach_resource;
+	virgl_renderer_resource_get_info;
+
+	# fake gralloc1 implementation
+	hw_get_module;
+
+	# fake libsync implementation
+	sync_wait;
+
+	# Type-strings and type-infos required by sanitizers
+	_ZTS*;
+	_ZTI*;
+
+local:
+	*;
+};
diff --git a/host/libs/virglrenderer/renderControl_dec/renderControl.attrib b/host/libs/virglrenderer/renderControl_dec/renderControl.attrib
new file mode 100644
index 0000000000000000000000000000000000000000..6ff20b66e27801864570a1f069a1526bd0806be1
--- /dev/null
+++ b/host/libs/virglrenderer/renderControl_dec/renderControl.attrib
@@ -0,0 +1,105 @@
+GLOBAL
+    base_opcode 10000
+
+rcGetEGLVersion
+    flag custom_decoder
+    dir major out
+    len major sizeof(EGLint)
+    dir minor out
+    len minor sizeof(EGLint)
+
+rcQueryEGLString
+    flag custom_decoder
+    dir buffer out
+    len buffer bufferSize
+
+rcGetGLString
+    flag custom_decoder
+    dir buffer out
+    len buffer bufferSize
+
+rcGetNumConfigs
+    dir numAttribs out
+    len numAttribs sizeof(uint32_t)
+
+rcGetConfigs
+    dir buffer out
+    len buffer bufSize
+
+rcChooseConfig
+    flag custom_decoder
+    dir attribs in
+    len attribs attribs_size
+    dir configs out
+    var_flag configs nullAllowed
+    len configs configs_size*sizeof(uint32_t)
+
+rcCreateContext
+    flag custom_decoder
+
+rcDestroyContext
+    flag custom_decoder
+
+rcCreateWindowSurface
+    flag custom_decoder
+
+rcDestroyWindowSurface
+    flag custom_decoder
+
+rcCloseColorBuffer
+    flag flushOnEncode
+
+rcSetWindowColorBuffer
+    flag custom_decoder
+
+rcMakeCurrent
+    flag custom_decoder
+
+rcFBSetSwapInterval
+    flag custom_decoder
+
+rcBindTexture
+    flag custom_decoder
+
+rcBindRenderbuffer
+    flag custom_decoder
+
+rcReadColorBuffer
+    dir pixels out
+
+rcUpdateColorBuffer
+    dir pixels in
+    var_flag pixels isLarge
+
+rcCreateClientImage
+    flag custom_decoder
+
+rcSelectChecksumHelper
+    flag custom_decoder
+
+rcCreateSyncKHR
+    flag custom_decoder
+    dir attribs in
+    len attribs num_attribs
+    dir glsync_out out
+    len glsync_out sizeof(uint64_t)
+    dir syncthread_out out
+    len syncthread_out sizeof(uint64_t)
+
+rcClientWaitSyncKHR
+    flag custom_decoder
+
+rcDestroySyncKHR
+    flag custom_decoder
+
+rcSetPuid
+    flag custom_decoder
+
+rcUpdateColorBufferDMA
+    dir pixels in
+    len pixels pixels_size
+    var_flag pixels DMA
+    flag flushOnEncode
+
+rcWaitSyncKHR
+    flag custom_decoder
diff --git a/host/libs/virglrenderer/renderControl_dec/renderControl.in b/host/libs/virglrenderer/renderControl_dec/renderControl.in
new file mode 100644
index 0000000000000000000000000000000000000000..e1dea92c102534f0e815b21a48def38a890845cc
--- /dev/null
+++ b/host/libs/virglrenderer/renderControl_dec/renderControl.in
@@ -0,0 +1,37 @@
+GL_ENRTY(GLint, rcGetRendererVersion)
+GL_ENTRY(EGLint, rcGetEGLVersion, EGLint *major, EGLint *minor)
+GL_ENTRY(EGLint, rcQueryEGLString, EGLenum name, void *buffer, EGLint bufferSize)
+GL_ENTRY(EGLint, rcGetGLString, EGLenum name, void *buffer, EGLint bufferSize)
+GL_ENTRY(EGLint, rcGetNumConfigs, uint32_t *numAttribs)
+GL_ENTRY(EGLint, rcGetConfigs, uint32_t bufSize, GLuint *buffer)
+GL_ENTRY(EGLint, rcChooseConfig, EGLint *attribs, uint32_t attribs_size, uint32_t *configs, uint32_t configs_size)
+GL_ENTRY(EGLint, rcGetFBParam, EGLint param)
+GL_ENTRY(uint32_t, rcCreateContext, uint32_t config, uint32_t share, uint32_t glVersion)
+GL_ENTRY(void, rcDestroyContext, uint32_t context)
+GL_ENTRY(uint32_t, rcCreateWindowSurface, uint32_t config, uint32_t width, uint32_t height)
+GL_ENTRY(void, rcDestroyWindowSurface, uint32_t windowSurface)
+GL_ENTRY(uint32_t, rcCreateColorBuffer, uint32_t width, uint32_t height, GLenum internalFormat)
+GL_ENTRY(void, rcOpenColorBuffer, uint32_t colorbuffer)
+GL_ENTRY(void, rcCloseColorBuffer, uint32_t colorbuffer)
+GL_ENTRY(void, rcSetWindowColorBuffer, uint32_t windowSurface, uint32_t colorBuffer)
+GL_ENTRY(int, rcFlushWindowColorBuffer, uint32_t windowSurface)
+GL_ENTRY(EGLint, rcMakeCurrent, uint32_t context, uint32_t drawSurf, uint32_t readSurf)
+GL_ENTRY(void, rcFBPost, uint32_t colorBuffer)
+GL_ENTRY(void, rcFBSetSwapInterval, EGLint interval)
+GL_ENTRY(void, rcBindTexture, uint32_t colorBuffer)
+GL_ENTRY(void, rcBindRenderbuffer, uint32_t colorBuffer)
+GL_ENTRY(EGLint, rcColorBufferCacheFlush, uint32_t colorbuffer, EGLint postCount, int forRead)
+GL_ENTRY(void, rcReadColorBuffer, uint32_t colorbuffer, GLint x, GLint y, GLint width, GLint height, GLenum format, GLenum type, void *pixels)
+GL_ENTRY(int, rcUpdateColorBuffer, uint32_t colorbuffer, GLint x, GLint y, GLint width, GLint height, GLenum format, GLenum type, void *pixels)
+GL_ENTRY(int, rcOpenColorBuffer2, uint32_t colorbuffer)
+GL_ENTRY(uint32_t, rcCreateClientImage, uint32_t context, EGLenum target, GLuint buffer)
+GL_ENTRY(int, rcDestroyClientImage, uint32_t image)
+GL_ENTRY(void, rcSelectChecksumHelper, uint32_t newProtocol, uint32_t reserved)
+GL_ENTRY(void, rcCreateSyncKHR, EGLenum type, EGLint* attribs, uint32_t num_attribs, int destroy_when_signaled, uint64_t* glsync_out, uint64_t* syncthread_out)
+GL_ENTRY(EGLint, rcClientWaitSyncKHR, uint64_t sync, EGLint flags, uint64_t timeout)
+GL_ENTRY(void, rcFlushWindowColorBufferAsync, uint32_t windowSurface)
+GL_ENTRY(int, rcDestroySyncKHR, uint64_t sync)
+GL_ENTRY(void, rcSetPuid, uint64_t puid)
+GL_ENTRY(int, rcUpdateColorBufferDMA, uint32_t colorbuffer, GLint x, GLint y, GLint width, GLint height, GLenum format, GLenum type, void* pixels, uint32_t pixels_size)
+GL_ENTRY(uint32_t, rcCreateColorBufferDMA, uint32_t width, uint32_t height, GLenum internalFormat, int frameworkFormat)
+GL_ENTRY(void, rcWaitSyncKHR, uint64_t sync, EGLint flags);
diff --git a/host/libs/virglrenderer/renderControl_dec/renderControl.types b/host/libs/virglrenderer/renderControl_dec/renderControl.types
new file mode 100644
index 0000000000000000000000000000000000000000..578492b621da9d5c59fd989329d25e33ea7a756e
--- /dev/null
+++ b/host/libs/virglrenderer/renderControl_dec/renderControl.types
@@ -0,0 +1,14 @@
+uint32_t 32 0x%08x
+uint64_t 64 0x%016lx
+EGLint 32 0x%08x
+GLint 32 0x%08x
+GLuint 32 0x%08x
+GLenum 32 0x%08x
+EGLenum 32 0x%08x
+uint32_t* 32 0x%08x
+EGLint* 32 0x%08x
+int* 32 0x%08x
+GLint* 32 0x%08x
+GLuint* 32 0x%08x
+void* 32 0x%08x
+uint64_t* 32 0x%08x
diff --git a/host/libs/virglrenderer/renderControl_dec/renderControl_types.h b/host/libs/virglrenderer/renderControl_dec/renderControl_types.h
new file mode 100644
index 0000000000000000000000000000000000000000..dd6b41271acf37c4da1474d9d4bbe551e60b3c9c
--- /dev/null
+++ b/host/libs/virglrenderer/renderControl_dec/renderControl_types.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <EGL/egl.h>
+
+#include <GLES/gl.h>
diff --git a/host/linux_uapi/linux/virtio_gpu.h b/host/linux_uapi/linux/virtio_gpu.h
new file mode 100644
index 0000000000000000000000000000000000000000..b43671f42a932c81069a4be7e52a107dafc6b054
--- /dev/null
+++ b/host/linux_uapi/linux/virtio_gpu.h
@@ -0,0 +1,226 @@
+/****************************************************************************
+ ****************************************************************************
+ ***
+ ***   This header was automatically generated from a Linux kernel header
+ ***   of the same name, to make information necessary for userspace to
+ ***   call into the kernel available to libc.  It contains only constants,
+ ***   structures, and macros generated from the original header, and thus,
+ ***   contains no copyrightable information.
+ ***
+ ***   To edit the content of this header, modify the corresponding
+ ***   source file (e.g. under external/kernel-headers/original/) then
+ ***   run bionic/libc/kernel/tools/update_all.py
+ ***
+ ***   Any manual change here will be lost the next time this script will
+ ***   be run. You've been warned!
+ ***
+ ****************************************************************************
+ ****************************************************************************/
+#ifndef VIRTIO_GPU_HW_H
+#define VIRTIO_GPU_HW_H
+#include <linux/types.h>
+#define VIRTIO_GPU_F_VIRGL 0
+enum virtio_gpu_ctrl_type {
+  VIRTIO_GPU_UNDEFINED = 0,
+  VIRTIO_GPU_CMD_GET_DISPLAY_INFO = 0x0100,
+  VIRTIO_GPU_CMD_RESOURCE_CREATE_2D,
+  VIRTIO_GPU_CMD_RESOURCE_UNREF,
+  VIRTIO_GPU_CMD_SET_SCANOUT,
+  VIRTIO_GPU_CMD_RESOURCE_FLUSH,
+  VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D,
+  VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING,
+  VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING,
+  VIRTIO_GPU_CMD_GET_CAPSET_INFO,
+  VIRTIO_GPU_CMD_GET_CAPSET,
+  VIRTIO_GPU_CMD_CTX_CREATE = 0x0200,
+  VIRTIO_GPU_CMD_CTX_DESTROY,
+  VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE,
+  VIRTIO_GPU_CMD_CTX_DETACH_RESOURCE,
+  VIRTIO_GPU_CMD_RESOURCE_CREATE_3D,
+  VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D,
+  VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D,
+  VIRTIO_GPU_CMD_SUBMIT_3D,
+  VIRTIO_GPU_CMD_UPDATE_CURSOR = 0x0300,
+  VIRTIO_GPU_CMD_MOVE_CURSOR,
+  VIRTIO_GPU_RESP_OK_NODATA = 0x1100,
+  VIRTIO_GPU_RESP_OK_DISPLAY_INFO,
+  VIRTIO_GPU_RESP_OK_CAPSET_INFO,
+  VIRTIO_GPU_RESP_OK_CAPSET,
+  VIRTIO_GPU_RESP_ERR_UNSPEC = 0x1200,
+  VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY,
+  VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID,
+  VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID,
+  VIRTIO_GPU_RESP_ERR_INVALID_CONTEXT_ID,
+  VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER,
+};
+#define VIRTIO_GPU_FLAG_FENCE (1 << 0)
+struct virtio_gpu_ctrl_hdr {
+  __le32 type;
+  __le32 flags;
+  __le64 fence_id;
+  __le32 ctx_id;
+  __le32 padding;
+};
+struct virtio_gpu_cursor_pos {
+  __le32 scanout_id;
+  __le32 x;
+  __le32 y;
+  __le32 padding;
+};
+struct virtio_gpu_update_cursor {
+  struct virtio_gpu_ctrl_hdr hdr;
+  struct virtio_gpu_cursor_pos pos;
+  __le32 resource_id;
+  __le32 hot_x;
+  __le32 hot_y;
+  __le32 padding;
+};
+struct virtio_gpu_rect {
+  __le32 x;
+  __le32 y;
+  __le32 width;
+  __le32 height;
+};
+struct virtio_gpu_resource_unref {
+  struct virtio_gpu_ctrl_hdr hdr;
+  __le32 resource_id;
+  __le32 padding;
+};
+struct virtio_gpu_resource_create_2d {
+  struct virtio_gpu_ctrl_hdr hdr;
+  __le32 resource_id;
+  __le32 format;
+  __le32 width;
+  __le32 height;
+};
+struct virtio_gpu_set_scanout {
+  struct virtio_gpu_ctrl_hdr hdr;
+  struct virtio_gpu_rect r;
+  __le32 scanout_id;
+  __le32 resource_id;
+};
+struct virtio_gpu_resource_flush {
+  struct virtio_gpu_ctrl_hdr hdr;
+  struct virtio_gpu_rect r;
+  __le32 resource_id;
+  __le32 padding;
+};
+struct virtio_gpu_transfer_to_host_2d {
+  struct virtio_gpu_ctrl_hdr hdr;
+  struct virtio_gpu_rect r;
+  __le64 offset;
+  __le32 resource_id;
+  __le32 padding;
+};
+struct virtio_gpu_mem_entry {
+  __le64 addr;
+  __le32 length;
+  __le32 padding;
+};
+struct virtio_gpu_resource_attach_backing {
+  struct virtio_gpu_ctrl_hdr hdr;
+  __le32 resource_id;
+  __le32 nr_entries;
+};
+struct virtio_gpu_resource_detach_backing {
+  struct virtio_gpu_ctrl_hdr hdr;
+  __le32 resource_id;
+  __le32 padding;
+};
+#define VIRTIO_GPU_MAX_SCANOUTS 16
+struct virtio_gpu_resp_display_info {
+  struct virtio_gpu_ctrl_hdr hdr;
+  struct virtio_gpu_display_one {
+    struct virtio_gpu_rect r;
+    __le32 enabled;
+    __le32 flags;
+  } pmodes[VIRTIO_GPU_MAX_SCANOUTS];
+};
+struct virtio_gpu_box {
+  __le32 x, y, z;
+  __le32 w, h, d;
+};
+struct virtio_gpu_transfer_host_3d {
+  struct virtio_gpu_ctrl_hdr hdr;
+  struct virtio_gpu_box box;
+  __le64 offset;
+  __le32 resource_id;
+  __le32 level;
+  __le32 stride;
+  __le32 layer_stride;
+};
+#define VIRTIO_GPU_RESOURCE_FLAG_Y_0_TOP (1 << 0)
+struct virtio_gpu_resource_create_3d {
+  struct virtio_gpu_ctrl_hdr hdr;
+  __le32 resource_id;
+  __le32 target;
+  __le32 format;
+  __le32 bind;
+  __le32 width;
+  __le32 height;
+  __le32 depth;
+  __le32 array_size;
+  __le32 last_level;
+  __le32 nr_samples;
+  __le32 flags;
+  __le32 padding;
+};
+struct virtio_gpu_ctx_create {
+  struct virtio_gpu_ctrl_hdr hdr;
+  __le32 nlen;
+  __le32 padding;
+  char debug_name[64];
+};
+struct virtio_gpu_ctx_destroy {
+  struct virtio_gpu_ctrl_hdr hdr;
+};
+struct virtio_gpu_ctx_resource {
+  struct virtio_gpu_ctrl_hdr hdr;
+  __le32 resource_id;
+  __le32 padding;
+};
+struct virtio_gpu_cmd_submit {
+  struct virtio_gpu_ctrl_hdr hdr;
+  __le32 size;
+  __le32 padding;
+};
+#define VIRTIO_GPU_CAPSET_VIRGL 1
+struct virtio_gpu_get_capset_info {
+  struct virtio_gpu_ctrl_hdr hdr;
+  __le32 capset_index;
+  __le32 padding;
+};
+struct virtio_gpu_resp_capset_info {
+  struct virtio_gpu_ctrl_hdr hdr;
+  __le32 capset_id;
+  __le32 capset_max_version;
+  __le32 capset_max_size;
+  __le32 padding;
+};
+struct virtio_gpu_get_capset {
+  struct virtio_gpu_ctrl_hdr hdr;
+  __le32 capset_id;
+  __le32 capset_version;
+};
+struct virtio_gpu_resp_capset {
+  struct virtio_gpu_ctrl_hdr hdr;
+  __u8 capset_data[];
+};
+#define VIRTIO_GPU_EVENT_DISPLAY (1 << 0)
+struct virtio_gpu_config {
+  __u32 events_read;
+  __u32 events_clear;
+  __u32 num_scanouts;
+  __u32 num_capsets;
+};
+enum virtio_gpu_formats {
+  VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM = 1,
+  VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM = 2,
+  VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM = 3,
+  VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM = 4,
+  VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM = 67,
+  VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM = 68,
+  VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM = 121,
+  VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM = 134,
+};
+#endif