Support for calling null draws from the guest

bug: 123635308
Change-Id: I039abf4d7de08747e11aeebc28fd5bde6e77d7b4
diff --git a/system/GLESv2_enc/GL2Encoder.cpp b/system/GLESv2_enc/GL2Encoder.cpp
index 3515d9e..ff88b31 100755
--- a/system/GLESv2_enc/GL2Encoder.cpp
+++ b/system/GLESv2_enc/GL2Encoder.cpp
@@ -123,6 +123,8 @@
     OVERRIDE(glDeleteBuffers);
     OVERRIDE(glDrawArrays);
     OVERRIDE(glDrawElements);
+    OVERRIDE(glDrawArraysNullAEMU);
+    OVERRIDE(glDrawElementsNullAEMU);
     OVERRIDE(glGetIntegerv);
     OVERRIDE(glGetFloatv);
     OVERRIDE(glGetBooleanv);
@@ -1426,6 +1428,120 @@
     }
 }
 
+void GL2Encoder::s_glDrawArraysNullAEMU(void *self, GLenum mode, GLint first, GLsizei count)
+{
+    GL2Encoder *ctx = (GL2Encoder *)self;
+    assert(ctx->m_state != NULL);
+    SET_ERROR_IF(!isValidDrawMode(mode), GL_INVALID_ENUM);
+    SET_ERROR_IF(count < 0, GL_INVALID_VALUE);
+
+    bool has_client_vertex_arrays = false;
+    bool has_indirect_arrays = false;
+    ctx->getVBOUsage(&has_client_vertex_arrays,
+                     &has_indirect_arrays);
+
+    if (has_client_vertex_arrays ||
+        (!has_client_vertex_arrays &&
+         !has_indirect_arrays)) {
+        ctx->sendVertexAttributes(first, count, true);
+        ctx->m_glDrawArraysNullAEMU_enc(ctx, mode, 0, count);
+    } else {
+        ctx->sendVertexAttributes(0, count, false);
+        ctx->m_glDrawArraysNullAEMU_enc(ctx, mode, first, count);
+    }
+}
+
+void GL2Encoder::s_glDrawElementsNullAEMU(void *self, GLenum mode, GLsizei count, GLenum type, const void *indices)
+{
+
+    GL2Encoder *ctx = (GL2Encoder *)self;
+    assert(ctx->m_state != NULL);
+    SET_ERROR_IF(!isValidDrawMode(mode), GL_INVALID_ENUM);
+    SET_ERROR_IF(count < 0, GL_INVALID_VALUE);
+    SET_ERROR_IF(!(type == GL_UNSIGNED_BYTE || type == GL_UNSIGNED_SHORT || type == GL_UNSIGNED_INT), GL_INVALID_ENUM);
+    SET_ERROR_IF(ctx->m_state->getTransformFeedbackActiveUnpaused(), GL_INVALID_OPERATION);
+
+    bool has_client_vertex_arrays = false;
+    bool has_indirect_arrays = false;
+    int nLocations = ctx->m_state->nLocations();
+    GLintptr offset = 0;
+
+    ctx->getVBOUsage(&has_client_vertex_arrays, &has_indirect_arrays);
+
+    if (!has_client_vertex_arrays && !has_indirect_arrays) {
+        // ALOGW("glDrawElements: no vertex arrays / buffers bound to the command\n");
+        GLenum status = ctx->m_glCheckFramebufferStatus_enc(self, GL_FRAMEBUFFER);
+        SET_ERROR_IF(status != GL_FRAMEBUFFER_COMPLETE, GL_INVALID_FRAMEBUFFER_OPERATION);
+    }
+
+    BufferData* buf = NULL;
+    int minIndex = 0, maxIndex = 0;
+
+    // For validation/immediate index array purposes,
+    // we need the min/max vertex index of the index array.
+    // If the VBO != 0, this may not be the first time we have
+    // used this particular index buffer. getBufferIndexRange
+    // can more quickly get min/max vertex index by
+    // caching previous results.
+    if (ctx->m_state->currentIndexVbo() != 0) {
+        buf = ctx->m_shared->getBufferData(ctx->m_state->currentIndexVbo());
+        offset = (GLintptr)indices;
+        indices = (void*)((GLintptr)buf->m_fixedBuffer.ptr() + (GLintptr)indices);
+        ctx->getBufferIndexRange(buf,
+                                 indices,
+                                 type,
+                                 (size_t)count,
+                                 (size_t)offset,
+                                 &minIndex, &maxIndex);
+    } else {
+        // In this case, the |indices| field holds a real
+        // array, so calculate the indices now. They will
+        // also be needed to know how much data to
+        // transfer to host.
+        ctx->calcIndexRange(indices,
+                            type,
+                            count,
+                            &minIndex,
+                            &maxIndex);
+    }
+
+    if (count == 0) return;
+
+    bool adjustIndices = true;
+    if (ctx->m_state->currentIndexVbo() != 0) {
+        if (!has_client_vertex_arrays) {
+            ctx->sendVertexAttributes(0, maxIndex + 1, false);
+            ctx->m_glBindBuffer_enc(self, GL_ELEMENT_ARRAY_BUFFER, ctx->m_state->currentIndexVbo());
+            ctx->glDrawElementsOffsetNullAEMU(ctx, mode, count, type, offset);
+            ctx->flushDrawCall();
+            adjustIndices = false;
+        } else {
+            BufferData * buf = ctx->m_shared->getBufferData(ctx->m_state->currentIndexVbo());
+            ctx->m_glBindBuffer_enc(self, GL_ELEMENT_ARRAY_BUFFER, 0);
+        }
+    }
+    if (adjustIndices) {
+        void *adjustedIndices =
+            ctx->recenterIndices(indices,
+                                 type,
+                                 count,
+                                 minIndex);
+
+        if (has_indirect_arrays || 1) {
+            ctx->sendVertexAttributes(minIndex, maxIndex - minIndex + 1, true);
+            ctx->glDrawElementsDataNullAEMU(ctx, mode, count, type, adjustedIndices,
+                                    count * glSizeof(type));
+            // XXX - OPTIMIZATION (see the other else branch) should be implemented
+            if(!has_indirect_arrays) {
+                //ALOGD("unoptimized drawelements !!!\n");
+            }
+        } else {
+            // we are all direct arrays and immidate mode index array -
+            // rebuild the arrays and the index array;
+            ALOGE("glDrawElementsNullAEMU: direct index & direct buffer data - will be implemented in later versions;\n");
+        }
+    }
+}
 
 GLint * GL2Encoder::getCompressedTextureFormats()
 {
diff --git a/system/GLESv2_enc/GL2Encoder.h b/system/GLESv2_enc/GL2Encoder.h
index 35d4737..a25f071 100644
--- a/system/GLESv2_enc/GL2Encoder.h
+++ b/system/GLESv2_enc/GL2Encoder.h
@@ -205,6 +205,12 @@
     glDrawElements_client_proc_t m_glDrawElements_enc;
     static void s_glDrawElements(void *self, GLenum mode, GLsizei count, GLenum type, const void *indices);
 
+    glDrawArraysNullAEMU_client_proc_t m_glDrawArraysNullAEMU_enc;
+    static void s_glDrawArraysNullAEMU(void *self, GLenum mode, GLint first, GLsizei count);
+
+    glDrawElementsNullAEMU_client_proc_t m_glDrawElementsNullAEMU_enc;
+    static void s_glDrawElementsNullAEMU(void *self, GLenum mode, GLsizei count, GLenum type, const void *indices);
+
     glGetIntegerv_client_proc_t m_glGetIntegerv_enc;
     static void s_glGetIntegerv(void *self, GLenum pname, GLint *ptr);
 
diff --git a/system/GLESv2_enc/gl2_client_context.cpp b/system/GLESv2_enc/gl2_client_context.cpp
index 783ecd0..c811b66 100644
--- a/system/GLESv2_enc/gl2_client_context.cpp
+++ b/system/GLESv2_enc/gl2_client_context.cpp
@@ -430,6 +430,10 @@
 	glReadnPixelsEXT = (glReadnPixelsEXT_client_proc_t) getProc("glReadnPixelsEXT", userData);
 	glGetnUniformfvEXT = (glGetnUniformfvEXT_client_proc_t) getProc("glGetnUniformfvEXT", userData);
 	glGetnUniformivEXT = (glGetnUniformivEXT_client_proc_t) getProc("glGetnUniformivEXT", userData);
+	glDrawArraysNullAEMU = (glDrawArraysNullAEMU_client_proc_t) getProc("glDrawArraysNullAEMU", userData);
+	glDrawElementsNullAEMU = (glDrawElementsNullAEMU_client_proc_t) getProc("glDrawElementsNullAEMU", userData);
+	glDrawElementsOffsetNullAEMU = (glDrawElementsOffsetNullAEMU_client_proc_t) getProc("glDrawElementsOffsetNullAEMU", userData);
+	glDrawElementsDataNullAEMU = (glDrawElementsDataNullAEMU_client_proc_t) getProc("glDrawElementsDataNullAEMU", userData);
 	return 0;
 }
 
