Add glMapBufferRange implemented via direct memory access

goldfish_address_space is a memory sharing device between
the QEMU host and an Android guest. This approach allows
to access host's memory from the guest directly without
copying bits.

Bug: 116046430
Test: Run the emulator with an OpenGL app that calls to
      glMapBufferRange.
Change-Id: I1bee79e732fffe5eb853d4f511d707af624ae843
Signed-off-by: Roman Kiryanov <rkir@google.com>
diff --git a/GNUmakefile b/GNUmakefile
index 0610f29..9f3aa00 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -57,4 +57,4 @@
 cmake:
 	@rm -f $(JSON_FILE)
 	$(call write-to-file,$(JSON_FILE),30,$(JSON_DUMP))
-	$(hide) python cmake_transform.py -i $(JSON_FILE) -c $(JSON_FILE) -o ${_BUILD_ROOT} 
\ No newline at end of file
+	$(hide) python cmake_transform.py -i $(JSON_FILE) -c $(JSON_FILE) -o ${_BUILD_ROOT} 
diff --git a/shared/OpenglCodecCommon/Android.mk b/shared/OpenglCodecCommon/Android.mk
index 3971eae..5ca0a08 100644
--- a/shared/OpenglCodecCommon/Android.mk
+++ b/shared/OpenglCodecCommon/Android.mk
@@ -13,6 +13,7 @@
         SocketStream.cpp \
         TcpStream.cpp \
         auto_goldfish_dma_context.cpp \
+        goldfish_address_space.cpp \
 
 ifeq (true,$(GOLDFISH_OPENGL_BUILD_FOR_HOST))
 
diff --git a/shared/OpenglCodecCommon/CMakeLists.txt b/shared/OpenglCodecCommon/CMakeLists.txt
index 6f1f4ea..5d5ee8d 100644
--- a/shared/OpenglCodecCommon/CMakeLists.txt
+++ b/shared/OpenglCodecCommon/CMakeLists.txt
@@ -1,8 +1,8 @@
 # This is an autogenerated file! Do not edit!
 # instead run make from .../device/generic/goldfish-opengl
 # which will re-generate this file.
-android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/shared/OpenglCodecCommon/Android.mk" "b90bb271cb6f2c60c9d50bfe2a1273396e77e082d3482316f50185efdfb534c9")
-set(OpenglCodecCommon_host_src GLClientState.cpp GLESTextureUtils.cpp ChecksumCalculator.cpp GLSharedGroup.cpp glUtils.cpp IndexRangeCache.cpp SocketStream.cpp TcpStream.cpp auto_goldfish_dma_context.cpp goldfish_dma_host.cpp qemu_pipe_host.cpp)
+android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/shared/OpenglCodecCommon/Android.mk" "8aaff0a6f86ae81d01d6e87b9477d200a774b95a3f15267921e4e1f9cbb9848e")
+set(OpenglCodecCommon_host_src GLClientState.cpp GLESTextureUtils.cpp ChecksumCalculator.cpp GLSharedGroup.cpp glUtils.cpp IndexRangeCache.cpp SocketStream.cpp TcpStream.cpp auto_goldfish_dma_context.cpp goldfish_address_space.cpp goldfish_dma_host.cpp qemu_pipe_host.cpp)
 android_add_shared_library(OpenglCodecCommon_host)
 target_include_directories(OpenglCodecCommon_host PRIVATE ${GOLDFISH_DEVICE_ROOT}/shared/OpenglCodecCommon ${GOLDFISH_DEVICE_ROOT}/./host/include/libOpenglRender ${GOLDFISH_DEVICE_ROOT}/./system/include ${GOLDFISH_DEVICE_ROOT}/./../../../external/qemu/android/android-emugl/guest)
 target_compile_definitions(OpenglCodecCommon_host PRIVATE "-DWITH_GLES2" "-DPLATFORM_SDK_VERSION=29" "-DGOLDFISH_HIDL_GRALLOC" "-DEMULATOR_OPENGL_POST_O=1" "-DHOST_BUILD" "-DANDROID" "-DGL_GLEXT_PROTOTYPES" "-DPAGE_SIZE=4096" "-DGOLDFISH_VULKAN" "-DLOG_TAG=\"eglCodecCommon\"")
