Snap for 6405781 from 7464a44a074bf32e6993b5d7cb2271ded944acaf to sdk-release

Change-Id: I1e9ed05fe29c8e2ade1ee898356eb74fde5403ad
diff --git a/fuchsia/releasepackage.py b/fuchsia/releasepackage.py
index dda9432..7f8c40b 100644
--- a/fuchsia/releasepackage.py
+++ b/fuchsia/releasepackage.py
@@ -110,5 +110,5 @@
 print ("""
   <package name="%s"
            version="git_revision:%s"
-           path="prebuild/third_party/%s"/>
+           path="prebuilt/third_party/%s"/>
 """ % (package_name, git_rev, package_dir))[1:-1]
diff --git a/host/include/libOpenglRender/IOStream.h b/host/include/libOpenglRender/IOStream.h
index 2f699bc..159da1d 100644
--- a/host/include/libOpenglRender/IOStream.h
+++ b/host/include/libOpenglRender/IOStream.h
@@ -94,6 +94,7 @@
     }
 
     void readbackPixels(void* context, int width, int height, unsigned int format, unsigned int type, void* pixels);
+    void uploadPixels(void* context, int width, int height, unsigned int format, unsigned int type, const void* pixels);
 
 
 private:
diff --git a/shared/OpenglCodecCommon/GLClientState.cpp b/shared/OpenglCodecCommon/GLClientState.cpp
index c6140db..3f207b8 100644
--- a/shared/OpenglCodecCommon/GLClientState.cpp
+++ b/shared/OpenglCodecCommon/GLClientState.cpp
@@ -875,6 +875,29 @@
     *skipRows = m_pixelStore.pack_skip_rows;
 }
 
+void GLClientState::getUnpackingOffsets2D(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.unpack_alignment,
+            m_pixelStore.unpack_row_length,
+            m_pixelStore.unpack_skip_pixels,
+            m_pixelStore.unpack_skip_rows,
+            startOffset,
+            pixelRowSize,
+            totalRowSize);
+
+    *skipRows = m_pixelStore.unpack_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 5180338..f9f8ee3 100644
--- a/shared/OpenglCodecCommon/GLClientState.h
+++ b/shared/OpenglCodecCommon/GLClientState.h
@@ -254,6 +254,7 @@
     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 getUnpackingOffsets2D(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/system/GLESv2_enc/GLESv2Validation.cpp b/system/GLESv2_enc/GLESv2Validation.cpp
index 9f72853..aff7902 100644
--- a/system/GLESv2_enc/GLESv2Validation.cpp
+++ b/system/GLESv2_enc/GLESv2Validation.cpp
@@ -797,6 +797,35 @@
     f(GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2) \
     f(GL_COMPRESSED_RGBA8_ETC2_EAC) \
     f(GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC) \
+    f(GL_COMPRESSED_RGBA_ASTC_4x4_KHR) \
+    f(GL_COMPRESSED_RGBA_ASTC_5x4_KHR) \
+    f(GL_COMPRESSED_RGBA_ASTC_5x5_KHR) \
+    f(GL_COMPRESSED_RGBA_ASTC_6x5_KHR) \
+    f(GL_COMPRESSED_RGBA_ASTC_6x6_KHR) \
+    f(GL_COMPRESSED_RGBA_ASTC_8x5_KHR) \
+    f(GL_COMPRESSED_RGBA_ASTC_8x6_KHR) \
+    f(GL_COMPRESSED_RGBA_ASTC_8x8_KHR) \
+    f(GL_COMPRESSED_RGBA_ASTC_10x5_KHR) \
+    f(GL_COMPRESSED_RGBA_ASTC_10x6_KHR) \
+    f(GL_COMPRESSED_RGBA_ASTC_10x8_KHR) \
+    f(GL_COMPRESSED_RGBA_ASTC_10x10_KHR) \
+    f(GL_COMPRESSED_RGBA_ASTC_12x10_KHR) \
+    f(GL_COMPRESSED_RGBA_ASTC_12x12_KHR) \
+    f(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR) \
+    f(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR) \
+    f(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR) \
+    f(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR) \
+    f(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR) \
+    f(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR) \
+    f(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR) \
+    f(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR) \
+    f(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR) \
+    f(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR) \
+    f(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR) \
+    f(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR) \
+    f(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR) \
+    f(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR) \
+
 
 bool pixelInternalFormat(GLenum internalformat) {
 #define VALID_INTERNAL_FORMAT(format) \
diff --git a/system/GLESv2_enc/gl2_enc.cpp b/system/GLESv2_enc/gl2_enc.cpp
index 0df93f8..fb70443 100644
--- a/system/GLESv2_enc/gl2_enc.cpp
+++ b/system/GLESv2_enc/gl2_enc.cpp
@@ -3344,7 +3344,7 @@
 	stream->writeFully(&__size_pixels,4);
 	if (useChecksum) checksumCalculator->addBuffer(&__size_pixels,4);
 	if (pixels != NULL) {
-		stream->writeFully(pixels, __size_pixels);
+	    stream->uploadPixels(self, width, height, format, type, pixels);
 		if (useChecksum) checksumCalculator->addBuffer(pixels, __size_pixels);
 	}
 	buf = stream->alloc(checksumSize);
@@ -3497,7 +3497,7 @@
 	stream->writeFully(&__size_pixels,4);
 	if (useChecksum) checksumCalculator->addBuffer(&__size_pixels,4);
 	if (pixels != NULL) {
-		stream->writeFully(pixels, __size_pixels);
+	    stream->uploadPixels(self, width, height, format, type, pixels);
 		if (useChecksum) checksumCalculator->addBuffer(pixels, __size_pixels);
 	}
 	buf = stream->alloc(checksumSize);
diff --git a/system/OpenglSystemCommon/EmulatorFeatureInfo.h b/system/OpenglSystemCommon/EmulatorFeatureInfo.h
index 9142ac9..626048f 100644
--- a/system/OpenglSystemCommon/EmulatorFeatureInfo.h
+++ b/system/OpenglSystemCommon/EmulatorFeatureInfo.h
@@ -102,6 +102,9 @@
 
 static const char kHasSharedSlotsHostMemoryAllocator[] = "ANDROID_EMU_has_shared_slots_host_memory_allocator";
 
+// Vulkan free memory sync
+static const char kVulkanFreeMemorySync[] = "ANDROID_EMU_vulkan_free_memory_sync";
+
 // Struct describing available emulator features
 struct EmulatorFeatureInfo {
 
@@ -119,7 +122,8 @@
         hasYUVCache (false),
         hasAsyncUnmapBuffer (false),
         hasVirtioGpuNext (false),
-        hasSharedSlotsHostMemoryAllocator(false)
+        hasSharedSlotsHostMemoryAllocator(false),
+        hasVulkanFreeMemorySync(false)
     { }
 
     SyncImpl syncImpl;
@@ -136,6 +140,7 @@
     bool hasAsyncUnmapBuffer;
     bool hasVirtioGpuNext;
     bool hasSharedSlotsHostMemoryAllocator;
+    bool hasVulkanFreeMemorySync;
 };
 
 enum HostConnectionType {
diff --git a/system/OpenglSystemCommon/HostConnection.cpp b/system/OpenglSystemCommon/HostConnection.cpp
index a67a724..fbb946f 100644
--- a/system/OpenglSystemCommon/HostConnection.cpp
+++ b/system/OpenglSystemCommon/HostConnection.cpp
@@ -615,6 +615,7 @@
         queryAndSetAsyncUnmapBuffer(m_rcEnc);
         queryAndSetVirtioGpuNext(m_rcEnc);
         queryHasSharedSlotsHostMemoryAllocator(m_rcEnc);
+        queryAndSetVulkanFreeMemorySync(m_rcEnc);
         if (m_processPipe) {
             m_processPipe->processPipeInit(m_connectionType, m_rcEnc);
         }
@@ -825,3 +826,10 @@
         rcEnc->featureInfo()->hasSharedSlotsHostMemoryAllocator = true;
     }
 }
+
+void HostConnection::queryAndSetVulkanFreeMemorySync(ExtendedRCEncoderContext *rcEnc) {
+    const std::string& glExtensions = queryGLExtensions(rcEnc);
+    if (glExtensions.find(kVulkanFreeMemorySync) != std::string::npos) {
+        rcEnc->featureInfo()->hasVulkanFreeMemorySync = true;
+    }
+}
diff --git a/system/OpenglSystemCommon/HostConnection.h b/system/OpenglSystemCommon/HostConnection.h
index 08ec7da..02c8681 100644
--- a/system/OpenglSystemCommon/HostConnection.h
+++ b/system/OpenglSystemCommon/HostConnection.h
@@ -205,6 +205,7 @@
     void queryAndSetAsyncUnmapBuffer(ExtendedRCEncoderContext *rcEnc);
     void queryAndSetVirtioGpuNext(ExtendedRCEncoderContext *rcEnc);
     void queryHasSharedSlotsHostMemoryAllocator(ExtendedRCEncoderContext *rcEnc);
+    void queryAndSetVulkanFreeMemorySync(ExtendedRCEncoderContext *rcEnc);
 
 private:
     HostConnectionType m_connectionType;
diff --git a/system/codecs/omx/plugin/GoldfishOMXPlugin.cpp b/system/codecs/omx/plugin/GoldfishOMXPlugin.cpp
index 47c22a3..7ff9fa4 100644
--- a/system/codecs/omx/plugin/GoldfishOMXPlugin.cpp
+++ b/system/codecs/omx/plugin/GoldfishOMXPlugin.cpp
@@ -76,10 +76,12 @@
 }
 
 static const GoldfishComponent kComponents[] = {
-    { "OMX.google.goldfish.vp8.decoder", "vpxdec", "video_decoder.vp8" },
-    { "OMX.google.goldfish.vp9.decoder", "vpxdec", "video_decoder.vp9" },
-    { "OMX.google.goldfish.h264.decoder", "avcdec", "video_decoder.avc" },
-    { "OMX.android.goldfish.h264.decoder", "avcdec", "video_decoder.avc" },
+        {"OMX.google.goldfish.vp8.decoder", "vpxdec", "video_decoder.vp8"},
+        {"OMX.google.goldfish.vp9.decoder", "vpxdec", "video_decoder.vp9"},
+        {"OMX.google.goldfish.h264.decoder", "avcdec", "video_decoder.avc"},
+        {"OMX.android.goldfish.vp8.decoder", "vpxdec", "video_decoder.vp8"},
+        {"OMX.android.goldfish.vp9.decoder", "vpxdec", "video_decoder.vp9"},
+        {"OMX.android.goldfish.h264.decoder", "avcdec", "video_decoder.avc"},
 };
 
 static std::vector<GoldfishComponent> kActiveComponents;
