gl2 encoder: async unmapbuffer

bug: 140112486

- No need to talk to the host if we glMapBufferRange with invalidation.
- No need to talk to the host if we glUnmapBuffer without wanting to
write.

Use the extension string to decide which to use, as it may or
may not be available on the host.

Change-Id: Ib50d24064d4c4d5517dc02b4d65f0f314f5d4ccf
diff --git a/system/GLESv2_enc/GL2Encoder.cpp b/system/GLESv2_enc/GL2Encoder.cpp
index 478b823..2f20516 100755
--- a/system/GLESv2_enc/GL2Encoder.cpp
+++ b/system/GLESv2_enc/GL2Encoder.cpp
@@ -72,6 +72,7 @@
 {
     m_currMajorVersion = 2;
     m_currMinorVersion = 0;
+    m_hasAsyncUnmapBuffer = false;
     m_initialized = false;
     m_noHostError = false;
     m_state = NULL;
@@ -2953,11 +2954,16 @@
                                              GLbitfield access, BufferData* buf) {
     char* bits = (char*)buf->m_fixedBuffer.ptr() + offset;
 
-    ctx->glMapBufferRangeAEMU(
-            ctx, target,
-            offset, length,
-            access,
-            bits);
+    if ((access & GL_MAP_READ_BIT) ||
+        ((access & GL_MAP_WRITE_BIT) &&
+        (!(access & GL_MAP_INVALIDATE_RANGE_BIT) &&
+         !(access & GL_MAP_INVALIDATE_BUFFER_BIT)))) {
+        ctx->glMapBufferRangeAEMU(
+                ctx, target,
+                offset, length,
+                access,
+                bits);
+    }
 
     return bits;
 }
@@ -3069,13 +3075,25 @@
             goldfish_dma_guest_paddr(&buf->dma_buffer.get()),
             &host_res);
     } else {
-        ctx->glUnmapBufferAEMU(
-                ctx, target,
-                buf->m_mappedOffset,
-                buf->m_mappedLength,
-                buf->m_mappedAccess,
-                (void*)((char*)buf->m_fixedBuffer.ptr() + buf->m_mappedOffset),
-                &host_res);
+        if (ctx->m_hasAsyncUnmapBuffer) {
+            ctx->glUnmapBufferAsyncAEMU(
+                    ctx, target,
+                    buf->m_mappedOffset,
+                    buf->m_mappedLength,
+                    buf->m_mappedAccess,
+                    (void*)((char*)buf->m_fixedBuffer.ptr() + buf->m_mappedOffset),
+                    &host_res);
+        } else {
+            if (buf->m_mappedAccess & GL_MAP_WRITE_BIT) {
+                ctx->glUnmapBufferAEMU(
+                        ctx, target,
+                        buf->m_mappedOffset,
+                        buf->m_mappedLength,
+                        buf->m_mappedAccess,
+                        (void*)((char*)buf->m_fixedBuffer.ptr() + buf->m_mappedOffset),
+                        &host_res);
+            }
+        }
     }
 
     buf->m_mapped = false;
@@ -3107,12 +3125,21 @@
 
     buf->m_indexRangeCache.invalidateRange(totalOffset, length);
 
-    ctx->glFlushMappedBufferRangeAEMU(
-            ctx, target,
-            totalOffset,
-            length,
-            buf->m_mappedAccess,
-            (void*)((char*)buf->m_fixedBuffer.ptr() + totalOffset));
+    if (ctx->m_hasAsyncUnmapBuffer) {
+        ctx->glFlushMappedBufferRangeAEMU2(
+                ctx, target,
+                totalOffset,
+                length,
+                buf->m_mappedAccess,
+                (void*)((char*)buf->m_fixedBuffer.ptr() + totalOffset));
+    } 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 9f1a444..d016898 100644
--- a/system/GLESv2_enc/GL2Encoder.h
+++ b/system/GLESv2_enc/GL2Encoder.h
@@ -31,6 +31,9 @@
     void setDrawCallFlushInterval(uint32_t interval) {
         m_drawCallFlushInterval = interval;
     }
+    void setHasAsyncUnmapBuffer(int version) {
+        m_hasAsyncUnmapBuffer = version;
+    }
     void setNoHostError(bool noHostError) {
         m_noHostError = noHostError;
     }
@@ -101,6 +104,7 @@
     std::string m_currExtensions;
     std::vector<std::string> m_currExtensionsArray;
 
+    bool    m_hasAsyncUnmapBuffer;
     bool    m_initialized;
     bool    m_noHostError;
     GLClientState *m_state;
