Merge "[vulkan] Fix variable init on Fuchsia."
diff --git a/shared/OpenglCodecCommon/SocketStream.cpp b/shared/OpenglCodecCommon/SocketStream.cpp
index 067a75f..d6d31c0 100644
--- a/shared/OpenglCodecCommon/SocketStream.cpp
+++ b/shared/OpenglCodecCommon/SocketStream.cpp
@@ -132,7 +132,7 @@
 
 const unsigned char *SocketStream::commitBufferAndReadFully(size_t size, void *buf, size_t len)
 {
-    return commitBuffer(size) ? nullptr : readFully(buf, len);
+    return commitBuffer(size) ? NULL : readFully(buf, len);
 }
 
 const unsigned char *SocketStream::read( void *buf, size_t *inout_len)
diff --git a/system/OpenglSystemCommon/EmulatorFeatureInfo.h b/system/OpenglSystemCommon/EmulatorFeatureInfo.h
index b2add4a..95b3e60 100644
--- a/system/OpenglSystemCommon/EmulatorFeatureInfo.h
+++ b/system/OpenglSystemCommon/EmulatorFeatureInfo.h
@@ -85,6 +85,12 @@
 // Vulkan create resources with requirements
 static const char kVulkanCreateResourcesWithRequirements[] = "ANDROID_EMU_vulkan_create_resources_with_requirements";
 
+// YUV420_888 to NV21
+static const char kYUV420888toNV21[] = "ANDROID_EMU_YUV420_888_to_NV21";
+
+// YUV host cache
+static const char kYUVCache[] = "ANDROID_EMU_YUV_Cache";
+
 // Struct describing available emulator features
 struct EmulatorFeatureInfo {
 
@@ -97,7 +103,9 @@
         hasVulkan(false),
         hasDeferredVulkanCommands(false),
         hasVulkanNullOptionalStrings(false),
-        hasVulkanCreateResourcesWithRequirements(false) { }
+        hasVulkanCreateResourcesWithRequirements(false),
+        hasYUV420888toNV21(false),
+        hasYUVCache (false) { }
 
     SyncImpl syncImpl;
     DmaImpl dmaImpl;
@@ -108,6 +116,8 @@
     bool hasDeferredVulkanCommands;
     bool hasVulkanNullOptionalStrings;
     bool hasVulkanCreateResourcesWithRequirements;
+    bool hasYUV420888toNV21;
+    bool hasYUVCache;
 };
 
 #endif // __COMMON_EMULATOR_FEATURE_INFO_H
diff --git a/system/OpenglSystemCommon/FormatConversions.cpp b/system/OpenglSystemCommon/FormatConversions.cpp
index 92d7f0b..4b5c31c 100644
--- a/system/OpenglSystemCommon/FormatConversions.cpp
+++ b/system/OpenglSystemCommon/FormatConversions.cpp
@@ -55,9 +55,9 @@
                                 uint32_t* totalSz_out) {
     uint32_t align = 1;
     uint32_t yStride = (width + (align - 1)) & ~(align-1);
-    uint32_t uvStride = (yStride / 2 + (align - 1)) & ~(align-1);
+    uint32_t uvStride = yStride;
     uint32_t uvHeight = height / 2;
-    uint32_t sz = yStride * height + 2 * (uvHeight * uvStride);
+    uint32_t sz = yStride * height + uvHeight * uvStride;
 
     if (yStride_out) *yStride_out = yStride;
     if (cStride_out) *cStride_out = uvStride;
@@ -218,6 +218,44 @@
         }
     }
 }
+
+//HAL_PIXEL_FORMAT_YCbCr_420_888, or yuv420p is treated as NV21 across our
+//gralloc and camera module when feature YUV420888toNV21 enabled
+void rgb888_to_nv21(char* dest, char* src, int width, int height,
+                    int left, int top, int right, int bottom) {
+    const int rgb_stride = 3;
+
+    DD("%s convert %d by %d", __func__, width, height);
+    int yStride = width;
+    int cStride = yStride;
+    int yOffset = 0;
+
+    uint8_t *rgb_ptr0 = (uint8_t *)src;
+    uint8_t *nv21_y0 = (uint8_t *)dest;
+    uint8_t *nv21_v0 = nv21_y0 + yStride * height;
+
+    for (int j = top; j <= bottom; ++j) {
+        uint8_t *nv21_y = nv21_y0 + j * yStride;
+        uint8_t *nv21_v = nv21_v0 + (j/2) * cStride;
+        uint8_t *nv21_u = nv21_v + 1;
+        uint8_t *rgb_ptr = rgb_ptr0 + get_rgb_offset(j, width, rgb_stride);
+        bool jeven = (j & 1) == 0;
+        for (int i = left; i <= right; ++i) {
+            uint8_t R = rgb_ptr[i*rgb_stride];
+            uint8_t G = rgb_ptr[i*rgb_stride+1];
+            uint8_t B = rgb_ptr[i*rgb_stride+2];
+            // convert to YV12
+            // frameworks/base/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
+            nv21_y[i] = clamp_rgb((77 * R + 150 * G +  29 * B) >> 8);
+            bool ieven = (i & 1) == 0;
+            if (jeven && ieven) {
+                nv21_u[i] = clamp_rgb((( -43 * R - 85 * G + 128 * B) >> 8) + 128);
+                nv21_v[i] = clamp_rgb((( 128 * R - 107 * G - 21 * B) >> 8) + 128);
+            }
+        }
+    }
+}
+
 // YV12 is aka YUV420Planar, or YUV420p; the only difference is that YV12 has
 // certain stride requirements for Y and UV respectively.
 void yv12_to_rgb565(char* dest, char* src, int width, int height,
@@ -305,8 +343,6 @@
     }
 }
 
-// YV12 is aka YUV420Planar, or YUV420p; the only difference is that YV12 has
-// certain stride requirements for Y and UV respectively.
 void yuv420p_to_rgb888(char* dest, char* src, int width, int height,
         int left, int top, int right, int bottom) {
     const int rgb_stride = 3;
@@ -350,6 +386,50 @@
     }
 }
 