diff --git a/system/codecs/omx/vpxdec/Android.mk b/system/codecs/omx/vpxdec/Android.mk
index 6374ac3..ce2ab89 100644
--- a/system/codecs/omx/vpxdec/Android.mk
+++ b/system/codecs/omx/vpxdec/Android.mk
@@ -34,12 +34,21 @@
 	                      libhidlbase_impl_internal \
 	                      libbase
 
+LOCAL_HEADER_LIBRARIES += libui_headers \
+                          libnativewindow_headers \
+                          libhardware_headers \
+                          libarect_headers \
+                          libarect_headers_for_ndk
+
 LOCAL_SHARED_LIBRARIES :=       \
         libbinder               \
         libutils                \
         liblog                  \
         libcutils               \
+        libui                   \
         android.hardware.media.omx@1.0 \
+        android.hardware.graphics.allocator@3.0 \
+        android.hardware.graphics.mapper@3.0 \
         libstagefright_foundation
 
 $(call emugl-export,C_INCLUDES,$(LOCAL_PATH))
diff --git a/system/codecs/omx/vpxdec/GoldfishVPX.cpp b/system/codecs/omx/vpxdec/GoldfishVPX.cpp
index 5b9fb2d..2e7043f 100644
--- a/system/codecs/omx/vpxdec/GoldfishVPX.cpp
+++ b/system/codecs/omx/vpxdec/GoldfishVPX.cpp
@@ -19,11 +19,29 @@
 #include <utils/misc.h>
 //#include "OMX_VideoExt.h"
 
+#define DEBUG 0
+#if DEBUG
+#define DDD(...) ALOGD(__VA_ARGS__)
+#else
+#define DDD(...) ((void)0)
+#endif
+
 #include "GoldfishVPX.h"
 
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/MediaDefs.h>
 
+#include <OMX_VideoExt.h>
+#include <inttypes.h>
+
+#include <nativebase/nativebase.h>
+
+#include <android/hardware/graphics/allocator/3.0/IAllocator.h>
+#include <android/hardware/graphics/mapper/3.0/IMapper.h>
+#include <hidl/LegacySupport.h>
+
+using ::android::hardware::graphics::common::V1_0::BufferUsage;
+using ::android::hardware::graphics::common::V1_2::PixelFormat;
 
 namespace android {
 
@@ -35,19 +53,26 @@
     { OMX_VIDEO_VP9Profile2HDR10Plus, OMX_VIDEO_VP9Level5 },
 };
 
-GoldfishVPX::GoldfishVPX(
-        const char *name,
-        const char *componentRole,
-        OMX_VIDEO_CODINGTYPE codingType,
-        const OMX_CALLBACKTYPE *callbacks,
-        OMX_PTR appData,
-        OMX_COMPONENTTYPE **component)
+GoldfishVPX::GoldfishVPX(const char* name,
+                         const char* componentRole,
+                         OMX_VIDEO_CODINGTYPE codingType,
+                         const OMX_CALLBACKTYPE* callbacks,
+                         OMX_PTR appData,
+                         OMX_COMPONENTTYPE** component,
+                         RenderMode renderMode)
     : GoldfishVideoDecoderOMXComponent(
-            name, componentRole, codingType,
-            codingType == OMX_VIDEO_CodingVP8 ? NULL : kVP9ProfileLevels,
-            codingType == OMX_VIDEO_CodingVP8 ?  0 : NELEM(kVP9ProfileLevels),
-            320 /* width */, 240 /* height */, callbacks, appData, component),
+              name,
+              componentRole,
+              codingType,
+              codingType == OMX_VIDEO_CodingVP8 ? NULL : kVP9ProfileLevels,
+              codingType == OMX_VIDEO_CodingVP8 ? 0 : NELEM(kVP9ProfileLevels),
+              320 /* width */,
+              240 /* height */,
+              callbacks,
+              appData,
+              component),
       mMode(codingType == OMX_VIDEO_CodingVP8 ? MODE_VP8 : MODE_VP9),
+      mRenderMode(renderMode),
       mEOSStatus(INPUT_DATA_AVAILABLE),
       mCtx(NULL),
       mFrameParallelMode(false),
@@ -55,17 +80,19 @@
       mImg(NULL) {
     // arbitrary from avc/hevc as vpx does not specify a min compression ratio
     const size_t kMinCompressionRatio = mMode == MODE_VP8 ? 2 : 4;
-    const char *mime = mMode == MODE_VP8 ? MEDIA_MIMETYPE_VIDEO_VP8 : MEDIA_MIMETYPE_VIDEO_VP9;
-    const size_t kMaxOutputBufferSize = 2560 * 2560 * 3 / 2;
-    initPorts(
-            kNumBuffers, kMaxOutputBufferSize / kMinCompressionRatio /* inputBufferSize */,
-            kNumBuffers, mime, kMinCompressionRatio);
-    ALOGE("calling constructor of GoldfishVPX");
-    CHECK_EQ(initDecoder(), (status_t)OK);
+    const char* mime = mMode == MODE_VP8 ? MEDIA_MIMETYPE_VIDEO_VP8
+                                         : MEDIA_MIMETYPE_VIDEO_VP9;
+    const size_t kMaxOutputBufferSize = 3840 * 2160 * 3 / 2;  // 4k
+    initPorts(kNumBuffers,
+              kMaxOutputBufferSize / kMinCompressionRatio /* inputBufferSize */,
+              kNumBuffers, mime, kMinCompressionRatio);
+    ALOGI("calling constructor of GoldfishVPX");
+    // wait till later
+    // CHECK_EQ(initDecoder(), (status_t)OK);
 }
 
 GoldfishVPX::~GoldfishVPX() {
-    ALOGE("calling destructor of GoldfishVPX");
+    ALOGI("calling destructor of GoldfishVPX");
     destroyDecoder();
 }
 
@@ -81,25 +108,33 @@
     mCtx = new vpx_codec_ctx_t;
     mCtx->vpversion = mMode == MODE_VP8 ? 8 : 9;
 
+    mCtx->version = mEnableAndroidNativeBuffers ? 200 : 100;
+
     int vpx_err = 0;
     if ((vpx_err = vpx_codec_dec_init(mCtx))) {
         ALOGE("vpx decoder failed to initialize. (%d)", vpx_err);
         return UNKNOWN_ERROR;
     }
 