diff --git a/shared/OpenglCodecCommon/GLSharedGroup.h b/shared/OpenglCodecCommon/GLSharedGroup.h
index 9ef92ea..8a35a89 100755
--- a/shared/OpenglCodecCommon/GLSharedGroup.h
+++ b/shared/OpenglCodecCommon/GLSharedGroup.h
@@ -39,6 +39,7 @@
 #include <utils/threads.h>
 #include "FixedBuffer.h"
 #include "auto_goldfish_dma_context.h"
+#include "goldfish_address_space.h"
 #include "IndexRangeCache.h"
 #include "SmartPtr.h"
 
@@ -63,6 +64,8 @@
 
     // DMA support
     AutoGoldfishDmaContext dma_buffer;
+    // Direct memory access support
+    GoldfishAddressSpaceBlock shared_block;
 };
 
 class ProgramData {
diff --git a/shared/OpenglCodecCommon/goldfish_address_space.cpp b/shared/OpenglCodecCommon/goldfish_address_space.cpp
new file mode 100644
index 0000000..7852dc9
--- /dev/null
+++ b/shared/OpenglCodecCommon/goldfish_address_space.cpp
@@ -0,0 +1,194 @@
+#include <log/log.h>
+#include "goldfish_address_space.h"
+
+#ifdef GOLDFISH_OPENGL_BUILD_FOR_HOST
+GoldfishAddressSpaceBlock::GoldfishAddressSpaceBlock() : m_guest_ptr(NULL) {}
+
+bool GoldfishAddressSpaceBlock::allocate(GoldfishAddressSpaceBlockProvider *provider, size_t size)
+{
+    return true;
+}
+
+uint64_t GoldfishAddressSpaceBlock::physAddr() const
+{
+    return 42;  // some random number, not used
+}
+
+uint64_t GoldfishAddressSpaceBlock::hostAddr() const
+{
+    return 42;  // some random number, not used
+}
+
+void *GoldfishAddressSpaceBlock::mmap(uint64_t opaque)
+{
+    m_guest_ptr = reinterpret_cast<void *>(opaque);
+    return m_guest_ptr;
+}
+
+void *GoldfishAddressSpaceBlock::guestPtr() const
+{
+    return m_guest_ptr;
+}
+
+void GoldfishAddressSpaceBlock::destroy()
+{
+    m_guest_ptr = NULL;
+}
+
+void GoldfishAddressSpaceBlock::replace(GoldfishAddressSpaceBlock *other)
+{
+    if (other) {
+        this->m_guest_ptr = other->m_guest_ptr;
+        other->m_guest_ptr = NULL;
+    } else {
+        this->m_guest_ptr = NULL;
+    }
+}
+#else
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <cstdlib>
+#include <errno.h>
+
+struct goldfish_address_space_allocate_block {
+    __u64 size;
+    __u64 offset;
+    __u64 phys_addr;
+};
+
+#define GOLDFISH_ADDRESS_SPACE_IOCTL_MAGIC		'G'
+#define GOLDFISH_ADDRESS_SPACE_IOCTL_OP(OP, T)		_IOWR(GOLDFISH_ADDRESS_SPACE_IOCTL_MAGIC, OP, T)
+#define GOLDFISH_ADDRESS_SPACE_IOCTL_ALLOCATE_BLOCK	GOLDFISH_ADDRESS_SPACE_IOCTL_OP(10, struct goldfish_address_space_allocate_block)
+#define GOLDFISH_ADDRESS_SPACE_IOCTL_DEALLOCATE_BLOCK	GOLDFISH_ADDRESS_SPACE_IOCTL_OP(11, __u64)
+
+const char GOLDFISH_ADDRESS_SPACE_DEVICE_NAME[] = "/dev/goldfish_address_space";
+
+GoldfishAddressSpaceBlockProvider::GoldfishAddressSpaceBlockProvider()
+    : m_fd(::open(GOLDFISH_ADDRESS_SPACE_DEVICE_NAME, O_RDWR)) {}
+
+GoldfishAddressSpaceBlockProvider::~GoldfishAddressSpaceBlockProvider()
+{
+    ::close(m_fd);
+}
+
+GoldfishAddressSpaceBlock::GoldfishAddressSpaceBlock()
+    : m_mmaped_ptr(NULL)
+    , m_phys_addr(0)
+    , m_host_addr(0)
+    , m_offset(0)
+    , m_size(0)
+    , m_fd(-1) {}
+
+GoldfishAddressSpaceBlock::~GoldfishAddressSpaceBlock()
+{
+    destroy();
+}
+
+GoldfishAddressSpaceBlock &GoldfishAddressSpaceBlock::operator=(const GoldfishAddressSpaceBlock &rhs)
+{
+    m_mmaped_ptr = rhs.m_mmaped_ptr;
+    m_phys_addr = rhs.m_phys_addr;
+    m_host_addr = rhs.m_host_addr;
+    m_offset = rhs.m_offset;
+    m_size = rhs.m_size;
+    m_fd = rhs.m_fd;
+
+    return *this;
+}
+
+bool GoldfishAddressSpaceBlock::allocate(GoldfishAddressSpaceBlockProvider *provider, size_t size)
+{
+    destroy();
+
+    if (!provider->is_opened()) {
+        return false;
+    }
+
+    struct goldfish_address_space_allocate_block request;
+    long res;
+
+    request.size = size;
+    res = ::ioctl(provider->m_fd, GOLDFISH_ADDRESS_SPACE_IOCTL_ALLOCATE_BLOCK, &request);
+    if (res) {
+        return false;
+    } else {
+        m_phys_addr = request.phys_addr;
+        m_offset = request.offset;
+        m_size = request.size;
+        m_fd = provider->m_fd;
+        return true;
+    }
+}
+
+uint64_t GoldfishAddressSpaceBlock::physAddr() const
+{
+    return m_phys_addr;
+}
+
+uint64_t GoldfishAddressSpaceBlock::hostAddr() const
+{
+    return m_host_addr;
+}
+
+void *GoldfishAddressSpaceBlock::mmap(uint64_t host_addr)
+{
+    if (m_size == 0) {
+        return NULL;
+    }
+    if (m_mmaped_ptr) {
+        ALOGE("'mmap' called for an already mmaped address block");
+        ::abort();
+    }
+
+    void *result = ::mmap(NULL, m_size, PROT_WRITE, MAP_SHARED, m_fd, m_offset);
+    if (result == MAP_FAILED) {
+        return NULL;
+    } else {
+        m_mmaped_ptr = result;
+        m_host_addr = host_addr;
+        return guestPtr();
+    }
+}
+
+void *GoldfishAddressSpaceBlock::guestPtr() const
+{
+    return reinterpret_cast<char *>(m_mmaped_ptr) + (m_host_addr & (PAGE_SIZE - 1));
+}
+
+void GoldfishAddressSpaceBlock::destroy()
+{
+    if (m_mmaped_ptr && m_size) {
+        ::munmap(m_mmaped_ptr, m_size);
+        m_mmaped_ptr = NULL;
+    }
+
+    if (m_size) {
+        ::ioctl(m_fd, GOLDFISH_ADDRESS_SPACE_IOCTL_DEALLOCATE_BLOCK, &m_offset);
+        m_phys_addr = 0;
+        m_host_addr = 0;
+        m_offset = 0;
+        m_size = 0;
+    }
+}
+
+void GoldfishAddressSpaceBlock::replace(GoldfishAddressSpaceBlock *other)
+{
+    destroy();
+
+    if (other) {
+        *this = *other;
+        *other = GoldfishAddressSpaceBlock();
+    }
+}
+
+bool GoldfishAddressSpaceBlockProvider::is_opened()
+{
+    return m_fd >= 0;
+}
+#endif
diff --git a/shared/OpenglCodecCommon/goldfish_address_space.h b/shared/OpenglCodecCommon/goldfish_address_space.h
new file mode 100644
index 0000000..dc784da
--- /dev/null
+++ b/shared/OpenglCodecCommon/goldfish_address_space.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2018 Google, Inc.
+ *
+ * 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.
+ *
+ */
+
+#ifndef ANDROID_INCLUDE_HARDWARE_GOLDFISH_ADDRESS_SPACE_H
+#define ANDROID_INCLUDE_HARDWARE_GOLDFISH_ADDRESS_SPACE_H
+
+#include <inttypes.h>
+
+class GoldfishAddressSpaceBlock;
+
+#ifdef GOLDFISH_OPENGL_BUILD_FOR_HOST
+class GoldfishAddressSpaceBlockProvider {};
+#else
+class GoldfishAddressSpaceBlockProvider {
+public:
+    GoldfishAddressSpaceBlockProvider();
+    ~GoldfishAddressSpaceBlockProvider();
+
+private:
+   GoldfishAddressSpaceBlockProvider(const GoldfishAddressSpaceBlockProvider &rhs);
+   GoldfishAddressSpaceBlockProvider &operator=(const GoldfishAddressSpaceBlockProvider &rhs);
+
+   bool is_opened();
+   int m_fd;
+
+   friend class GoldfishAddressSpaceBlock;
+};
+#endif
+
+class GoldfishAddressSpaceBlock {
+public:
+    GoldfishAddressSpaceBlock();
+    ~GoldfishAddressSpaceBlock();
+
+    bool allocate(GoldfishAddressSpaceBlockProvider *provider, size_t size);
+    uint64_t physAddr() const;
+    uint64_t hostAddr() const;
+    void *mmap(uint64_t opaque);
+    void *guestPtr() const;
+    void replace(GoldfishAddressSpaceBlock *x);
+
+private:
+    void destroy();
+    GoldfishAddressSpaceBlock &operator=(const GoldfishAddressSpaceBlock &);
+
+#ifdef GOLDFISH_OPENGL_BUILD_FOR_HOST
+    void     *m_guest_ptr;
+#else
+    void     *m_mmaped_ptr;
+    uint64_t  m_phys_addr;
+    uint64_t  m_host_addr;
+    uint64_t  m_offset;
+    size_t    m_size;
+    int       m_fd;
+#endif
+};
+
+#endif
diff --git a/system/GLESv1_enc/gl_client_proc.h b/system/GLESv1_enc/gl_client_proc.h
index 707c524..7d0f857 100644
--- a/system/GLESv1_enc/gl_client_proc.h
+++ b/system/GLESv1_enc/gl_client_proc.h
@@ -6,6 +6,9 @@
 
 
 #include "gl_types.h"
+#ifdef _MSC_VER
+#include <stdint.h>
+#endif
 #ifndef gl_APIENTRY
 #define gl_APIENTRY 
 #endif
diff --git a/system/GLESv2_enc/GL2Encoder.cpp b/system/GLESv2_enc/GL2Encoder.cpp
index 220f198..daa891d 100755
--- a/system/GLESv2_enc/GL2Encoder.cpp
+++ b/system/GLESv2_enc/GL2Encoder.cpp
@@ -76,6 +76,7 @@
     m_noHostError = false;
     m_state = NULL;
     m_error = GL_NO_ERROR;
+
     m_num_compressedTextureFormats = 0;
     m_max_combinedTextureImageUnits = 0;
     m_max_vertexTextureImageUnits = 0;
@@ -2898,6 +2899,42 @@
                 buf->m_guest_paddr);
 
         return reinterpret_cast<void*>(buf->dma_buffer.get().mapped_addr);