diff --git a/system/GLESv2_enc/gl2_client_context.cpp b/system/GLESv2_enc/gl2_client_context.cpp
index c811b66..aaa0325 100644
--- a/system/GLESv2_enc/gl2_client_context.cpp
+++ b/system/GLESv2_enc/gl2_client_context.cpp
@@ -434,6 +434,8 @@
 	glDrawElementsNullAEMU = (glDrawElementsNullAEMU_client_proc_t) getProc("glDrawElementsNullAEMU", userData);
 	glDrawElementsOffsetNullAEMU = (glDrawElementsOffsetNullAEMU_client_proc_t) getProc("glDrawElementsOffsetNullAEMU", userData);
 	glDrawElementsDataNullAEMU = (glDrawElementsDataNullAEMU_client_proc_t) getProc("glDrawElementsDataNullAEMU", userData);
+	glUnmapBufferAsyncAEMU = (glUnmapBufferAsyncAEMU_client_proc_t) getProc("glUnmapBufferAsyncAEMU", userData);
+	glFlushMappedBufferRangeAEMU2 = (glFlushMappedBufferRangeAEMU2_client_proc_t) getProc("glFlushMappedBufferRangeAEMU2", userData);
 	return 0;
 }
 
diff --git a/system/GLESv2_enc/gl2_client_context.h b/system/GLESv2_enc/gl2_client_context.h
index ce0cf47..575395a 100644
--- a/system/GLESv2_enc/gl2_client_context.h
+++ b/system/GLESv2_enc/gl2_client_context.h
@@ -434,6 +434,8 @@
 	glDrawElementsNullAEMU_client_proc_t glDrawElementsNullAEMU;
 	glDrawElementsOffsetNullAEMU_client_proc_t glDrawElementsOffsetNullAEMU;
 	glDrawElementsDataNullAEMU_client_proc_t glDrawElementsDataNullAEMU;
+	glUnmapBufferAsyncAEMU_client_proc_t glUnmapBufferAsyncAEMU;
+	glFlushMappedBufferRangeAEMU2_client_proc_t glFlushMappedBufferRangeAEMU2;
 	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 dea6d12..615b123 100644
--- a/system/GLESv2_enc/gl2_client_proc.h
+++ b/system/GLESv2_enc/gl2_client_proc.h
@@ -436,6 +436,8 @@
 typedef void (gl2_APIENTRY *glDrawElementsNullAEMU_client_proc_t) (void * ctx, GLenum, GLsizei, GLenum, const GLvoid*);
 typedef void (gl2_APIENTRY *glDrawElementsOffsetNullAEMU_client_proc_t) (void * ctx, GLenum, GLsizei, GLenum, GLuint);
 typedef void (gl2_APIENTRY *glDrawElementsDataNullAEMU_client_proc_t) (void * ctx, GLenum, GLsizei, GLenum, void*, GLuint);
+typedef void (gl2_APIENTRY *glUnmapBufferAsyncAEMU_client_proc_t) (void * ctx, GLenum, GLintptr, GLsizeiptr, GLbitfield, void*, GLboolean*);
+typedef void (gl2_APIENTRY *glFlushMappedBufferRangeAEMU2_client_proc_t) (void * ctx, GLenum, GLintptr, GLsizeiptr, GLbitfield, void*);
 
 
 #endif
diff --git a/system/GLESv2_enc/gl2_enc.cpp b/system/GLESv2_enc/gl2_enc.cpp
index 17b3cba..0df93f8 100644
--- a/system/GLESv2_enc/gl2_enc.cpp
+++ b/system/GLESv2_enc/gl2_enc.cpp
@@ -11482,6 +11482,87 @@
 
 }
 