+    ALOGI("calling init GoldfishVPX ctx %p", mCtx);
     return OK;
 }
 
 status_t GoldfishVPX::destroyDecoder() {
-    vpx_codec_destroy(mCtx);
-    delete mCtx;
-    mCtx = NULL;
+    if (mCtx) {
+        ALOGI("calling destroying GoldfishVPX ctx %p", mCtx);
+        vpx_codec_destroy(mCtx);
+        delete mCtx;
+        mCtx = NULL;
+    }
     return OK;
 }
 
-void GoldfishVPX::setup_ctx_parameters(vpx_codec_ctx_t* ctx) {
+void GoldfishVPX::setup_ctx_parameters(vpx_codec_ctx_t* ctx,
+                                       int hostColorBufferId) {
     ctx->width = mWidth;
     ctx->height = mHeight;
+    ctx->hostColorBufferId = hostColorBufferId;
     ctx->outputBufferWidth = outputBufferWidth();
     ctx->outputBufferHeight = outputBufferHeight();
     OMX_PARAM_PORTDEFINITIONTYPE *outDef = &editPortInfo(kOutputPortIndex)->mDef;
@@ -111,6 +146,7 @@
     List<BufferInfo *> &outQueue = getPortQueue(1);
     BufferInfo *outInfo = NULL;
     OMX_BUFFERHEADERTYPE *outHeader = NULL;
+    DDD("%s %d", __func__, __LINE__);
 
     if (flushDecoder && mFrameParallelMode) {
         // Flush decoder by passing NULL data ptr and 0 size.
@@ -136,8 +172,11 @@
     }
 
     while (!outQueue.empty()) {
+        DDD("%s %d", __func__, __LINE__);
+        outInfo = *outQueue.begin();
+        outHeader = outInfo->mHeader;
         if (mImg == NULL) {
-            setup_ctx_parameters(mCtx);
+            setup_ctx_parameters(mCtx, getHostColorBufferId(outHeader));
             mImg = vpx_codec_get_frame(mCtx);
             if (mImg == NULL) {
                 break;
@@ -145,8 +184,6 @@
         }
         uint32_t width = mImg->d_w;
         uint32_t height = mImg->d_h;
-        outInfo = *outQueue.begin();
-        outHeader = outInfo->mHeader;
         CHECK(mImg->fmt == VPX_IMG_FMT_I420 || mImg->fmt == VPX_IMG_FMT_I42016);
         OMX_COLOR_FORMATTYPE outputColorFormat = OMX_COLOR_FormatYUV420Planar;
         int32_t bpp = 1;
@@ -168,11 +205,12 @@
             queueOutputFrameConfig(privInfo->mHdr10PlusInfo);
         }
 
-        if (outputBufferSafe(outHeader)) {
+        if (outputBufferSafe(outHeader) &&
+            getHostColorBufferId(outHeader) < 0) {
             uint8_t *dst = outHeader->pBuffer;
             memcpy(dst, mCtx->dst, outHeader->nFilledLen);
         } else {
-            outHeader->nFilledLen = 0;
+            // outHeader->nFilledLen = 0;
         }
 
         mImg = NULL;
@@ -202,6 +240,7 @@
 }
 
 bool GoldfishVPX::outputBufferSafe(OMX_BUFFERHEADERTYPE *outHeader) {
+    DDD("%s %d", __func__, __LINE__);
     uint32_t width = outputBufferWidth();
     uint32_t height = outputBufferHeight();
     uint64_t nFilledLen = width;
@@ -221,10 +260,19 @@
 }
 
 void GoldfishVPX::onQueueFilled(OMX_U32 /* portIndex */) {
+    DDD("%s %d", __func__, __LINE__);
     if (mOutputPortSettingsChange != NONE || mEOSStatus == OUTPUT_FRAMES_FLUSHED) {
         return;
     }
 
+    if (mCtx == nullptr) {
+        if (OK != initDecoder()) {
+            ALOGE("Failed to initialize decoder");
+            notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL);
+            return;
+        }
+    }
+
     List<BufferInfo *> &inQueue = getPortQueue(0);
     List<BufferInfo *> &outQueue = getPortQueue(1);
     bool EOSseen = false;
@@ -313,6 +361,7 @@
 }
 
 void GoldfishVPX::onPortFlushCompleted(OMX_U32 portIndex) {
+    DDD("%s %d", __func__, __LINE__);
     if (portIndex == kInputPortIndex) {
         bool portWillReset = false;
         if (!outputBuffers(
@@ -326,6 +375,7 @@
 }
 
 void GoldfishVPX::onReset() {
+    DDD("%s %d", __func__, __LINE__);
     bool portWillReset = false;
     if (!outputBuffers(
              true /* flushDecoder */, false /* display */, false /* eos */, &portWillReset)) {
@@ -336,21 +386,141 @@
     mEOSStatus = INPUT_DATA_AVAILABLE;
 }
 
+int GoldfishVPX::getHostColorBufferId(void* header) {
+    DDD("%s %d", __func__, __LINE__);
+    if (mNWBuffers.find(header) == mNWBuffers.end()) {
+        DDD("cannot find color buffer for header %p", header);
+        return -1;
+    }
+    sp<ANativeWindowBuffer> nBuf = mNWBuffers[header];
+    cb_handle_t* handle = (cb_handle_t*)nBuf->handle;
+    DDD("found color buffer for header %p --> %d", header, handle->hostHandle);
+    return handle->hostHandle;
+}
+
+OMX_ERRORTYPE GoldfishVPX::internalGetParameter(OMX_INDEXTYPE index,
+                                                OMX_PTR params) {
+    const int32_t indexFull = index;
+    switch (indexFull) {
+        case kGetAndroidNativeBufferUsageIndex: {
+            DDD("calling kGetAndroidNativeBufferUsageIndex");
+            GetAndroidNativeBufferUsageParams* nativeBuffersUsage =
+                    (GetAndroidNativeBufferUsageParams*)params;
+            nativeBuffersUsage->nUsage =
+                    (unsigned int)(BufferUsage::GPU_DATA_BUFFER);
+            return OMX_ErrorNone;
+        }
+
+        default:
+            return GoldfishVideoDecoderOMXComponent::internalGetParameter(
+                    index, params);
+    }
+}
+
+OMX_ERRORTYPE GoldfishVPX::internalSetParameter(OMX_INDEXTYPE index,
+                                                const OMX_PTR params) {
+    // Include extension index OMX_INDEXEXTTYPE.
+    const int32_t indexFull = index;
+
+    switch (indexFull) {
+        case kEnableAndroidNativeBuffersIndex: {
+            DDD("calling kEnableAndroidNativeBuffersIndex");
+            EnableAndroidNativeBuffersParams* enableNativeBuffers =
+                    (EnableAndroidNativeBuffersParams*)params;
+            if (enableNativeBuffers) {
+                mEnableAndroidNativeBuffers = enableNativeBuffers->enable;
+                if (mEnableAndroidNativeBuffers == false) {
+                    mNWBuffers.clear();
+                    DDD("disabled kEnableAndroidNativeBuffersIndex");
+                } else {
+                    DDD("enabled kEnableAndroidNativeBuffersIndex");
+                }
+            }
+            return OMX_ErrorNone;
+        }
+
+        case kUseAndroidNativeBufferIndex: {
+            if (mEnableAndroidNativeBuffers == false) {
+                ALOGE("Error: not enabled Android Native Buffers");
+                return OMX_ErrorBadParameter;
+            }
+            UseAndroidNativeBufferParams* use_buffer_params =
+                    (UseAndroidNativeBufferParams*)params;
+            if (use_buffer_params) {
+                sp<ANativeWindowBuffer> nBuf = use_buffer_params->nativeBuffer;
+                cb_handle_t* handle = (cb_handle_t*)nBuf->handle;
+                void* dst = NULL;
+                DDD("kUseAndroidNativeBufferIndex with handle %p host color "
+                    "handle %d "
+                    "calling usebuffer",
+                    handle, handle->hostHandle);
+                useBufferCallerLockedAlready(use_buffer_params->bufferHeader,
+                                             use_buffer_params->nPortIndex,
+                                             use_buffer_params->pAppPrivate,
+                                             handle->allocatedSize(),
+                                             (OMX_U8*)dst);
+                mNWBuffers[*(use_buffer_params->bufferHeader)] =
+                        use_buffer_params->nativeBuffer;
+                ;
+            }
+            return OMX_ErrorNone;
+        }
+
+        default:
+            return GoldfishVideoDecoderOMXComponent::internalSetParameter(
+                    index, params);
+    }
+}
+
+OMX_ERRORTYPE GoldfishVPX::getExtensionIndex(const char* name,
+                                             OMX_INDEXTYPE* index) {
+    if (mRenderMode == RenderMode::RENDER_BY_HOST_GPU) {
+        if (!strcmp(name,
+                    "OMX.google.android.index.enableAndroidNativeBuffers")) {
+            DDD("calling getExtensionIndex for enable ANB");
+            *(int32_t*)index = kEnableAndroidNativeBuffersIndex;
+            return OMX_ErrorNone;
+        } else if (!strcmp(name,
+                           "OMX.google.android.index.useAndroidNativeBuffer")) {
+            *(int32_t*)index = kUseAndroidNativeBufferIndex;
+            return OMX_ErrorNone;
+        } else if (!strcmp(name,
+                           "OMX.google.android.index."
+                           "getAndroidNativeBufferUsage")) {
+            *(int32_t*)index = kGetAndroidNativeBufferUsageIndex;
+            return OMX_ErrorNone;
+        }
+    }
+    return GoldfishVideoDecoderOMXComponent::getExtensionIndex(name, index);
+}
+
 }  // namespace android
 
 android::GoldfishOMXComponent *createGoldfishOMXComponent(
         const char *name, const OMX_CALLBACKTYPE *callbacks,
         OMX_PTR appData, OMX_COMPONENTTYPE **component) {
-    if (!strcmp(name, "OMX.google.goldfish.vp8.decoder")) {
+    DDD("%s %d", __func__, __LINE__);
+    // only support vp9 to use host hardware decoder, for now
+    if (!strncmp("OMX.android.goldfish.vp9.decoder", name, 32)) {
         return new android::GoldfishVPX(
-                name, "video_decoder.vp8", OMX_VIDEO_CodingVP8,
-                callbacks, appData, component);
-    } else if (!strcmp(name, "OMX.google.goldfish.vp9.decoder")) {
-        return new android::GoldfishVPX(
-                name, "video_decoder.vp9", OMX_VIDEO_CodingVP9,
-                callbacks, appData, component);
-    } else {
-        CHECK(!"Unknown component");
+                name, "video_decoder.vp9", OMX_VIDEO_CodingVP9, callbacks,
+                appData, component, RenderMode::RENDER_BY_HOST_GPU);
     }
+    if (!strncmp("OMX.android.goldfish.vp8.decoder", name, 32)) {
+        return new android::GoldfishVPX(
+                name, "video_decoder.vp8", OMX_VIDEO_CodingVP8, callbacks,
+                appData, component, RenderMode::RENDER_BY_HOST_GPU);
+    }
+    if (!strncmp("OMX.google.goldfish.vp9.decoder", name, 30)) {
+        return new android::GoldfishVPX(
+                name, "video_decoder.vp9", OMX_VIDEO_CodingVP9, callbacks,
+                appData, component, RenderMode::RENDER_BY_GUEST_CPU);
+    }
+    if (!strncmp("OMX.google.goldfish.vp8.decoder", name, 30)) {
+        return new android::GoldfishVPX(
+                name, "video_decoder.vp8", OMX_VIDEO_CodingVP8, callbacks,
+                appData, component, RenderMode::RENDER_BY_GUEST_CPU);
+    }
+    { CHECK(!"Unknown component"); }
     return NULL;
 }
diff --git a/system/codecs/omx/vpxdec/GoldfishVPX.h b/system/codecs/omx/vpxdec/GoldfishVPX.h
index 2ba8beb..2eb762c 100644
--- a/system/codecs/omx/vpxdec/GoldfishVPX.h
+++ b/system/codecs/omx/vpxdec/GoldfishVPX.h
@@ -21,17 +21,30 @@
 #include "GoldfishVideoDecoderOMXComponent.h"
 #include "goldfish_vpx_defs.h"
 
+#include <sys/time.h>
+
+#include <map>
+#include <vector>
+
+#include <ui/GraphicBuffer.h>
+#include <utils/List.h>
+#include <utils/RefBase.h>
+#include <utils/Vector.h>
+#include <utils/threads.h>
+#include "gralloc_cb.h"
+
 namespace android {
 
 struct ABuffer;
 
 struct GoldfishVPX : public GoldfishVideoDecoderOMXComponent {
-    GoldfishVPX(const char *name,
-            const char *componentRole,
-            OMX_VIDEO_CODINGTYPE codingType,
-            const OMX_CALLBACKTYPE *callbacks,
-            OMX_PTR appData,
-            OMX_COMPONENTTYPE **component);
+    GoldfishVPX(const char* name,
+                const char* componentRole,
+                OMX_VIDEO_CODINGTYPE codingType,
+                const OMX_CALLBACKTYPE* callbacks,
+                OMX_PTR appData,
+                OMX_COMPONENTTYPE** component,
+                RenderMode renderMode);
 
 protected:
     virtual ~GoldfishVPX();
@@ -42,6 +55,15 @@
     virtual bool supportDescribeHdrStaticInfo();
     virtual bool supportDescribeHdr10PlusInfo();
 
+    virtual OMX_ERRORTYPE internalGetParameter(OMX_INDEXTYPE index,
+                                               OMX_PTR params);
+
+    virtual OMX_ERRORTYPE internalSetParameter(OMX_INDEXTYPE index,
+                                               const OMX_PTR params);
+
+    virtual OMX_ERRORTYPE getExtensionIndex(const char* name,
+                                            OMX_INDEXTYPE* index);
+
 private:
     enum {
         kNumBuffers = 10
@@ -52,6 +74,12 @@
         MODE_VP9
     } mMode;
 
+    RenderMode mRenderMode = RenderMode::RENDER_BY_GUEST_CPU;
+    bool mEnableAndroidNativeBuffers = false;
+    std::map<void*, sp<ANativeWindowBuffer>> mNWBuffers;
+
+    int getHostColorBufferId(void* header);
+
     enum {
         INPUT_DATA_AVAILABLE,  // VPX component is ready to decode data.
         INPUT_EOS_SEEN,        // VPX component saw EOS and is flushing On2 decoder.
@@ -73,7 +101,7 @@
     bool outputBuffers(bool flushDecoder, bool display, bool eos, bool *portWillReset);
     bool outputBufferSafe(OMX_BUFFERHEADERTYPE *outHeader);
 
-    void setup_ctx_parameters(vpx_codec_ctx_t*);
+    void setup_ctx_parameters(vpx_codec_ctx_t*, int hostColorBufferId = -1);
 
     DISALLOW_EVIL_CONSTRUCTORS(GoldfishVPX);
 };
diff --git a/system/codecs/omx/vpxdec/goldfish_vpx_defs.h b/system/codecs/omx/vpxdec/goldfish_vpx_defs.h
index 1b1358c..25fecde 100644
--- a/system/codecs/omx/vpxdec/goldfish_vpx_defs.h
+++ b/system/codecs/omx/vpxdec/goldfish_vpx_defs.h
@@ -9,6 +9,11 @@
 
 typedef unsigned char uint8_t;
 
+enum class RenderMode {
+    RENDER_BY_HOST_GPU = 1,
+    RENDER_BY_GUEST_CPU = 2,
+};
+
 enum vpx_img_fmt_t {
   VPX_IMG_FMT_NONE,
   VPX_IMG_FMT_YV12 =
@@ -34,6 +39,11 @@
 
 struct vpx_codec_ctx_t {
     int vpversion; //8: vp8 or 9: vp9
+    int version;   // 100: return decoded frame to guest; 200: render on host
+    int hostColorBufferId;
+    uint64_t id;  // >= 1, unique
+    int memory_slot;
+    uint64_t address_offset = 0;
     size_t outputBufferWidth;
     size_t outputBufferHeight;
     size_t width;
@@ -41,11 +51,12 @@
     size_t bpp;
     uint8_t *data;
     uint8_t *dst;
+    vpx_image_t myImg;
 };
 
 int vpx_codec_destroy(vpx_codec_ctx_t*);
 int vpx_codec_dec_init(vpx_codec_ctx_t*);
-vpx_image_t *vpx_codec_get_frame(vpx_codec_ctx_t*);
+vpx_image_t* vpx_codec_get_frame(vpx_codec_ctx_t*, int hostColorBufferId = -1);
 int vpx_codec_flush(vpx_codec_ctx_t *ctx);
 int vpx_codec_decode(vpx_codec_ctx_t *ctx, const uint8_t *data,
                                  unsigned int data_sz, void *user_priv,
diff --git a/system/codecs/omx/vpxdec/goldfish_vpx_impl.cpp b/system/codecs/omx/vpxdec/goldfish_vpx_impl.cpp
index 0771176..92dfcfa 100644
--- a/system/codecs/omx/vpxdec/goldfish_vpx_impl.cpp
+++ b/system/codecs/omx/vpxdec/goldfish_vpx_impl.cpp
@@ -14,27 +14,73 @@
 #include "goldfish_vpx_defs.h"
 #include "goldfish_media_utils.h"
 
-static vpx_image_t myImg;
+#include <memory>
+#include <mutex>
+#include <vector>
+
+#define DEBUG 0
+#if DEBUG
+#define DDD(...) ALOGD(__VA_ARGS__)
+#else
+#define DDD(...) ((void)0)
+#endif
+
+// static vpx_image_t myImg;
+static uint64_t s_CtxId = 0;
+static std::mutex sCtxidMutex;
+
+static uint64_t applyForOneId() {
+    DDD("%s %d", __func__, __LINE__);
+    std::lock_guard<std::mutex> g{sCtxidMutex};
+    ++s_CtxId;
+    return s_CtxId;
+}
 
 static void sendVpxOperation(vpx_codec_ctx_t* ctx, MediaOperation op) {
+    DDD("%s %d", __func__, __LINE__);
+    if (ctx->memory_slot < 0) {
+        ALOGE("ERROR: Failed %s %d: there is no memory slot", __func__,
+              __LINE__);
+    }
     auto transport = GoldfishMediaTransport::getInstance();
-    transport->sendOperation(
-            ctx->vpversion == 8 ?
-                MediaCodecType::VP8Codec :
-                MediaCodecType::VP9Codec,
-            op);
+    transport->sendOperation(ctx->vpversion == 9 ? MediaCodecType::VP9Codec
+                                                 : MediaCodecType::VP8Codec,
+                             op, ctx->address_offset);
 }
 
 int vpx_codec_destroy(vpx_codec_ctx_t* ctx) {
+    DDD("%s %d", __func__, __LINE__);
+    auto transport = GoldfishMediaTransport::getInstance();
+    transport->writeParam(ctx->id, 0, ctx->address_offset);
     sendVpxOperation(ctx, MediaOperation::DestroyContext);
+    transport->returnMemorySlot(ctx->memory_slot);
+    ctx->memory_slot = -1;
     return 0;
 }
 
 int vpx_codec_dec_init(vpx_codec_ctx_t* ctx) {
+    DDD("%s %d", __func__, __LINE__);
     auto transport = GoldfishMediaTransport::getInstance();
+    int slot = transport->getMemorySlot();
+    if (slot < 0) {
+        ALOGE("ERROR: Failed %s %d: cannot get memory slot", __func__,
+              __LINE__);
+        return -1;
+    } else {
+        DDD("got slot %d", slot);
+    }
+    ctx->id = applyForOneId();
+    ctx->memory_slot = slot;
+    ctx->address_offset = static_cast<unsigned int>(slot) * 8 * (1 << 20);
+    DDD("got address offset 0x%x version %d", (int)(ctx->address_offset),
+        ctx->version);
+
     // data and dst are on the host side actually
-    ctx->data = transport->getInputAddr();
-    ctx->dst = transport->getOutputAddr();
+    ctx->data = transport->getInputAddr(ctx->address_offset);
+    ctx->dst = transport->getInputAddr(
+            ctx->address_offset);  // re-use input address
+    transport->writeParam(ctx->id, 0, ctx->address_offset);
+    transport->writeParam(ctx->version, 1, ctx->address_offset);
     sendVpxOperation(ctx, MediaOperation::InitContext);
     return 0;
 }
@@ -44,7 +90,9 @@
     return *pint;
 }
 
-static void getVpxFrame(uint8_t* ptr) {
+// vpx_image_t myImg;
+static void getVpxFrame(uint8_t* ptr, vpx_image_t& myImg) {
+    DDD("%s %d", __func__, __LINE__);
     uint8_t* imgptr = (ptr + 8);
     myImg.fmt = *(vpx_img_fmt_t*)imgptr;
     imgptr += 8;
@@ -53,31 +101,41 @@
     myImg.d_h = *(unsigned int *)imgptr;
     imgptr += 8;
     myImg.user_priv = (void*)(*(uint64_t*)imgptr);
+    DDD("fmt %d dw %d dh %d userpriv %p", (int)myImg.fmt, (int)myImg.d_w,
+        (int)myImg.d_h, myImg.user_priv);
 }
 
 //TODO: we might not need to do the putting all the time
-vpx_image_t* vpx_codec_get_frame(vpx_codec_ctx_t* ctx) {
+vpx_image_t* vpx_codec_get_frame(vpx_codec_ctx_t* ctx, int hostColorBufferId) {
+    DDD("%s %d %p", __func__, __LINE__);
     auto transport = GoldfishMediaTransport::getInstance();
 
-    transport->writeParam(ctx->outputBufferWidth, 0);
-    transport->writeParam(ctx->outputBufferHeight, 1);
-    transport->writeParam(ctx->width, 2);
-    transport->writeParam(ctx->height, 3);
-    transport->writeParam(ctx->bpp, 4);
-    transport->writeParam(transport->offsetOf((uint64_t)(ctx->dst)), 5);
+    transport->writeParam(ctx->id, 0, ctx->address_offset);
+    transport->writeParam(ctx->outputBufferWidth, 1, ctx->address_offset);
+    transport->writeParam(ctx->outputBufferHeight, 2, ctx->address_offset);
+    transport->writeParam(ctx->width, 3, ctx->address_offset);
+    transport->writeParam(ctx->height, 4, ctx->address_offset);
+    transport->writeParam(ctx->bpp, 5, ctx->address_offset);
+    transport->writeParam(ctx->hostColorBufferId, 6, ctx->address_offset);
+    transport->writeParam(
+            transport->offsetOf((uint64_t)(ctx->dst)) - ctx->address_offset, 7,
+            ctx->address_offset);
 
     sendVpxOperation(ctx, MediaOperation::GetImage);
 
-    auto* retptr = transport->getReturnAddr();
+    auto* retptr = transport->getReturnAddr(ctx->address_offset);
     int ret = getReturnCode(retptr);
     if (ret) {
         return nullptr;
     }
-    getVpxFrame(retptr);
-    return &myImg;
+    getVpxFrame(retptr, ctx->myImg);
+    return &(ctx->myImg);
 }
 
 int vpx_codec_flush(vpx_codec_ctx_t* ctx) {
+    DDD("%s %d", __func__, __LINE__);
+    auto transport = GoldfishMediaTransport::getInstance();
+    transport->writeParam(ctx->id, 0, ctx->address_offset);
     sendVpxOperation(ctx, MediaOperation::Flush);
     return 0;
 }
@@ -87,12 +145,17 @@
                      unsigned int data_sz,
                      void* user_priv,
                      long deadline) {
+    DDD("%s %d data size %d userpriv %p", __func__, __LINE__, (int)data_sz,
+        user_priv);
     auto transport = GoldfishMediaTransport::getInstance();
     memcpy(ctx->data, data, data_sz);
 
-    transport->writeParam(transport->offsetOf((uint64_t)(ctx->data)), 0);
-    transport->writeParam((__u64)data_sz, 1);
-    transport->writeParam((__u64)user_priv, 2);
+    transport->writeParam(ctx->id, 0, ctx->address_offset);
+    transport->writeParam(
+            transport->offsetOf((uint64_t)(ctx->data)) - ctx->address_offset, 1,
+            ctx->address_offset);
+    transport->writeParam((__u64)data_sz, 2, ctx->address_offset);
+    transport->writeParam((__u64)user_priv, 3, ctx->address_offset);
     sendVpxOperation(ctx, MediaOperation::DecodeImage);
     return 0;
 }
diff --git a/system/enc_common/IOStream_common.cpp b/system/enc_common/IOStream_common.cpp
index 901ad1d..1362d3e 100644
--- a/system/enc_common/IOStream_common.cpp
+++ b/system/enc_common/IOStream_common.cpp
@@ -59,3 +59,55 @@
         }
     }
 }
+
+void IOStream::uploadPixels(void* context, int width, int height, unsigned int format, unsigned int type, const void* pixels) {
+    GL2Encoder *ctx = (GL2Encoder *)context;
+    assert (ctx->state() != NULL);
+
+    int startOffset = 0;
+    int pixelRowSize = 0;
+    int totalRowSize = 0;
+    int skipRows = 0;
+
+    ctx->state()->getUnpackingOffsets2D(width, height, format, type,
+                                        &startOffset,
+                                        &pixelRowSize,
+                                        &totalRowSize,
+                                        &skipRows);
+
+    size_t pixelDataSize =
+        ctx->state()->pixelDataSize(
+            width, height, 1, format, type, 0 /* is unpack */);
+
+    if (startOffset == 0 &&
+        pixelRowSize == totalRowSize) {
+        // fast path
+        writeFully(pixels, pixelDataSize);
+    } else if (pixelRowSize == totalRowSize) {
+        // fast path but with skip in the beginning
+        std::vector<char> paddingToDiscard(startOffset, 0);
+        writeFully(&paddingToDiscard[0], startOffset);
+        writeFully((char*)pixels + startOffset, pixelDataSize - startOffset);
+    } else {
+        int totalReadback = 0;
+
+        if (startOffset > 0) {
+            std::vector<char> paddingToDiscard(startOffset, 0);
+            writeFully(&paddingToDiscard[0], startOffset);
+            totalReadback += startOffset;
+        }
+        // need to upload 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++) {
+            writeFully(start, pixelRowSize);
+            totalReadback += pixelRowSize;
+            writeFully(&paddingToDiscard[0], paddingSize);
+            totalReadback += paddingSize;
+            start += totalRowSize;
+        }
+    }
+}
diff --git a/system/vulkan/func_table.cpp b/system/vulkan/func_table.cpp
index 3f77e85..721e7c5 100644
--- a/system/vulkan/func_table.cpp
+++ b/system/vulkan/func_table.cpp
@@ -5256,6 +5256,35 @@
     return vkGetMemoryHostAddressInfoGOOGLE_VkResult_return;
 }
 #endif
+#ifdef VK_GOOGLE_free_memory_sync
+static VkResult entry_vkFreeMemorySyncGOOGLE(
+    VkDevice device,
+    VkDeviceMemory memory,
+    const VkAllocationCallbacks* pAllocator)
+{
+    AEMU_SCOPED_TRACE("vkFreeMemorySyncGOOGLE");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkFreeMemorySyncGOOGLE_VkResult_return = (VkResult)0;
+    vkFreeMemorySyncGOOGLE_VkResult_return = vkEnc->vkFreeMemorySyncGOOGLE(device, memory, pAllocator);
+    return vkFreeMemorySyncGOOGLE_VkResult_return;
+}
+static VkResult dynCheck_entry_vkFreeMemorySyncGOOGLE(
+    VkDevice device,
+    VkDeviceMemory memory,
+    const VkAllocationCallbacks* pAllocator)
+{
+    auto resources = ResourceTracker::get();
+    if (!resources->hasDeviceExtension(device, "VK_GOOGLE_free_memory_sync"))
+    {
+        sOnInvalidDynamicallyCheckedCall("vkFreeMemorySyncGOOGLE", "VK_GOOGLE_free_memory_sync");
+    }
+    AEMU_SCOPED_TRACE("vkFreeMemorySyncGOOGLE");
+    auto vkEnc = HostConnection::get()->vkEncoder();
+    VkResult vkFreeMemorySyncGOOGLE_VkResult_return = (VkResult)0;
+    vkFreeMemorySyncGOOGLE_VkResult_return = vkEnc->vkFreeMemorySyncGOOGLE(device, memory, pAllocator);
+    return vkFreeMemorySyncGOOGLE_VkResult_return;
+}
+#endif
 void* goldfish_vulkan_get_proc_address(const char* name){
 #ifdef VK_VERSION_1_0
     if (!strcmp(name, "vkCreateInstance"))
@@ -6707,6 +6736,12 @@
         return nullptr;
     }
 #endif
+#ifdef VK_GOOGLE_free_memory_sync
+    if (!strcmp(name, "vkFreeMemorySyncGOOGLE"))
+    {
+        return nullptr;
+    }
+#endif
     return nullptr;
 }
 void* goldfish_vulkan_get_instance_proc_address(VkInstance instance, const char* name){
@@ -8255,6 +8290,12 @@
         return (void*)dynCheck_entry_vkGetMemoryHostAddressInfoGOOGLE;
     }
 #endif
+#ifdef VK_GOOGLE_free_memory_sync
+    if (!strcmp(name, "vkFreeMemorySyncGOOGLE"))
+    {
+        return (void*)dynCheck_entry_vkFreeMemorySyncGOOGLE;
+    }
+#endif
     return nullptr;
 }
 void* goldfish_vulkan_get_device_proc_address(VkDevice device, const char* name){
@@ -9873,6 +9914,13 @@
         return hasExt ? (void*)entry_vkGetMemoryHostAddressInfoGOOGLE : nullptr;
     }
 #endif
+#ifdef VK_GOOGLE_free_memory_sync
+    if (!strcmp(name, "vkFreeMemorySyncGOOGLE"))
+    {
+        bool hasExt = resources->hasDeviceExtension(device, "VK_GOOGLE_free_memory_sync");
+        return hasExt ? (void*)entry_vkFreeMemorySyncGOOGLE : nullptr;
+    }
+#endif
     return nullptr;
 }
 
diff --git a/system/vulkan/func_table.h b/system/vulkan/func_table.h
index 91ffd65..c0d4224 100644
--- a/system/vulkan/func_table.h
+++ b/system/vulkan/func_table.h
@@ -288,6 +288,8 @@
 #endif
 #ifdef VK_GOOGLE_address_space_info
 #endif
+#ifdef VK_GOOGLE_free_memory_sync
+#endif
 void* goldfish_vulkan_get_proc_address(const char* name);
 void* goldfish_vulkan_get_instance_proc_address(VkInstance instance, const char* name);
 void* goldfish_vulkan_get_device_proc_address(VkDevice device, const char* name);
diff --git a/system/vulkan/goldfish_vulkan.cpp b/system/vulkan/goldfish_vulkan.cpp
index a9acba1..44071ec 100644
--- a/system/vulkan/goldfish_vulkan.cpp
+++ b/system/vulkan/goldfish_vulkan.cpp
@@ -735,7 +735,7 @@
                                .tags = nullptr,
                                .num_tags = 0};
 