+    } else if (ctx->hasExtension("ANDROID_EMU_direct_mem")) {
+        GoldfishAddressSpaceBlock new_shared_block;
+
+        if (new_shared_block.allocate(&ctx->m_goldfish_address_block_provider, length)) {
+            uint64_t gpu_addr =
+                ctx->glMapBufferRangeDirect(ctx,
+                                            target,
+                                            offset,
+                                            length,
+                                            access,
+                                            new_shared_block.physAddr());
+            if (gpu_addr) {
+                void *user_ptr = new_shared_block.mmap(gpu_addr);
+                if (user_ptr) {
+                    buf->shared_block.replace(&new_shared_block);
+                    return user_ptr;
+                } else {
+                    GLboolean host_res = GL_TRUE;
+
+                    ctx->glUnmapBufferDirect(
+                        ctx, target,
+                        offset,
+                        length,
+                        access,
+                        new_shared_block.physAddr(),
+                        gpu_addr,
+                        &host_res);
+
+                    return s_glMapBufferRangeAEMUImpl(ctx, target, offset, length, access, buf);
+                }
+            } else {
+                return s_glMapBufferRangeAEMUImpl(ctx, target, offset, length, access, buf);
+            }
+        } else {
+            return s_glMapBufferRangeAEMUImpl(ctx, target, offset, length, access, buf);
+        }
     } else {
         return s_glMapBufferRangeAEMUImpl(ctx, target, offset, length, access, buf);
     }