diff --git a/system/GLESv2_enc/gl2_client_context.h b/system/GLESv2_enc/gl2_client_context.h
index fe5c893..ce0cf47 100644
--- a/system/GLESv2_enc/gl2_client_context.h
+++ b/system/GLESv2_enc/gl2_client_context.h
@@ -430,6 +430,10 @@
 	glReadnPixelsEXT_client_proc_t glReadnPixelsEXT;
 	glGetnUniformfvEXT_client_proc_t glGetnUniformfvEXT;
 	glGetnUniformivEXT_client_proc_t glGetnUniformivEXT;
+	glDrawArraysNullAEMU_client_proc_t glDrawArraysNullAEMU;
+	glDrawElementsNullAEMU_client_proc_t glDrawElementsNullAEMU;
+	glDrawElementsOffsetNullAEMU_client_proc_t glDrawElementsOffsetNullAEMU;
+	glDrawElementsDataNullAEMU_client_proc_t glDrawElementsDataNullAEMU;
 	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 1237dad..dea6d12 100644
--- a/system/GLESv2_enc/gl2_client_proc.h
+++ b/system/GLESv2_enc/gl2_client_proc.h
@@ -432,6 +432,10 @@
 typedef void (gl2_APIENTRY *glReadnPixelsEXT_client_proc_t) (void * ctx, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, GLsizei, GLvoid*);
 typedef void (gl2_APIENTRY *glGetnUniformfvEXT_client_proc_t) (void * ctx, GLuint, GLint, GLsizei, GLfloat*);
 typedef void (gl2_APIENTRY *glGetnUniformivEXT_client_proc_t) (void * ctx, GLuint, GLint, GLsizei, GLint*);