-  fx_log_init_with_config(&config);
+  fx_log_reconfigure(&config);
 }
 
 extern "C" __attribute__((visibility("default"))) PFN_vkVoidFunction
diff --git a/system/vulkan_enc/AndroidHardwareBuffer.cpp b/system/vulkan_enc/AndroidHardwareBuffer.cpp
index fe5a847..a40a3a7 100644
--- a/system/vulkan_enc/AndroidHardwareBuffer.cpp
+++ b/system/vulkan_enc/AndroidHardwareBuffer.cpp
@@ -123,6 +123,7 @@
     // (hard to make actual dedicated allocs)
     uint32_t memoryTypeBits = 0;
     for (uint32_t i = 0; i < VK_MAX_MEMORY_TYPES; ++i) {
+        if (isNoFlagsMemoryTypeIndexForGuest(hostMemVirtInfo, i)) continue;
         if (isHostVisibleMemoryTypeIndexForGuest(hostMemVirtInfo, i)) continue;
         memoryTypeBits |= (1 << i);
     }
diff --git a/system/vulkan_enc/HostVisibleMemoryVirtualization.cpp b/system/vulkan_enc/HostVisibleMemoryVirtualization.cpp
index 318940e..a5b02f8 100644
--- a/system/vulkan_enc/HostVisibleMemoryVirtualization.cpp
+++ b/system/vulkan_enc/HostVisibleMemoryVirtualization.cpp
@@ -250,6 +250,7 @@
 }
 
 void destroyHostMemAlloc(
+    bool freeMemorySyncSupported,
     VkEncoder* enc,
     VkDevice device,
     HostMemAlloc* toDestroy) {
@@ -257,7 +258,12 @@
     if (toDestroy->initResult != VK_SUCCESS) return;
     if (!toDestroy->initialized) return;
 
-    enc->vkFreeMemory(device, toDestroy->memory, nullptr);
+    if (freeMemorySyncSupported) {
+        enc->vkFreeMemorySyncGOOGLE(device, toDestroy->memory, nullptr);
+    } else {
+        enc->vkFreeMemory(device, toDestroy->memory, nullptr);
+    }
+
     delete toDestroy->subAlloc;
 }
 
