Reland: Support host decoding with update_color_buffer on minigbm

minigbm creates an NV12 image when the guest wanted yuv_420_888. our
host decoder outputs yuv_420_888, but this isn't compatible with nv21,
and resulted in garbled images when fed to YUVConverter.

but gfxstream never created a yuv_420_888 gpu image on the host anyway. All
we need to do is explicitly tell YUVConverter to convert from yuv_420_888.

Bug: 162770284
Change-Id: I3788183e7c94adfd0d52caafbbe67a1ed0d23c77
diff --git a/stream-servers/FrameBuffer.cpp b/stream-servers/FrameBuffer.cpp
index 095c487..2824185 100644
--- a/stream-servers/FrameBuffer.cpp
+++ b/stream-servers/FrameBuffer.cpp
@@ -2197,6 +2197,28 @@
     return true;
 }
 
+bool FrameBuffer::updateColorBufferFromFrameworkFormat(HandleType p_colorbuffer, int x, int y,
+                                                       int width, int height,
+                                                       FrameworkFormat fwkFormat, GLenum format,
+                                                       GLenum type, void* pixels) {
+    if (width == 0 || height == 0) {
+        return false;
+    }
+
+    AutoLock mutex(m_lock);
+
+    ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer));
+    if (c == m_colorbuffers.end()) {
+        // bad colorbuffer handle
+        return false;
+    }
+
+    (*c).second.cb->subUpdateFromFrameworkFormat(x, y, width, height, fwkFormat, format, type,
+                                                 pixels);
+
+    return true;
+}
+
 bool FrameBuffer::replaceColorBufferContents(
     HandleType p_colorbuffer, const void* pixels, size_t numBytes) {
     AutoLock mutex(m_lock);
diff --git a/stream-servers/FrameBuffer.h b/stream-servers/FrameBuffer.h
index ceb785b..e190a75 100644
--- a/stream-servers/FrameBuffer.h
+++ b/stream-servers/FrameBuffer.h
@@ -406,6 +406,9 @@
     bool updateColorBuffer(HandleType p_colorbuffer, int x, int y, int width,
                            int height, GLenum format, GLenum type,
                            void* pixels);
+    bool updateColorBufferFromFrameworkFormat(HandleType p_colorbuffer, int x, int y, int width,
+                                              int height, FrameworkFormat fwkFormat, GLenum format,
+                                              GLenum type, void* pixels);
     // Replaces contents completely using the color buffer's current format,
     // with row length equal to width of a row in bytes.
     // The number of bytes is passed as a check.
diff --git a/stream-servers/RendererImpl.cpp b/stream-servers/RendererImpl.cpp
index 9916eea..7c3dbf9 100644
--- a/stream-servers/RendererImpl.cpp
+++ b/stream-servers/RendererImpl.cpp
@@ -523,170 +523,118 @@
 }
 
 static struct AndroidVirtioGpuOps sVirtioGpuOps = {
-        .create_buffer_with_handle =
-                [](uint64_t size, uint32_t handle) {
-                    FrameBuffer::getFB()->createBufferWithHandle(size, handle);
-                },
-        .create_color_buffer_with_handle =
-                [](uint32_t width,
-                   uint32_t height,
-                   uint32_t format,
-                   uint32_t fwkFormat,
-                   uint32_t handle) {
-                    FrameBuffer::getFB()->createColorBufferWithHandle(
-                            width, height, (GLenum)format,
-                            (FrameworkFormat)fwkFormat, handle);
-                },
-        .open_color_buffer =
-                [](uint32_t handle) {
-                    FrameBuffer::getFB()->openColorBuffer(handle);
-                },
-        .close_buffer =
-                [](uint32_t handle) {
-                    FrameBuffer::getFB()->closeBuffer(handle);
-                },
-        .close_color_buffer =
-                [](uint32_t handle) {
-                    FrameBuffer::getFB()->closeColorBuffer(handle);
-                },
-        .update_buffer =
-                [](uint32_t handle,
-                   uint64_t offset,
-                   uint64_t size,
-                   void* bytes) {
-                    FrameBuffer::getFB()->updateBuffer(
-                            handle, offset, size, bytes);
-                },
-        .update_color_buffer =
-                [](uint32_t handle,
-                   int x,
-                   int y,
-                   int width,
-                   int height,
-                   uint32_t format,
-                   uint32_t type,
-                   void* pixels) {
-                    FrameBuffer::getFB()->updateColorBuffer(
-                            handle, x, y, width, height, format, type, pixels);
-                },
-        .read_buffer =
-                [](uint32_t handle,
-                   uint64_t offset,
-                   uint64_t size,
-                   void* bytes) {
-                    FrameBuffer::getFB()->readBuffer(
-                            handle, offset, size, bytes);
-                },
-        .read_color_buffer =
-                [](uint32_t handle,
-                   int x,
-                   int y,
-                   int width,
-                   int height,
-                   uint32_t format,
-                   uint32_t type,
-                   void* pixels) {
-                    FrameBuffer::getFB()->readColorBuffer(
-                            handle, x, y, width, height, format, type, pixels);
-                },
-        .read_color_buffer_yuv =
-                [](uint32_t handle,
-                   int x,
-                   int y,
-                   int width,
-                   int height,
-                   void* pixels,
-                   uint32_t pixels_size) {
-                    FrameBuffer::getFB()->readColorBufferYUV(
-                            handle, x, y, width, height, pixels, pixels_size);
-                },
-        .post_color_buffer =
-                [](uint32_t handle) { FrameBuffer::getFB()->post(handle); },
-        .async_post_color_buffer =
-                [](uint32_t handle, CpuCompletionCallback cb) {
-                    FrameBuffer::getFB()->postWithCallback(handle, cb); },
-        .repost = []() { FrameBuffer::getFB()->repost(); },
-        .create_yuv_textures =
-                [](uint32_t type,
-                   uint32_t count,
-                   int width,
-                   int height,
-                   uint32_t* output) {
-                    FrameBuffer::getFB()->createYUVTextures(type, count, width,
-                                                            height, output);
-                },
-        .destroy_yuv_textures =
-                [](uint32_t type, uint32_t count, uint32_t* textures) {
-                    FrameBuffer::getFB()->destroyYUVTextures(type, count,
-                                                             textures);
-                },
-        .update_yuv_textures =
-                [](uint32_t type,
-                   uint32_t* textures,
-                   void* privData,
-                   void* func) {
-                    FrameBuffer::getFB()->updateYUVTextures(type, textures,
-                                                            privData, func);
-                },
-        .swap_textures_and_update_color_buffer =
-                [](uint32_t colorbufferhandle,
-                   int x,
-                   int y,
-                   int width,
-                   int height,
-                   uint32_t format,
-                   uint32_t type,
-                   uint32_t texture_type,
-                   uint32_t* textures,
-                   void* metadata) {
-                    (void)metadata;
-                    // TODO(joshuaduong): CP go/oag/2170490
-                    FrameBuffer::getFB()->swapTexturesAndUpdateColorBuffer(
-                            colorbufferhandle, x, y, width, height, format,
-                            type, texture_type, textures);
-                },
-        .get_last_posted_color_buffer = []() {
-            return FrameBuffer::getFB()->getLastPostedColorBuffer();
+    .create_buffer_with_handle =
+        [](uint64_t size, uint32_t handle) {
+            FrameBuffer::getFB()->createBufferWithHandle(size, handle);
         },
-        .bind_color_buffer_to_texture = [](uint32_t handle) {
-            FrameBuffer::getFB()->bindColorBufferToTexture2(handle);
+    .create_color_buffer_with_handle =
+        [](uint32_t width, uint32_t height, uint32_t format, uint32_t fwkFormat, uint32_t handle) {
+            FrameBuffer::getFB()->createColorBufferWithHandle(width, height, (GLenum)format,
+                                                              (FrameworkFormat)fwkFormat, handle);
         },
-        .get_global_egl_context = []() {
-            return FrameBuffer::getFB()->getGlobalEGLContext();
+    .open_color_buffer = [](uint32_t handle) { FrameBuffer::getFB()->openColorBuffer(handle); },
+    .close_buffer = [](uint32_t handle) { FrameBuffer::getFB()->closeBuffer(handle); },
+    .close_color_buffer = [](uint32_t handle) { FrameBuffer::getFB()->closeColorBuffer(handle); },
+    .update_buffer =
+        [](uint32_t handle, uint64_t offset, uint64_t size, void* bytes) {
+            FrameBuffer::getFB()->updateBuffer(handle, offset, size, bytes);
         },
-        .wait_for_gpu = [](uint64_t eglsync) {
-            FrameBuffer::getFB()->waitForGpu(eglsync);
+    .update_color_buffer =
+        [](uint32_t handle, int x, int y, int width, int height, uint32_t format, uint32_t type,
+           void* pixels) {
+            FrameBuffer::getFB()->updateColorBuffer(handle, x, y, width, height, format, type,
+                                                    pixels);
         },
-        .wait_for_gpu_vulkan = [](uint64_t device, uint64_t fence) {
+    .read_buffer =
+        [](uint32_t handle, uint64_t offset, uint64_t size, void* bytes) {
+            FrameBuffer::getFB()->readBuffer(handle, offset, size, bytes);
+        },
+    .read_color_buffer =
+        [](uint32_t handle, int x, int y, int width, int height, uint32_t format, uint32_t type,
+           void* pixels) {
+            FrameBuffer::getFB()->readColorBuffer(handle, x, y, width, height, format, type,
+                                                  pixels);
+        },
+    .read_color_buffer_yuv =
+        [](uint32_t handle, int x, int y, int width, int height, void* pixels,
+           uint32_t pixels_size) {
+            FrameBuffer::getFB()->readColorBufferYUV(handle, x, y, width, height, pixels,
+                                                     pixels_size);
+        },
+    .post_color_buffer = [](uint32_t handle) { FrameBuffer::getFB()->post(handle); },
+    .async_post_color_buffer =
+        [](uint32_t handle, CpuCompletionCallback cb) {
+            FrameBuffer::getFB()->postWithCallback(handle, cb);
+        },
+    .repost = []() { FrameBuffer::getFB()->repost(); },
+    .create_yuv_textures =
+        [](uint32_t type, uint32_t count, int width, int height, uint32_t* output) {
+            FrameBuffer::getFB()->createYUVTextures(type, count, width, height, output);
+        },
+    .destroy_yuv_textures =
+        [](uint32_t type, uint32_t count, uint32_t* textures) {
+            FrameBuffer::getFB()->destroyYUVTextures(type, count, textures);
+        },
+    .update_yuv_textures =
+        [](uint32_t type, uint32_t* textures, void* privData, void* func) {
+            FrameBuffer::getFB()->updateYUVTextures(type, textures, privData, func);
+        },
+    .swap_textures_and_update_color_buffer =
+        [](uint32_t colorbufferhandle, int x, int y, int width, int height, uint32_t format,
+           uint32_t type, uint32_t texture_type, uint32_t* textures, void* metadata) {
+            (void)metadata;
+            // TODO(joshuaduong): CP go/oag/2170490
+            FrameBuffer::getFB()->swapTexturesAndUpdateColorBuffer(
+                colorbufferhandle, x, y, width, height, format, type, texture_type, textures);
+        },
+    .get_last_posted_color_buffer =
+        []() { return FrameBuffer::getFB()->getLastPostedColorBuffer(); },
+    .bind_color_buffer_to_texture =
+        [](uint32_t handle) { FrameBuffer::getFB()->bindColorBufferToTexture2(handle); },
+    .get_global_egl_context = []() { return FrameBuffer::getFB()->getGlobalEGLContext(); },
+    .wait_for_gpu = [](uint64_t eglsync) { FrameBuffer::getFB()->waitForGpu(eglsync); },
+    .wait_for_gpu_vulkan =
+        [](uint64_t device, uint64_t fence) {
             FrameBuffer::getFB()->waitForGpuVulkan(device, fence);
         },
-        .set_guest_managed_color_buffer_lifetime = [](bool guestManaged) {
+    .set_guest_managed_color_buffer_lifetime =
+        [](bool guestManaged) {
             FrameBuffer::getFB()->setGuestManagedColorBufferLifetime(guestManaged);
         },
-        .async_wait_for_gpu_with_cb = [](uint64_t eglsync, FenceCompletionCallback cb) {
+    .async_wait_for_gpu_with_cb =
+        [](uint64_t eglsync, FenceCompletionCallback cb) {
             FrameBuffer::getFB()->asyncWaitForGpuWithCb(eglsync, cb);
         },
-        .async_wait_for_gpu_vulkan_with_cb = [](uint64_t device, uint64_t fence, FenceCompletionCallback cb) {
+    .async_wait_for_gpu_vulkan_with_cb =
+        [](uint64_t device, uint64_t fence, FenceCompletionCallback cb) {
             FrameBuffer::getFB()->asyncWaitForGpuVulkanWithCb(device, fence, cb);
         },
-        .async_wait_for_gpu_vulkan_qsri_with_cb = [](uint64_t image, FenceCompletionCallback cb) {
+    .async_wait_for_gpu_vulkan_qsri_with_cb =
+        [](uint64_t image, FenceCompletionCallback cb) {
             FrameBuffer::getFB()->asyncWaitForGpuVulkanQsriWithCb(image, cb);
         },
-        .wait_for_gpu_vulkan_qsri = [](uint64_t image) {
-            FrameBuffer::getFB()->waitForGpuVulkanQsri(image);
-        },
-        .platform_import_resource = [](uint32_t handle, uint32_t info, void* resource) {
+    .wait_for_gpu_vulkan_qsri =
+        [](uint64_t image) { FrameBuffer::getFB()->waitForGpuVulkanQsri(image); },
+    .platform_import_resource =
+        [](uint32_t handle, uint32_t info, void* resource) {
             return FrameBuffer::getFB()->platformImportResource(handle, info, resource);
         },
-        .platform_resource_info = [](uint32_t handle, int32_t* width, int32_t* height, int32_t* internal_format) {
+    .platform_resource_info =
+        [](uint32_t handle, int32_t* width, int32_t* height, int32_t* internal_format) {
             return FrameBuffer::getFB()->getColorBufferInfo(handle, width, height, internal_format);
         },
-        .platform_create_shared_egl_context = []() {
-            return FrameBuffer::getFB()->platformCreateSharedEglContext();
-        },
-        .platform_destroy_shared_egl_context = [](void* context) {
+    .platform_create_shared_egl_context =
+        []() { return FrameBuffer::getFB()->platformCreateSharedEglContext(); },
+    .platform_destroy_shared_egl_context =
+        [](void* context) {
             return FrameBuffer::getFB()->platformDestroySharedEglContext(context);
         },
+    .update_color_buffer_from_framework_format =
+        [](uint32_t handle, int x, int y, int width, int height, uint32_t fwkFormat,
+           uint32_t format, uint32_t type, void* pixels, void* pMetadata) {
+            FrameBuffer::getFB()->updateColorBufferFromFrameworkFormat(
+                handle, x, y, width, height, (FrameworkFormat)fwkFormat, format, type, pixels);
+        },
 };
 
 struct AndroidVirtioGpuOps* RendererImpl::getVirtioGpuOps() {
diff --git a/stream-servers/gl/ColorBufferGl.cpp b/stream-servers/gl/ColorBufferGl.cpp
index b6adab0..10625be 100644
--- a/stream-servers/gl/ColorBufferGl.cpp
+++ b/stream-servers/gl/ColorBufferGl.cpp
@@ -584,7 +584,12 @@
     if (m_vulkanOnly) {
         return;
     }
+    subUpdateFromFrameworkFormat(x, y, width, height, m_frameworkFormat, p_format, p_type, pixels);
+}
 
+void ColorBuffer::subUpdateFromFrameworkFormat(int x, int y, int width, int height,
+                                               FrameworkFormat fwkFormat, GLenum p_format,
+                                               GLenum p_type, void* pixels) {
     const GLenum p_unsizedFormat = sGetUnsizedColorBufferFormat(p_format);
     RecursiveScopedContextBind context(m_helper);
     if (!context.isOk()) {
@@ -602,13 +607,13 @@
         m_needFormatCheck = false;
     }
 
-    if (m_frameworkFormat != FRAMEWORK_FORMAT_GL_COMPATIBLE) {
+    if (m_frameworkFormat != FRAMEWORK_FORMAT_GL_COMPATIBLE || fwkFormat != m_frameworkFormat) {
         assert(m_yuv_converter.get());
 
         // This FBO will convert the YUV frame to RGB
         // and render it to |m_tex|.
         bindFbo(&m_yuv_conversion_fbo, m_tex, m_needFboReattach);
-        m_yuv_converter->drawConvert(x, y, width, height, (char*)pixels);
+        m_yuv_converter->drawConvertFromFormat(fwkFormat, x, y, width, height, (char*)pixels);
         unbindFbo();
 
         // |m_tex| still needs to be bound afterwards
diff --git a/stream-servers/gl/ColorBufferGl.h b/stream-servers/gl/ColorBufferGl.h
index 800059a..6add3d5 100644
--- a/stream-servers/gl/ColorBufferGl.h
+++ b/stream-servers/gl/ColorBufferGl.h
@@ -150,6 +150,9 @@
                    GLenum p_format,
                    GLenum p_type,
                    void* pixels);
+    void subUpdateFromFrameworkFormat(int x, int y, int width, int height,
+                                      FrameworkFormat fwkFormat, GLenum p_format, GLenum p_type,
+                                      void* pixels);
 
     // Completely replaces contents, assuming that |pixels| is a buffer
     // that is allocated and filled with the same format.
diff --git a/stream-servers/gl/YUVConverter.cpp b/stream-servers/gl/YUVConverter.cpp
index 36aac25..1f0732e 100644
--- a/stream-servers/gl/YUVConverter.cpp
+++ b/stream-servers/gl/YUVConverter.cpp
@@ -880,17 +880,35 @@
     }
 
     mFormat = format;
+    mTexturesSwapped = true;
 }
 
+// drawConvert: per-frame updates.
+// Update YUV textures, then draw the fullscreen
+// quad set up above, which results in a framebuffer
+// with the RGB colors.
 void YUVConverter::drawConvert(int x, int y, int width, int height, const char* pixels) {
-    YUV_DEBUG_LOG("x:%d y:%d w:%d h:%d", x, y, width, height);
+    drawConvertFromFormat(mFormat, x, y, width, height, pixels);
+}
 
+void YUVConverter::drawConvertFromFormat(FrameworkFormat format, int x, int y, int width,
+                                         int height, const char* pixels) {
     saveGLState();
     if (pixels && (width != mWidth || height != mHeight)) {
         reset();
     }
 
-    if (mProgram == 0) {
+    bool uploadFormatChanged = !mTexturesSwapped && pixels && (format != mFormat);
+    bool initNeeded = (mProgram == 0) || uploadFormatChanged;
+
+    if (initNeeded) {
+        if (uploadFormatChanged) {
+            mFormat = format;
+            // TODO: missing cherry-picks, put it back
+            // b/264928117
+            //mCbFormat = format;
+            reset();
+        }
         init(width, height, mFormat);
     }
 
diff --git a/stream-servers/gl/YUVConverter.h b/stream-servers/gl/YUVConverter.h
index eebeb4c..8cddee1 100644
--- a/stream-servers/gl/YUVConverter.h
+++ b/stream-servers/gl/YUVConverter.h
@@ -63,6 +63,8 @@
     // the host color buffer
     // (rcUpdateColorBuffer)
     void drawConvert(int x, int y, int width, int height, const char* pixels);
+    void drawConvertFromFormat(FrameworkFormat format, int x, int y, int width, int height,
+                               const char* pixels);
 
     uint32_t getDataSize();
     // read YUV data into pixels, exactly pixels_size bytes;
@@ -101,6 +103,7 @@
     GLuint mTextureY = 0;
     GLuint mTextureU = 0;
     GLuint mTextureV = 0;
+    bool mTexturesSwapped = false;
     GLint mUniformLocYWidthCutoff = -1;
     GLint mUniformLocUVWidthCutoff = -1;
     GLint mUniformLocSamplerY = -1;