+typedef void (gl2_APIENTRY *glDrawArraysNullAEMU_client_proc_t) (void * ctx, GLenum, GLint, GLsizei);
+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);
 
 
 #endif
diff --git a/system/GLESv2_enc/gl2_enc.cpp b/system/GLESv2_enc/gl2_enc.cpp
index 6fecec4..17b3cba 100644
--- a/system/GLESv2_enc/gl2_enc.cpp
+++ b/system/GLESv2_enc/gl2_enc.cpp
@@ -11396,6 +11396,92 @@
 	}
 }
 
+void glDrawArraysNullAEMU_enc(void *self , GLenum mode, GLint first, GLsizei count)
+{
+
+	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;
+	 const size_t checksumSize = checksumCalculator->checksumByteSize();
+	 const size_t totalSize = sizeWithoutChecksum + checksumSize;
+	buf = stream->alloc(totalSize);
+	ptr = buf;
+	int tmp = OP_glDrawArraysNullAEMU;memcpy(ptr, &tmp, 4); ptr += 4;
+	memcpy(ptr, &totalSize, 4);  ptr += 4;
+
+		memcpy(ptr, &mode, 4); ptr += 4;
+		memcpy(ptr, &first, 4); ptr += 4;
+		memcpy(ptr, &count, 4); ptr += 4;
+
+	if (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf);
+	if (useChecksum) checksumCalculator->writeChecksum(ptr, checksumSize); ptr += checksumSize;
+
+}
+
+void glDrawElementsOffsetNullAEMU_enc(void *self , GLenum mode, GLsizei count, GLenum type, GLuint offset)
+{
+
+	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_glDrawElementsOffsetNullAEMU;memcpy(ptr, &tmp, 4); ptr += 4;
+	memcpy(ptr, &totalSize, 4);  ptr += 4;
+
+		memcpy(ptr, &mode, 4); ptr += 4;
+		memcpy(ptr, &count, 4); ptr += 4;
+		memcpy(ptr, &type, 4); ptr += 4;
+		memcpy(ptr, &offset, 4); ptr += 4;
+
+	if (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf);
+	if (useChecksum) checksumCalculator->writeChecksum(ptr, checksumSize); ptr += checksumSize;
+
+}
+
+void glDrawElementsDataNullAEMU_enc(void *self , GLenum mode, GLsizei count, GLenum type, void* data, GLuint datalen)
+{
+
+	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_data =  datalen;
+	 unsigned char *ptr;
+	 unsigned char *buf;
+	 const size_t sizeWithoutChecksum = 8 + 4 + 4 + 4 + __size_data + 4 + 1*4;
+	 const size_t checksumSize = checksumCalculator->checksumByteSize();
+	 const size_t totalSize = sizeWithoutChecksum + checksumSize;
+	buf = stream->alloc(totalSize);
+	ptr = buf;
+	int tmp = OP_glDrawElementsDataNullAEMU;memcpy(ptr, &tmp, 4); ptr += 4;
+	memcpy(ptr, &totalSize, 4);  ptr += 4;
+
+		memcpy(ptr, &mode, 4); ptr += 4;
+		memcpy(ptr, &count, 4); ptr += 4;
+		memcpy(ptr, &type, 4); ptr += 4;
+	*(unsigned int *)(ptr) = __size_data; ptr += 4;
+	memcpy(ptr, data, __size_data);ptr += __size_data;
+		memcpy(ptr, &datalen, 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)
@@ -11823,5 +11909,9 @@
 	this->glReadnPixelsEXT = &glReadnPixelsEXT_enc;
 	this->glGetnUniformfvEXT = &glGetnUniformfvEXT_enc;
 	this->glGetnUniformivEXT = &glGetnUniformivEXT_enc;
+	this->glDrawArraysNullAEMU = &glDrawArraysNullAEMU_enc;
+	this->glDrawElementsNullAEMU = (glDrawElementsNullAEMU_client_proc_t) &enc_unsupported;
+	this->glDrawElementsOffsetNullAEMU = &glDrawElementsOffsetNullAEMU_enc;
+	this->glDrawElementsDataNullAEMU = &glDrawElementsDataNullAEMU_enc;
 }
 