@@ -303,4 +309,15 @@
     return true;
 }
 
+bool isNoFlagsMemoryTypeIndexForGuest(
+    const HostVisibleMemoryVirtualizationInfo* info,
+    uint32_t index) {
+    const auto& props =
+        info->virtualizationSupported ?
+        info->guestMemoryProperties :
+        info->hostMemoryProperties;
+    return props.memoryTypes[index].propertyFlags == 0;
+}
+
+
 } // namespace goldfish_vk
diff --git a/system/vulkan_enc/HostVisibleMemoryVirtualization.h b/system/vulkan_enc/HostVisibleMemoryVirtualization.h
index 46e69ec..e190a1e 100644
--- a/system/vulkan_enc/HostVisibleMemoryVirtualization.h
+++ b/system/vulkan_enc/HostVisibleMemoryVirtualization.h
@@ -96,6 +96,7 @@
     HostMemAlloc* out);
 
 void destroyHostMemAlloc(
+    bool freeMemorySyncSupported,
     VkEncoder* enc,
     VkDevice device,
     HostMemAlloc* toDestroy);
@@ -119,4 +120,9 @@
 void subFreeHostMemory(SubAlloc* toFree);
 
 bool canSubAlloc(android::base::guest::SubAllocator* subAlloc, VkDeviceSize size);