@@ -2934,12 +2971,29 @@
                buf->m_mappedLength);
 
         ctx->glUnmapBufferDMA(
+            ctx, target,
+            buf->m_mappedOffset,
+            buf->m_mappedLength,
+            buf->m_mappedAccess,
+            goldfish_dma_guest_paddr(&buf->dma_buffer.get()),
+            &host_res);
+    } else if (buf->shared_block.guestPtr()) {
+        GoldfishAddressSpaceBlock *shared_block = &buf->shared_block;
+
+        memcpy(static_cast<char*>(buf->m_fixedBuffer.ptr()) + buf->m_mappedOffset,
+               shared_block->guestPtr(),
+               buf->m_mappedLength);
+
+        ctx->glUnmapBufferDirect(
                 ctx, target,
                 buf->m_mappedOffset,
                 buf->m_mappedLength,
                 buf->m_mappedAccess,
-                goldfish_dma_guest_paddr(&buf->dma_buffer.get()),
+                shared_block->physAddr(),
+                shared_block->hostAddr(),
                 &host_res);
+
+        shared_block->replace(NULL);
     } else {
         ctx->glUnmapBufferAEMU(
                 ctx, target,
@@ -2980,12 +3034,20 @@
 
     buf->m_indexRangeCache.invalidateRange(totalOffset, length);
 
-    ctx->glFlushMappedBufferRangeAEMU(
-            ctx, target,
-            totalOffset,
-            length,
-            buf->m_mappedAccess,
-            (void*)((char*)buf->m_fixedBuffer.ptr() + totalOffset));
+    if (buf->shared_block.guestPtr()) {
+        ctx->glFlushMappedBufferRangeDirect(
+                ctx, target,
+                totalOffset,
+                length,
+                buf->m_mappedAccess);
+    } else {
+        ctx->glFlushMappedBufferRangeAEMU(
+                ctx, target,
+                totalOffset,
+                length,
+                buf->m_mappedAccess,
+                (void*)((char*)buf->m_fixedBuffer.ptr() + totalOffset));
+    }
 }
 
 void GL2Encoder::s_glCompressedTexImage2D(void* self, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data) {
diff --git a/system/GLESv2_enc/GL2Encoder.h b/system/GLESv2_enc/GL2Encoder.h
index 5b51f7b..39f7feb 100644
--- a/system/GLESv2_enc/GL2Encoder.h
+++ b/system/GLESv2_enc/GL2Encoder.h
@@ -104,6 +104,8 @@
     GLSharedGroupPtr m_shared;
     GLenum  m_error;
 
+    GoldfishAddressSpaceBlockProvider m_goldfish_address_block_provider;
+
     GLint *m_compressedTextureFormats;
     GLint m_num_compressedTextureFormats;
     GLint *getCompressedTextureFormats();
diff --git a/system/GLESv2_enc/gl2_client_context.cpp b/system/GLESv2_enc/gl2_client_context.cpp
index 7da3e33..482b604 100644
--- a/system/GLESv2_enc/gl2_client_context.cpp
+++ b/system/GLESv2_enc/gl2_client_context.cpp
@@ -423,6 +423,9 @@
 	glGetTexLevelParameteriv = (glGetTexLevelParameteriv_client_proc_t) getProc("glGetTexLevelParameteriv", userData);
 	glMapBufferRangeDMA = (glMapBufferRangeDMA_client_proc_t) getProc("glMapBufferRangeDMA", userData);
 	glUnmapBufferDMA = (glUnmapBufferDMA_client_proc_t) getProc("glUnmapBufferDMA", userData);
+	glMapBufferRangeDirect = (glMapBufferRangeDirect_client_proc_t) getProc("glMapBufferRangeDirect", userData);
+	glUnmapBufferDirect = (glUnmapBufferDirect_client_proc_t) getProc("glUnmapBufferDirect", userData);
+	glFlushMappedBufferRangeDirect = (glFlushMappedBufferRangeDirect_client_proc_t) getProc("glFlushMappedBufferRangeDirect", userData);
 	return 0;
 }
 
diff --git a/system/GLESv2_enc/gl2_client_context.h b/system/GLESv2_enc/gl2_client_context.h
index e2400a9..4a11c2a 100644
--- a/system/GLESv2_enc/gl2_client_context.h
+++ b/system/GLESv2_enc/gl2_client_context.h
@@ -423,6 +423,9 @@
 	glGetTexLevelParameteriv_client_proc_t glGetTexLevelParameteriv;
 	glMapBufferRangeDMA_client_proc_t glMapBufferRangeDMA;
 	glUnmapBufferDMA_client_proc_t glUnmapBufferDMA;
+	glMapBufferRangeDirect_client_proc_t glMapBufferRangeDirect;
+	glUnmapBufferDirect_client_proc_t glUnmapBufferDirect;
+	glFlushMappedBufferRangeDirect_client_proc_t glFlushMappedBufferRangeDirect;
 	virtual ~gl2_client_context_t() {}
 
 	typedef gl2_client_context_t *CONTEXT_ACCESSOR_TYPE(void);
diff --git a/system/GLESv2_enc/gl2_client_proc.h b/system/GLESv2_enc/gl2_client_proc.h
index 8829c58..05d006a 100644
--- a/system/GLESv2_enc/gl2_client_proc.h
+++ b/system/GLESv2_enc/gl2_client_proc.h
@@ -6,6 +6,9 @@
 
 
 #include "gl2_types.h"
+#ifdef _MSC_VER
+#include <stdint.h>
+#endif
 #ifndef gl2_APIENTRY
 #define gl2_APIENTRY 
 #endif
@@ -422,6 +425,9 @@
 typedef void (gl2_APIENTRY *glGetTexLevelParameteriv_client_proc_t) (void * ctx, GLenum, GLint, GLenum, GLint*);
 typedef void (gl2_APIENTRY *glMapBufferRangeDMA_client_proc_t) (void * ctx, GLenum, GLintptr, GLsizeiptr, GLbitfield, uint64_t);
 typedef void (gl2_APIENTRY *glUnmapBufferDMA_client_proc_t) (void * ctx, GLenum, GLintptr, GLsizeiptr, GLbitfield, uint64_t, GLboolean*);
+typedef uint64_t (gl2_APIENTRY *glMapBufferRangeDirect_client_proc_t) (void * ctx, GLenum, GLintptr, GLsizeiptr, GLbitfield, uint64_t);
+typedef void (gl2_APIENTRY *glUnmapBufferDirect_client_proc_t) (void * ctx, GLenum, GLintptr, GLsizeiptr, GLbitfield, uint64_t, uint64_t, GLboolean*);
+typedef void (gl2_APIENTRY *glFlushMappedBufferRangeDirect_client_proc_t) (void * ctx, GLenum, GLintptr, GLsizeiptr, GLbitfield);
 
 
 #endif
diff --git a/system/GLESv2_enc/gl2_enc.cpp b/system/GLESv2_enc/gl2_enc.cpp
index d5ae4b5..300994e 100644
--- a/system/GLESv2_enc/gl2_enc.cpp
+++ b/system/GLESv2_enc/gl2_enc.cpp
@@ -11116,6 +11116,122 @@
 	}
 }
 