+void glUnmapBufferAsyncAEMU_enc(void *self , GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, void* guest_buffer, 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_guest_buffer = ((guest_buffer != NULL) ?  length : 0);
+	const unsigned int __size_out_res =  (sizeof(GLboolean));
+	 unsigned char *ptr;
+	 unsigned char *buf;
+	 const size_t sizeWithoutChecksum = 8 + 4 + 4 + 4 + 4 + __size_guest_buffer + __size_out_res + 2*4;
+	 const size_t checksumSize = checksumCalculator->checksumByteSize();
+	 const size_t totalSize = sizeWithoutChecksum + checksumSize;
+	buf = stream->alloc(8 + 4 + 4 + 4 + 4);
+	ptr = buf;
+	int tmp = OP_glUnmapBufferAsyncAEMU;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);
+	stream->flush();
+	stream->writeFully(&__size_guest_buffer,4);
+	if (useChecksum) checksumCalculator->addBuffer(&__size_guest_buffer,4);
+	if (guest_buffer != NULL) {
+		stream->writeFully(guest_buffer, __size_guest_buffer);
+		if (useChecksum) checksumCalculator->addBuffer(guest_buffer, __size_guest_buffer);
+	}
+	buf = stream->alloc(__size_out_res + 1*4);
+	ptr = buf;
+	*(unsigned int *)(ptr) = __size_out_res; ptr += 4;
+	memcpy(ptr, out_res, __size_out_res);ptr += __size_out_res;
+
+	if (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf);
+	buf = stream->alloc(checksumSize);
+	if (useChecksum) checksumCalculator->writeChecksum(buf, checksumSize);
+
+}
+
+void glFlushMappedBufferRangeAEMU2_enc(void *self , GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, void* guest_buffer)
+{
+
+	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_guest_buffer = ((guest_buffer != NULL) ?  length : 0);
+	 unsigned char *ptr;
+	 unsigned char *buf;
+	 const size_t sizeWithoutChecksum = 8 + 4 + 4 + 4 + 4 + __size_guest_buffer + 1*4;
+	 const size_t checksumSize = checksumCalculator->checksumByteSize();
+	 const size_t totalSize = sizeWithoutChecksum + checksumSize;
+	buf = stream->alloc(8 + 4 + 4 + 4 + 4);
+	ptr = buf;
+	int tmp = OP_glFlushMappedBufferRangeAEMU2;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);
+	stream->flush();
+	stream->writeFully(&__size_guest_buffer,4);
+	if (useChecksum) checksumCalculator->addBuffer(&__size_guest_buffer,4);
+	if (guest_buffer != NULL) {
+		stream->writeFully(guest_buffer, __size_guest_buffer);
+		if (useChecksum) checksumCalculator->addBuffer(guest_buffer, __size_guest_buffer);
+	}
+	buf = stream->alloc(checksumSize);
+	if (useChecksum) checksumCalculator->writeChecksum(buf, checksumSize);
+
+}
+
 }  // namespace
 
 gl2_encoder_context_t::gl2_encoder_context_t(IOStream *stream, ChecksumCalculator *checksumCalculator)
@@ -11913,5 +11994,7 @@
 	this->glDrawElementsNullAEMU = (glDrawElementsNullAEMU_client_proc_t) &enc_unsupported;
 	this->glDrawElementsOffsetNullAEMU = &glDrawElementsOffsetNullAEMU_enc;
 	this->glDrawElementsDataNullAEMU = &glDrawElementsDataNullAEMU_enc;
+	this->glUnmapBufferAsyncAEMU = &glUnmapBufferAsyncAEMU_enc;
+	this->glFlushMappedBufferRangeAEMU2 = &glFlushMappedBufferRangeAEMU2_enc;
 }
 
diff --git a/system/GLESv2_enc/gl2_entry.cpp b/system/GLESv2_enc/gl2_entry.cpp
index 69ce39d..a5d6c87 100644
--- a/system/GLESv2_enc/gl2_entry.cpp
+++ b/system/GLESv2_enc/gl2_entry.cpp
@@ -429,6 +429,8 @@
 	void glDrawElementsNullAEMU(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices);
 	void glDrawElementsOffsetNullAEMU(GLenum mode, GLsizei count, GLenum type, GLuint offset);
 	void glDrawElementsDataNullAEMU(GLenum mode, GLsizei count, GLenum type, void* data, GLuint datalen);
+	void glUnmapBufferAsyncAEMU(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, void* guest_buffer, GLboolean* out_res);
+	void glFlushMappedBufferRangeAEMU2(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, void* guest_buffer);
 };
 
 #ifndef GET_CONTEXT
@@ -3018,3 +3020,15 @@
 	ctx->glDrawElementsDataNullAEMU(ctx, mode, count, type, data, datalen);
 }
 
+void glUnmapBufferAsyncAEMU(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, void* guest_buffer, GLboolean* out_res)
+{
+	GET_CONTEXT;
+	ctx->glUnmapBufferAsyncAEMU(ctx, target, offset, length, access, guest_buffer, out_res);
+}
+
+void glFlushMappedBufferRangeAEMU2(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, void* guest_buffer)
+{
+	GET_CONTEXT;
+	ctx->glFlushMappedBufferRangeAEMU2(ctx, target, offset, length, access, guest_buffer);
+}
+
diff --git a/system/GLESv2_enc/gl2_opcodes.h b/system/GLESv2_enc/gl2_opcodes.h
index 7628a2e..9c619e1 100644
--- a/system/GLESv2_enc/gl2_opcodes.h
+++ b/system/GLESv2_enc/gl2_opcodes.h
@@ -427,7 +427,9 @@
 #define OP_glDrawElementsNullAEMU 					2469
 #define OP_glDrawElementsOffsetNullAEMU 					2470
 #define OP_glDrawElementsDataNullAEMU 					2471
-#define OP_last 					2472
+#define OP_glUnmapBufferAsyncAEMU 					2472
+#define OP_glFlushMappedBufferRangeAEMU2 					2473
+#define OP_last 					2474
 
 
 #endif