+
+bool isNoFlagsMemoryTypeIndexForGuest(
+    const HostVisibleMemoryVirtualizationInfo* info,
+    uint32_t index);
+
 } // namespace goldfish_vk
diff --git a/system/vulkan_enc/ResourceTracker.cpp b/system/vulkan_enc/ResourceTracker.cpp
index a62b411..b81a6ab 100644
--- a/system/vulkan_enc/ResourceTracker.cpp
+++ b/system/vulkan_enc/ResourceTracker.cpp
@@ -1143,7 +1143,6 @@
             { "VK_KHR_external_memory", 1 },
             { "VK_KHR_external_semaphore", 1 },
             { "VK_FUCHSIA_external_semaphore", 1 },
-            { "VK_FUCHSIA_buffer_collection", 1 },
 #endif
         };
 
@@ -1151,11 +1150,13 @@
             filteredExts.push_back(anbExtProp);
         }
 
+#ifndef VK_USE_PLATFORM_FUCHSIA
         if (hostSupportsExternalSemaphore &&
             !hostHasPosixExternalSemaphore) {
             filteredExts.push_back(
                 { "VK_KHR_external_semaphore_fd", 1});
         }
+#endif
 
         bool win32ExtMemAvailable =
             getHostDeviceExtensionIndex(
@@ -1163,12 +1164,12 @@
         bool posixExtMemAvailable =
             getHostDeviceExtensionIndex(
                 "VK_KHR_external_memory_fd") != -1;
-        bool extMoltenVkAvailable =
-            getHostDeviceExtensionIndex(
+        bool moltenVkExtAvailable =
+            getHostInstanceExtensionIndex(
                 "VK_MVK_moltenvk") != -1;
 
         bool hostHasExternalMemorySupport =
-            win32ExtMemAvailable || posixExtMemAvailable || extMoltenVkAvailable;
+            win32ExtMemAvailable || posixExtMemAvailable || moltenVkExtAvailable;
 
         if (hostHasExternalMemorySupport) {
 #ifdef VK_USE_PLATFORM_ANDROID_KHR
@@ -1183,6 +1184,9 @@
             filteredExts.push_back({
                 "VK_FUCHSIA_external_memory", 1
             });
+            filteredExts.push_back({
+                "VK_FUCHSIA_buffer_collection", 1
+            });
 #endif
         }
 
@@ -1420,9 +1424,13 @@
 
         VkEncoder* enc = (VkEncoder*)context;
 
+        bool freeMemorySyncSupported =
+            mFeatureInfo->hasVulkanFreeMemorySync;
         for (uint32_t i = 0; i < VK_MAX_MEMORY_TYPES; ++i) {
             for (auto& block : info.hostMemBlocks[i]) {
-                destroyHostMemAlloc(enc, device, &block);
+                destroyHostMemAlloc(
+                    freeMemorySyncSupported,
+                    enc, device, &block);
             }
         }
     }
diff --git a/system/vulkan_enc/VkEncoder.cpp b/system/vulkan_enc/VkEncoder.cpp
index b5b6eea..8c00e0c 100644
--- a/system/vulkan_enc/VkEncoder.cpp
+++ b/system/vulkan_enc/VkEncoder.cpp
@@ -23433,5 +23433,79 @@
 }
 
 #endif