+uint64_t glMapBufferRangeDirect_enc(void *self , GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, uint64_t paddr)
+{
+
+	gl2_encoder_context_t *ctx = (gl2_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 + 4 + 4 + 8;
+	 const size_t checksumSize = checksumCalculator->checksumByteSize();
+	 const size_t totalSize = sizeWithoutChecksum + checksumSize;
+	buf = stream->alloc(totalSize);
+	ptr = buf;
+	int tmp = OP_glMapBufferRangeDirect;memcpy(ptr, &tmp, 4); ptr += 4;
+	memcpy(ptr, &totalSize, 4);  ptr += 4;
+
+		memcpy(ptr, &target, 4); ptr += 4;
+		memcpy(ptr, &offset, 4); ptr += 4;
+		memcpy(ptr, &length, 4); ptr += 4;
+		memcpy(ptr, &access, 4); ptr += 4;
+		memcpy(ptr, &paddr, 8); ptr += 8;
+
+	if (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf);
+	if (useChecksum) checksumCalculator->writeChecksum(ptr, checksumSize); ptr += checksumSize;
+
+
+	uint64_t retval;
+	stream->readback(&retval, 8);
+	if (useChecksum) checksumCalculator->addBuffer(&retval, 8);
+	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("glMapBufferRangeDirect: GL communication error, please report this issue to b.android.com.\n");
+			abort();
+		}
+	}
+	return retval;
+}
+
+void glUnmapBufferDirect_enc(void *self , GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, uint64_t paddr, uint64_t guest_ptr, GLboolean* out_res)
+{
+
+	gl2_encoder_context_t *ctx = (gl2_encoder_context_t *)self;
+	IOStream *stream = ctx->m_stream;
+	ChecksumCalculator *checksumCalculator = ctx->m_checksumCalculator;
+	bool useChecksum = checksumCalculator->getVersion() > 0;
+
+	const unsigned int __size_out_res =  (sizeof(GLboolean));
+	 unsigned char *ptr;
+	 unsigned char *buf;
+	 const size_t sizeWithoutChecksum = 8 + 4 + 4 + 4 + 4 + 8 + 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_glUnmapBufferDirect;memcpy(ptr, &tmp, 4); ptr += 4;
+	memcpy(ptr, &totalSize, 4);  ptr += 4;
+
+		memcpy(ptr, &target, 4); ptr += 4;
+		memcpy(ptr, &offset, 4); ptr += 4;
+		memcpy(ptr, &length, 4); ptr += 4;
+		memcpy(ptr, &access, 4); ptr += 4;
+		memcpy(ptr, &paddr, 8); ptr += 8;
+		memcpy(ptr, &guest_ptr, 8); ptr += 8;
+	*(unsigned int *)(ptr) = __size_out_res; ptr += 4;
+
+	if (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf);
+	if (useChecksum) checksumCalculator->writeChecksum(ptr, checksumSize); ptr += checksumSize;
+
+	stream->readback(out_res, __size_out_res);
+	if (useChecksum) checksumCalculator->addBuffer(out_res, __size_out_res);
+	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("glUnmapBufferDirect: GL communication error, please report this issue to b.android.com.\n");
+			abort();
+		}
+	}
+}
+
+void glFlushMappedBufferRangeDirect_enc(void *self , GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access)
+{
+
+	gl2_encoder_context_t *ctx = (gl2_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 + 4 + 4;
+	 const size_t checksumSize = checksumCalculator->checksumByteSize();
+	 const size_t totalSize = sizeWithoutChecksum + checksumSize;
+	buf = stream->alloc(totalSize);
+	ptr = buf;
+	int tmp = OP_glFlushMappedBufferRangeDirect;memcpy(ptr, &tmp, 4); ptr += 4;
+	memcpy(ptr, &totalSize, 4);  ptr += 4;
+
+		memcpy(ptr, &target, 4); ptr += 4;
+		memcpy(ptr, &offset, 4); ptr += 4;
+		memcpy(ptr, &length, 4); ptr += 4;
+		memcpy(ptr, &access, 4); ptr += 4;
+
+	if (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf);
+	if (useChecksum) checksumCalculator->writeChecksum(ptr, checksumSize); ptr += checksumSize;
+
+}
+
 }  // namespace
 
 gl2_encoder_context_t::gl2_encoder_context_t(IOStream *stream, ChecksumCalculator *checksumCalculator)