+//HAL_PIXEL_FORMAT_YCbCr_420_888, or yuv420p is treated as NV21 across our
+//gralloc and camera module when feature YUV420888toNV21 enabled
+void nv21_to_rgb888(char* dest, char* src, int width, int height,
+                    int left, int top, int right, int bottom) {
+    const int rgb_stride = 3;
+
+    DD("%s convert %d by %d", __func__, width, height);
+    int yStride = width;
+    int cStride = yStride;
+    int yOffset = 0;
+
+    uint8_t *rgb_ptr0 = (uint8_t *)dest;
+    uint8_t *nv21_y0 = (uint8_t *)src;
+    uint8_t *nv21_v0 = nv21_y0 + yStride * height;
+
+    for (int j = top; j <= bottom; ++j) {
+        uint8_t *nv21_y = nv21_y0 + j * yStride;
+        uint8_t *nv21_v = nv21_v0 + (j/2) * cStride;
+        uint8_t *nv21_u = nv21_v + 1;
+        uint8_t *rgb_ptr = rgb_ptr0 + get_rgb_offset(j - top, right - left + 1, rgb_stride);
+        for (int i = left; i <= right; ++i) {
+            // convert to rgb
+            // frameworks/av/media/libstagefright/colorconversion/ColorConverter.cpp
+            signed y1 = (signed)nv21_y[i] - 16;
+            signed u = (signed)nv21_u[i / 2] - 128;
+            signed v = (signed)nv21_v[i / 2] - 128;
+
+            signed u_b = u * 517;
+            signed u_g = -u * 100;
+            signed v_g = -v * 208;
+            signed v_r = v * 409;
+
+            signed tmp1 = y1 * 298;
+            signed b1 = clamp_rgb((tmp1 + u_b) / 256);
+            signed g1 = clamp_rgb((tmp1 + v_g + u_g) / 256);
+            signed r1 = clamp_rgb((tmp1 + v_r) / 256);
+
+            rgb_ptr[(i-left)*rgb_stride] = r1;
+            rgb_ptr[(i-left)*rgb_stride+1] = g1;
+            rgb_ptr[(i-left)*rgb_stride+2] = b1;
+        }
+    }
+}
+
 void copy_rgb_buffer_from_unlocked(
         char* _dst, char* raw_data,
         int unlockedWidth,
diff --git a/system/OpenglSystemCommon/FormatConversions.h b/system/OpenglSystemCommon/FormatConversions.h
index 6e15f36..196ca37 100644
--- a/system/OpenglSystemCommon/FormatConversions.h
+++ b/system/OpenglSystemCommon/FormatConversions.h
@@ -33,12 +33,16 @@
                     int left, int top, int right, int bottom);
 void rgb888_to_yuv420p(char* dest, char* src, int width, int height,
                        int left, int top, int right, int bottom);
+void rgb888_to_nv21(char* dest, char* src, int width, int height,
+                    int left, int top, int right, int bottom);
 void yv12_to_rgb565(char* dest, char* src, int width, int height,
                     int left, int top, int right, int bottom);
 void yv12_to_rgb888(char* dest, char* src, int width, int height,
                     int left, int top, int right, int bottom);
 void yuv420p_to_rgb888(char* dest, char* src, int width, int height,
                        int left, int top, int right, int bottom);
+void nv21_to_rgb888(char* dest, char* src, int width, int height,
+                    int left, int top, int right, int bottom);
 void copy_rgb_buffer_from_unlocked(char* _dst, char* raw_data,
                                    int unlockedWidth,
                                    int width, int height, int top, int left,
diff --git a/system/OpenglSystemCommon/HostConnection.cpp b/system/OpenglSystemCommon/HostConnection.cpp
index cfe31b5..5e81ead 100644
--- a/system/OpenglSystemCommon/HostConnection.cpp
+++ b/system/OpenglSystemCommon/HostConnection.cpp
@@ -295,6 +295,8 @@
         queryAndSetDeferredVulkanCommandsSupport(m_rcEnc);
         queryAndSetVulkanNullOptionalStringsSupport(m_rcEnc);
         queryAndSetVulkanCreateResourcesWithRequirementsSupport(m_rcEnc);
+        queryAndSetYUV420888toNV21(m_rcEnc);
+        queryAndSetYUVCache(m_rcEnc);
         if (m_processPipe) {
             m_processPipe->processPipeInit(m_rcEnc);
         }
@@ -464,3 +466,17 @@
         rcEnc->featureInfo()->hasVulkanCreateResourcesWithRequirements = true;
     }
 }
+
+void HostConnection::queryAndSetYUV420888toNV21(ExtendedRCEncoderContext* rcEnc) {
+    std::string glExtensions = queryGLExtensions(rcEnc);
+    if (glExtensions.find(kYUV420888toNV21) != std::string::npos) {
+        rcEnc->featureInfo()->hasYUV420888toNV21 = true;
+    }
+}
+
+void HostConnection::queryAndSetYUVCache(ExtendedRCEncoderContext* rcEnc) {
+    std::string glExtensions = queryGLExtensions(rcEnc);
+    if (glExtensions.find(kYUVCache) != std::string::npos) {
+        rcEnc->featureInfo()->hasYUVCache = true;
+    }
+}
diff --git a/system/OpenglSystemCommon/HostConnection.h b/system/OpenglSystemCommon/HostConnection.h
index f79c11f..22b36b0 100644
--- a/system/OpenglSystemCommon/HostConnection.h
+++ b/system/OpenglSystemCommon/HostConnection.h
@@ -21,6 +21,7 @@
 #include "renderControl_enc.h"
 #include "ChecksumCalculator.h"
 #include "goldfish_dma.h"
+#include "goldfish_address_space.h"
 
 #include <cutils/native_handle.h>
 
@@ -47,7 +48,7 @@
 public:
     ExtendedRCEncoderContext(IOStream *stream, ChecksumCalculator *checksumCalculator)
         : renderControl_encoder_context_t(stream, checksumCalculator),