+#ifdef VK_GOOGLE_free_memory_sync
+VkResult VkEncoder::vkFreeMemorySyncGOOGLE(
+    VkDevice device,
+    VkDeviceMemory memory,
+    const VkAllocationCallbacks* pAllocator)
+{
+    AutoLock encoderLock(mImpl->lock);
+    AEMU_SCOPED_TRACE("vkFreeMemorySyncGOOGLE encode");
+    mImpl->log("start vkFreeMemorySyncGOOGLE");
+    auto stream = mImpl->stream();
+    auto countingStream = mImpl->countingStream();
+    auto resources = mImpl->resources();
+    auto pool = mImpl->pool();
+    stream->setHandleMapping(resources->unwrapMapping());
+    VkDevice local_device;
+    VkDeviceMemory local_memory;
+    VkAllocationCallbacks* local_pAllocator;
+    local_device = device;
+    local_memory = memory;
+    local_pAllocator = nullptr;
+    if (pAllocator)
+    {
+        local_pAllocator = (VkAllocationCallbacks*)pool->alloc(sizeof(const VkAllocationCallbacks));
+        deepcopy_VkAllocationCallbacks(pool, pAllocator, (VkAllocationCallbacks*)(local_pAllocator));
+    }
+    local_pAllocator = nullptr;
+    mImpl->resources()->deviceMemoryTransform_tohost((VkDeviceMemory*)&local_memory, 1, (VkDeviceSize*)nullptr, 0, (VkDeviceSize*)nullptr, 0, (uint32_t*)nullptr, 0, (uint32_t*)nullptr, 0);
+    countingStream->rewind();
+    {
+        uint64_t cgen_var_1547;
+        countingStream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1547, 1);
+        countingStream->write((uint64_t*)&cgen_var_1547, 1 * 8);
+        uint64_t cgen_var_1548;
+        countingStream->handleMapping()->mapHandles_VkDeviceMemory_u64(&local_memory, &cgen_var_1548, 1);
+        countingStream->write((uint64_t*)&cgen_var_1548, 1 * 8);
+        // WARNING PTR CHECK
+        uint64_t cgen_var_1549 = (uint64_t)(uintptr_t)local_pAllocator;
+        countingStream->putBe64(cgen_var_1549);
+        if (local_pAllocator)
+        {
+            marshal_VkAllocationCallbacks(countingStream, (VkAllocationCallbacks*)(local_pAllocator));
+        }
+    }
+    uint32_t packetSize_vkFreeMemorySyncGOOGLE = 4 + 4 + (uint32_t)countingStream->bytesWritten();
+    countingStream->rewind();
+    uint32_t opcode_vkFreeMemorySyncGOOGLE = OP_vkFreeMemorySyncGOOGLE;
+    stream->write(&opcode_vkFreeMemorySyncGOOGLE, sizeof(uint32_t));
+    stream->write(&packetSize_vkFreeMemorySyncGOOGLE, sizeof(uint32_t));
+    uint64_t cgen_var_1550;
+    stream->handleMapping()->mapHandles_VkDevice_u64(&local_device, &cgen_var_1550, 1);
+    stream->write((uint64_t*)&cgen_var_1550, 1 * 8);
+    uint64_t cgen_var_1551;
+    stream->handleMapping()->mapHandles_VkDeviceMemory_u64(&local_memory, &cgen_var_1551, 1);
+    stream->write((uint64_t*)&cgen_var_1551, 1 * 8);
+    // WARNING PTR CHECK
+    uint64_t cgen_var_1552 = (uint64_t)(uintptr_t)local_pAllocator;
+    stream->putBe64(cgen_var_1552);
+    if (local_pAllocator)
+    {
+        marshal_VkAllocationCallbacks(stream, (VkAllocationCallbacks*)(local_pAllocator));
+    }
+    AEMU_SCOPED_TRACE("vkFreeMemorySyncGOOGLE readParams");
+    AEMU_SCOPED_TRACE("vkFreeMemorySyncGOOGLE returnUnmarshal");
+    VkResult vkFreeMemorySyncGOOGLE_VkResult_return = (VkResult)0;
+    stream->read(&vkFreeMemorySyncGOOGLE_VkResult_return, sizeof(VkResult));
+    countingStream->clearPool();
+    stream->clearPool();
+    pool->freeAll();
+    resources->destroyMapping()->mapHandles_VkDeviceMemory((VkDeviceMemory*)&memory);
+    mImpl->log("finish vkFreeMemorySyncGOOGLE");;
+    return vkFreeMemorySyncGOOGLE_VkResult_return;
+}
+
+#endif
 
 } // namespace goldfish_vk
