Snap for 8701376 from ef8778a609108985745ab3b94cbbc64f6a763f5c to mainline-appsearch-release

Change-Id: I2e4cbc3d0c0a851e0ee198a9361f11958630cc33
diff --git a/shared/OpenglCodecCommon/GLClientState.cpp b/shared/OpenglCodecCommon/GLClientState.cpp
index 903a437..852f36a 100644
--- a/shared/OpenglCodecCommon/GLClientState.cpp
+++ b/shared/OpenglCodecCommon/GLClientState.cpp
@@ -123,7 +123,7 @@
     m_tex.activeUnit = &m_tex.unit[0];
     m_tex.textureRecs = NULL;
 
-    mRboState.boundRenderbuffer = 0;
+    mRboState.boundRenderbuffer = nullptr;
 
     mFboState.boundDrawFramebuffer = 0;
     mFboState.boundReadFramebuffer = 0;
@@ -1051,17 +1051,17 @@
 }
 
 bool GLClientState::isTexture(GLuint tex_name) const {
-    return getTextureRec(tex_name);
+    return getTextureRec(tex_name) != nullptr;
 }
 
 bool GLClientState::isTextureWithStorage(GLuint tex_name) const {
-    TextureRec* rec = getTextureRec(tex_name);
+    TextureRec* rec = getTextureRecPtr(tex_name);
     if (!rec) return false;
     return rec->hasStorage;
 }
 
 bool GLClientState::isTextureCubeMap(GLuint tex_name) const {
-    TextureRec* texrec = getTextureRec(tex_name);
+    TextureRec* texrec = getTextureRecPtr(tex_name);
     if (!texrec) return false;
     switch (texrec->target) {
         case GL_TEXTURE_CUBE_MAP:
@@ -1445,7 +1445,7 @@
 {
     GLboolean first = GL_FALSE;
 
-    TextureRec* texrec = getTextureRec(texture);
+    TextureRec* texrec = getTextureRecPtr(texture);
     if (!texrec) {
         texrec = addTextureRec(texture, target);
         first = GL_TRUE;
@@ -1496,7 +1496,7 @@
         setBoundRenderbufferDimensions(width, height);
     } else {
         GLuint texture = getBoundTexture(target);
-        TextureRec* texrec = getTextureRec(texture);
+        TextureRec* texrec = getTextureRecPtr(texture);
         if (!texrec) return;
         texrec->boundEGLImage = true;
         setBoundTextureInternalFormat(target, GL_RGBA);
@@ -1526,11 +1526,12 @@
     tex->hasCubePosZ = false;
 
     AutoWriteLock guard(m_tex.textureRecs->lock);
-    m_tex.textureRecs->map[id] = tex;
+    m_tex.textureRecs->map[id] = std::shared_ptr<TextureRec>(tex);
     return tex;
 }
 
-TextureRec* GLClientState::getTextureRecLocked(GLuint id) const {
+std::shared_ptr<TextureRec> GLClientState::getTextureRec(GLuint id) const {
+    AutoReadLock guard(m_tex.textureRecs->lock);
     SharedTextureDataMap::const_iterator it =
         m_tex.textureRecs->map.find(id);
     if (it == m_tex.textureRecs->map.end()) {
@@ -1539,28 +1540,37 @@
     return it->second;
 }
 
-TextureRec* GLClientState::getTextureRec(GLuint id) const {
+TextureRec* GLClientState::getTextureRecPtrLocked(GLuint id) const {
+    SharedTextureDataMap::const_iterator it =
+        m_tex.textureRecs->map.find(id);
+    if (it == m_tex.textureRecs->map.end()) {
+        return NULL;
+    }
+    return it->second.get();
+}
+
+TextureRec* GLClientState::getTextureRecPtr(GLuint id) const {
     AutoReadLock guard(m_tex.textureRecs->lock);
-    return getTextureRecLocked(id);
+    return getTextureRecPtrLocked(id);
 }
 
 void GLClientState::setBoundTextureInternalFormat(GLenum target, GLint internalformat) {
     GLuint texture = getBoundTexture(target);
-    TextureRec* texrec = getTextureRec(texture);
+    TextureRec* texrec = getTextureRecPtr(texture);
     if (!texrec) return;
     texrec->internalformat = internalformat;
 }
 
 void GLClientState::setBoundTextureFormat(GLenum target, GLenum format) {
     GLuint texture = getBoundTexture(target);
-    TextureRec* texrec = getTextureRec(texture);
+    TextureRec* texrec = getTextureRecPtr(texture);
     if (!texrec) return;
     texrec->format = format;
 }
 
 void GLClientState::setBoundTextureType(GLenum target, GLenum type) {
     GLuint texture = getBoundTexture(target);
-    TextureRec* texrec = getTextureRec(texture);
+    TextureRec* texrec = getTextureRecPtr(texture);
     if (!texrec) return;
     texrec->type = type;
 }
@@ -1585,7 +1595,7 @@
 
 void GLClientState::setBoundTextureDims(GLenum target, GLenum cubetarget, GLsizei level, GLsizei width, GLsizei height, GLsizei depth) {
     GLuint texture = getBoundTexture(target);
-    TextureRec* texrec = getTextureRec(texture);
+    TextureRec* texrec = getTextureRecPtr(texture);
     if (!texrec) {
         return;
     }
@@ -1643,7 +1653,7 @@
 
 void GLClientState::setBoundTextureSamples(GLenum target, GLsizei samples) {
     GLuint texture = getBoundTexture(target);
-    TextureRec* texrec = getTextureRec(texture);
+    TextureRec* texrec = getTextureRecPtr(texture);
     if (!texrec) return;
     texrec->multisamples = samples;
 }
@@ -1652,7 +1662,7 @@
     if (stateTarget != GL_TEXTURE_CUBE_MAP) return;
 
     GLuint texture = getBoundTexture(stateTarget);
-    TextureRec* texrec = getTextureRec(texture);
+    TextureRec* texrec = getTextureRecPtr(texture);
     if (!texrec) return;
 
     switch (cubeTarget) {
@@ -1679,7 +1689,7 @@
 
 void GLClientState::setBoundTextureImmutableFormat(GLenum target) {
     GLuint texture = getBoundTexture(target);
-    TextureRec* texrec = getTextureRec(texture);
+    TextureRec* texrec = getTextureRecPtr(texture);
     if (!texrec) return;
     texrec->immutable = true;
     if (target == GL_TEXTURE_CUBE_MAP) {
@@ -1694,14 +1704,14 @@
 
 bool GLClientState::isBoundTextureImmutableFormat(GLenum target) const {
     GLuint texture = getBoundTexture(target);
-    TextureRec* texrec = getTextureRec(texture);
+    TextureRec* texrec = getTextureRecPtr(texture);
     if (!texrec) return false;
     return texrec->immutable;
 }
 
 bool GLClientState::isBoundTextureComplete(GLenum target) const {
     GLuint texture = getBoundTexture(target);
-    TextureRec* texrec = getTextureRec(texture);
+    TextureRec* texrec = getTextureRecPtr(texture);
     if (!texrec) return false;
 
     if (texrec->immutable) return true;
@@ -1914,25 +1924,27 @@
     if (!renderable) return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
 
     // Check dimensions
-    GLuint id;
+    std::shared_ptr<TextureRec> texrec;
+    std::shared_ptr<RboProps> rbo;
     switch (fbo_format_info.type) {
     case FBO_ATTACHMENT_RENDERBUFFER:
-        id = getFboAttachmentRboId(target, attachment);
+        rbo = getFboAttachmentRbo(target, attachment);
         if (!fbo_format_info.rb_external) {
-            if (0 == queryRboWidth(id) || 0 == queryRboHeight(id)) {
+            if (!rbo || 0 == rbo->width || 0 == rbo->height) {
                 ALOGD("%s: rbo has zero dimension\n", __func__);
                 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
             }
         }
         break;
     case FBO_ATTACHMENT_TEXTURE:
-        id = getFboAttachmentTextureId(target, attachment);
+        texrec = getFboAttachmentTexture(target, attachment);
         if (!fbo_format_info.tex_external) {
-            if (0 == queryTexWidth(fbo_format_info.tex_level, id) || 0 == queryTexHeight(fbo_format_info.tex_level, id)) {
+            if (0 == texrec->dims->widths[fbo_format_info.tex_level] ||
+                    0 == texrec->dims->heights[fbo_format_info.tex_level]) {
                 ALOGD("%s: texture has zero dimension\n", __func__);
                 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
             }
-            GLsizei depth = queryTexDepth(fbo_format_info.tex_level, id);
+            GLsizei depth = texrec->dims->depths[fbo_format_info.tex_level];
             if (fbo_format_info.tex_layer >= depth) {
                 ALOGD("%s: texture layer/zoffset too high, wanted %d but only have %d layers\n", __func__,
                       fbo_format_info.tex_layer, depth);
@@ -2053,13 +2065,12 @@
     TextureRec* texrec;
     for (const GLuint* texture = textures; texture != textures + n; texture++) {
         AutoWriteLock guard(m_tex.textureRecs->lock);
-        texrec = getTextureRecLocked(*texture);
+        texrec = getTextureRecPtrLocked(*texture);
         if (texrec && texrec->dims) {
             delete [] texrec->dims;
         }
         if (texrec) {
             m_tex.textureRecs->map.erase(*texture);
-            delete texrec;
             for (TextureUnit* unit = m_tex.unit;
                  unit != m_tex.unit + MAX_TEXTURE_UNITS;
                  unit++)
@@ -2090,25 +2101,27 @@
 }
 
 void GLClientState::removeRenderbuffers(GLsizei n, const GLuint* renderbuffers) {
-    std::vector<GLuint> to_remove;
-    for (size_t i = 0; i < n; i++) {
-        if (renderbuffers[i] != 0) { // Never remove the zero rb.
-            to_remove.push_back(renderbuffers[i]);
-            setFboCompletenessDirtyForRbo(renderbuffers[i]);
-        }
-    }
-
+    std::vector<std::shared_ptr<RboProps>> to_remove;
     bool unbindCurrent = false;
     {
         RenderbufferInfo::ScopedView view(mRboState.rboData);
-        for (size_t i = 0; i < to_remove.size(); i++) {
-            view.unref(to_remove[i]);
+        for (size_t i = 0; i < n; i++) {
+            if (renderbuffers[i] != 0) { // Never remove the zero rb.
+                auto rboPtr = view.get_shared_ptr(renderbuffers[i]);
+                if (!rboPtr) {
+                    continue;
+                }
+                to_remove.push_back(rboPtr);
+                setFboCompletenessDirtyForRbo(rboPtr);
+            }
         }
+
         for (size_t i = 0; i < to_remove.size(); i++) {
-            if (mRboState.boundRenderbuffer == renderbuffers[i]) {
+            if (mRboState.boundRenderbuffer == to_remove[i]) {
                 unbindCurrent = true;
                 break;
             }
+            view.remove(to_remove[i]->id);
         }
     }
 
@@ -2128,98 +2141,40 @@
 
     (void)target; // Must be GL_RENDERBUFFER
     RenderbufferInfo::ScopedView view(mRboState.rboData);
-    if (name == mRboState.boundRenderbuffer) {
-        return;
-    }
-    view.unref(mRboState.boundRenderbuffer);
-
-    mRboState.boundRenderbuffer = name;
-
-    if (!name) return;
-
-    view.bind(name);
+    mRboState.boundRenderbuffer = view.bind(name);
 }
 
 GLuint GLClientState::boundRenderbuffer() const {
-    return mRboState.boundRenderbuffer;
+    return mRboState.boundRenderbuffer->id;
 }
 
 void GLClientState::setBoundRenderbufferFormat(GLenum format) {
-    RenderbufferInfo::ScopedView view(mRboState.rboData);
-    RboProps* props = view.get(mRboState.boundRenderbuffer);
-    if (!props) return;
-    props->format = format;
+    mRboState.boundRenderbuffer->format = format;
 }
 
 void GLClientState::setBoundRenderbufferSamples(GLsizei samples) {
-    RenderbufferInfo::ScopedView view(mRboState.rboData);
-    RboProps* props = view.get(mRboState.boundRenderbuffer);
-    if (!props) return;
-    props->multisamples = samples;
+    mRboState.boundRenderbuffer->multisamples = samples;
 }
 
 void GLClientState::setBoundRenderbufferDimensions(GLsizei width, GLsizei height) {
-    RenderbufferInfo::ScopedView view(mRboState.rboData);
-    RboProps* props = view.get(mRboState.boundRenderbuffer);
-    if (!props) return;
-    props->width = width;
-    props->height = height;
+    mRboState.boundRenderbuffer->width = width;
+    mRboState.boundRenderbuffer->height = height;
 }
 
 void GLClientState::setBoundRenderbufferEGLImageBacked() {
-    RenderbufferInfo::ScopedView view(mRboState.rboData);
-    RboProps* props = view.get(mRboState.boundRenderbuffer);
-    if (!props) return;
-    props->boundEGLImage = true;
+    mRboState.boundRenderbuffer->boundEGLImage = true;
 }
 
 // FBO//////////////////////////////////////////////////////////////////////////
 
-// Format querying
-
-GLenum GLClientState::queryRboFormat(GLuint rbo_name) const {
-    RenderbufferInfo::ScopedView view(mRboState.rboData);
-    const RboProps* props = view.get(rbo_name);
-    if (!props) return 0;
-    return props->format;
-}
-
-GLsizei GLClientState::queryRboSamples(GLuint rbo_name) const {
-    RenderbufferInfo::ScopedView view(mRboState.rboData);
-    const RboProps* props = view.get(rbo_name);
-    if (!props) return 0;
-    return props->multisamples;
-}
-
-GLsizei GLClientState::queryRboWidth(GLuint rbo_name) const {
-    RenderbufferInfo::ScopedView view(mRboState.rboData);
-    const RboProps* props = view.get(rbo_name);
-    if (!props) return 0;
-    return props->width;
-}
-
-GLsizei GLClientState::queryRboHeight(GLuint rbo_name) const {
-    RenderbufferInfo::ScopedView view(mRboState.rboData);
-    const RboProps* props = view.get(rbo_name);
-    if (!props) return 0;
-    return props->height;
-}
-
-bool GLClientState::queryRboEGLImageBacked(GLuint rbo_name) const {
-    RenderbufferInfo::ScopedView view(mRboState.rboData);
-    const RboProps* props = view.get(rbo_name);
-    if (!props) return 0;
-    return props->boundEGLImage;
-}
-
 GLint GLClientState::queryTexInternalFormat(GLuint tex_name) const {
-    TextureRec* texrec = getTextureRec(tex_name);
+    TextureRec* texrec = getTextureRecPtr(tex_name);
     if (!texrec) return -1;
     return texrec->internalformat;
 }
 
 GLsizei GLClientState::queryTexWidth(GLsizei level, GLuint tex_name) const {
-    TextureRec* texrec = getTextureRec(tex_name);
+    TextureRec* texrec = getTextureRecPtr(tex_name);
     if (!texrec) {
         return 0;
     }
@@ -2227,43 +2182,43 @@
 }
 
 GLsizei GLClientState::queryTexHeight(GLsizei level, GLuint tex_name) const {
-    TextureRec* texrec = getTextureRec(tex_name);
+    TextureRec* texrec = getTextureRecPtr(tex_name);
     if (!texrec) return 0;
     return texrec->dims->heights[level];
 }
 
 GLsizei GLClientState::queryTexDepth(GLsizei level, GLuint tex_name) const {
-    TextureRec* texrec = getTextureRec(tex_name);
+    TextureRec* texrec = getTextureRecPtr(tex_name);
     if (!texrec) return 0;
     return texrec->dims->depths[level];
 }
 
 bool GLClientState::queryTexEGLImageBacked(GLuint tex_name) const {
-    TextureRec* texrec = getTextureRec(tex_name);
+    TextureRec* texrec = getTextureRecPtr(tex_name);
     if (!texrec) return false;
     return texrec->boundEGLImage;
 }
 
 GLenum GLClientState::queryTexFormat(GLuint tex_name) const {
-    TextureRec* texrec = getTextureRec(tex_name);
+    TextureRec* texrec = getTextureRecPtr(tex_name);
     if (!texrec) return -1;
     return texrec->format;
 }
 
 GLenum GLClientState::queryTexType(GLuint tex_name) const {
-    TextureRec* texrec = getTextureRec(tex_name);
+    TextureRec* texrec = getTextureRecPtr(tex_name);
     if (!texrec) return -1;
     return texrec->type;
 }
 
 GLsizei GLClientState::queryTexSamples(GLuint tex_name) const {
-    TextureRec* texrec = getTextureRec(tex_name);
+    TextureRec* texrec = getTextureRecPtr(tex_name);
     if (!texrec) return 0;
     return texrec->multisamples;
 }
 
 GLenum GLClientState::queryTexLastBoundTarget(GLuint tex_name) const {
-    TextureRec* texrec = getTextureRec(tex_name);
+    TextureRec* texrec = getTextureRecPtr(tex_name);
     if (!texrec) return GL_NONE;
     return texrec->target;
 }
@@ -2289,29 +2244,23 @@
     if (colorAttachmentIndex != -1) {
         if (props.colorAttachmenti_hasRbo[colorAttachmentIndex]) {
             res_info->type = FBO_ATTACHMENT_RENDERBUFFER;
-            res_info->rb_format =
-                queryRboFormat(
-                        props.colorAttachmenti_rbos[colorAttachmentIndex]);
+            res_info->rb_format = props.colorAttachmenti_rbos[colorAttachmentIndex]->format;
             res_info->rb_multisamples =
-                queryRboSamples(
-                        props.colorAttachmenti_rbos[colorAttachmentIndex]);
+                    props.colorAttachmenti_rbos[colorAttachmentIndex]->multisamples;
             res_info->rb_external =
-                queryRboEGLImageBacked(
-                        props.colorAttachmenti_rbos[colorAttachmentIndex]);
+                    props.colorAttachmenti_rbos[colorAttachmentIndex]->boundEGLImage;
         } else if (props.colorAttachmenti_hasTex[colorAttachmentIndex]) {
             res_info->type = FBO_ATTACHMENT_TEXTURE;
-            res_info->tex_external = queryTexEGLImageBacked(
-                    props.colorAttachmenti_textures[colorAttachmentIndex]);
+            res_info->tex_external =
+                    props.colorAttachmenti_textures[colorAttachmentIndex]->boundEGLImage;
             res_info->tex_internalformat =
-                queryTexInternalFormat(
-                        props.colorAttachmenti_textures[colorAttachmentIndex]);
+                    props.colorAttachmenti_textures[colorAttachmentIndex]->internalformat;
             res_info->tex_format =
-                queryTexFormat(
-                        props.colorAttachmenti_textures[colorAttachmentIndex]);
+                    props.colorAttachmenti_textures[colorAttachmentIndex]->format;
             res_info->tex_type =
-                queryTexType(props.colorAttachmenti_textures[colorAttachmentIndex]);
+                    props.colorAttachmenti_textures[colorAttachmentIndex]->type;
             res_info->tex_multisamples =
-                queryTexSamples(props.colorAttachmenti_textures[colorAttachmentIndex]);
+                    props.colorAttachmenti_textures[colorAttachmentIndex]->multisamples;
             res_info->tex_level = props.colorAttachmenti_texture_levels[colorAttachmentIndex];
             res_info->tex_layer = props.colorAttachmenti_texture_layers[colorAttachmentIndex];
         } else {
@@ -2323,21 +2272,16 @@
     case GL_DEPTH_ATTACHMENT:
         if (props.depthAttachment_hasRbo) {
             res_info->type = FBO_ATTACHMENT_RENDERBUFFER;
-            res_info->rb_format = queryRboFormat(props.depthAttachment_rbo);
-            res_info->rb_multisamples =
-                queryRboSamples(
-                        props.depthAttachment_rbo);
-            res_info->rb_external =
-                queryRboEGLImageBacked(
-                        props.depthAttachment_rbo);
+            res_info->rb_format = props.depthAttachment_rbo->format;
+            res_info->rb_multisamples = props.depthAttachment_rbo->multisamples;
+            res_info->rb_external = props.depthAttachment_rbo->boundEGLImage;
         } else if (props.depthAttachment_hasTexObj) {
             res_info->type = FBO_ATTACHMENT_TEXTURE;
-            res_info->tex_external = queryTexEGLImageBacked(props.depthAttachment_texture);
-            res_info->tex_internalformat = queryTexInternalFormat(props.depthAttachment_texture);
-            res_info->tex_format = queryTexFormat(props.depthAttachment_texture);
-            res_info->tex_type = queryTexType(props.depthAttachment_texture);
-            res_info->tex_multisamples =
-                queryTexSamples(props.depthAttachment_texture);
+            res_info->tex_external = props.depthAttachment_texture->boundEGLImage;
+            res_info->tex_internalformat = props.depthAttachment_texture->internalformat;
+            res_info->tex_format = props.depthAttachment_texture->format;
+            res_info->tex_type = props.depthAttachment_texture->type;
+            res_info->tex_multisamples = props.depthAttachment_texture->multisamples;
             res_info->tex_level = props.depthAttachment_texture_level;
             res_info->tex_layer = props.depthAttachment_texture_layer;
         } else {
@@ -2347,21 +2291,16 @@
     case GL_STENCIL_ATTACHMENT:
         if (props.stencilAttachment_hasRbo) {
             res_info->type = FBO_ATTACHMENT_RENDERBUFFER;
-            res_info->rb_format = queryRboFormat(props.stencilAttachment_rbo);
-            res_info->rb_multisamples =
-                queryRboSamples(
-                        props.stencilAttachment_rbo);
-            res_info->rb_external =
-                queryRboEGLImageBacked(
-                        props.stencilAttachment_rbo);
+            res_info->rb_format = props.stencilAttachment_rbo->format;
+            res_info->rb_multisamples = props.stencilAttachment_rbo->multisamples;
+            res_info->rb_external = props.stencilAttachment_rbo->boundEGLImage;
         } else if (props.stencilAttachment_hasTexObj) {
             res_info->type = FBO_ATTACHMENT_TEXTURE;
-            res_info->tex_external = queryTexEGLImageBacked(props.stencilAttachment_texture);
-            res_info->tex_internalformat = queryTexInternalFormat(props.stencilAttachment_texture);
-            res_info->tex_format = queryTexFormat(props.stencilAttachment_texture);
-            res_info->tex_type = queryTexType(props.stencilAttachment_texture);
-            res_info->tex_multisamples =
-                queryTexSamples(props.stencilAttachment_texture);
+            res_info->tex_external = props.stencilAttachment_texture->boundEGLImage;
+            res_info->tex_internalformat = props.stencilAttachment_texture->internalformat;
+            res_info->tex_format = props.stencilAttachment_texture->format;
+            res_info->tex_type = props.stencilAttachment_texture->type;
+            res_info->tex_multisamples = props.stencilAttachment_texture->multisamples;
             res_info->tex_level = props.depthAttachment_texture_level;
             res_info->tex_layer = props.depthAttachment_texture_layer;
         } else {
@@ -2371,21 +2310,16 @@
     case GL_DEPTH_STENCIL_ATTACHMENT:
         if (props.depthstencilAttachment_hasRbo) {
             res_info->type = FBO_ATTACHMENT_RENDERBUFFER;
-            res_info->rb_format = queryRboFormat(props.depthstencilAttachment_rbo);
-            res_info->rb_multisamples =
-                queryRboSamples(
-                        props.depthstencilAttachment_rbo);
-            res_info->rb_external =
-                queryRboEGLImageBacked(
-                        props.depthstencilAttachment_rbo);
+            res_info->rb_format = props.depthstencilAttachment_rbo->format;
+            res_info->rb_multisamples = props.depthstencilAttachment_rbo->multisamples;
+            res_info->rb_external = props.depthstencilAttachment_rbo->boundEGLImage;
         } else if (props.depthstencilAttachment_hasTexObj) {
             res_info->type = FBO_ATTACHMENT_TEXTURE;
-            res_info->tex_external = queryTexEGLImageBacked(props.depthstencilAttachment_texture);
-            res_info->tex_internalformat = queryTexInternalFormat(props.depthstencilAttachment_texture);
-            res_info->tex_format = queryTexFormat(props.depthstencilAttachment_texture);
-            res_info->tex_type = queryTexType(props.depthstencilAttachment_texture);
-            res_info->tex_multisamples =
-                queryTexSamples(props.depthstencilAttachment_texture);
+            res_info->tex_external = props.depthstencilAttachment_texture->boundEGLImage;
+            res_info->tex_internalformat = props.depthstencilAttachment_texture->internalformat;
+            res_info->tex_format = props.depthstencilAttachment_texture->format;
+            res_info->tex_type = props.depthstencilAttachment_texture->type;
+            res_info->tex_multisamples = props.depthstencilAttachment_texture->multisamples;
             res_info->tex_level = props.depthAttachment_texture_level;
             res_info->tex_layer = props.depthAttachment_texture_layer;
         } else {
@@ -2506,22 +2440,6 @@
             if (framebuffers[i] == mFboState.boundReadFramebuffer) {
                 bindFramebuffer(GL_READ_FRAMEBUFFER, 0);
             }
-            // Remove references to all attachments
-            auto fboProps = mFboState.fboData.find(framebuffers[i]);
-            if (fboProps != mFboState.fboData.end()) {
-                for (size_t j = 0; j < fboProps->second.colorAttachmenti_hasRbo.size(); j++) {
-                    view.unref(fboProps->second.colorAttachmenti_rbos[j]);
-                }
-                if (fboProps->second.depthAttachment_hasRbo && fboProps->second.depthAttachment_rbo) {
-                    view.unref(fboProps->second.depthAttachment_rbo);
-                }
-                if (fboProps->second.stencilAttachment_hasRbo && fboProps->second.stencilAttachment_rbo) {
-                    view.unref(fboProps->second.stencilAttachment_rbo);
-                }
-                if (fboProps->second.depthstencilAttachment_hasRbo && fboProps->second.depthstencilAttachment_rbo) {
-                    view.unref(fboProps->second.depthstencilAttachment_rbo);
-                }
-            }
             mFboState.fboData.erase(framebuffers[i]);
         }
     }
@@ -2625,6 +2543,7 @@
         GLenum attachment, GLuint texture, GLint level, GLint layer) {
 
     bool attach = texture != 0;
+    std::shared_ptr<TextureRec> texrec = getTextureRec(texture);
 
     int colorAttachmentIndex =
         glUtilsColorAttachmentIndex(attachment);
@@ -2632,7 +2551,7 @@
     boundFboProps(target).completenessDirty = true;
 
     if (colorAttachmentIndex != -1) {
-        boundFboProps(target).colorAttachmenti_textures[colorAttachmentIndex] = texture;
+        boundFboProps(target).colorAttachmenti_textures[colorAttachmentIndex] = texrec;
         boundFboProps(target).colorAttachmenti_texture_levels[colorAttachmentIndex] = level;
         boundFboProps(target).colorAttachmenti_texture_layers[colorAttachmentIndex] = layer;
         boundFboProps(target).colorAttachmenti_hasTex[colorAttachmentIndex] = attach;
@@ -2640,23 +2559,23 @@
 
     switch (attachment) {
     case GL_DEPTH_ATTACHMENT:
-        boundFboProps(target).depthAttachment_texture = texture;
+        boundFboProps(target).depthAttachment_texture = texrec;
         boundFboProps(target).depthAttachment_texture_level = level;
         boundFboProps(target).depthAttachment_texture_layer = layer;
         boundFboProps(target).depthAttachment_hasTexObj = attach;
         break;
     case GL_STENCIL_ATTACHMENT:
-        boundFboProps(target).stencilAttachment_texture = texture;
+        boundFboProps(target).stencilAttachment_texture = texrec;
         boundFboProps(target).stencilAttachment_texture_level = level;
         boundFboProps(target).stencilAttachment_texture_layer = layer;
         boundFboProps(target).stencilAttachment_hasTexObj = attach;
         break;
     case GL_DEPTH_STENCIL_ATTACHMENT:
-        boundFboProps(target).depthstencilAttachment_texture = texture;
+        boundFboProps(target).depthstencilAttachment_texture = texrec;
         boundFboProps(target).depthstencilAttachment_hasTexObj = attach;
-        boundFboProps(target).stencilAttachment_texture = texture;
+        boundFboProps(target).stencilAttachment_texture = texrec;
         boundFboProps(target).stencilAttachment_hasTexObj = attach;
-        boundFboProps(target).depthAttachment_texture = texture;
+        boundFboProps(target).depthAttachment_texture = texrec;
         boundFboProps(target).depthAttachment_hasTexObj = attach;
         boundFboProps(target).depthAttachment_texture_level = level;
         boundFboProps(target).depthAttachment_texture_layer = layer;
@@ -2666,8 +2585,8 @@
     }
 }
 
-GLuint GLClientState::getFboAttachmentTextureId(GLenum target, GLenum attachment) const {
-    GLuint res = 0; // conservative
+std::shared_ptr<TextureRec> GLClientState::getFboAttachmentTexture(GLenum target, GLenum attachment) const {
+    std::shared_ptr<TextureRec> res = {}; // conservative
 
     int colorAttachmentIndex =
         glUtilsColorAttachmentIndex(attachment);
@@ -2715,50 +2634,46 @@
     boundFboProps(target).completenessDirty = true;
 
     RenderbufferInfo::ScopedView view(mRboState.rboData);
+    auto renderBufferSharedPtr = view.get_shared_ptr(renderbuffer);
     if (colorAttachmentIndex != -1) {
         if (boundFboProps(target).colorAttachmenti_hasRbo[colorAttachmentIndex] &&
-            boundFboProps(target).colorAttachmenti_rbos[colorAttachmentIndex] == renderbuffer) {
-            boundFboProps(target).colorAttachmenti_rbos[colorAttachmentIndex] = 0;
+            boundFboProps(target).colorAttachmenti_rbos[colorAttachmentIndex]
+                    == renderBufferSharedPtr) {
+            boundFboProps(target).colorAttachmenti_rbos[colorAttachmentIndex] = nullptr;
             boundFboProps(target).colorAttachmenti_hasRbo[colorAttachmentIndex] = false;
-            view.unref(renderbuffer);
         }
     }
 
     switch (attachment) {
     case GL_DEPTH_ATTACHMENT:
-        if (boundFboProps(target).depthAttachment_rbo == renderbuffer &&
+        if (boundFboProps(target).depthAttachment_rbo == renderBufferSharedPtr &&
             boundFboProps(target).depthAttachment_hasRbo) {
-            boundFboProps(target).depthAttachment_rbo = 0;
+            boundFboProps(target).depthAttachment_rbo = nullptr;
             boundFboProps(target).depthAttachment_hasRbo = false;
-            view.unref(renderbuffer);
         }
         break;
     case GL_STENCIL_ATTACHMENT:
-        if (boundFboProps(target).stencilAttachment_rbo == renderbuffer &&
+        if (boundFboProps(target).stencilAttachment_rbo == renderBufferSharedPtr &&
             boundFboProps(target).stencilAttachment_hasRbo) {
-            boundFboProps(target).stencilAttachment_rbo = 0;
+            boundFboProps(target).stencilAttachment_rbo = nullptr;
             boundFboProps(target).stencilAttachment_hasRbo = false;
-            view.unref(renderbuffer);
         }
         break;
     case GL_DEPTH_STENCIL_ATTACHMENT:
-        if (boundFboProps(target).depthAttachment_rbo == renderbuffer &&
+        if (boundFboProps(target).depthAttachment_rbo == renderBufferSharedPtr &&
             boundFboProps(target).depthAttachment_hasRbo) {
-            boundFboProps(target).depthAttachment_rbo = 0;
+            boundFboProps(target).depthAttachment_rbo = nullptr;
             boundFboProps(target).depthAttachment_hasRbo = false;
-            view.unref(renderbuffer);
         }
-        if (boundFboProps(target).stencilAttachment_rbo == renderbuffer &&
+        if (boundFboProps(target).stencilAttachment_rbo == renderBufferSharedPtr &&
             boundFboProps(target).stencilAttachment_hasRbo) {
-            boundFboProps(target).stencilAttachment_rbo = 0;
+            boundFboProps(target).stencilAttachment_rbo = nullptr;
             boundFboProps(target).stencilAttachment_hasRbo = false;
-            view.unref(renderbuffer);
         }
-        if (boundFboProps(target).depthstencilAttachment_rbo == renderbuffer &&
+        if (boundFboProps(target).depthstencilAttachment_rbo == renderBufferSharedPtr &&
             boundFboProps(target).depthstencilAttachment_hasRbo) {
-            boundFboProps(target).depthstencilAttachment_rbo = 0;
+            boundFboProps(target).depthstencilAttachment_rbo = nullptr;
             boundFboProps(target).depthstencilAttachment_hasRbo = false;
-            view.unref(renderbuffer);
         }
         break;
     }
@@ -2774,74 +2689,61 @@
     boundFboProps(target).completenessDirty = true;
 
     RenderbufferInfo::ScopedView view(mRboState.rboData);
+    auto rboSharedPtr = view.get_or_add_shared_ptr(renderbuffer);
     if (colorAttachmentIndex != -1) {
-        view.unref(boundFboProps(target).colorAttachmenti_rbos[colorAttachmentIndex]);
-        view.ref(renderbuffer);
-        boundFboProps(target).colorAttachmenti_rbos[colorAttachmentIndex] = renderbuffer;
+        boundFboProps(target).colorAttachmenti_rbos[colorAttachmentIndex] = rboSharedPtr;
         boundFboProps(target).colorAttachmenti_hasRbo[colorAttachmentIndex] = attach;
     }
 
     switch (attachment) {
     case GL_DEPTH_ATTACHMENT:
-        view.unref(boundFboProps(target).depthAttachment_rbo);
-        view.ref(renderbuffer);
-        boundFboProps(target).depthAttachment_rbo = renderbuffer;
+        boundFboProps(target).depthAttachment_rbo = rboSharedPtr;
         boundFboProps(target).depthAttachment_hasRbo = attach;
         break;
     case GL_STENCIL_ATTACHMENT:
-        view.unref(boundFboProps(target).stencilAttachment_rbo);
-        view.ref(renderbuffer);
-        boundFboProps(target).stencilAttachment_rbo = renderbuffer;
+        boundFboProps(target).stencilAttachment_rbo = rboSharedPtr;
         boundFboProps(target).stencilAttachment_hasRbo = attach;
         break;
     case GL_DEPTH_STENCIL_ATTACHMENT:
-        view.unref(boundFboProps(target).depthAttachment_rbo);
-        view.ref(renderbuffer);
-        view.unref(boundFboProps(target).stencilAttachment_rbo);
-        view.ref(renderbuffer);
-        view.unref(boundFboProps(target).depthstencilAttachment_rbo);
-        view.ref(renderbuffer);
-        boundFboProps(target).depthAttachment_rbo = renderbuffer;
+        boundFboProps(target).depthAttachment_rbo = rboSharedPtr;
         boundFboProps(target).depthAttachment_hasRbo = attach;
-        boundFboProps(target).stencilAttachment_rbo = renderbuffer;
+        boundFboProps(target).stencilAttachment_rbo = rboSharedPtr;
         boundFboProps(target).stencilAttachment_hasRbo = attach;
-        boundFboProps(target).depthstencilAttachment_rbo = renderbuffer;
+        boundFboProps(target).depthstencilAttachment_rbo = rboSharedPtr;
         boundFboProps(target).depthstencilAttachment_hasRbo = attach;
         break;
     }
 }
 
-GLuint GLClientState::getFboAttachmentRboId(GLenum target, GLenum attachment) const {
-    GLuint res = 0; // conservative
-
+std::shared_ptr<RboProps> GLClientState::getFboAttachmentRbo(GLenum target, GLenum attachment) const {
     int colorAttachmentIndex =
         glUtilsColorAttachmentIndex(attachment);
 
     if (colorAttachmentIndex != -1) {
-        res = boundFboProps_const(target).colorAttachmenti_rbos[colorAttachmentIndex];
+        return boundFboProps_const(target).colorAttachmenti_rbos[colorAttachmentIndex];
     }
 
     switch (attachment) {
     case GL_DEPTH_ATTACHMENT:
-        res = boundFboProps_const(target).depthAttachment_rbo;
-        break;
+        return  boundFboProps_const(target).depthAttachment_rbo;
     case GL_STENCIL_ATTACHMENT:
-        res = boundFboProps_const(target).stencilAttachment_rbo;
-        break;
+        return  boundFboProps_const(target).stencilAttachment_rbo;
     case GL_DEPTH_STENCIL_ATTACHMENT:
-        res = boundFboProps_const(target).depthstencilAttachment_rbo;
-        break;
+        return  boundFboProps_const(target).depthstencilAttachment_rbo;
     }
-    return res;
+
+    // Bad attachment enum. Should be unreachable.
+    return nullptr;
 }
 
 void GLClientState::setFboCompletenessDirtyForTexture(GLuint texture) {
+    std::shared_ptr<TextureRec> texrec = getTextureRec(texture);
     std::map<GLuint, FboProps>::iterator it = mFboState.fboData.begin();
     while (it != mFboState.fboData.end()) {
         FboProps& props = it->second;
         for (int i = 0; i < m_hostDriverCaps.max_color_attachments; ++i) {
             if (props.colorAttachmenti_hasTex[i]) {
-                if (texture == props.colorAttachmenti_textures[i]) {
+                if (texrec == props.colorAttachmenti_textures[i]) {
                     props.completenessDirty = true;
                     return;
                 }
@@ -2849,21 +2751,21 @@
         }
 
         if (props.depthAttachment_hasTexObj) {
-            if (texture == props.depthAttachment_texture) {
+            if (texrec == props.depthAttachment_texture) {
                     props.completenessDirty = true;
                     return;
             }
         }
 
         if (props.stencilAttachment_hasTexObj) {
-            if (texture == props.stencilAttachment_texture) {
+            if (texrec == props.stencilAttachment_texture) {
                 props.completenessDirty = true;
                 return;
             }
         }
 
         if (props.depthstencilAttachment_hasTexObj) {
-            if (texture == props.depthstencilAttachment_texture) {
+            if (texrec == props.depthstencilAttachment_texture) {
                 props.completenessDirty = true;
                 return;
             }
@@ -2872,12 +2774,12 @@
     }
 }
 
-void GLClientState::setFboCompletenessDirtyForRbo(GLuint rbo) {
+void GLClientState::setFboCompletenessDirtyForRbo(std::shared_ptr<RboProps> rbo) {
     std::map<GLuint, FboProps>::iterator it = mFboState.fboData.begin();
     while (it != mFboState.fboData.end()) {
         FboProps& props = it->second;
         for (int i = 0; i < m_hostDriverCaps.max_color_attachments; ++i) {
-            if (props.colorAttachmenti_hasTex[i]) {
+            if (props.colorAttachmenti_hasRbo[i]) {
                 if (rbo == props.colorAttachmenti_rbos[i]) {
                     props.completenessDirty = true;
                     return;
@@ -2885,14 +2787,14 @@
             }
         }
 
-        if (props.depthAttachment_hasTexObj) {
+        if (props.depthAttachment_hasRbo) {
             if (rbo == props.depthAttachment_rbo) {
                     props.completenessDirty = true;
                     return;
             }
         }
 
-        if (props.stencilAttachment_hasTexObj) {
+        if (props.stencilAttachment_hasRbo) {
             if (rbo == props.stencilAttachment_rbo) {
                 props.completenessDirty = true;
                 return;
@@ -2937,51 +2839,21 @@
     return res;
 }
 
-GLuint GLClientState::objectOfAttachment(GLenum target, GLenum attachment) const {
+bool GLClientState::depthStencilHasSameObject(GLenum target) const {
     const FboProps& props = boundFboProps_const(target);
 
-    int colorAttachmentIndex =
-        glUtilsColorAttachmentIndex(attachment);
-
-    if (colorAttachmentIndex != -1) {
-        if (props.colorAttachmenti_hasTex[colorAttachmentIndex]) {
-            return props.colorAttachmenti_textures[colorAttachmentIndex];
-        } else if (props.colorAttachmenti_hasRbo[colorAttachmentIndex]) {
-            return props.colorAttachmenti_rbos[colorAttachmentIndex];
-        } else {
-            return 0;
-        }
+    if (props.depthAttachment_hasTexObj != props.stencilAttachment_hasTexObj
+            || props.depthAttachment_hasRbo != props.stencilAttachment_hasRbo) {
+        return false;
     }
-
-    switch (attachment) {
-    case GL_DEPTH_ATTACHMENT:
-        if (props.depthAttachment_hasTexObj) {
-            return props.depthAttachment_texture;
-        } else if (props.depthAttachment_hasRbo) {
-            return props.depthAttachment_rbo;
-        } else {
-            return 0;
-        }
-        break;
-    case GL_STENCIL_ATTACHMENT:
-        if (props.stencilAttachment_hasTexObj) {
-            return props.stencilAttachment_texture;
-        } else if (props.stencilAttachment_hasRbo) {
-            return props.stencilAttachment_rbo;
-        } else {
-            return 0;
-        }
-    case GL_DEPTH_STENCIL_ATTACHMENT:
-        if (props.depthstencilAttachment_hasTexObj) {
-            return props.depthstencilAttachment_texture;
-        } else if (props.depthstencilAttachment_hasRbo) {
-            return props.depthstencilAttachment_rbo;
-        } else {
-            return 0;
-        }
-        break;
+    if (props.depthAttachment_hasTexObj) {
+        return props.depthAttachment_texture == props.stencilAttachment_texture;
     }
-    return 0;
+    if (props.depthAttachment_hasRbo) {
+        return props.depthAttachment_rbo == props.stencilAttachment_rbo;
+    }
+    // No attachment in either
+    return true;
 }
 
 void GLClientState::setTransformFeedbackActive(bool active) {
@@ -3056,6 +2928,11 @@
 
 void GLClientState::setRenderbufferInfo(RenderbufferInfo* rbInfo) {
     mRboState.rboData = rbInfo;
+    if (rbInfo) {
+        RenderbufferInfo::ScopedView view(mRboState.rboData);
+        auto rbo = view.get_or_add_shared_ptr(0);
+        mRboState.boundRenderbuffer = rbo;
+    }
 }
 
 void GLClientState::setSamplerInfo(SamplerInfo* samplerInfo) {
@@ -3072,6 +2949,19 @@
 void GLClientState::fromMakeCurrent() {
     if (mFboState.fboData.find(0) == mFboState.fboData.end()) {
         addFreshFramebuffer(0);
+        FboProps& default_fb_props = mFboState.fboData[0];
+        default_fb_props.colorAttachmenti_hasRbo[0] = true;
+        default_fb_props.depthAttachment_hasRbo = true;
+        default_fb_props.stencilAttachment_hasRbo = true;
+        default_fb_props.depthstencilAttachment_hasRbo = true;
+        RenderbufferInfo::ScopedView view(mRboState.rboData);
+        // Use RBO 0 as placeholder
+        auto rbo0 = view.get_or_add_shared_ptr(0);
+        default_fb_props.colorAttachmenti_rbos[0] = rbo0;
+        default_fb_props.depthAttachment_rbo = rbo0;
+        default_fb_props.stencilAttachment_rbo = rbo0;
+        default_fb_props.depthstencilAttachment_rbo = rbo0;
+
     }
 
     if (!samplerExists(0)) {
@@ -3079,11 +2969,6 @@
         setExistence(ObjectType::Sampler, true, 1, &id);
     }
 
-    FboProps& default_fb_props = mFboState.fboData[0];
-    default_fb_props.colorAttachmenti_hasRbo[0] = true;
-    default_fb_props.depthAttachment_hasRbo = true;
-    default_fb_props.stencilAttachment_hasRbo = true;
-    default_fb_props.depthstencilAttachment_hasRbo = true;
 }
 
 void GLClientState::initFromCaps(
diff --git a/shared/OpenglCodecCommon/GLClientState.h b/shared/OpenglCodecCommon/GLClientState.h
index a9da8d0..0639962 100644
--- a/shared/OpenglCodecCommon/GLClientState.h
+++ b/shared/OpenglCodecCommon/GLClientState.h
@@ -40,6 +40,7 @@
 
 #include <vector>
 #include <map>
+#include <memory>
 #include <set>
 #include <string>
 
@@ -81,7 +82,7 @@
     bool previouslyBound;
     bool completenessDirty;
     GLenum cachedCompleteness;
-    std::vector<GLuint> colorAttachmenti_textures;
+    std::vector<std::shared_ptr<TextureRec>> colorAttachmenti_textures;
     std::vector<GLint> colorAttachmenti_texture_levels;
     std::vector<GLint> colorAttachmenti_texture_layers;
 
@@ -90,19 +91,19 @@
     GLint stencilAttachment_texture_level;
     GLint stencilAttachment_texture_layer;
 
-    GLuint depthAttachment_texture;
-    GLuint stencilAttachment_texture;
-    GLuint depthstencilAttachment_texture;
+    std::shared_ptr<TextureRec> depthAttachment_texture;
+    std::shared_ptr<TextureRec> stencilAttachment_texture;
+    std::shared_ptr<TextureRec> depthstencilAttachment_texture;
 
     std::vector<bool> colorAttachmenti_hasTex;
     bool depthAttachment_hasTexObj;
     bool stencilAttachment_hasTexObj;
     bool depthstencilAttachment_hasTexObj;
 
-    std::vector<GLuint> colorAttachmenti_rbos;
-    GLuint depthAttachment_rbo = 0;
-    GLuint stencilAttachment_rbo = 0;
-    GLuint depthstencilAttachment_rbo = 0;
+    std::vector<std::shared_ptr<RboProps>> colorAttachmenti_rbos;
+    std::shared_ptr<RboProps> depthAttachment_rbo = 0;
+    std::shared_ptr<RboProps> stencilAttachment_rbo = 0;
+    std::shared_ptr<RboProps> depthstencilAttachment_rbo = 0;
 
     std::vector<bool> colorAttachmenti_hasRbo;
     bool depthAttachment_hasRbo = false;
@@ -489,21 +490,21 @@
 
     // Texture object -> FBO
     void attachTextureObject(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
-    GLuint getFboAttachmentTextureId(GLenum target, GLenum attachment) const;
+    std::shared_ptr<TextureRec> getFboAttachmentTexture(GLenum target, GLenum attachment) const;
 
     // RBO -> FBO
     void detachRbo(GLuint renderbuffer);
     void detachRboFromFbo(GLenum target, GLenum attachment, GLuint renderbuffer);
     void attachRbo(GLenum target, GLenum attachment, GLuint renderbuffer);
-    GLuint getFboAttachmentRboId(GLenum target, GLenum attachment) const;
+    std::shared_ptr<RboProps> getFboAttachmentRbo(GLenum target, GLenum attachment) const;
 
     // FBO attachments in general
     bool attachmentHasObject(GLenum target, GLenum attachment) const;
-    GLuint objectOfAttachment(GLenum target, GLenum attachment) const;
+    bool depthStencilHasSameObject(GLenum target) const;
 
     // Dirty FBO completeness
     void setFboCompletenessDirtyForTexture(GLuint texture);
-    void setFboCompletenessDirtyForRbo(GLuint rbo_name);
+    void setFboCompletenessDirtyForRbo(std::shared_ptr<RboProps> rbo);
 
     // Transform feedback state
     void setTransformFeedbackActive(bool active);
@@ -712,7 +713,7 @@
                                     GLenum internalformat);
 
     struct RboState {
-        GLuint boundRenderbuffer;
+        std::shared_ptr<RboProps> boundRenderbuffer;
         // Connects to share group.
         // Expected that share group lifetime outlives this context.
         RenderbufferInfo* rboData;
@@ -734,18 +735,14 @@
     const FboProps& boundFboProps_const(GLenum target) const;
 
     // Querying framebuffer format
-    GLenum queryRboFormat(GLuint name) const;
-    GLsizei queryRboSamples(GLuint name) const;
-    GLsizei queryRboWidth(GLuint name) const;
-    GLsizei queryRboHeight(GLuint name) const;
-    bool queryRboEGLImageBacked(GLuint name) const;
     GLenum queryTexType(GLuint name) const;
     GLsizei queryTexSamples(GLuint name) const;
 
     static int compareTexId(const void* pid, const void* prec);
     TextureRec* addTextureRec(GLuint id, GLenum target);
-    TextureRec* getTextureRec(GLuint id) const;
-    TextureRec* getTextureRecLocked(GLuint id) const;
+    std::shared_ptr<TextureRec> getTextureRec(GLuint id) const;
+    TextureRec* getTextureRecPtr(GLuint id) const;
+    TextureRec* getTextureRecPtrLocked(GLuint id) const;
 
 public:
     bool isTexture(GLuint name) const;
diff --git a/shared/OpenglCodecCommon/StateTrackingSupport.h b/shared/OpenglCodecCommon/StateTrackingSupport.h
index 7a009d8..6ed8460 100644
--- a/shared/OpenglCodecCommon/StateTrackingSupport.h
+++ b/shared/OpenglCodecCommon/StateTrackingSupport.h
@@ -20,6 +20,7 @@
 #include "android/base/synchronization/AndroidLock.h"
 
 #include <GLES2/gl2.h>
+#include <memory>
 
 template <class IndexType, bool initialIsTrue>
 class PredicateMap {
@@ -104,8 +105,8 @@
     GLsizei width;
     GLsizei height;
     bool previouslyBound;
-    uint32_t refcount;
     bool boundEGLImage;
+    GLuint id;
 };
 
 struct SamplerProps {
@@ -130,7 +131,7 @@
 
 struct RenderbufferInfo {
     android::base::guest::Lock infoLock;
-    android::base::HybridComponentManager<1000, uint32_t, RboProps> component;
+    android::base::HybridComponentManager<1000, uint32_t, std::shared_ptr<RboProps>> component;
 
     void lock() { infoLock.lock(); }
     void unlock() { infoLock.unlock(); }
@@ -139,62 +140,63 @@
         public:
             ScopedView(RenderbufferInfo* info) : ScopedLockedView<RenderbufferInfo>(info) { }
             bool hasRbo(GLuint id) const {
-                const RboProps* info = internalInfo_const()->component.get_const(id);
-                if (!info) return false;
-                return 0 != info->refcount;
+                return nullptr != internalInfo_const()->component.get_const(id);
             }
             virtual ~ScopedView() = default;
             RboProps* get(GLuint id) {
-                return internalInfo()->component.get(id);
+                auto rboPropPtr = internalInfo()->component.get(id);
+                if (!rboPropPtr) {
+                    return nullptr;
+                }
+                return rboPropPtr->get();
+            }
+            std::shared_ptr<RboProps> get_or_add_shared_ptr(GLuint id) {
+                auto rboPropPtr = internalInfo()->component.get(id);
+                if (!rboPropPtr) {
+                    addFresh(id);
+                    rboPropPtr = internalInfo()->component.get(id);
+                }
+                return *rboPropPtr;
+            }
+            std::shared_ptr<RboProps> get_shared_ptr(GLuint id) {
+                auto rboPropPtr = internalInfo()->component.get(id);
+                if (!internalInfo()->component.get(id)) {
+                    return nullptr;
+                }
+                return *rboPropPtr;
             }
             const RboProps* get_const(GLuint id) {
-                return internalInfo_const()->component.get_const(id);
+                auto rboPropPtr = internalInfo()->component.get_const(id);
+                if (!rboPropPtr) {
+                    return nullptr;
+                }
+                return rboPropPtr->get();
             }
             void addFresh(GLuint id) {
-                RboProps props;
-                props.format = GL_NONE;
-                props.multisamples = 0;
-                props.width = 0;
-                props.height = 0;
-                props.previouslyBound = false;
-                props.refcount = 1;
-                props.boundEGLImage = false;
-                internalInfo()->component.add(id, props);
+                std::shared_ptr<RboProps> props(new RboProps());
+                props->format = GL_NONE;
+                props->multisamples = 0;
+                props->width = 0;
+                props->height = 0;
+                props->previouslyBound = false;
+                props->boundEGLImage = false;
+                props->id = id;
+                internalInfo()->component.add(id, std::move(props));
             }
-            RboProps* bind(GLuint id) {
-                if (!hasRbo(id)) addFresh(id);
-                ref(id);
-                RboProps* res = get(id);
+            std::shared_ptr<RboProps> bind(GLuint id) {
+                auto res = get_shared_ptr(id);
+                if (!res) {
+                    addFresh(id);
+                    res = get_shared_ptr(id);
+                }
                 res->previouslyBound = true;
                 return res;
             }
-            void ref(GLuint id) {
+            void remove(GLuint id) {
                 if (id == 0) {
                     return;
                 }
-                if (!hasRbo(id)) addFresh(id);
-                RboProps* props = get(id);
-                if (!props) return;
-                ++props->refcount;
-            }
-            bool unref(GLuint id) {
-                if (id == 0) {
-                    return false;
-                }
-                RboProps* props = get(id);
-                if (!props) return false;
-                if (!props->refcount) return false;
-                --props->refcount;
-                bool gone = 0 == props->refcount;
-                if (gone) {
-                    props->format = 0;
-                    props->multisamples = 0;
-                    props->width = 0;
-                    props->height = 0;
-                    props->previouslyBound = false;
-                    props->boundEGLImage = false;
-                }
-                return gone;
+                internalInfo()->component.remove(id);
             }
     };
 };
diff --git a/shared/OpenglCodecCommon/TextureSharedData.h b/shared/OpenglCodecCommon/TextureSharedData.h
index aee1996..fafb435 100644
--- a/shared/OpenglCodecCommon/TextureSharedData.h
+++ b/shared/OpenglCodecCommon/TextureSharedData.h
@@ -18,6 +18,7 @@
 
 #include <GLES/gl.h>
 #include <map>
+#include <memory>
 
 #include "android/base/synchronization/AndroidLock.h"
 
@@ -49,7 +50,7 @@
 };
 
 struct SharedTextureDataMap {
-  using MapType = std::map<GLuint, TextureRec*>;
+  using MapType = std::map<GLuint, std::shared_ptr<TextureRec>>;
 
   using iterator = MapType::iterator;
   using const_iterator = MapType::const_iterator;
diff --git a/system/GLESv2_enc/GL2Encoder.cpp b/system/GLESv2_enc/GL2Encoder.cpp
index 382274c..63b4ff4 100755
--- a/system/GLESv2_enc/GL2Encoder.cpp
+++ b/system/GLESv2_enc/GL2Encoder.cpp
@@ -3091,8 +3091,7 @@
         GL_INVALID_ENUM);
     SET_ERROR_IF(attachment == GL_DEPTH_STENCIL_ATTACHMENT &&
                  pname == GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME &&
-                 (state->objectOfAttachment(target, GL_DEPTH_ATTACHMENT) !=
-                  state->objectOfAttachment(target, GL_STENCIL_ATTACHMENT)),
+                 !state->depthStencilHasSameObject(target),
                  GL_INVALID_OPERATION);
     SET_ERROR_IF(state->boundFramebuffer(target) &&
                  (attachment == GL_BACK ||
diff --git a/system/OpenglSystemCommon/HostConnection.cpp b/system/OpenglSystemCommon/HostConnection.cpp
index ac7ef15..9d41be4 100644
--- a/system/OpenglSystemCommon/HostConnection.cpp
+++ b/system/OpenglSystemCommon/HostConnection.cpp
@@ -745,7 +745,8 @@
         queryAndSetHWCMultiConfigs(rcEnc);
         queryVersion(rcEnc);
         if (m_processPipe) {
-            m_processPipe->processPipeInit(m_rendernodeFd, m_connectionType, rcEnc);
+            auto fd = (m_connectionType == HOST_CONNECTION_VIRTIO_GPU_ADDRESS_SPACE) ? m_rendernodeFd : -1;
+            m_processPipe->processPipeInit(fd, m_connectionType, rcEnc);
         }
     }
     return m_rcEnc.get();
diff --git a/system/codecs/c2/decoders/avcdec/Android.bp b/system/codecs/c2/decoders/avcdec/Android.bp
index 78ffd82..5d840b0 100644
--- a/system/codecs/c2/decoders/avcdec/Android.bp
+++ b/system/codecs/c2/decoders/avcdec/Android.bp
@@ -15,6 +15,7 @@
     ],
 
     srcs: ["C2GoldfishAvcDec.cpp",
+        "GoldfishH264Helper.cpp",
         "MediaH264Decoder.cpp",
     ],
 
@@ -27,4 +28,7 @@
    header_libs: [
     "libgralloc_cb.ranchu",
     ],
+
+   static_libs: ["libavcdec",
+   ],
 }
diff --git a/system/codecs/c2/decoders/avcdec/C2GoldfishAvcDec.cpp b/system/codecs/c2/decoders/avcdec/C2GoldfishAvcDec.cpp
index 93bd079..90b5653 100644
--- a/system/codecs/c2/decoders/avcdec/C2GoldfishAvcDec.cpp
+++ b/system/codecs/c2/decoders/avcdec/C2GoldfishAvcDec.cpp
@@ -670,31 +670,14 @@
 void C2GoldfishAvcDec::checkMode(const std::shared_ptr<C2BlockPool> &pool) {
     mWidth = mIntf->width();
     mHeight = mIntf->height();
-    {
-        // now get the block
-        constexpr uint32_t format = HAL_PIXEL_FORMAT_YCBCR_420_888;
-        std::shared_ptr<C2GraphicBlock> block;
-        C2MemoryUsage usage = {C2MemoryUsage::CPU_READ,
-                               C2MemoryUsage::CPU_WRITE};
-        usage.expected = (uint64_t)(BufferUsage::VIDEO_DECODER);
-
-        c2_status_t err = pool->fetchGraphicBlock(align(mWidth, 16), mHeight,
-                                                  format, usage, &block);
-        if (err != C2_OK) {
-            ALOGE("fetchGraphicBlock for Output failed with status %d", err);
-            return;
-        }
-        auto c2Handle = block->handle();
-        native_handle_t *grallocHandle =
-            UnwrapNativeCodec2GrallocHandle(c2Handle);
-        int hostColorBufferId = getColorBufferHandle(grallocHandle);
-        if (hostColorBufferId > 0) {
-            DDD("decoding to host color buffer");
-            mEnableAndroidNativeBuffers = true;
-        } else {
-            DDD("decoding to guest byte buffer");
-            mEnableAndroidNativeBuffers = false;
-        }
+    const bool isGraphic = (pool->getAllocatorId() & C2Allocator::GRAPHIC);
+    DDD("buffer id %d", (int)(pool->getAllocatorId()));
+    if (isGraphic) {
+        DDD("decoding to host color buffer");
+        mEnableAndroidNativeBuffers = true;
+    } else {
+        DDD("decoding to guest byte buffer");
+        mEnableAndroidNativeBuffers = false;
     }
 }
 
@@ -894,11 +877,6 @@
                 return;
             }
 
-            if (false == mHeaderDecoded) {
-                /* Decode header and get dimensions */
-                setParams(mStride);
-            }
-
             DDD("flag is %x", work->input.flags);
             if (work->input.flags & C2FrameData::FLAG_CODEC_CONFIG) {
                 hasPicture = false;
@@ -913,9 +891,50 @@
                 removePts(mPts);
             }
 
+            bool whChanged = false;
+            if (GoldfishH264Helper::isSpsFrame(mInPBuffer, mInPBufferSize)) {
+                mH264Helper.reset(new GoldfishH264Helper(mWidth, mHeight));
+                whChanged = mH264Helper->decodeHeader(mInPBuffer, mInPBufferSize);
+                if (whChanged) {
+                        DDD("w changed from old %d to new %d\n", mWidth, mH264Helper->getWidth());
+                        DDD("h changed from old %d to new %d\n", mHeight, mH264Helper->getHeight());
+                        if (1) {
+                            drainInternal(DRAIN_COMPONENT_NO_EOS, pool, work);
+                            resetDecoder();
+                            resetPlugin();
+                            work->workletsProcessed = 0u;
+                        }
+                        {
+                            mWidth = mH264Helper->getWidth();
+                            mHeight = mH264Helper->getHeight();
+                            C2StreamPictureSizeInfo::output size(0u, mWidth, mHeight);
+                            std::vector<std::unique_ptr<C2SettingResult>> failures;
+                            c2_status_t err = mIntf->config({&size}, C2_MAY_BLOCK, &failures);
+                            if (err == OK) {
+                                work->worklets.front()->output.configUpdate.push_back(
+                                        C2Param::Copy(size));
+                                ensureDecoderState(pool);
+                            } else {
+                                ALOGE("Cannot set width and height");
+                                mSignalledError = true;
+                                work->workletsProcessed = 1u;
+                                work->result = C2_CORRUPTED;
+                                return;
+                            }
+                        }
+                        if (!mContext) {
+                            DDD("creating decoder context to host in process work");
+                            checkMode(pool);
+                            createDecoder();
+                        }
+                        continue;
+                } // end of whChanged
+            } // end of isSpsFrame
+
             uint32_t delay;
             GETTIME(&mTimeStart, nullptr);
             TIME_DIFF(mTimeEnd, mTimeStart, delay);
+            (void)delay;
             //(void) ivdec_api_function(mDecHandle, &s_decode_ip, &s_decode_op);
             DDD("decoding");
             h264_result_t h264Res =
@@ -932,44 +951,10 @@
             uint32_t decodeTime;
             GETTIME(&mTimeEnd, nullptr);
             TIME_DIFF(mTimeStart, mTimeEnd, decodeTime);
+            (void)decodeTime;
         }
-        // TODO: handle res change
-        if (0) {
-            DDD("resolution changed");
-            drainInternal(DRAIN_COMPONENT_NO_EOS, pool, work);
-            resetDecoder();
-            resetPlugin();
-            work->workletsProcessed = 0u;
 
-            /* Decode header and get new dimensions */
-            setParams(mStride);
-            //            (void) ivdec_api_function(mDecHandle, &s_decode_ip,
-            //            &s_decode_op);
-        }
         if (mImg.data != nullptr) {
-            // check for new width and height
-            auto decodedW = mImg.width;
-            auto decodedH = mImg.height;
-            if (decodedW != mWidth || decodedH != mHeight) {
-                mWidth = decodedW;
-                mHeight = decodedH;
-
-                C2StreamPictureSizeInfo::output size(0u, mWidth, mHeight);
-                std::vector<std::unique_ptr<C2SettingResult>> failures;
-                c2_status_t err = mIntf->config({&size}, C2_MAY_BLOCK, &failures);
-                if (err == OK) {
-                    work->worklets.front()->output.configUpdate.push_back(
-                        C2Param::Copy(size));
-                    ensureDecoderState(pool);
-                } else {
-                    ALOGE("Cannot set width and height");
-                    mSignalledError = true;
-                    work->workletsProcessed = 1u;
-                    work->result = C2_CORRUPTED;
-                    return;
-                }
-            }
-
             DDD("got data %" PRIu64 " with pts %" PRIu64,  getWorkIndex(mImg.pts), mImg.pts);
             mHeaderDecoded = true;
             copyImageData(mImg);
diff --git a/system/codecs/c2/decoders/avcdec/C2GoldfishAvcDec.h b/system/codecs/c2/decoders/avcdec/C2GoldfishAvcDec.h
index 914a10e..afa27f5 100644
--- a/system/codecs/c2/decoders/avcdec/C2GoldfishAvcDec.h
+++ b/system/codecs/c2/decoders/avcdec/C2GoldfishAvcDec.h
@@ -22,6 +22,7 @@
 #include <media/stagefright/foundation/ColorUtils.h>
 
 #include "MediaH264Decoder.h"
+#include "GoldfishH264Helper.h"
 #include <SimpleC2Component.h>
 #include <atomic>
 #include <map>
@@ -152,6 +153,8 @@
     std::vector<uint8_t> mCsd1;
     void decodeHeaderAfterFlush();
 
+    std::unique_ptr<GoldfishH264Helper> mH264Helper;
+
     C2_DO_NOT_COPY(C2GoldfishAvcDec);
 };
 
diff --git a/system/codecs/c2/decoders/avcdec/GoldfishH264Helper.cpp b/system/codecs/c2/decoders/avcdec/GoldfishH264Helper.cpp
new file mode 100644
index 0000000..077ef15
--- /dev/null
+++ b/system/codecs/c2/decoders/avcdec/GoldfishH264Helper.cpp
@@ -0,0 +1,311 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "GoldfishH264Helper.h"
+
+#define LOG_TAG "GoldfishH264Helper"
+#include <log/log.h>
+
+
+#define DEBUG 0
+#if DEBUG
+#define DDD(...) ALOGD(__VA_ARGS__)
+#else
+#define DDD(...) ((void)0)
+#endif
+
+
+#include <Codec2Mapper.h>
+
+#define ivdec_api_function              ih264d_api_function
+#define ivdext_create_ip_t              ih264d_create_ip_t
+#define ivdext_create_op_t              ih264d_create_op_t
+#define ivdext_delete_ip_t              ih264d_delete_ip_t
+#define ivdext_delete_op_t              ih264d_delete_op_t
+#define ivdext_ctl_set_num_cores_ip_t   ih264d_ctl_set_num_cores_ip_t
+#define ivdext_ctl_set_num_cores_op_t   ih264d_ctl_set_num_cores_op_t
+#define ivdext_ctl_get_vui_params_ip_t  ih264d_ctl_get_vui_params_ip_t
+#define ivdext_ctl_get_vui_params_op_t  ih264d_ctl_get_vui_params_op_t
+#define ALIGN128(x)                     ((((x) + 127) >> 7) << 7)
+#define MAX_NUM_CORES                   4
+#define IVDEXT_CMD_CTL_SET_NUM_CORES    \
+        (IVD_CONTROL_API_COMMAND_TYPE_T)IH264D_CMD_CTL_SET_NUM_CORES
+#define MIN(a, b)                       (((a) < (b)) ? (a) : (b))
+
+namespace android {
+
+static void *ivd_aligned_malloc(void *ctxt, WORD32 alignment, WORD32 size) {
+    (void) ctxt;
+    return memalign(alignment, size);
+}
+
+static void ivd_aligned_free(void *ctxt, void *mem) {
+    (void) ctxt;
+    free(mem);
+}
+
+
+GoldfishH264Helper::GoldfishH264Helper(int w, int h):mWidth(w),mHeight(h) { createDecoder(); }
+
+GoldfishH264Helper::~GoldfishH264Helper() {
+    destroyDecoder();
+}
+
+void GoldfishH264Helper::createDecoder() {
+    ivdext_create_ip_t s_create_ip = {};
+    ivdext_create_op_t s_create_op = {};
+
+    s_create_ip.s_ivd_create_ip_t.u4_size = sizeof(ivdext_create_ip_t);
+    s_create_ip.s_ivd_create_ip_t.e_cmd = IVD_CMD_CREATE;
+    s_create_ip.s_ivd_create_ip_t.u4_share_disp_buf = 0;
+    s_create_ip.s_ivd_create_ip_t.e_output_format = mIvColorformat;
+    s_create_ip.s_ivd_create_ip_t.pf_aligned_alloc = ivd_aligned_malloc;
+    s_create_ip.s_ivd_create_ip_t.pf_aligned_free = ivd_aligned_free;
+    s_create_ip.s_ivd_create_ip_t.pv_mem_ctxt = nullptr;
+    s_create_op.s_ivd_create_op_t.u4_size = sizeof(ivdext_create_op_t);
+    IV_API_CALL_STATUS_T status =
+        ivdec_api_function(mDecHandle, &s_create_ip, &s_create_op);
+    if (status != IV_SUCCESS) {
+        ALOGE("error in %s: 0x%x", __func__,
+              s_create_op.s_ivd_create_op_t.u4_error_code);
+        return;
+    }
+    mDecHandle = (iv_obj_t *)s_create_op.s_ivd_create_op_t.pv_handle;
+    mDecHandle->pv_fxns = (void *)ivdec_api_function;
+    mDecHandle->u4_size = sizeof(iv_obj_t);
+
+    mStride = ALIGN128(mWidth);
+
+    setNumCores();
+}
+
+void GoldfishH264Helper::destroyDecoder() {
+    if (mDecHandle) {
+        ivdext_delete_ip_t s_delete_ip = {};
+        ivdext_delete_op_t s_delete_op = {};
+
+        s_delete_ip.s_ivd_delete_ip_t.u4_size = sizeof(ivdext_delete_ip_t);
+        s_delete_ip.s_ivd_delete_ip_t.e_cmd = IVD_CMD_DELETE;
+        s_delete_op.s_ivd_delete_op_t.u4_size = sizeof(ivdext_delete_op_t);
+        IV_API_CALL_STATUS_T status =
+            ivdec_api_function(mDecHandle, &s_delete_ip, &s_delete_op);
+        if (status != IV_SUCCESS) {
+            ALOGE("error in %s: 0x%x", __func__,
+                  s_delete_op.s_ivd_delete_op_t.u4_error_code);
+        }
+        mDecHandle = nullptr;
+    }
+}
+
+void GoldfishH264Helper::setNumCores() {
+    ivdext_ctl_set_num_cores_ip_t s_set_num_cores_ip = {};
+    ivdext_ctl_set_num_cores_op_t s_set_num_cores_op = {};
+
+    s_set_num_cores_ip.u4_size = sizeof(ivdext_ctl_set_num_cores_ip_t);
+    s_set_num_cores_ip.e_cmd = IVD_CMD_VIDEO_CTL;
+    s_set_num_cores_ip.e_sub_cmd = IVDEXT_CMD_CTL_SET_NUM_CORES;
+    s_set_num_cores_ip.u4_num_cores = mNumCores;
+    s_set_num_cores_op.u4_size = sizeof(ivdext_ctl_set_num_cores_op_t);
+    IV_API_CALL_STATUS_T status = ivdec_api_function(
+        mDecHandle, &s_set_num_cores_ip, &s_set_num_cores_op);
+    if (IV_SUCCESS != status) {
+        DDD("error in %s: 0x%x", __func__, s_set_num_cores_op.u4_error_code);
+    }
+}
+
+void GoldfishH264Helper::resetDecoder() {
+    ivd_ctl_reset_ip_t s_reset_ip = {};
+    ivd_ctl_reset_op_t s_reset_op = {};
+
+    s_reset_ip.u4_size = sizeof(ivd_ctl_reset_ip_t);
+    s_reset_ip.e_cmd = IVD_CMD_VIDEO_CTL;
+    s_reset_ip.e_sub_cmd = IVD_CMD_CTL_RESET;
+    s_reset_op.u4_size = sizeof(ivd_ctl_reset_op_t);
+    IV_API_CALL_STATUS_T status =
+        ivdec_api_function(mDecHandle, &s_reset_ip, &s_reset_op);
+    if (IV_SUCCESS != status) {
+        ALOGE("error in %s: 0x%x", __func__, s_reset_op.u4_error_code);
+    }
+    setNumCores();
+}
+
+void GoldfishH264Helper::setParams(size_t stride,
+                                   IVD_VIDEO_DECODE_MODE_T dec_mode) {
+    ih264d_ctl_set_config_ip_t s_h264d_set_dyn_params_ip = {};
+    ih264d_ctl_set_config_op_t s_h264d_set_dyn_params_op = {};
+    ivd_ctl_set_config_ip_t *ps_set_dyn_params_ip =
+        &s_h264d_set_dyn_params_ip.s_ivd_ctl_set_config_ip_t;
+    ivd_ctl_set_config_op_t *ps_set_dyn_params_op =
+        &s_h264d_set_dyn_params_op.s_ivd_ctl_set_config_op_t;
+
+    ps_set_dyn_params_ip->u4_size = sizeof(ih264d_ctl_set_config_ip_t);
+    ps_set_dyn_params_ip->e_cmd = IVD_CMD_VIDEO_CTL;
+    ps_set_dyn_params_ip->e_sub_cmd = IVD_CMD_CTL_SETPARAMS;
+    ps_set_dyn_params_ip->u4_disp_wd = (UWORD32) stride;
+    ps_set_dyn_params_ip->e_frm_skip_mode = IVD_SKIP_NONE;
+    ps_set_dyn_params_ip->e_frm_out_mode = IVD_DISPLAY_FRAME_OUT;
+    ps_set_dyn_params_ip->e_vid_dec_mode = dec_mode;
+    ps_set_dyn_params_op->u4_size = sizeof(ih264d_ctl_set_config_op_t);
+    IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
+                                                     &s_h264d_set_dyn_params_ip,
+                                                     &s_h264d_set_dyn_params_op);
+    if (status != IV_SUCCESS) {
+        ALOGE("error in %s: 0x%x", __func__,
+              ps_set_dyn_params_op->u4_error_code);
+    }
+}
+
+bool GoldfishH264Helper::isSpsFrame(const uint8_t* frame, int inSize) {
+    if (inSize < 5) return false;
+    if (frame[0] == 0 && frame[1] == 0 && frame[2] == 0 && frame[3] == 1) {
+        const bool forbiddenBitIsInvalid = 0x80 & frame[4];
+        if (forbiddenBitIsInvalid) {
+            return false;
+        }
+        // nalu type is the lower 5 bits
+        uint8_t naluType = 0x1f & frame[4];
+        if (naluType == 7
+            || naluType == 8
+                ) return true;
+        else return false;
+    } else {
+        return false;
+    }
+}
+
+bool GoldfishH264Helper::decodeHeader(const uint8_t *frame, int inSize) {
+    // should we check the header for vps/sps/pps frame ? otherwise
+    // there is no point calling decoder
+    if (!isSpsFrame(frame, inSize)) {
+        DDD("could not find valid vps frame");
+        return false;
+    } else {
+        DDD("found valid vps frame");
+    }
+
+    ih264d_video_decode_ip_t s_h264d_decode_ip = {};
+    ih264d_video_decode_op_t s_h264d_decode_op = {};
+    ivd_video_decode_ip_t *ps_decode_ip = &s_h264d_decode_ip.s_ivd_video_decode_ip_t;
+    ivd_video_decode_op_t *ps_decode_op = &s_h264d_decode_op.s_ivd_video_decode_op_t;
+
+    // setup input/output arguments to decoder
+    setDecodeArgs(ps_decode_ip, ps_decode_op, frame, mStride,
+            0, // offset
+            inSize, // size
+            0 // time-stamp, does not matter
+            );
+
+    setParams(mStride, IVD_DECODE_HEADER);
+
+    // now kick off the decoding
+    IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle, ps_decode_ip, ps_decode_op);
+    if (status != IV_SUCCESS) {
+        ALOGE("failed to call decoder function for header\n");
+        ALOGE("error in %s: 0x%x", __func__,
+              ps_decode_op->u4_error_code);
+    }
+
+    if (IVD_RES_CHANGED == (ps_decode_op->u4_error_code & IVD_ERROR_MASK)) {
+        DDD("resolution changed, reset decoder");
+        resetDecoder();
+        setParams(mStride, IVD_DECODE_HEADER);
+        ivdec_api_function(mDecHandle, ps_decode_ip, ps_decode_op);
+    }
+
+    // get the w/h and update
+    if (0 < ps_decode_op->u4_pic_wd && 0 < ps_decode_op->u4_pic_ht) {
+        DDD("success decode w/h %d %d", ps_decode_op->u4_pic_wd , ps_decode_op->u4_pic_ht);
+        DDD("existing w/h %d %d", mWidth, mHeight);
+        if (ps_decode_op->u4_pic_wd != mWidth ||  ps_decode_op->u4_pic_ht != mHeight) {
+            mWidth = ps_decode_op->u4_pic_wd;
+            mHeight = ps_decode_op->u4_pic_ht;
+            return true;
+        } else {
+            DDD("success decode w/h, but they are the same %d %d", ps_decode_op->u4_pic_wd , ps_decode_op->u4_pic_ht);
+        }
+    } else {
+        ALOGE("could not decode w/h");
+    }
+
+    // get output delay
+    if (ps_decode_op->i4_reorder_depth >= 0) {
+        if (mOutputDelay != ps_decode_op->i4_reorder_depth) {
+            mOutputDelay = ps_decode_op->i4_reorder_depth;
+            DDD("New Output delay %d ", mOutputDelay);
+        } else {
+            DDD("same Output delay %d ", mOutputDelay);
+        }
+    }
+
+    return false;
+}
+
+bool GoldfishH264Helper::setDecodeArgs(ivd_video_decode_ip_t *ps_decode_ip,
+                                       ivd_video_decode_op_t *ps_decode_op,
+                                       const uint8_t *inBuffer,
+                                       uint32_t displayStride, size_t inOffset,
+                                       size_t inSize, uint32_t tsMarker) {
+    uint32_t displayHeight = mHeight;
+    size_t lumaSize = displayStride * displayHeight;
+    size_t chromaSize = lumaSize >> 2;
+
+    if (mStride != displayStride) {
+        mStride = displayStride;
+    }
+
+    // force decoder to always decode header and get dimensions,
+    // hope this will be quick and cheap
+    setParams(mStride, IVD_DECODE_HEADER);
+
+    ps_decode_ip->u4_size = sizeof(ih264d_video_decode_ip_t);
+    ps_decode_ip->e_cmd = IVD_CMD_VIDEO_DECODE;
+    if (inBuffer) {
+        ps_decode_ip->u4_ts = tsMarker;
+        ps_decode_ip->pv_stream_buffer = const_cast<uint8_t *>(inBuffer) + inOffset;
+        ps_decode_ip->u4_num_Bytes = inSize;
+    } else {
+        ps_decode_ip->u4_ts = 0;
+        ps_decode_ip->pv_stream_buffer = nullptr;
+        ps_decode_ip->u4_num_Bytes = 0;
+    }
+    DDD("setting pv_stream_buffer 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x",
+            ((uint8_t*)(ps_decode_ip->pv_stream_buffer))[0],
+            ((uint8_t*)(ps_decode_ip->pv_stream_buffer))[1],
+            ((uint8_t*)(ps_decode_ip->pv_stream_buffer))[2],
+            ((uint8_t*)(ps_decode_ip->pv_stream_buffer))[3],
+            ((uint8_t*)(ps_decode_ip->pv_stream_buffer))[4],
+            ((uint8_t*)(ps_decode_ip->pv_stream_buffer))[5],
+            ((uint8_t*)(ps_decode_ip->pv_stream_buffer))[6],
+            ((uint8_t*)(ps_decode_ip->pv_stream_buffer))[7]
+            );
+    DDD("input bytes %d", ps_decode_ip->u4_num_Bytes);
+
+    ps_decode_ip->s_out_buffer.u4_min_out_buf_size[0] = lumaSize;
+    ps_decode_ip->s_out_buffer.u4_min_out_buf_size[1] = chromaSize;
+    ps_decode_ip->s_out_buffer.u4_min_out_buf_size[2] = chromaSize;
+    {
+        ps_decode_ip->s_out_buffer.pu1_bufs[0] = nullptr;
+        ps_decode_ip->s_out_buffer.pu1_bufs[1] = nullptr;
+        ps_decode_ip->s_out_buffer.pu1_bufs[2] = nullptr;
+    }
+    ps_decode_ip->s_out_buffer.u4_num_bufs = 3;
+    ps_decode_op->u4_size = sizeof(ih264d_video_decode_op_t);
+    ps_decode_op->u4_output_present = 0;
+
+    return true;
+}
+
+} // namespace android
diff --git a/system/codecs/c2/decoders/avcdec/GoldfishH264Helper.h b/system/codecs/c2/decoders/avcdec/GoldfishH264Helper.h
new file mode 100644
index 0000000..ec3b384
--- /dev/null
+++ b/system/codecs/c2/decoders/avcdec/GoldfishH264Helper.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef GOLDFISH_H264_HELPER_H_
+#define GOLDFISH_H264_HELPER_H_
+
+#include <inttypes.h>
+#include "ih264_typedefs.h"
+#include "ih264d.h"
+
+
+namespace android {
+
+// this class is just to provide some functions to decode header
+// so that we know w/h of each sps
+class GoldfishH264Helper {
+  public:
+    GoldfishH264Helper(int w, int h);
+    ~GoldfishH264Helper();
+
+    // check whether the frame is sps; typical h264 will have
+    // a frame that is sps/pps together
+    static bool isSpsFrame(const uint8_t* frame, int inSize);
+  public:
+    // return true if decoding finds out w/h changed;
+    // otherwise false
+    bool decodeHeader(const uint8_t *frame, int inSize);
+    int getWidth() const { return mWidth; }
+    int getHeight() const { return mHeight; }
+
+  private:
+    void createDecoder();
+    void destroyDecoder();
+    void resetDecoder();
+    void setNumCores();
+    void setParams(size_t stride, IVD_VIDEO_DECODE_MODE_T dec_mode);
+    bool setDecodeArgs(ivd_video_decode_ip_t *ps_decode_ip,
+                       ivd_video_decode_op_t *ps_decode_op,
+                       const uint8_t *inBuffer, uint32_t displayStride,
+                       size_t inOffset, size_t inSize, uint32_t tsMarker);
+
+  private:
+    iv_obj_t *mDecHandle = nullptr;
+    int mWidth = 320;
+    int mHeight = 240;
+    int mNumCores = 1;
+    int mStride = 16;
+    int mOutputDelay = 8; // default
+    IV_COLOR_FORMAT_T mIvColorformat = IV_YUV_420P;
+};
+
+} // namespace android
+#endif
diff --git a/system/codecs/c2/decoders/hevcdec/Android.bp b/system/codecs/c2/decoders/hevcdec/Android.bp
index fddd276..f1b9c82 100644
--- a/system/codecs/c2/decoders/hevcdec/Android.bp
+++ b/system/codecs/c2/decoders/hevcdec/Android.bp
@@ -15,6 +15,7 @@
     ],
 
     srcs: ["C2GoldfishHevcDec.cpp",
+        "GoldfishHevcHelper.cpp",
         "MediaHevcDecoder.cpp",
     ],
 
@@ -28,5 +29,8 @@
     "libgralloc_cb.ranchu",
     ],
 
+   static_libs: ["libhevcdec",
+   ],
+
 }
 
diff --git a/system/codecs/c2/decoders/hevcdec/C2GoldfishHevcDec.cpp b/system/codecs/c2/decoders/hevcdec/C2GoldfishHevcDec.cpp
index 51934d5..7008bd5 100644
--- a/system/codecs/c2/decoders/hevcdec/C2GoldfishHevcDec.cpp
+++ b/system/codecs/c2/decoders/hevcdec/C2GoldfishHevcDec.cpp
@@ -457,6 +457,7 @@
     }
     mContext->initHevcContext(mWidth, mHeight, mWidth, mHeight,
                               MediaHevcDecoder::PixelFormat::YUV420P);
+
     return OK;
 }
 
@@ -660,31 +661,14 @@
 void C2GoldfishHevcDec::checkMode(const std::shared_ptr<C2BlockPool> &pool) {
     mWidth = mIntf->width();
     mHeight = mIntf->height();
-    {
-        // now get the block
-        constexpr uint32_t format = HAL_PIXEL_FORMAT_YCBCR_420_888;
-        std::shared_ptr<C2GraphicBlock> block;
-        C2MemoryUsage usage = {C2MemoryUsage::CPU_READ,
-                               C2MemoryUsage::CPU_WRITE};
-        usage.expected = (uint64_t)(BufferUsage::VIDEO_DECODER);
-
-        c2_status_t err = pool->fetchGraphicBlock(align(mWidth, 16), mHeight,
-                                                  format, usage, &block);
-        if (err != C2_OK) {
-            ALOGE("fetchGraphicBlock for Output failed with status %d", err);
-            return;
-        }
-        auto c2Handle = block->handle();
-        native_handle_t *grallocHandle =
-            UnwrapNativeCodec2GrallocHandle(c2Handle);
-        int hostColorBufferId = getColorBufferHandle(grallocHandle);
-        if (hostColorBufferId > 0) {
-            DDD("decoding to host color buffer");
-            mEnableAndroidNativeBuffers = true;
-        } else {
-            DDD("decoding to guest byte buffer");
-            mEnableAndroidNativeBuffers = false;
-        }
+    const bool isGraphic = (pool->getAllocatorId() & C2Allocator::GRAPHIC);
+    DDD("buffer id %d", (int)(pool->getAllocatorId()));
+    if (isGraphic) {
+        DDD("decoding to host color buffer");
+        mEnableAndroidNativeBuffers = true;
+    } else {
+        DDD("decoding to guest byte buffer");
+        mEnableAndroidNativeBuffers = false;
     }
 }
 
@@ -884,11 +868,6 @@
                 return;
             }
 
-            if (false == mHeaderDecoded) {
-                /* Decode header and get dimensions */
-                setParams(mStride);
-            }
-
             DDD("flag is %x", work->input.flags);
             if (work->input.flags & C2FrameData::FLAG_CODEC_CONFIG) {
                 hasPicture = false;
@@ -903,9 +882,50 @@
                 removePts(mPts);
             }
 
+            bool whChanged = false;
+            if (GoldfishHevcHelper::isVpsFrame(mInPBuffer, mInPBufferSize)) {
+                mHevcHelper.reset(new GoldfishHevcHelper(mWidth, mHeight));
+                whChanged = mHevcHelper->decodeHeader(mInPBuffer, mInPBufferSize);
+                if (whChanged) {
+                        DDD("w changed from old %d to new %d\n", mWidth, mHevcHelper->getWidth());
+                        DDD("h changed from old %d to new %d\n", mHeight, mHevcHelper->getHeight());
+                        if (1) {
+                            drainInternal(DRAIN_COMPONENT_NO_EOS, pool, work);
+                            resetDecoder();
+                            resetPlugin();
+                            work->workletsProcessed = 0u;
+                        }
+                        {
+                            mWidth = mHevcHelper->getWidth();
+                            mHeight = mHevcHelper->getHeight();
+                            C2StreamPictureSizeInfo::output size(0u, mWidth, mHeight);
+                            std::vector<std::unique_ptr<C2SettingResult>> failures;
+                            c2_status_t err = mIntf->config({&size}, C2_MAY_BLOCK, &failures);
+                            if (err == OK) {
+                                work->worklets.front()->output.configUpdate.push_back(
+                                        C2Param::Copy(size));
+                                ensureDecoderState(pool);
+                            } else {
+                                ALOGE("Cannot set width and height");
+                                mSignalledError = true;
+                                work->workletsProcessed = 1u;
+                                work->result = C2_CORRUPTED;
+                                return;
+                            }
+                        }
+                        if (!mContext) {
+                            DDD("creating decoder context to host in process work");
+                            checkMode(pool);
+                            createDecoder();
+                        }
+                        continue;//return;
+                } // end of whChanged
+            } // end of isVpsFrame
+
             uint32_t delay;
             GETTIME(&mTimeStart, nullptr);
             TIME_DIFF(mTimeEnd, mTimeStart, delay);
+            (void)delay;
             //(void) ivdec_api_function(mDecHandle, &s_decode_ip, &s_decode_op);
             DDD("decoding");
             hevc_result_t hevcRes =
@@ -922,44 +942,9 @@
             uint32_t decodeTime;
             GETTIME(&mTimeEnd, nullptr);
             TIME_DIFF(mTimeStart, mTimeEnd, decodeTime);
-        }
-        // TODO: handle res change
-        if (0) {
-            DDD("resolution changed");
-            drainInternal(DRAIN_COMPONENT_NO_EOS, pool, work);
-            resetDecoder();
-            resetPlugin();
-            work->workletsProcessed = 0u;
-
-            /* Decode header and get new dimensions */
-            setParams(mStride);
-            //            (void) ivdec_api_function(mDecHandle, &s_decode_ip,
-            //            &s_decode_op);
+            (void)decodeTime;
         }
         if (mImg.data != nullptr) {
-            // check for new width and height
-            auto decodedW = mImg.width;
-            auto decodedH = mImg.height;
-            if (decodedW != mWidth || decodedH != mHeight) {
-                mWidth = decodedW;
-                mHeight = decodedH;
-
-                C2StreamPictureSizeInfo::output size(0u, mWidth, mHeight);
-                std::vector<std::unique_ptr<C2SettingResult>> failures;
-                c2_status_t err = mIntf->config({&size}, C2_MAY_BLOCK, &failures);
-                if (err == OK) {
-                    work->worklets.front()->output.configUpdate.push_back(
-                        C2Param::Copy(size));
-                    ensureDecoderState(pool);
-                } else {
-                    ALOGE("Cannot set width and height");
-                    mSignalledError = true;
-                    work->workletsProcessed = 1u;
-                    work->result = C2_CORRUPTED;
-                    return;
-                }
-            }
-
             DDD("got data %" PRIu64 " with pts %" PRIu64,  getWorkIndex(mImg.pts), mImg.pts);
             mHeaderDecoded = true;
             copyImageData(mImg);
diff --git a/system/codecs/c2/decoders/hevcdec/C2GoldfishHevcDec.h b/system/codecs/c2/decoders/hevcdec/C2GoldfishHevcDec.h
index 575689a..fe080cf 100644
--- a/system/codecs/c2/decoders/hevcdec/C2GoldfishHevcDec.h
+++ b/system/codecs/c2/decoders/hevcdec/C2GoldfishHevcDec.h
@@ -22,6 +22,7 @@
 #include <media/stagefright/foundation/ColorUtils.h>
 
 #include "MediaHevcDecoder.h"
+#include "GoldfishHevcHelper.h"
 #include <SimpleC2Component.h>
 #include <atomic>
 #include <map>
@@ -152,6 +153,8 @@
     std::vector<uint8_t> mCsd1;
     void decodeHeaderAfterFlush();
 
+    std::unique_ptr<GoldfishHevcHelper> mHevcHelper;
+
     C2_DO_NOT_COPY(C2GoldfishHevcDec);
 };
 
diff --git a/system/codecs/c2/decoders/hevcdec/GoldfishHevcHelper.cpp b/system/codecs/c2/decoders/hevcdec/GoldfishHevcHelper.cpp
new file mode 100644
index 0000000..1b93a0d
--- /dev/null
+++ b/system/codecs/c2/decoders/hevcdec/GoldfishHevcHelper.cpp
@@ -0,0 +1,315 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "GoldfishHevcHelper.h"
+
+#define LOG_TAG "GoldfishHevcHelper"
+#include <log/log.h>
+
+#include "ihevc_typedefs.h"
+#include "ihevcd_cxa.h"
+
+#define DEBUG 0
+#if DEBUG
+#define DDD(...) ALOGD(__VA_ARGS__)
+#else
+#define DDD(...) ((void)0)
+#endif
+
+
+#include <Codec2Mapper.h>
+
+#define ivdec_api_function ihevcd_cxa_api_function
+#define ivdext_create_ip_t ihevcd_cxa_create_ip_t
+#define ivdext_create_op_t ihevcd_cxa_create_op_t
+#define ivdext_delete_ip_t ihevcd_cxa_delete_ip_t
+#define ivdext_delete_op_t ihevcd_cxa_delete_op_t
+#define ivdext_ctl_set_num_cores_ip_t ihevcd_cxa_ctl_set_num_cores_ip_t
+#define ivdext_ctl_set_num_cores_op_t ihevcd_cxa_ctl_set_num_cores_op_t
+#define ivdext_ctl_get_vui_params_ip_t ihevcd_cxa_ctl_get_vui_params_ip_t
+#define ivdext_ctl_get_vui_params_op_t ihevcd_cxa_ctl_get_vui_params_op_t
+#define ALIGN128(x) ((((x) + 127) >> 7) << 7)
+#define MAX_NUM_CORES 4
+#define IVDEXT_CMD_CTL_SET_NUM_CORES                                           \
+    (IVD_CONTROL_API_COMMAND_TYPE_T) IHEVCD_CXA_CMD_CTL_SET_NUM_CORES
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+
+namespace android {
+
+static void *ivd_aligned_malloc(void *ctxt, WORD32 alignment, WORD32 size) {
+    (void) ctxt;
+    return memalign(alignment, size);
+}
+
+static void ivd_aligned_free(void *ctxt, void *mem) {
+    (void) ctxt;
+    free(mem);
+}
+
+
+GoldfishHevcHelper::GoldfishHevcHelper(int w, int h):mWidth(w),mHeight(h) { createDecoder(); }
+
+GoldfishHevcHelper::~GoldfishHevcHelper() {
+    destroyDecoder();
+}
+
+void GoldfishHevcHelper::createDecoder() {
+    ivdext_create_ip_t s_create_ip = {};
+    ivdext_create_op_t s_create_op = {};
+
+    s_create_ip.s_ivd_create_ip_t.u4_size = sizeof(ivdext_create_ip_t);
+    s_create_ip.s_ivd_create_ip_t.e_cmd = IVD_CMD_CREATE;
+    s_create_ip.s_ivd_create_ip_t.u4_share_disp_buf = 0;
+    s_create_ip.s_ivd_create_ip_t.e_output_format = mIvColorformat;
+    s_create_ip.s_ivd_create_ip_t.pf_aligned_alloc = ivd_aligned_malloc;
+    s_create_ip.s_ivd_create_ip_t.pf_aligned_free = ivd_aligned_free;
+    s_create_ip.s_ivd_create_ip_t.pv_mem_ctxt = nullptr;
+    s_create_op.s_ivd_create_op_t.u4_size = sizeof(ivdext_create_op_t);
+    IV_API_CALL_STATUS_T status =
+        ivdec_api_function(mDecHandle, &s_create_ip, &s_create_op);
+    if (status != IV_SUCCESS) {
+        ALOGE("error in %s: 0x%x", __func__,
+              s_create_op.s_ivd_create_op_t.u4_error_code);
+        return;
+    }
+    mDecHandle = (iv_obj_t *)s_create_op.s_ivd_create_op_t.pv_handle;
+    mDecHandle->pv_fxns = (void *)ivdec_api_function;
+    mDecHandle->u4_size = sizeof(iv_obj_t);
+
+    mStride = ALIGN128(mWidth);
+
+    setNumCores();
+}
+
+void GoldfishHevcHelper::destroyDecoder() {
+    if (mDecHandle) {
+        ivdext_delete_ip_t s_delete_ip = {};
+        ivdext_delete_op_t s_delete_op = {};
+
+        s_delete_ip.s_ivd_delete_ip_t.u4_size = sizeof(ivdext_delete_ip_t);
+        s_delete_ip.s_ivd_delete_ip_t.e_cmd = IVD_CMD_DELETE;
+        s_delete_op.s_ivd_delete_op_t.u4_size = sizeof(ivdext_delete_op_t);
+        IV_API_CALL_STATUS_T status =
+            ivdec_api_function(mDecHandle, &s_delete_ip, &s_delete_op);
+        if (status != IV_SUCCESS) {
+            ALOGE("error in %s: 0x%x", __func__,
+                  s_delete_op.s_ivd_delete_op_t.u4_error_code);
+        }
+        mDecHandle = nullptr;
+    }
+}
+
+void GoldfishHevcHelper::setNumCores() {
+    ivdext_ctl_set_num_cores_ip_t s_set_num_cores_ip = {};
+    ivdext_ctl_set_num_cores_op_t s_set_num_cores_op = {};
+
+    s_set_num_cores_ip.u4_size = sizeof(ivdext_ctl_set_num_cores_ip_t);
+    s_set_num_cores_ip.e_cmd = IVD_CMD_VIDEO_CTL;
+    s_set_num_cores_ip.e_sub_cmd = IVDEXT_CMD_CTL_SET_NUM_CORES;
+    s_set_num_cores_ip.u4_num_cores = mNumCores;
+    s_set_num_cores_op.u4_size = sizeof(ivdext_ctl_set_num_cores_op_t);
+    IV_API_CALL_STATUS_T status = ivdec_api_function(
+        mDecHandle, &s_set_num_cores_ip, &s_set_num_cores_op);
+    if (IV_SUCCESS != status) {
+        DDD("error in %s: 0x%x", __func__, s_set_num_cores_op.u4_error_code);
+    }
+}
+
+void GoldfishHevcHelper::resetDecoder() {
+    ivd_ctl_reset_ip_t s_reset_ip = {};
+    ivd_ctl_reset_op_t s_reset_op = {};
+
+    s_reset_ip.u4_size = sizeof(ivd_ctl_reset_ip_t);
+    s_reset_ip.e_cmd = IVD_CMD_VIDEO_CTL;
+    s_reset_ip.e_sub_cmd = IVD_CMD_CTL_RESET;
+    s_reset_op.u4_size = sizeof(ivd_ctl_reset_op_t);
+    IV_API_CALL_STATUS_T status =
+        ivdec_api_function(mDecHandle, &s_reset_ip, &s_reset_op);
+    if (IV_SUCCESS != status) {
+        ALOGE("error in %s: 0x%x", __func__, s_reset_op.u4_error_code);
+    }
+    setNumCores();
+}
+
+void GoldfishHevcHelper::setParams(size_t stride,
+                                   IVD_VIDEO_DECODE_MODE_T dec_mode) {
+    ihevcd_cxa_ctl_set_config_ip_t s_hevcd_set_dyn_params_ip = {};
+    ihevcd_cxa_ctl_set_config_op_t s_hevcd_set_dyn_params_op = {};
+    ivd_ctl_set_config_ip_t *ps_set_dyn_params_ip =
+        &s_hevcd_set_dyn_params_ip.s_ivd_ctl_set_config_ip_t;
+    ivd_ctl_set_config_op_t *ps_set_dyn_params_op =
+        &s_hevcd_set_dyn_params_op.s_ivd_ctl_set_config_op_t;
+
+    ps_set_dyn_params_ip->u4_size = sizeof(ihevcd_cxa_ctl_set_config_ip_t);
+    ps_set_dyn_params_ip->e_cmd = IVD_CMD_VIDEO_CTL;
+    ps_set_dyn_params_ip->e_sub_cmd = IVD_CMD_CTL_SETPARAMS;
+    ps_set_dyn_params_ip->u4_disp_wd = (UWORD32)stride;
+    ps_set_dyn_params_ip->e_frm_skip_mode = IVD_SKIP_NONE;
+    ps_set_dyn_params_ip->e_frm_out_mode = IVD_DISPLAY_FRAME_OUT;
+    ps_set_dyn_params_ip->e_vid_dec_mode = dec_mode;
+    ps_set_dyn_params_op->u4_size = sizeof(ihevcd_cxa_ctl_set_config_op_t);
+    IV_API_CALL_STATUS_T status = ivdec_api_function(
+        mDecHandle, ps_set_dyn_params_ip, ps_set_dyn_params_op);
+    if (status != IV_SUCCESS) {
+        ALOGE("error in %s: 0x%x", __func__,
+              ps_set_dyn_params_op->u4_error_code);
+    }
+}
+
+bool GoldfishHevcHelper::isVpsFrame(const uint8_t* frame, int inSize) {
+    if (inSize < 5) return false;
+    if (frame[0] == 0 && frame[1] == 0 && frame[2] == 0 && frame[3] == 1) {
+        const bool forbiddenBitIsInvalid = 0x80 & frame[4];
+        if (forbiddenBitIsInvalid) {
+            return false;
+        }
+        // nalu type is the lower 6 bits after shiftting to right 1 bit
+        uint8_t naluType = 0x3f & (frame[4] >> 1);
+        if (naluType == 32
+            || naluType == 33
+            || naluType == 34
+                ) return true;
+        else return false;
+    } else {
+        return false;
+    }
+}
+
+bool GoldfishHevcHelper::decodeHeader(const uint8_t *frame, int inSize) {
+    // should we check the header for vps/sps/pps frame ? otherwise
+    // there is no point calling decoder
+    if (!isVpsFrame(frame, inSize)) {
+        DDD("could not find valid vps frame");
+        return false;
+    } else {
+        DDD("found valid vps frame");
+    }
+
+    ihevcd_cxa_video_decode_ip_t s_hevcd_decode_ip = {};
+    ihevcd_cxa_video_decode_op_t s_hevcd_decode_op = {};
+    ivd_video_decode_ip_t *ps_decode_ip =
+        &s_hevcd_decode_ip.s_ivd_video_decode_ip_t;
+    ivd_video_decode_op_t *ps_decode_op =
+        &s_hevcd_decode_op.s_ivd_video_decode_op_t;
+
+    // setup input/output arguments to decoder
+    setDecodeArgs(ps_decode_ip, ps_decode_op, frame, mStride,
+            0, // offset
+            inSize, // size
+            0 // time-stamp, does not matter
+            );
+
+    setParams(mStride, IVD_DECODE_HEADER);
+
+    // now kick off the decoding
+    IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle, ps_decode_ip, ps_decode_op);
+    if (status != IV_SUCCESS) {
+        ALOGE("failed to call decoder function for header\n");
+        ALOGE("error in %s: 0x%x", __func__,
+              ps_decode_op->u4_error_code);
+    }
+
+    if (IVD_RES_CHANGED == (ps_decode_op->u4_error_code & IVD_ERROR_MASK)) {
+        DDD("resolution changed, reset decoder");
+        resetDecoder();
+        setParams(mStride, IVD_DECODE_HEADER);
+        ivdec_api_function(mDecHandle, ps_decode_ip, ps_decode_op);
+    }
+
+    // get the w/h and update
+    if (0 < ps_decode_op->u4_pic_wd && 0 < ps_decode_op->u4_pic_ht) {
+        DDD("success decode w/h %d %d", ps_decode_op->u4_pic_wd , ps_decode_op->u4_pic_ht);
+        DDD("existing w/h %d %d", mWidth, mHeight);
+        if (ps_decode_op->u4_pic_wd != mWidth ||  ps_decode_op->u4_pic_ht != mHeight) {
+            mWidth = ps_decode_op->u4_pic_wd;
+            mHeight = ps_decode_op->u4_pic_ht;
+            return true;
+        } else {
+            DDD("success decode w/h, but they are the same %d %d", ps_decode_op->u4_pic_wd , ps_decode_op->u4_pic_ht);
+        }
+    } else {
+        ALOGE("could not decode w/h");
+    }
+
+    // get output delay
+    if (ps_decode_op->i4_reorder_depth >= 0) {
+        if (mOutputDelay != ps_decode_op->i4_reorder_depth) {
+            mOutputDelay = ps_decode_op->i4_reorder_depth;
+            DDD("New Output delay %d ", mOutputDelay);
+        } else {
+            DDD("same Output delay %d ", mOutputDelay);
+        }
+    }
+
+    return false;
+}
+
+bool GoldfishHevcHelper::setDecodeArgs(ivd_video_decode_ip_t *ps_decode_ip,
+                                       ivd_video_decode_op_t *ps_decode_op,
+                                       const uint8_t *inBuffer,
+                                       uint32_t displayStride, size_t inOffset,
+                                       size_t inSize, uint32_t tsMarker) {
+    uint32_t displayHeight = mHeight;
+    size_t lumaSize = displayStride * displayHeight;
+    size_t chromaSize = lumaSize >> 2;
+
+    if (mStride != displayStride) {
+        mStride = displayStride;
+    }
+
+    // force decoder to always decode header and get dimensions,
+    // hope this will be quick and cheap
+    setParams(mStride, IVD_DECODE_HEADER);
+
+    ps_decode_ip->u4_size = sizeof(ihevcd_cxa_video_decode_ip_t);
+    ps_decode_ip->e_cmd = IVD_CMD_VIDEO_DECODE;
+    if (inBuffer) {
+        ps_decode_ip->u4_ts = tsMarker;
+        ps_decode_ip->pv_stream_buffer = const_cast<uint8_t *>(inBuffer) + inOffset;
+        ps_decode_ip->u4_num_Bytes = inSize;
+    } else {
+        ps_decode_ip->u4_ts = 0;
+        ps_decode_ip->pv_stream_buffer = nullptr;
+        ps_decode_ip->u4_num_Bytes = 0;
+    }
+    DDD("setting pv_stream_buffer 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x",
+            ((uint8_t*)(ps_decode_ip->pv_stream_buffer))[0],
+            ((uint8_t*)(ps_decode_ip->pv_stream_buffer))[1],
+            ((uint8_t*)(ps_decode_ip->pv_stream_buffer))[2],
+            ((uint8_t*)(ps_decode_ip->pv_stream_buffer))[3],
+            ((uint8_t*)(ps_decode_ip->pv_stream_buffer))[4],
+            ((uint8_t*)(ps_decode_ip->pv_stream_buffer))[5],
+            ((uint8_t*)(ps_decode_ip->pv_stream_buffer))[6],
+            ((uint8_t*)(ps_decode_ip->pv_stream_buffer))[7]
+            );
+    DDD("input bytes %d", ps_decode_ip->u4_num_Bytes);
+
+    ps_decode_ip->s_out_buffer.u4_min_out_buf_size[0] = lumaSize;
+    ps_decode_ip->s_out_buffer.u4_min_out_buf_size[1] = chromaSize;
+    ps_decode_ip->s_out_buffer.u4_min_out_buf_size[2] = chromaSize;
+    {
+        ps_decode_ip->s_out_buffer.pu1_bufs[0] = nullptr;
+        ps_decode_ip->s_out_buffer.pu1_bufs[1] = nullptr;
+        ps_decode_ip->s_out_buffer.pu1_bufs[2] = nullptr;
+    }
+    ps_decode_ip->s_out_buffer.u4_num_bufs = 3;
+    ps_decode_op->u4_size = sizeof(ihevcd_cxa_video_decode_op_t);
+    ps_decode_op->u4_output_present = 0;
+
+    return true;
+}
+
+} // namespace android
diff --git a/system/codecs/c2/decoders/hevcdec/GoldfishHevcHelper.h b/system/codecs/c2/decoders/hevcdec/GoldfishHevcHelper.h
new file mode 100644
index 0000000..09de830
--- /dev/null
+++ b/system/codecs/c2/decoders/hevcdec/GoldfishHevcHelper.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef GOLDFISH_HEVC_HELPER_H_
+#define GOLDFISH_HEVC_HELPER_H_
+
+#include <inttypes.h>
+#include "ihevc_typedefs.h"
+#include "ihevcd_cxa.h"
+
+
+namespace android {
+
+// this class is just to provide some functions to decode header
+// so that we know w/h of each sps
+class GoldfishHevcHelper {
+  public:
+    GoldfishHevcHelper(int w, int h);
+    ~GoldfishHevcHelper();
+
+    // check whether the frame is vps; typical hevc will have
+    // a frame that is vps/sps/pps together
+    static bool isVpsFrame(const uint8_t* frame, int inSize);
+  public:
+    // return true if decoding finds out w/h changed;
+    // otherwise false
+    bool decodeHeader(const uint8_t *frame, int inSize);
+    int getWidth() const { return mWidth; }
+    int getHeight() const { return mHeight; }
+
+  private:
+    void createDecoder();
+    void destroyDecoder();
+    void resetDecoder();
+    void setNumCores();
+    void setParams(size_t stride, IVD_VIDEO_DECODE_MODE_T dec_mode);
+    bool setDecodeArgs(ivd_video_decode_ip_t *ps_decode_ip,
+                       ivd_video_decode_op_t *ps_decode_op,
+                       const uint8_t *inBuffer, uint32_t displayStride,
+                       size_t inOffset, size_t inSize, uint32_t tsMarker);
+
+  private:
+    iv_obj_t *mDecHandle = nullptr;
+    int mWidth = 320;
+    int mHeight = 240;
+    int mNumCores = 1;
+    int mStride = 16;
+    int mOutputDelay = 8; // default
+    IV_COLOR_FORMAT_T mIvColorformat = IV_YUV_420P;
+};
+
+} // namespace android
+#endif
diff --git a/system/codecs/c2/decoders/vpxdec/C2GoldfishVpxDec.cpp b/system/codecs/c2/decoders/vpxdec/C2GoldfishVpxDec.cpp
index 99ddcfd..99f0469 100644
--- a/system/codecs/c2/decoders/vpxdec/C2GoldfishVpxDec.cpp
+++ b/system/codecs/c2/decoders/vpxdec/C2GoldfishVpxDec.cpp
@@ -465,32 +465,14 @@
     mCtx = new vpx_codec_ctx_t;
     mCtx->vpversion = mMode == MODE_VP8 ? 8 : 9;
 
-    // check for decoding mode:
-    {
-        // now get the block
-        constexpr uint32_t format = HAL_PIXEL_FORMAT_YCBCR_420_888;
-        std::shared_ptr<C2GraphicBlock> block;
-        C2MemoryUsage usage = {C2MemoryUsage::CPU_READ,
-                               C2MemoryUsage::CPU_WRITE};
-        usage.expected = (uint64_t)(BufferUsage::VIDEO_DECODER);
-
-        c2_status_t err = pool->fetchGraphicBlock(align(mWidth, 2), mHeight,
-                                                  format, usage, &block);
-        if (err != C2_OK) {
-            ALOGE("fetchGraphicBlock for Output failed with status %d", err);
-            return;
-        }
-        auto c2Handle = block->handle();
-        native_handle_t *grallocHandle =
-            UnwrapNativeCodec2GrallocHandle(c2Handle);
-        int hostColorBufferId = getColorBufferHandle(grallocHandle);
-        if (hostColorBufferId > 0) {
-            DDD("decoding to host color buffer");
-            mEnableAndroidNativeBuffers = true;
-        } else {
-            DDD("decoding to guest byte buffer");
-            mEnableAndroidNativeBuffers = false;
-        }
+    const bool isGraphic = (pool->getAllocatorId() & C2Allocator::GRAPHIC);
+    DDD("buffer id %d", (int)(pool->getAllocatorId()));
+    if (isGraphic) {
+        DDD("decoding to host color buffer");
+        mEnableAndroidNativeBuffers = true;
+    } else {
+        DDD("decoding to guest byte buffer");
+        mEnableAndroidNativeBuffers = false;
     }
 
     mCtx->version = mEnableAndroidNativeBuffers ? 200 : 100;
@@ -721,24 +703,24 @@
         return UNKNOWN_ERROR;
     }
 
-    bool decodingToByteBuffer = false;
-    {
+    int hostColorBufferId = -1;
+    const bool decodingToHostColorBuffer = mEnableAndroidNativeBuffers;
+    if(decodingToHostColorBuffer){
         auto c2Handle = block->handle();
         native_handle_t *grallocHandle =
             UnwrapNativeCodec2GrallocHandle(c2Handle);
-        int hostColorBufferId = getColorBufferHandle(grallocHandle);
+        hostColorBufferId = getColorBufferHandle(grallocHandle);
         if (hostColorBufferId > 0) {
             DDD("found handle %d", hostColorBufferId);
         } else {
-            decodingToByteBuffer = true;
             DDD("decode to buffer, because handle %d is invalid",
                 hostColorBufferId);
             // change to -1 so host knows it is definitely invalid
             // 0 is a bit confusing
             hostColorBufferId = -1;
         }
-        setup_ctx_parameters(mCtx, hostColorBufferId);
     }
+    setup_ctx_parameters(mCtx, hostColorBufferId);
 
     vpx_image_t *img = vpx_codec_get_frame(mCtx);
 
@@ -798,7 +780,7 @@
         }
     }
 
-    if (decodingToByteBuffer) {
+    if (!decodingToHostColorBuffer) {
 
         C2GraphicView wView = block->map().get();
         if (wView.error()) {