diff --git a/system/OpenglSystemCommon/EmulatorFeatureInfo.h b/system/OpenglSystemCommon/EmulatorFeatureInfo.h
index 422812c..390d9a6 100644
--- a/system/OpenglSystemCommon/EmulatorFeatureInfo.h
+++ b/system/OpenglSystemCommon/EmulatorFeatureInfo.h
@@ -93,6 +93,9 @@
 // YUV host cache
 static const char kYUVCache[] = "ANDROID_EMU_YUV_Cache";
 
+// GL protocol v2
+static const char kAsyncUnmapBuffer[] = "ANDROID_EMU_async_unmap_buffer";
+
 // Struct describing available emulator features
 struct EmulatorFeatureInfo {
 
@@ -107,7 +110,8 @@
         hasVulkanNullOptionalStrings(false),
         hasVulkanCreateResourcesWithRequirements(false),
         hasYUV420888toNV21(false),
-        hasYUVCache (false) { }
+        hasYUVCache (false),
+        hasAsyncUnmapBuffer (false) { }
 
     SyncImpl syncImpl;
     DmaImpl dmaImpl;
@@ -120,6 +124,7 @@
     bool hasVulkanCreateResourcesWithRequirements;
     bool hasYUV420888toNV21;
     bool hasYUVCache;
+    bool hasAsyncUnmapBuffer;
 };
 
 #endif // __COMMON_EMULATOR_FEATURE_INFO_H
diff --git a/system/OpenglSystemCommon/HostConnection.cpp b/system/OpenglSystemCommon/HostConnection.cpp
index 16d3fd3..9907f9f 100644
--- a/system/OpenglSystemCommon/HostConnection.cpp
+++ b/system/OpenglSystemCommon/HostConnection.cpp
@@ -140,9 +140,7 @@
     m_checksumHelper(),
     m_glExtensions(),
     m_grallocOnly(true),
-    m_noHostError(false)
-{
-}
+    m_noHostError(false) { }
 
 HostConnection::~HostConnection()
 {
@@ -304,6 +302,7 @@
         m_gl2Enc->setNoHostError(m_noHostError);
         m_gl2Enc->setDrawCallFlushInterval(
             getDrawCallFlushIntervalFromProperty());
+        m_gl2Enc->setHasAsyncUnmapBuffer(m_rcEnc->hasAsyncUnmapBuffer());
     }
     return m_gl2Enc;
 }
@@ -333,6 +332,7 @@
         queryAndSetVulkanCreateResourcesWithRequirementsSupport(m_rcEnc);
         queryAndSetYUV420888toNV21(m_rcEnc);
         queryAndSetYUVCache(m_rcEnc);
+        queryAndSetAsyncUnmapBuffer(m_rcEnc);
         if (m_processPipe) {
             m_processPipe->processPipeInit(m_rcEnc);
         }
@@ -520,3 +520,11 @@
         rcEnc->featureInfo()->hasYUVCache = true;
     }
 }
+
+void HostConnection::queryAndSetAsyncUnmapBuffer(ExtendedRCEncoderContext* rcEnc) {
+    std::string glExtensions = queryGLExtensions(rcEnc);
+    if (glExtensions.find(kAsyncUnmapBuffer) != std::string::npos) {
+        rcEnc->featureInfo()->hasAsyncUnmapBuffer = true;
+    }
+}
+
diff --git a/system/OpenglSystemCommon/HostConnection.h b/system/OpenglSystemCommon/HostConnection.h
index cfc5f08..f477f60 100644
--- a/system/OpenglSystemCommon/HostConnection.h
+++ b/system/OpenglSystemCommon/HostConnection.h
@@ -62,6 +62,8 @@
         return m_featureInfo.hasYUV420888toNV21; }
     bool hasYUVCache() const {
         return m_featureInfo.hasYUVCache; }
+    bool hasAsyncUnmapBuffer() const {
+        return m_featureInfo.hasAsyncUnmapBuffer; }
     DmaImpl getDmaVersion() const { return m_featureInfo.dmaImpl; }
     void bindDmaContext(struct goldfish_dma_context* cxt) { m_dmaCxt = cxt; }
     void bindDmaDirectly(void* dmaPtr, uint64_t dmaPhysAddr) {
@@ -204,6 +206,7 @@
     void queryAndSetVulkanCreateResourcesWithRequirementsSupport(ExtendedRCEncoderContext *rcEnc);
     void queryAndSetYUV420888toNV21(ExtendedRCEncoderContext *mrcEnc);
     void queryAndSetYUVCache(ExtendedRCEncoderContext *mrcEnc);
+    void queryAndSetAsyncUnmapBuffer(ExtendedRCEncoderContext *rcEnc);
 
 private:
     HostConnectionType m_connectionType;