@@ -11536,5 +11652,8 @@
 	this->glGetTexLevelParameteriv = &glGetTexLevelParameteriv_enc;
 	this->glMapBufferRangeDMA = &glMapBufferRangeDMA_enc;
 	this->glUnmapBufferDMA = &glUnmapBufferDMA_enc;
+	this->glMapBufferRangeDirect = &glMapBufferRangeDirect_enc;
+	this->glUnmapBufferDirect = &glUnmapBufferDirect_enc;
+	this->glFlushMappedBufferRangeDirect = &glFlushMappedBufferRangeDirect_enc;
 }
 
diff --git a/system/GLESv2_enc/gl2_entry.cpp b/system/GLESv2_enc/gl2_entry.cpp
index f60eb44..118b2ee 100644
--- a/system/GLESv2_enc/gl2_entry.cpp
+++ b/system/GLESv2_enc/gl2_entry.cpp
@@ -418,6 +418,9 @@
 	void glGetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint* params);
 	void glMapBufferRangeDMA(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, uint64_t paddr);
 	void glUnmapBufferDMA(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, uint64_t paddr, GLboolean* out_res);
+	uint64_t glMapBufferRangeDirect(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, uint64_t paddr);
+	void glUnmapBufferDirect(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, uint64_t paddr, uint64_t guest_ptr, GLboolean* out_res);
+	void glFlushMappedBufferRangeDirect(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
 };
 
 #ifndef GET_CONTEXT
