Snap for 4813226 from 22dc42d6cf91ef90ae3fb6342d8e716666a87df8 to pi-release

Change-Id: I21f5684debac5913e77f16ec7d59801f50b98dd1
diff --git a/host/include/libOpenglRender/IOStream.h b/host/include/libOpenglRender/IOStream.h
index 445ec17..1d32ea1 100644
--- a/host/include/libOpenglRender/IOStream.h
+++ b/host/include/libOpenglRender/IOStream.h
@@ -83,6 +83,8 @@
         return readFully(buf, len);
     }
 
+    void readbackPixels(void* context, int width, int height, unsigned int format, unsigned int type, void* pixels);
+
 
 private:
     unsigned char *m_buf;
diff --git a/shared/OpenglCodecCommon/GLClientState.cpp b/shared/OpenglCodecCommon/GLClientState.cpp
index 6e9c8f6..7d40389 100644
--- a/shared/OpenglCodecCommon/GLClientState.cpp
+++ b/shared/OpenglCodecCommon/GLClientState.cpp
@@ -664,6 +664,29 @@
     return 1;
 }
 
+void GLClientState::getPackingOffsets2D(GLsizei width, GLsizei height, GLenum format, GLenum type, int* startOffset, int* pixelRowSize, int* totalRowSize, int* skipRows) const
+{
+    if (width <= 0 || height <= 0) {
+        *startOffset = 0;
+        *pixelRowSize = 0;
+        *totalRowSize = 0;
+        return;
+    }
+
+    GLESTextureUtils::computePackingOffsets2D(
+            width, height,
+            format, type,
+            m_pixelStore.pack_alignment,
+            m_pixelStore.pack_row_length,
+            m_pixelStore.pack_skip_pixels,
+            m_pixelStore.pack_skip_rows,
+            startOffset,
+            pixelRowSize,
+            totalRowSize);
+
+    *skipRows = m_pixelStore.pack_skip_rows;
+}
+
 void GLClientState::setNumActiveUniformsInUniformBlock(GLuint program, GLuint uniformBlockIndex, GLint numActiveUniforms) {
     UniformBlockInfoKey key;
     key.program = program;
diff --git a/shared/OpenglCodecCommon/GLClientState.h b/shared/OpenglCodecCommon/GLClientState.h
index e41cf44..675cea4 100644
--- a/shared/OpenglCodecCommon/GLClientState.h
+++ b/shared/OpenglCodecCommon/GLClientState.h
@@ -239,6 +239,7 @@
     size_t pixelDataSize(GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, int pack) const;
     size_t pboNeededDataSize(GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, int pack) const;
     size_t clearBufferNumElts(GLenum buffer) const;
+    void getPackingOffsets2D(GLsizei width, GLsizei height, GLenum format, GLenum type, int* startOffset, int* pixelRowSize, int* totalRowSize, int* skipRows) const;
 
     void setCurrentProgram(GLint program) { m_currentProgram = program; }
     void setCurrentShaderProgram(GLint program) { m_currentShaderProgram = program; }
diff --git a/shared/OpenglCodecCommon/GLESTextureUtils.cpp b/shared/OpenglCodecCommon/GLESTextureUtils.cpp
index 1aef8cb..4572905 100644
--- a/shared/OpenglCodecCommon/GLESTextureUtils.cpp
+++ b/shared/OpenglCodecCommon/GLESTextureUtils.cpp
@@ -284,4 +284,29 @@
     return end - start;
 }
 
+void computePackingOffsets2D(
+        GLsizei width, GLsizei height,
+        GLenum format, GLenum type,
+        int packAlignment,
+        int packRowLength,
+        int packSkipPixels,
+        int packSkipRows,
+        int* startOffset,
+        int* packingPixelRowSize,
+        int* packingTotalRowSize) {
+
+    int widthTotal = (packRowLength == 0) ? width : packRowLength;
+    int totalRowSize = computePitch(widthTotal, format, type, packAlignment);
+    int pixelsOnlyRowSize = computePitch(width, format, type, packAlignment);
+
+    int packingOffsetStart =
+        computePackingOffset(
+                format, type, widthTotal, height, packAlignment, packSkipPixels, packSkipRows, 0 /* skip images = 0 */);
+
+    if (startOffset) *startOffset = packingOffsetStart;
+    if (packingPixelRowSize) *packingPixelRowSize = pixelsOnlyRowSize;
+    if (packingTotalRowSize) *packingTotalRowSize = totalRowSize;
+}
+
+
 } // namespace GLESTextureUtils