diff --git a/system/vulkan_enc/VkEncoder.h b/system/vulkan_enc/VkEncoder.h
index 4cab74f..8f49f7d 100644
--- a/system/vulkan_enc/VkEncoder.h
+++ b/system/vulkan_enc/VkEncoder.h
@@ -1815,6 +1815,12 @@
         uint64_t* pSize,
         uint64_t* pHostmemId);
 #endif
+#ifdef VK_GOOGLE_free_memory_sync
+    VkResult vkFreeMemorySyncGOOGLE(
+    VkDevice device,
+        VkDeviceMemory memory,
+        const VkAllocationCallbacks* pAllocator);
+#endif
 
 private:
     class Impl;
diff --git a/system/vulkan_enc/goldfish_vk_deepcopy_guest.cpp b/system/vulkan_enc/goldfish_vk_deepcopy_guest.cpp
index 917ca59..e2d3294 100644
--- a/system/vulkan_enc/goldfish_vk_deepcopy_guest.cpp
+++ b/system/vulkan_enc/goldfish_vk_deepcopy_guest.cpp
@@ -6388,6 +6388,8 @@
 #endif
 #ifdef VK_GOOGLE_address_space_info
 #endif
+#ifdef VK_GOOGLE_free_memory_sync
+#endif
 void deepcopy_extension_struct(
     Pool* pool,
     const void* structExtension,
diff --git a/system/vulkan_enc/goldfish_vk_deepcopy_guest.h b/system/vulkan_enc/goldfish_vk_deepcopy_guest.h
index b1ffaa6..1164e1c 100644
--- a/system/vulkan_enc/goldfish_vk_deepcopy_guest.h
+++ b/system/vulkan_enc/goldfish_vk_deepcopy_guest.h
@@ -2030,5 +2030,7 @@
 #endif
 #ifdef VK_GOOGLE_address_space_info
 #endif
+#ifdef VK_GOOGLE_free_memory_sync
+#endif
 
 } // namespace goldfish_vk
diff --git a/system/vulkan_enc/goldfish_vk_extension_structs_guest.cpp b/system/vulkan_enc/goldfish_vk_extension_structs_guest.cpp
index 08bba9f..e4b1ca7 100644
--- a/system/vulkan_enc/goldfish_vk_extension_structs_guest.cpp
+++ b/system/vulkan_enc/goldfish_vk_extension_structs_guest.cpp
@@ -286,6 +286,8 @@
 #endif
 #ifdef VK_GOOGLE_address_space_info
 #endif
+#ifdef VK_GOOGLE_free_memory_sync
+#endif
 uint32_t goldfish_vk_struct_type(
     const void* structExtension)
 {
diff --git a/system/vulkan_enc/goldfish_vk_extension_structs_guest.h b/system/vulkan_enc/goldfish_vk_extension_structs_guest.h
index 4fa4e3c..5a3fc66 100644
--- a/system/vulkan_enc/goldfish_vk_extension_structs_guest.h
+++ b/system/vulkan_enc/goldfish_vk_extension_structs_guest.h
@@ -303,5 +303,7 @@
 #endif
 #ifdef VK_GOOGLE_address_space_info
 #endif
+#ifdef VK_GOOGLE_free_memory_sync
+#endif
 
 } // namespace goldfish_vk
diff --git a/system/vulkan_enc/goldfish_vk_handlemap_guest.cpp b/system/vulkan_enc/goldfish_vk_handlemap_guest.cpp
index 56adc3a..8e66554 100644
--- a/system/vulkan_enc/goldfish_vk_handlemap_guest.cpp
+++ b/system/vulkan_enc/goldfish_vk_handlemap_guest.cpp
@@ -4752,6 +4752,8 @@
 #endif
 #ifdef VK_GOOGLE_address_space_info
 #endif
+#ifdef VK_GOOGLE_free_memory_sync
+#endif
 void handlemap_extension_struct(
     VulkanHandleMapping* handlemap,
     void* structExtension_out)
diff --git a/system/vulkan_enc/goldfish_vk_handlemap_guest.h b/system/vulkan_enc/goldfish_vk_handlemap_guest.h
index 8785741..0dcedcb 100644
--- a/system/vulkan_enc/goldfish_vk_handlemap_guest.h
+++ b/system/vulkan_enc/goldfish_vk_handlemap_guest.h
@@ -1683,5 +1683,7 @@
 #endif
 #ifdef VK_GOOGLE_address_space_info
 #endif
+#ifdef VK_GOOGLE_free_memory_sync
+#endif
 
 } // namespace goldfish_vk
diff --git a/system/vulkan_enc/goldfish_vk_marshaling_guest.cpp b/system/vulkan_enc/goldfish_vk_marshaling_guest.cpp
index 24b8112..371e92e 100644
--- a/system/vulkan_enc/goldfish_vk_marshaling_guest.cpp
+++ b/system/vulkan_enc/goldfish_vk_marshaling_guest.cpp
@@ -13615,6 +13615,8 @@
 #endif
 #ifdef VK_GOOGLE_address_space_info
 #endif
+#ifdef VK_GOOGLE_free_memory_sync
+#endif
 void marshal_extension_struct(
     VulkanStreamGuest* vkStream,
     const void* structExtension)
@@ -16396,6 +16398,12 @@
             return "OP_vkGetMemoryHostAddressInfoGOOGLE";
         }
 #endif
+#ifdef VK_GOOGLE_free_memory_sync
+        case OP_vkFreeMemorySyncGOOGLE:
+        {
+            return "OP_vkFreeMemorySyncGOOGLE";
+        }
+#endif
         default:
         {
             return "OP_UNKNOWN_API_CALL";
diff --git a/system/vulkan_enc/goldfish_vk_marshaling_guest.h b/system/vulkan_enc/goldfish_vk_marshaling_guest.h
index da9e961..993c890 100644
--- a/system/vulkan_enc/goldfish_vk_marshaling_guest.h
+++ b/system/vulkan_enc/goldfish_vk_marshaling_guest.h
@@ -3397,6 +3397,9 @@
 #ifdef VK_GOOGLE_address_space_info
 #define OP_vkGetMemoryHostAddressInfoGOOGLE 20327
 #endif
+#ifdef VK_GOOGLE_free_memory_sync
+#define OP_vkFreeMemorySyncGOOGLE 20328
+#endif
 const char* api_opcode_to_string(
     const uint32_t opcode);
 
diff --git a/system/vulkan_enc/goldfish_vk_private_defs.h b/system/vulkan_enc/goldfish_vk_private_defs.h
index dd0c155..9e673c0 100644
--- a/system/vulkan_enc/goldfish_vk_private_defs.h
+++ b/system/vulkan_enc/goldfish_vk_private_defs.h
@@ -119,6 +119,10 @@
 
 typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryHostAddressInfoGOOGLE)(VkDevice device, VkDeviceMemory memory, uint64_t* pAddress, uint64_t* pSize);
 
+#define VK_GOOGLE_free_memory_sync 1
+
+typedef VkResult (VKAPI_PTR *PFN_vkFreeMemorySyncGOOGLE)(VkDevice device, VkDeviceMemory memory, const VkAllocationCallbacks* pAllocationCallbacks);
+
 #define VK_ANDROID_external_memory_android_hardware_buffer 1
 struct AHardwareBuffer;
 struct VkAndroidHardwareBufferPropertiesANDROID;
diff --git a/system/vulkan_enc/goldfish_vk_transform_guest.cpp b/system/vulkan_enc/goldfish_vk_transform_guest.cpp
index 9e7fbf5..550313f 100644
--- a/system/vulkan_enc/goldfish_vk_transform_guest.cpp
+++ b/system/vulkan_enc/goldfish_vk_transform_guest.cpp
@@ -8949,6 +8949,8 @@
 #endif
 #ifdef VK_GOOGLE_address_space_info
 #endif
+#ifdef VK_GOOGLE_free_memory_sync
+#endif
 void transform_tohost_extension_struct(
     ResourceTracker* resourceTracker,
     void* structExtension_out)
diff --git a/system/vulkan_enc/goldfish_vk_transform_guest.h b/system/vulkan_enc/goldfish_vk_transform_guest.h
index 6511666..d0b610b 100644
--- a/system/vulkan_enc/goldfish_vk_transform_guest.h
+++ b/system/vulkan_enc/goldfish_vk_transform_guest.h
@@ -3071,5 +3071,7 @@
 #endif
 #ifdef VK_GOOGLE_address_space_info
 #endif
+#ifdef VK_GOOGLE_free_memory_sync
+#endif
 
 } // namespace goldfish_vk