@@ -2941,3 +2944,21 @@
 	ctx->glUnmapBufferDMA(ctx, target, offset, length, access, paddr, out_res);
 }
 
+uint64_t glMapBufferRangeDirect(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, uint64_t paddr)
+{
+	GET_CONTEXT;
+	return ctx->glMapBufferRangeDirect(ctx, target, offset, length, access, paddr);
+}
+
+void glUnmapBufferDirect(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, uint64_t paddr, uint64_t guest_ptr, GLboolean* out_res)
+{
+	GET_CONTEXT;
+	ctx->glUnmapBufferDirect(ctx, target, offset, length, access, paddr, guest_ptr, out_res);
+}
+
+void glFlushMappedBufferRangeDirect(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access)
+{
+	GET_CONTEXT;
+	ctx->glFlushMappedBufferRangeDirect(ctx, target, offset, length, access);
+}
+
diff --git a/system/GLESv2_enc/gl2_opcodes.h b/system/GLESv2_enc/gl2_opcodes.h
index 2affe0e..b359570 100644
--- a/system/GLESv2_enc/gl2_opcodes.h
+++ b/system/GLESv2_enc/gl2_opcodes.h
@@ -416,7 +416,10 @@
 #define OP_glGetTexLevelParameteriv 					2458
 #define OP_glMapBufferRangeDMA 					2459
 #define OP_glUnmapBufferDMA 					2460
-#define OP_last 					2461
+#define OP_glMapBufferRangeDirect 					2461
+#define OP_glUnmapBufferDirect 					2462
+#define OP_glFlushMappedBufferRangeDirect 					2463
+#define OP_last 					2464
 
 
 #endif
diff --git a/system/renderControl_enc/renderControl_client_proc.h b/system/renderControl_enc/renderControl_client_proc.h
index 24708dd..2dc7486 100644
--- a/system/renderControl_enc/renderControl_client_proc.h
+++ b/system/renderControl_enc/renderControl_client_proc.h
@@ -6,6 +6,9 @@
 
 
 #include "renderControl_types.h"
+#ifdef _MSC_VER
+#include <stdint.h>
+#endif
 #ifndef renderControl_APIENTRY
 #define renderControl_APIENTRY 
 #endif