diff --git a/system/GLESv2_enc/gl2_entry.cpp b/system/GLESv2_enc/gl2_entry.cpp
index 70b22bc..69ce39d 100644
--- a/system/GLESv2_enc/gl2_entry.cpp
+++ b/system/GLESv2_enc/gl2_entry.cpp
@@ -425,6 +425,10 @@
 	void glReadnPixelsEXT(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, GLvoid* data);
 	void glGetnUniformfvEXT(GLuint program, GLint location, GLsizei bufSize, GLfloat* params);
 	void glGetnUniformivEXT(GLuint program, GLint location, GLsizei bufSize, GLint* params);
+	void glDrawArraysNullAEMU(GLenum mode, GLint first, GLsizei count);
+	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);
 };
 
 #ifndef GET_CONTEXT
@@ -2990,3 +2994,27 @@
 	ctx->glGetnUniformivEXT(ctx, program, location, bufSize, params);
 }
 
+void glDrawArraysNullAEMU(GLenum mode, GLint first, GLsizei count)
+{
+	GET_CONTEXT;
+	ctx->glDrawArraysNullAEMU(ctx, mode, first, count);
+}
+
+void glDrawElementsNullAEMU(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices)
+{
+	GET_CONTEXT;
+	ctx->glDrawElementsNullAEMU(ctx, mode, count, type, indices);
+}
+
+void glDrawElementsOffsetNullAEMU(GLenum mode, GLsizei count, GLenum type, GLuint offset)
+{
+	GET_CONTEXT;
+	ctx->glDrawElementsOffsetNullAEMU(ctx, mode, count, type, offset);
+}
+
+void glDrawElementsDataNullAEMU(GLenum mode, GLsizei count, GLenum type, void* data, GLuint datalen)
+{
+	GET_CONTEXT;
+	ctx->glDrawElementsDataNullAEMU(ctx, mode, count, type, data, datalen);
+}
+
diff --git a/system/GLESv2_enc/gl2_ftable.h b/system/GLESv2_enc/gl2_ftable.h
index 0e93cf1..ff3de2e 100644
--- a/system/GLESv2_enc/gl2_ftable.h
+++ b/system/GLESv2_enc/gl2_ftable.h
@@ -385,6 +385,8 @@
 	{"glReadnPixelsEXT", (void*)glReadnPixelsEXT},
 	{"glGetnUniformfvEXT", (void*)glGetnUniformfvEXT},
 	{"glGetnUniformivEXT", (void*)glGetnUniformivEXT},
+	{"glDrawArraysNullAEMU", (void*)glDrawArraysNullAEMU},
+	{"glDrawElementsNullAEMU", (void*)glDrawElementsNullAEMU},
 };
 static const int gl2_num_funcs = sizeof(gl2_funcs_by_name) / sizeof(struct _gl2_funcs_by_name);
 
diff --git a/system/GLESv2_enc/gl2_opcodes.h b/system/GLESv2_enc/gl2_opcodes.h
index 96688db..7628a2e 100644
--- a/system/GLESv2_enc/gl2_opcodes.h
+++ b/system/GLESv2_enc/gl2_opcodes.h
@@ -423,7 +423,11 @@
 #define OP_glReadnPixelsEXT 					2465
 #define OP_glGetnUniformfvEXT 					2466
 #define OP_glGetnUniformivEXT 					2467
-#define OP_last 					2468
+#define OP_glDrawArraysNullAEMU 					2468
+#define OP_glDrawElementsNullAEMU 					2469
+#define OP_glDrawElementsOffsetNullAEMU 					2470
+#define OP_glDrawElementsDataNullAEMU 					2471
+#define OP_last 					2472
 
 
 #endif