diff --git a/shared/OpenglCodecCommon/GLESTextureUtils.h b/shared/OpenglCodecCommon/GLESTextureUtils.h
index 906e590..f623d23 100644
--- a/shared/OpenglCodecCommon/GLESTextureUtils.h
+++ b/shared/OpenglCodecCommon/GLESTextureUtils.h
@@ -37,6 +37,21 @@
         int unpackSkipRows,
         int unpackSkipImages);
 
+// Writes out |height| offsets for glReadPixels to read back
+// data in separate rows of pixels. Returns:
+// 1. |startOffset|: offset in bytes to apply at the beginning
+// 2. |packingPixelRowSize|: the buffer size in bytes that has the actual pixels per row.
+// 2. |packingTotalRowSize|: the length in bytes of each row including the padding from row length.
+void computePackingOffsets2D(
+        GLsizei width, GLsizei height,
+        GLenum format, GLenum type,
+        int packAlignment,
+        int packRowLength,
+        int packSkipPixels,
+        int packSkipRows,
+        int* startOffset,
+        int* packingPixelRowSize,
+        int* packingTotalRowSize);
 
 } // namespace GLESTextureUtils
 #endif
diff --git a/system/GLESv2_enc/Android.mk b/system/GLESv2_enc/Android.mk
index c5081d3..f61c9f7 100644
--- a/system/GLESv2_enc/Android.mk
+++ b/system/GLESv2_enc/Android.mk
@@ -10,6 +10,7 @@
     gl2_client_context.cpp \
     gl2_enc.cpp \
     gl2_entry.cpp \
+    ../enc_common/IOStream_common.cpp \
 
 LOCAL_CFLAGS += -DLOG_TAG=\"emuglGLESv2_enc\"
 
diff --git a/system/GLESv2_enc/gl2_enc.cpp b/system/GLESv2_enc/gl2_enc.cpp
index 8357c68..f42e7ba 100644
--- a/system/GLESv2_enc/gl2_enc.cpp
+++ b/system/GLESv2_enc/gl2_enc.cpp
@@ -3028,7 +3028,10 @@
 	if (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf);
 	if (useChecksum) checksumCalculator->writeChecksum(ptr, checksumSize); ptr += checksumSize;
 
-	stream->readback(pixels, __size_pixels);
+    // TODO: make this part of autogenerated pipe code.
+    // b/79208762
+	stream->readbackPixels(self, width, height, format, type, pixels);
+
 	if (useChecksum) checksumCalculator->addBuffer(pixels, __size_pixels);
 	if (useChecksum) {
 		unsigned char *checksumBufPtr = NULL;
diff --git a/system/enc_common/IOStream_common.cpp b/system/enc_common/IOStream_common.cpp
new file mode 100644
index 0000000..43f03af
--- /dev/null
+++ b/system/enc_common/IOStream_common.cpp
@@ -0,0 +1,59 @@
+#include "IOStream.h"
+
+#include "GL2Encoder.h"
+
+#include <GLES3/gl31.h>
+
+#include <vector>
+
+void IOStream::readbackPixels(void* context, int width, int height, unsigned int format, unsigned int type, void* pixels) {
+    GL2Encoder *ctx = (GL2Encoder *)context;
+    assert (ctx->state() != NULL);
+
+    int startOffset = 0;
+    int pixelRowSize = 0;
+    int totalRowSize = 0;
+    int skipRows = 0;
+
+    ctx->state()->getPackingOffsets2D(width, height, format, type,
+                                      &startOffset,
+                                      &pixelRowSize,
+                                      &totalRowSize,
+                                      &skipRows);
+
+    size_t pixelDataSize =
+        ctx->state()->pixelDataSize(
+            width, height, 1, format, type, 1 /* is pack */);
+
+    if (startOffset == 0 &&
+        pixelRowSize == totalRowSize) {
+        // fast path
+        readback(pixels, pixelDataSize);
+    } else if (pixelRowSize == totalRowSize) {
+        // fast path but with skip in the beginning
+        std::vector<char> paddingToDiscard(startOffset, 0);
+        readback(&paddingToDiscard[0], startOffset);
+        readback((char*)pixels + startOffset, pixelDataSize - startOffset);
+    } else {
+        int totalReadback = 0;
+
+        if (startOffset > 0) {
+            std::vector<char> paddingToDiscard(startOffset, 0);
+            readback(&paddingToDiscard[0], startOffset);
+            totalReadback += startOffset;
+        }
+        // need to read back row by row
+        size_t paddingSize = totalRowSize - pixelRowSize;
+        std::vector<char> paddingToDiscard(paddingSize, 0);
+
+        char* start = (char*)pixels + startOffset;
+
+        for (int i = 0; i < height; i++) {
+            readback(start, pixelRowSize);
+            totalReadback += pixelRowSize;
+            readback(&paddingToDiscard[0], paddingSize);
+            totalReadback += paddingSize;
+            start += totalRowSize;
+        }
+    }
+}