-          m_dmaCxt(NULL) { }
+          m_dmaCxt(NULL), m_addressSpaceBlock(NULL) { }
     void setSyncImpl(SyncImpl syncImpl) { m_featureInfo.syncImpl = syncImpl; }
     void setDmaImpl(DmaImpl dmaImpl) { m_featureInfo.dmaImpl = dmaImpl; }
     void setHostComposition(HostComposition hostComposition) {
@@ -56,11 +57,20 @@
     bool hasNativeSyncV3() const { return m_featureInfo.syncImpl >= SYNC_IMPL_NATIVE_SYNC_V3; }
     bool hasHostCompositionV1() const {
         return m_featureInfo.hostComposition == HOST_COMPOSITION_V1; }
+    bool hasYUV420toNV21() const {
+        return m_featureInfo.hasYUV420888toNV21; }
+    bool hasYUVCache() const {
+        return m_featureInfo.hasYUVCache; }
     DmaImpl getDmaVersion() const { return m_featureInfo.dmaImpl; }
     void bindDmaContext(struct goldfish_dma_context* cxt) { m_dmaCxt = cxt; }
+    void bindAddressSpaceBlock(GoldfishAddressSpaceBlock* block) {
+        m_addressSpaceBlock = block;
+    }
     virtual uint64_t lockAndWriteDma(void* data, uint32_t size) {
-        if (m_dmaCxt) {
-            return lockAndWriteGoldfishDma(data, size, m_dmaCxt);
+        if (m_addressSpaceBlock) {
+            return writeAddressSpaceBlock(data, size, m_addressSpaceBlock);
+        } else if (m_dmaCxt) {
+            return writeGoldfishDma(data, size, m_dmaCxt);
         } else {
             ALOGE("%s: ERROR: No DMA context bound!", __func__);
             return 0;
@@ -68,12 +78,20 @@
     }
     void setGLESMaxVersion(GLESMaxVersion ver) { m_featureInfo.glesMaxVersion = ver; }
     GLESMaxVersion getGLESMaxVersion() const { return m_featureInfo.glesMaxVersion; }
+    bool hasDirectMem() const {
+#ifdef HOST_BUILD
+        // unit tests do not support restoring "guest" ram because there is no VM
+        return false;
+#else
+        return m_featureInfo.hasDirectMem;
+#endif
+    }
 
     const EmulatorFeatureInfo* featureInfo_const() const { return &m_featureInfo; }
     EmulatorFeatureInfo* featureInfo() { return &m_featureInfo; }
 private:
-    static uint64_t lockAndWriteGoldfishDma(void* data, uint32_t size,
-                                            struct goldfish_dma_context* dmaCxt) {
+    static uint64_t writeGoldfishDma(void* data, uint32_t size,
+                                     struct goldfish_dma_context* dmaCxt) {
         ALOGV("%s(data=%p, size=%u): call", __func__, data, size);
 
         goldfish_dma_write(dmaCxt, data, size);
@@ -83,8 +101,20 @@
         return paddr;
     }
 
+    static uint64_t writeAddressSpaceBlock(void* data, uint32_t size,
+                                           GoldfishAddressSpaceBlock* block) {
+        ALOGV("%s(data=%p, size=%u): call", __func__, data, size);
+
+        memcpy(block->guestPtr(), data, size);
+        const uint64_t paddr = block->physAddr();
+
+        ALOGV("%s: paddr=0x%llx", __func__, (unsigned long long)paddr);
+        return paddr;
+    }
+
     EmulatorFeatureInfo m_featureInfo;
     struct goldfish_dma_context* m_dmaCxt;
+    GoldfishAddressSpaceBlock* m_addressSpaceBlock;
 };
 
 // Abstraction for gralloc handle conversion
@@ -168,6 +198,8 @@
     void queryAndSetDeferredVulkanCommandsSupport(ExtendedRCEncoderContext *rcEnc);
     void queryAndSetVulkanNullOptionalStringsSupport(ExtendedRCEncoderContext *rcEnc);
     void queryAndSetVulkanCreateResourcesWithRequirementsSupport(ExtendedRCEncoderContext *rcEnc);
+    void queryAndSetYUV420888toNV21(ExtendedRCEncoderContext *mrcEnc);
+    void queryAndSetYUVCache(ExtendedRCEncoderContext *mrcEnc);
 
 private:
     IOStream *m_stream;
diff --git a/system/OpenglSystemCommon/VirtioGpuStream.h b/system/OpenglSystemCommon/VirtioGpuStream.h
index 5d44bcc..0be50e6 100644
--- a/system/OpenglSystemCommon/VirtioGpuStream.h
+++ b/system/OpenglSystemCommon/VirtioGpuStream.h
@@ -69,7 +69,7 @@
     virtual int writeFully(const void *buf, size_t len);
     virtual const unsigned char *readFully(void *buf, size_t len);
     virtual int commitBuffer(size_t size);
-    virtual int commitBufferAndReadFully(size_t size, void *buf, size_t len)
+    virtual const unsigned char* commitBufferAndReadFully(size_t size, void *buf, size_t len)
     {
         return commitBuffer(size) ? nullptr : readFully(buf, len);
     }
diff --git a/system/gralloc/gralloc.cpp b/system/gralloc/gralloc.cpp
index 817107f..39e7e16 100644
--- a/system/gralloc/gralloc.cpp
+++ b/system/gralloc/gralloc.cpp
@@ -29,6 +29,7 @@
 #endif
 
 #include "goldfish_dma.h"
+#include "goldfish_address_space.h"
 #include "FormatConversions.h"
 #include "HostConnection.h"
 #include "ProcessPipe.h"
@@ -125,13 +126,20 @@
 #define INITIAL_DMA_REGION_SIZE 4096
 struct gralloc_dmaregion_t {
     gralloc_dmaregion_t(ExtendedRCEncoderContext *rcEnc)
-      : sz(0), refcount(0), bigbufCount(0) {
+      : sz(INITIAL_DMA_REGION_SIZE), refcount(0), bigbufCount(0) {
+        memset(&goldfish_dma, 0, sizeof(goldfish_dma));
         pthread_mutex_init(&lock, NULL);
-        sz = INITIAL_DMA_REGION_SIZE;
-        goldfish_dma_create_region(sz, &goldfish_dma);
+
+        if (rcEnc->hasDirectMem()) {
+            host_memory_allocator.hostMalloc(&address_space_block, sz);
+        } else if (rcEnc->getDmaVersion() > 0) {
+            goldfish_dma_create_region(sz, &goldfish_dma);
+        }
     }
 
     goldfish_dma_context goldfish_dma;
+    GoldfishAddressSpaceHostMemoryAllocator host_memory_allocator;
+    GoldfishAddressSpaceBlock address_space_block;
     uint32_t sz;
     uint32_t refcount;
     pthread_mutex_t lock;
@@ -149,6 +157,10 @@
     return s_memregions;
 }
 
+static bool has_DMA_support(const ExtendedRCEncoderContext *rcEnc) {
+    return rcEnc->getDmaVersion() > 0 || rcEnc->hasDirectMem();
+}
+
 static gralloc_dmaregion_t* init_gralloc_dmaregion(ExtendedRCEncoderContext *rcEnc) {
     D("%s: call\n", __func__);
     if (!s_grdma) {
@@ -178,6 +190,15 @@
 // max dma size: 2x 4K rgba8888
 #define MAX_DMA_SIZE 66355200
 
+static bool put_gralloc_region_direct_mem_locked(gralloc_dmaregion_t* grdma, uint32_t sz) {
+    const bool shouldDelete = !grdma->refcount;
+    if (shouldDelete) {
+        grdma->host_memory_allocator.hostFree(&grdma->address_space_block);
+    }
+
+    return shouldDelete;
+}
+
 static bool put_gralloc_region_dma_locked(gralloc_dmaregion_t* grdma, uint32_t sz) {
     D("%s: call. refcount before: %u\n", __func__, grdma->refcount);
     grdma->refcount--;
@@ -199,13 +220,29 @@
 
     gralloc_dmaregion_t* grdma = init_gralloc_dmaregion(rcEnc);
     pthread_mutex_lock(&grdma->lock);
-    shouldDelete = put_gralloc_region_dma_locked(grdma, sz);
+    if (rcEnc->hasDirectMem()) {
+        shouldDelete = put_gralloc_region_direct_mem_locked(grdma, sz);
+    } else if (rcEnc->getDmaVersion() > 0) {
+        shouldDelete = put_gralloc_region_dma_locked(grdma, sz);
+    } else {
+        shouldDelete = false;
+    }
     pthread_mutex_unlock(&grdma->lock);
 
     return shouldDelete;
 }
 
-static void gralloc_dmaregion_register_ashmem_dma(gralloc_dmaregion_t* grdma, uint32_t new_sz) {
+static void gralloc_dmaregion_register_ashmem_direct_mem_locked(gralloc_dmaregion_t* grdma, uint32_t new_sz) {
+    if (new_sz == grdma->sz) return;
+
+    GoldfishAddressSpaceHostMemoryAllocator* allocator = &grdma->host_memory_allocator;
+    GoldfishAddressSpaceBlock* block = &grdma->address_space_block;
+    allocator->hostFree(block);
+    allocator->hostMalloc(block, new_sz);
+    grdma->sz = new_sz;
+}
+
+static void gralloc_dmaregion_register_ashmem_dma_locked(gralloc_dmaregion_t* grdma, uint32_t new_sz) {
     if (new_sz != grdma->sz) {
         if (new_sz > MAX_DMA_SIZE)  {
             D("%s: requested sz %u too large (limit %u), set to fallback.",
@@ -227,7 +264,15 @@
     pthread_mutex_lock(&grdma->lock);
     D("%s: for sz %u, refcount %u", __func__, sz, grdma->refcount);
     const uint32_t new_sz = std::max(grdma->sz, sz);
-    gralloc_dmaregion_register_ashmem_dma(grdma, new_sz);
+
+    if (rcEnc->hasDirectMem()) {
+        gralloc_dmaregion_register_ashmem_direct_mem_locked(grdma, new_sz);
+    } else if (rcEnc->getDmaVersion() > 0) {
+        gralloc_dmaregion_register_ashmem_dma_locked(grdma, new_sz);
+    } else {
+        ALOGE("%s: unexpected DMA type", __func__);
+    }
+
     pthread_mutex_unlock(&grdma->lock);
 }
 
@@ -389,37 +434,40 @@
         cb->frameworkFormat != HAL_PIXEL_FORMAT_YCbCr_420_888;
 
     std::vector<char> convertedBuf;
-    if ((doLocked && is_rgb_format) ||
-        (!grdma && (doLocked || !is_rgb_format))) {
-        convertedBuf.resize(rgbSz);
-        to_send = &convertedBuf.front();
-        send_buffer_size = rgbSz;
-    }
 
     if (doLocked && is_rgb_format) {
+        convertedBuf.resize(rgbSz);
+        to_send = &convertedBuf.front();
         copy_rgb_buffer_from_unlocked(
                 to_send, pixels,
                 cb->width,
                 width, height, top, left, bpp);
     }
 
-    const bool hasDMA = rcEnc->getDmaVersion() > 0;
+    const bool hasDMA = has_DMA_support(rcEnc);
     if (hasDMA && grdma->bigbufCount) {
         D("%s: there are big buffers alive, use fallback (count %u)", __FUNCTION__,
           grdma->bigbufCount);
     }
 
     if (hasDMA && !grdma->bigbufCount) {
-        if (cb->frameworkFormat == HAL_PIXEL_FORMAT_YV12) {
-            get_yv12_offsets(width, height, NULL, NULL,
-                             &send_buffer_size);
-        }
-        if (cb->frameworkFormat == HAL_PIXEL_FORMAT_YCbCr_420_888) {
-            get_yuv420p_offsets(width, height, NULL, NULL,
-                                &send_buffer_size);
+        switch (cb->frameworkFormat) {
+        case HAL_PIXEL_FORMAT_YV12:
+            get_yv12_offsets(width, height, NULL, NULL, &send_buffer_size);
+            break;
+
+        case HAL_PIXEL_FORMAT_YCbCr_420_888:
+            get_yuv420p_offsets(width, height, NULL, NULL, &send_buffer_size);
+            break;
         }
 
-        rcEnc->bindDmaContext(&grdma->goldfish_dma);
+        if (grdma->address_space_block.guestPtr()) {
+            rcEnc->bindAddressSpaceBlock(&grdma->address_space_block);
+        } else if (grdma->goldfish_dma.mapped_addr) {
+            rcEnc->bindDmaContext(&grdma->goldfish_dma);
+        } else {
+            ALOGE("%s: Unexpected DMA", __func__);
+        }
 
         D("%s: call. dma update with sz=%u", __func__, send_buffer_size);
         pthread_mutex_lock(&grdma->lock);
@@ -429,28 +477,33 @@
                 to_send, send_buffer_size);
         pthread_mutex_unlock(&grdma->lock);
     } else {
-        char *tmpBuf = nullptr;
-        if (cb->frameworkFormat == HAL_PIXEL_FORMAT_YV12) {
-            tmpBuf = new char[cb->lockedWidth * cb->lockedHeight * bpp];
+        switch (cb->frameworkFormat) {
+        case HAL_PIXEL_FORMAT_YV12:
+            convertedBuf.resize(rgbSz);
+            to_send = &convertedBuf.front();
             D("convert yv12 to rgb888 here");
-            to_send = tmpBuf;
             yv12_to_rgb888(to_send, pixels,
                            width, height, left, top,
                            left + width - 1, top + height - 1);
-        }
-        if (cb->frameworkFormat == HAL_PIXEL_FORMAT_YCbCr_420_888) {
-            tmpBuf = new char[cb->lockedWidth * cb->lockedHeight * bpp];
-            to_send = tmpBuf;
-            yuv420p_to_rgb888(to_send, pixels,
-                              width, height, left, top,
-                              left + width - 1, top + height - 1);
+            break;
+
+        case HAL_PIXEL_FORMAT_YCbCr_420_888:
+            convertedBuf.resize(rgbSz);
+            to_send = &convertedBuf.front();
+            if (rcEnc->hasYUV420toNV21()) {
+                nv21_to_rgb888(to_send, pixels,
+                               width, height, left, top,
+                               left + width - 1, top + height - 1);
+            } else {
+                yuv420p_to_rgb888(to_send, pixels,
+                                  width, height, left, top,
+                                  left + width - 1, top + height - 1);
+            }
+            break;
         }
         rcEnc->rcUpdateColorBuffer(rcEnc, cb->hostHandle,
                 left, top, width, height,
                 cb->glFormat, cb->glType, to_send);
-        if (tmpBuf != nullptr) {
-            delete [] tmpBuf;
-        }
     }
 }
 
@@ -747,6 +800,8 @@
         cb->setFd(fd);
     }
 
+    const bool hasDMA = has_DMA_support(rcEnc);
+
     if (needHostCb) {
         if (hostCon && rcEnc) {
             GLenum allocFormat = glFormat;
@@ -759,9 +814,8 @@
                 allocFormat = GL_RGB;
             }
 
-            gralloc_dmaregion_t* grdma = init_gralloc_dmaregion(rcEnc);
             hostCon->lock();
-            if (rcEnc->getDmaVersion() > 0) {
+            if (hasDMA) {
                 cb->hostHandle = rcEnc->rcCreateColorBufferDMA(rcEnc, w, h, allocFormat, cb->emuFrameworkFormat);
             } else {
                 cb->hostHandle = rcEnc->rcCreateColorBuffer(rcEnc, w, h, allocFormat);
@@ -773,7 +827,7 @@
             // Could not create colorbuffer on host !!!
             close(fd);
             delete cb;
-            ALOGD("%s: failed to create host cb! -EIO", __FUNCTION__);
+            ALOGE("%s: failed to create host cb! -EIO", __FUNCTION__);
             return -EIO;
         } else {
             QEMU_PIPE_HANDLE refcountPipeFd = qemu_pipe_open("refcount");
@@ -807,7 +861,7 @@
     }
 
     hostCon->lock();
-    if (rcEnc->getDmaVersion() > 0) {
+    if (hasDMA) {
         get_gralloc_region(rcEnc);  // map_buffer(cb, ...) refers here
     }
     hostCon->unlock();
@@ -1207,30 +1261,51 @@
         // camera delivers bits to the buffer directly and does not require
         // an explicit read, it also writes in YUV_420 (interleaved)
         if (sw_read & !(usage & GRALLOC_USAGE_HW_CAMERA_MASK)) {
+            D("gralloc_lock read back color buffer %d %d ashmem base %p sz %d\n",
+              cb->width, cb->height, cb->ashmemBase, cb->ashmemSize);
             void* rgb_addr = cpu_addr;
             char* tmpBuf = 0;
             if (cb->frameworkFormat == HAL_PIXEL_FORMAT_YV12 ||
                 cb->frameworkFormat == HAL_PIXEL_FORMAT_YCbCr_420_888) {
-                // We are using RGB888
-                tmpBuf = new char[cb->width * cb->height * 3];
-                rgb_addr = tmpBuf;
-            }
-            D("gralloc_lock read back color buffer %d %d ashmem base %p sz %d\n",
-              cb->width, cb->height, cb->ashmemBase, cb->ashmemSize);
-            rcEnc->rcReadColorBuffer(rcEnc, cb->hostHandle,
-                    0, 0, cb->width, cb->height, cb->glFormat, cb->glType, rgb_addr);
-            if (tmpBuf) {
-                if (cb->frameworkFormat == HAL_PIXEL_FORMAT_YV12) {
-                    D("convert rgb888 to yv12 here");
-                    rgb888_to_yv12((char*)cpu_addr, tmpBuf, cb->width, cb->height, l, t, l+w-1, t+h-1);
-                } else if (cb->frameworkFormat == HAL_PIXEL_FORMAT_YCbCr_420_888) {
-                    rgb888_to_yuv420p((char*)cpu_addr, tmpBuf, cb->width, cb->height, l, t, l+w-1, t+h-1);
+                if (rcEnc->hasYUVCache()) {
+                    uint32_t buffer_size;
+                    if (cb->frameworkFormat == HAL_PIXEL_FORMAT_YV12) {
+                       get_yv12_offsets(cb->width, cb->height, NULL, NULL,
+                                        &buffer_size);
+                    } else {
+                       get_yuv420p_offsets(cb->width, cb->height, NULL, NULL,
+                                           &buffer_size);
+                    }
+                    D("read YUV copy from host");
+                    rcEnc->rcReadColorBufferYUV(rcEnc, cb->hostHandle,
+                                            0, 0, cb->width, cb->height,
+                                            rgb_addr, buffer_size);
+                } else {
+                    // We are using RGB888
+                    tmpBuf = new char[cb->width * cb->height * 3];
+                    rcEnc->rcReadColorBuffer(rcEnc, cb->hostHandle,
+                                              0, 0, cb->width, cb->height, cb->glFormat, cb->glType, tmpBuf);
+                    if (cb->frameworkFormat == HAL_PIXEL_FORMAT_YV12) {
+                        D("convert rgb888 to yv12 here");
+                        rgb888_to_yv12((char*)cpu_addr, tmpBuf, cb->width, cb->height, l, t, l+w-1, t+h-1);
+                    } else if (cb->frameworkFormat == HAL_PIXEL_FORMAT_YCbCr_420_888) {
+                        if (rcEnc->hasYUV420toNV21()) {
+                            D("convert rgb888 to nv21 here");
+                            rgb888_to_nv21((char*)cpu_addr, tmpBuf, cb->width, cb->height, l, t, l+w-1, t+h-1);
+                        } else {
+                            D("convert rgb888 to yuv420p here");
+                            rgb888_to_yuv420p((char*)cpu_addr, tmpBuf, cb->width, cb->height, l, t, l+w-1, t+h-1);
+                        }
+                    }
+                    delete [] tmpBuf;
                 }
-                delete [] tmpBuf;
+            } else {
+                rcEnc->rcReadColorBuffer(rcEnc, cb->hostHandle,
+                        0, 0, cb->width, cb->height, cb->glFormat, cb->glType, rgb_addr);
             }
         }
 
-        if (rcEnc->getDmaVersion() > 0) {
+        if (has_DMA_support(rcEnc)) {
             gralloc_dmaregion_register_ashmem(rcEnc, cb->ashmemSize);
         }
         hostCon->unlock();
@@ -1374,8 +1449,9 @@
             uOffset = vOffset + cSize;
             cStep = 1;
             break;
-        case HAL_PIXEL_FORMAT_YCbCr_420_888:
-            if (usage & GRALLOC_USAGE_HW_CAMERA_MASK) {
+        case HAL_PIXEL_FORMAT_YCbCr_420_888: {
+            DEFINE_AND_VALIDATE_HOST_CONNECTION
+            if (rcEnc->hasYUV420toNV21()) {
                 yStride = cb->width;
                 cStride = cb->width;
                 yOffset = 0;
@@ -1383,14 +1459,24 @@
                 uOffset = vOffset + 1;
                 cStep = 2;
             } else {
-                yStride = cb->width;
-                cStride = yStride / 2;
-                yOffset = 0;
-                uOffset = cb->height * yStride;
-                vOffset = uOffset + cStride * cb->height / 2;
-                cStep = 1;
+                if (usage & GRALLOC_USAGE_HW_CAMERA_MASK) {
+                    yStride = cb->width;
+                    cStride = cb->width;
+                    yOffset = 0;
+                    vOffset = yStride * cb->height;
+                    uOffset = vOffset + 1;
+                    cStep = 2;
+                } else {
+                    yStride = cb->width;
+                    cStride = yStride / 2;
+                    yOffset = 0;
+                    uOffset = cb->height * yStride;
+                    vOffset = uOffset + cStride * cb->height / 2;
+                    cStep = 1;
+                }
             }
             break;
+        }
         default:
             ALOGE("gralloc_lock_ycbcr unexpected internal format %x",
                     cb->format);
diff --git a/system/renderControl_enc/renderControl_client_context.cpp b/system/renderControl_enc/renderControl_client_context.cpp
index 6da72fc..476d0da 100644
--- a/system/renderControl_enc/renderControl_client_context.cpp
+++ b/system/renderControl_enc/renderControl_client_context.cpp
@@ -56,6 +56,7 @@
 	rcGetDisplayPose = (rcGetDisplayPose_client_proc_t) getProc("rcGetDisplayPose", userData);
 	rcSetDisplayPose = (rcSetDisplayPose_client_proc_t) getProc("rcSetDisplayPose", userData);
 	rcSetColorBufferVulkanMode = (rcSetColorBufferVulkanMode_client_proc_t) getProc("rcSetColorBufferVulkanMode", userData);
+	rcReadColorBufferYUV = (rcReadColorBufferYUV_client_proc_t) getProc("rcReadColorBufferYUV", userData);
 	return 0;
 }
 
diff --git a/system/renderControl_enc/renderControl_client_context.h b/system/renderControl_enc/renderControl_client_context.h
index d05fee1..8905afa 100644
--- a/system/renderControl_enc/renderControl_client_context.h
+++ b/system/renderControl_enc/renderControl_client_context.h
@@ -56,6 +56,7 @@
 	rcGetDisplayPose_client_proc_t rcGetDisplayPose;
 	rcSetDisplayPose_client_proc_t rcSetDisplayPose;
 	rcSetColorBufferVulkanMode_client_proc_t rcSetColorBufferVulkanMode;
+	rcReadColorBufferYUV_client_proc_t rcReadColorBufferYUV;
 	virtual ~renderControl_client_context_t() {}
 
 	typedef renderControl_client_context_t *CONTEXT_ACCESSOR_TYPE(void);
diff --git a/system/renderControl_enc/renderControl_client_proc.h b/system/renderControl_enc/renderControl_client_proc.h
index f9690b6..6bba308 100644
--- a/system/renderControl_enc/renderControl_client_proc.h
+++ b/system/renderControl_enc/renderControl_client_proc.h
@@ -50,14 +50,15 @@
 typedef uint32_t (renderControl_APIENTRY *rcCreateColorBufferDMA_client_proc_t) (void * ctx, uint32_t, uint32_t, GLenum, int);
 typedef void (renderControl_APIENTRY *rcWaitSyncKHR_client_proc_t) (void * ctx, uint64_t, EGLint);
 typedef GLint (renderControl_APIENTRY *rcCompose_client_proc_t) (void * ctx, uint32_t, void*);
-typedef GLint (renderControl_APIENTRY *rcCreateDisplay_client_proc_t) (void * ctx, uint32_t*);
-typedef GLint (renderControl_APIENTRY *rcDestroyDisplay_client_proc_t) (void * ctx, uint32_t);
-typedef GLint (renderControl_APIENTRY *rcSetDisplayColorBuffer_client_proc_t) (void * ctx, uint32_t, uint32_t);
-typedef GLint (renderControl_APIENTRY *rcGetDisplayColorBuffer_client_proc_t) (void * ctx, uint32_t, uint32_t*);
-typedef GLint (renderControl_APIENTRY *rcGetColorBufferDisplay_client_proc_t) (void * ctx, uint32_t, uint32_t*);
-typedef GLint (renderControl_APIENTRY *rcGetDisplayPose_client_proc_t) (void * ctx, uint32_t, uint32_t*, uint32_t*, uint32_t*, uint32_t*);
-typedef GLint (renderControl_APIENTRY *rcSetDisplayPose_client_proc_t) (void * ctx, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t);
+typedef int (renderControl_APIENTRY *rcCreateDisplay_client_proc_t) (void * ctx, uint32_t*);
+typedef int (renderControl_APIENTRY *rcDestroyDisplay_client_proc_t) (void * ctx, uint32_t);
+typedef int (renderControl_APIENTRY *rcSetDisplayColorBuffer_client_proc_t) (void * ctx, uint32_t, uint32_t);
+typedef int (renderControl_APIENTRY *rcGetDisplayColorBuffer_client_proc_t) (void * ctx, uint32_t, uint32_t*);
+typedef int (renderControl_APIENTRY *rcGetColorBufferDisplay_client_proc_t) (void * ctx, uint32_t, uint32_t*);
+typedef int (renderControl_APIENTRY *rcGetDisplayPose_client_proc_t) (void * ctx, uint32_t, GLint*, GLint*, uint32_t*, uint32_t*);
+typedef int (renderControl_APIENTRY *rcSetDisplayPose_client_proc_t) (void * ctx, uint32_t, GLint, GLint, uint32_t, uint32_t);
 typedef GLint (renderControl_APIENTRY *rcSetColorBufferVulkanMode_client_proc_t) (void * ctx, uint32_t, uint32_t);
+typedef void (renderControl_APIENTRY *rcReadColorBufferYUV_client_proc_t) (void * ctx, uint32_t, GLint, GLint, GLint, GLint, void*, uint32_t);
 
 
 #endif
diff --git a/system/renderControl_enc/renderControl_enc.cpp b/system/renderControl_enc/renderControl_enc.cpp
index a2d765f..fab8a15 100644
--- a/system/renderControl_enc/renderControl_enc.cpp
+++ b/system/renderControl_enc/renderControl_enc.cpp
@@ -1436,7 +1436,7 @@
 	return retval;
 }
 
-GLint rcCreateDisplay_enc(void *self , uint32_t* displayId)
+int rcCreateDisplay_enc(void *self , uint32_t* displayId)
 {
 
 	renderControl_encoder_context_t *ctx = (renderControl_encoder_context_t *)self;
@@ -1463,7 +1463,7 @@
 	stream->readback(displayId, __size_displayId);
 	if (useChecksum) checksumCalculator->addBuffer(displayId, __size_displayId);
 
-	GLint retval;
+	int retval;
 	stream->readback(&retval, 4);
 	if (useChecksum) checksumCalculator->addBuffer(&retval, 4);
 	if (useChecksum) {
@@ -1479,7 +1479,7 @@
 	return retval;
 }
 
-GLint rcDestroyDisplay_enc(void *self , uint32_t displayId)
+int rcDestroyDisplay_enc(void *self , uint32_t displayId)
 {
 
 	renderControl_encoder_context_t *ctx = (renderControl_encoder_context_t *)self;
@@ -1503,7 +1503,7 @@
 	if (useChecksum) checksumCalculator->writeChecksum(ptr, checksumSize); ptr += checksumSize;
 
 
-	GLint retval;
+	int retval;
 	stream->readback(&retval, 4);
 	if (useChecksum) checksumCalculator->addBuffer(&retval, 4);
 	if (useChecksum) {
@@ -1519,7 +1519,7 @@
 	return retval;
 }
 
-GLint rcSetDisplayColorBuffer_enc(void *self , uint32_t displayId, uint32_t colorBuffer)
+int rcSetDisplayColorBuffer_enc(void *self , uint32_t displayId, uint32_t colorBuffer)
 {
 
 	renderControl_encoder_context_t *ctx = (renderControl_encoder_context_t *)self;
@@ -1544,7 +1544,7 @@
 	if (useChecksum) checksumCalculator->writeChecksum(ptr, checksumSize); ptr += checksumSize;
 
 
-	GLint retval;
+	int retval;
 	stream->readback(&retval, 4);
 	if (useChecksum) checksumCalculator->addBuffer(&retval, 4);
 	if (useChecksum) {
@@ -1560,7 +1560,7 @@
 	return retval;
 }
 
-GLint rcGetDisplayColorBuffer_enc(void *self , uint32_t displayId, uint32_t* colorBuffer)
+int rcGetDisplayColorBuffer_enc(void *self , uint32_t displayId, uint32_t* colorBuffer)
 {
 
 	renderControl_encoder_context_t *ctx = (renderControl_encoder_context_t *)self;
@@ -1588,7 +1588,7 @@
 	stream->readback(colorBuffer, __size_colorBuffer);
 	if (useChecksum) checksumCalculator->addBuffer(colorBuffer, __size_colorBuffer);
 
-	GLint retval;
+	int retval;
 	stream->readback(&retval, 4);
 	if (useChecksum) checksumCalculator->addBuffer(&retval, 4);
 	if (useChecksum) {
@@ -1604,7 +1604,7 @@
 	return retval;
 }
 
-GLint rcGetColorBufferDisplay_enc(void *self , uint32_t colorBuffer, uint32_t* displayId)
+int rcGetColorBufferDisplay_enc(void *self , uint32_t colorBuffer, uint32_t* displayId)
 {
 
 	renderControl_encoder_context_t *ctx = (renderControl_encoder_context_t *)self;
@@ -1632,7 +1632,7 @@
 	stream->readback(displayId, __size_displayId);
 	if (useChecksum) checksumCalculator->addBuffer(displayId, __size_displayId);
 
-	GLint retval;
+	int retval;
 	stream->readback(&retval, 4);
 	if (useChecksum) checksumCalculator->addBuffer(&retval, 4);
 	if (useChecksum) {
@@ -1648,7 +1648,7 @@
 	return retval;
 }
 
-GLint rcGetDisplayPose_enc(void *self , uint32_t displayId, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h)
+int rcGetDisplayPose_enc(void *self , uint32_t displayId, GLint* x, GLint* y, uint32_t* w, uint32_t* h)
 {
 
 	renderControl_encoder_context_t *ctx = (renderControl_encoder_context_t *)self;
@@ -1688,7 +1688,7 @@
 	stream->readback(h, __size_h);
 	if (useChecksum) checksumCalculator->addBuffer(h, __size_h);
 
-	GLint retval;
+	int retval;
 	stream->readback(&retval, 4);
 	if (useChecksum) checksumCalculator->addBuffer(&retval, 4);
 	if (useChecksum) {
@@ -1704,7 +1704,7 @@
 	return retval;
 }
 
-GLint rcSetDisplayPose_enc(void *self , uint32_t displayId, uint32_t x, uint32_t y, uint32_t w, uint32_t h)
+int rcSetDisplayPose_enc(void *self , uint32_t displayId, GLint x, GLint y, uint32_t w, uint32_t h)
 {
 
 	renderControl_encoder_context_t *ctx = (renderControl_encoder_context_t *)self;
@@ -1732,7 +1732,7 @@
 	if (useChecksum) checksumCalculator->writeChecksum(ptr, checksumSize); ptr += checksumSize;
 
 
-	GLint retval;
+	int retval;
 	stream->readback(&retval, 4);
 	if (useChecksum) checksumCalculator->addBuffer(&retval, 4);
 	if (useChecksum) {
@@ -1789,6 +1789,50 @@
 	return retval;
 }
 
+void rcReadColorBufferYUV_enc(void *self , uint32_t colorbuffer, GLint x, GLint y, GLint width, GLint height, void* pixels, uint32_t pixels_size)
+{
+
+	renderControl_encoder_context_t *ctx = (renderControl_encoder_context_t *)self;
+	IOStream *stream = ctx->m_stream;
+	ChecksumCalculator *checksumCalculator = ctx->m_checksumCalculator;
+	bool useChecksum = checksumCalculator->getVersion() > 0;
+
+	const unsigned int __size_pixels =  pixels_size;
+	 unsigned char *ptr;
+	 unsigned char *buf;
+	 const size_t sizeWithoutChecksum = 8 + 4 + 4 + 4 + 4 + 4 + 0 + 4 + 1*4;
+	 const size_t checksumSize = checksumCalculator->checksumByteSize();
+	 const size_t totalSize = sizeWithoutChecksum + checksumSize;
+	buf = stream->alloc(totalSize);
+	ptr = buf;
+	int tmp = OP_rcReadColorBufferYUV;memcpy(ptr, &tmp, 4); ptr += 4;
+	memcpy(ptr, &totalSize, 4);  ptr += 4;
+
+		memcpy(ptr, &colorbuffer, 4); ptr += 4;
+		memcpy(ptr, &x, 4); ptr += 4;
+		memcpy(ptr, &y, 4); ptr += 4;
+		memcpy(ptr, &width, 4); ptr += 4;
+		memcpy(ptr, &height, 4); ptr += 4;
+	*(unsigned int *)(ptr) = __size_pixels; ptr += 4;
+		memcpy(ptr, &pixels_size, 4); ptr += 4;
+
+	if (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf);
+	if (useChecksum) checksumCalculator->writeChecksum(ptr, checksumSize); ptr += checksumSize;
+
+	stream->readback(pixels, __size_pixels);
+	if (useChecksum) checksumCalculator->addBuffer(pixels, __size_pixels);
+	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("rcReadColorBufferYUV: GL communication error, please report this issue to b.android.com.\n");
+			abort();
+		}
+	}
+}
+
 }  // namespace
 
 renderControl_encoder_context_t::renderControl_encoder_context_t(IOStream *stream, ChecksumCalculator *checksumCalculator)
@@ -1842,5 +1886,6 @@
 	this->rcGetDisplayPose = &rcGetDisplayPose_enc;
 	this->rcSetDisplayPose = &rcSetDisplayPose_enc;
 	this->rcSetColorBufferVulkanMode = &rcSetColorBufferVulkanMode_enc;
+	this->rcReadColorBufferYUV = &rcReadColorBufferYUV_enc;
 }
 
diff --git a/system/renderControl_enc/renderControl_entry.cpp b/system/renderControl_enc/renderControl_entry.cpp
index 1314c7d..0974a96 100644
--- a/system/renderControl_enc/renderControl_entry.cpp
+++ b/system/renderControl_enc/renderControl_entry.cpp
@@ -43,14 +43,15 @@
 	uint32_t rcCreateColorBufferDMA(uint32_t width, uint32_t height, GLenum internalFormat, int frameworkFormat);
 	void rcWaitSyncKHR(uint64_t sync, EGLint flags);
 	GLint rcCompose(uint32_t bufferSize, void* buffer);
-	GLint rcCreateDisplay(uint32_t* displayId);
-	GLint rcDestroyDisplay(uint32_t displayId);
-	GLint rcSetDisplayColorBuffer(uint32_t displayId, uint32_t colorBuffer);
-	GLint rcGetDisplayColorBuffer(uint32_t displayId, uint32_t* colorBuffer);
-	GLint rcGetColorBufferDisplay(uint32_t colorBuffer, uint32_t* displayId);
-	GLint rcGetDisplayPose(uint32_t displayId, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h);
-	GLint rcSetDisplayPose(uint32_t displayId, uint32_t x, uint32_t y, uint32_t w, uint32_t h);
+	int rcCreateDisplay(uint32_t* displayId);
+	int rcDestroyDisplay(uint32_t displayId);
+	int rcSetDisplayColorBuffer(uint32_t displayId, uint32_t colorBuffer);
+	int rcGetDisplayColorBuffer(uint32_t displayId, uint32_t* colorBuffer);
+	int rcGetColorBufferDisplay(uint32_t colorBuffer, uint32_t* displayId);
+	int rcGetDisplayPose(uint32_t displayId, GLint* x, GLint* y, uint32_t* w, uint32_t* h);
+	int rcSetDisplayPose(uint32_t displayId, GLint x, GLint y, uint32_t w, uint32_t h);
 	GLint rcSetColorBufferVulkanMode(uint32_t colorBuffer, uint32_t mode);
+	void rcReadColorBufferYUV(uint32_t colorbuffer, GLint x, GLint y, GLint width, GLint height, void* pixels, uint32_t pixels_size);
 };
 
 #ifndef GET_CONTEXT
@@ -287,43 +288,43 @@
 	return ctx->rcCompose(ctx, bufferSize, buffer);
 }
 
-GLint rcCreateDisplay(uint32_t* displayId)
+int rcCreateDisplay(uint32_t* displayId)
 {
 	GET_CONTEXT;
 	return ctx->rcCreateDisplay(ctx, displayId);
 }
 
-GLint rcDestroyDisplay(uint32_t displayId)
+int rcDestroyDisplay(uint32_t displayId)
 {
 	GET_CONTEXT;
 	return ctx->rcDestroyDisplay(ctx, displayId);
 }
 
-GLint rcSetDisplayColorBuffer(uint32_t displayId, uint32_t colorBuffer)
+int rcSetDisplayColorBuffer(uint32_t displayId, uint32_t colorBuffer)
 {
 	GET_CONTEXT;
 	return ctx->rcSetDisplayColorBuffer(ctx, displayId, colorBuffer);
 }
 
-GLint rcGetDisplayColorBuffer(uint32_t displayId, uint32_t* colorBuffer)
+int rcGetDisplayColorBuffer(uint32_t displayId, uint32_t* colorBuffer)
 {
 	GET_CONTEXT;
 	return ctx->rcGetDisplayColorBuffer(ctx, displayId, colorBuffer);
 }
 
-GLint rcGetColorBufferDisplay(uint32_t colorBuffer, uint32_t* displayId)
+int rcGetColorBufferDisplay(uint32_t colorBuffer, uint32_t* displayId)
 {
 	GET_CONTEXT;
 	return ctx->rcGetColorBufferDisplay(ctx, colorBuffer, displayId);
 }
 
-GLint rcGetDisplayPose(uint32_t displayId, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h)
+int rcGetDisplayPose(uint32_t displayId, GLint* x, GLint* y, uint32_t* w, uint32_t* h)
 {
 	GET_CONTEXT;
 	return ctx->rcGetDisplayPose(ctx, displayId, x, y, w, h);
 }
 
-GLint rcSetDisplayPose(uint32_t displayId, uint32_t x, uint32_t y, uint32_t w, uint32_t h)
+int rcSetDisplayPose(uint32_t displayId, GLint x, GLint y, uint32_t w, uint32_t h)
 {
 	GET_CONTEXT;
 	return ctx->rcSetDisplayPose(ctx, displayId, x, y, w, h);
@@ -335,3 +336,9 @@
 	return ctx->rcSetColorBufferVulkanMode(ctx, colorBuffer, mode);
 }
 
+void rcReadColorBufferYUV(uint32_t colorbuffer, GLint x, GLint y, GLint width, GLint height, void* pixels, uint32_t pixels_size)
+{
+	GET_CONTEXT;
+	ctx->rcReadColorBufferYUV(ctx, colorbuffer, x, y, width, height, pixels, pixels_size);
+}
+
diff --git a/system/renderControl_enc/renderControl_ftable.h b/system/renderControl_enc/renderControl_ftable.h
index 035dfac..da58a04 100644
--- a/system/renderControl_enc/renderControl_ftable.h
+++ b/system/renderControl_enc/renderControl_ftable.h
@@ -54,6 +54,7 @@
 	{"rcGetDisplayPose", (void*)rcGetDisplayPose},
 	{"rcSetDisplayPose", (void*)rcSetDisplayPose},
 	{"rcSetColorBufferVulkanMode", (void*)rcSetColorBufferVulkanMode},
+	{"rcReadColorBufferYUV", (void*)rcReadColorBufferYUV},
 };
 static const int renderControl_num_funcs = sizeof(renderControl_funcs_by_name) / sizeof(struct _renderControl_funcs_by_name);
 
diff --git a/system/renderControl_enc/renderControl_opcodes.h b/system/renderControl_enc/renderControl_opcodes.h
index d2927d2..2c3780b 100644
--- a/system/renderControl_enc/renderControl_opcodes.h
+++ b/system/renderControl_enc/renderControl_opcodes.h
@@ -49,7 +49,8 @@
 #define OP_rcGetDisplayPose 					10043
 #define OP_rcSetDisplayPose 					10044
 #define OP_rcSetColorBufferVulkanMode 					10045
-#define OP_last 					10046
+#define OP_rcReadColorBufferYUV 					10046
+#define OP_last 					10047
 
 
 #endif