[scenic] adding YUY2 to image pipe
We copy from host memory to GPU memory right now anyway
so this adds in a conversion step from YUY2 to BGRA if
the Image_Info has that format set.
Change-Id: I4c96f4a2d819da11ce0ba04ffc2fc332e8ec79c8
diff --git a/lib/ui/scenic/resources/gpu_image.cc b/lib/ui/scenic/resources/gpu_image.cc
index e59a530..b239432 100644
--- a/lib/ui/scenic/resources/gpu_image.cc
+++ b/lib/ui/scenic/resources/gpu_image.cc
@@ -43,6 +43,10 @@
bytes_per_pixel = 4u;
pixel_alignment = 4u;
break;
+ case scenic::ImageInfo::PixelFormat::YUY2:
+ error_reporter->ERROR()
+ << "GpuImage::CreateFromMemory(): PixelFormat must be BGRA_8.";
+ return nullptr;
}
if (image_info->width <= 0) {
diff --git a/lib/ui/scenic/resources/host_image.cc b/lib/ui/scenic/resources/host_image.cc
index b08d59e..3ddeac1 100644
--- a/lib/ui/scenic/resources/host_image.cc
+++ b/lib/ui/scenic/resources/host_image.cc
@@ -8,6 +8,7 @@
#include "garnet/lib/ui/scenic/resources/gpu_memory.h"
#include "garnet/lib/ui/scenic/resources/host_memory.h"
#include "lib/escher/util/image_utils.h"
+#include "lib/escher/util/image_formats.h"
namespace scene_manager {
@@ -18,74 +19,74 @@
HostImage::HostImage(Session* session,
scenic::ResourceId id,
HostMemoryPtr memory,
- escher::ImagePtr image,
- uint64_t host_memory_offset)
+ escher::ImagePtr gpu_image,
+ uint64_t host_memory_offset,
+ scenic::ImageInfo host_image_format)
: Image(session, id, HostImage::kTypeInfo),
memory_(std::move(memory)),
- memory_offset_(host_memory_offset) {
- image_ = std::move(image);
+ memory_offset_(host_memory_offset),
+ host_image_format_(host_image_format) {
+ image_ = std::move(gpu_image);
+ image_conversion_function_ =
+ escher::image_formats::GetConversionFunction(host_image_format);
}
ImagePtr HostImage::New(Session* session,
scenic::ResourceId id,
HostMemoryPtr host_memory,
- const scenic::ImageInfoPtr& image_info,
+ const scenic::ImageInfoPtr& host_image_info,
uint64_t memory_offset,
mz::ErrorReporter* error_reporter) {
- vk::Format pixel_format = vk::Format::eUndefined;
- size_t bytes_per_pixel;
- size_t pixel_alignment;
- switch (image_info->pixel_format) {
- case scenic::ImageInfo::PixelFormat::BGRA_8:
- pixel_format = vk::Format::eB8G8R8A8Unorm;
- bytes_per_pixel = 4u;
- pixel_alignment = 4u;
- break;
- }
+ // No matter what the incoming format, the gpu format will be BGRA:
+ vk::Format gpu_image_pixel_format = vk::Format::eB8G8R8A8Unorm;
+ size_t bytes_per_pixel =
+ escher::image_formats::BytesPerPixel(host_image_info->pixel_format);
+ size_t pixel_alignment =
+ escher::image_formats::PixelAlignment(host_image_info->pixel_format);
- if (image_info->width <= 0) {
+ if (host_image_info->width <= 0) {
error_reporter->ERROR()
<< "Image::CreateFromMemory(): width must be greater than 0.";
return nullptr;
}
- if (image_info->height <= 0) {
+ if (host_image_info->height <= 0) {
error_reporter->ERROR()
<< "Image::CreateFromMemory(): height must be greater than 0.";
return nullptr;
}
auto& caps = session->engine()->escher()->device()->caps();
- if (image_info->width > caps.max_image_width) {
+ if (host_image_info->width > caps.max_image_width) {
error_reporter->ERROR()
<< "Image::CreateFromMemory(): image width exceeds maximum ("
- << image_info->width << " vs. " << caps.max_image_width << ").";
+ << host_image_info->width << " vs. " << caps.max_image_width << ").";
return nullptr;
}
- if (image_info->height > caps.max_image_height) {
+ if (host_image_info->height > caps.max_image_height) {
error_reporter->ERROR()
<< "Image::CreateFromMemory(): image height exceeds maximum ("
- << image_info->height << " vs. " << caps.max_image_height << ").";
+ << host_image_info->height << " vs. " << caps.max_image_height << ").";
return nullptr;
}
- if (image_info->stride < image_info->width * bytes_per_pixel) {
+ if (host_image_info->stride < host_image_info->width * bytes_per_pixel) {
error_reporter->ERROR()
<< "Image::CreateFromMemory(): stride too small for width.";
return nullptr;
}
- if (image_info->stride % pixel_alignment != 0) {
+ if (host_image_info->stride % pixel_alignment != 0) {
error_reporter->ERROR()
<< "Image::CreateFromMemory(): stride must preserve pixel alignment.";
return nullptr;
}
- if (image_info->tiling != scenic::ImageInfo::Tiling::LINEAR) {
+ if (host_image_info->tiling != scenic::ImageInfo::Tiling::LINEAR) {
error_reporter->ERROR()
<< "Image::CreateFromMemory(): tiling must be LINEAR for images "
<< "created using host memory.";
return nullptr;
}
- size_t image_size = image_info->height * image_info->stride;
+ size_t image_size = host_image_info->height * host_image_info->stride;
if (memory_offset >= host_memory->size()) {
error_reporter->ERROR()
<< "Image::CreateFromMemory(): the offset of the Image must be "
@@ -101,27 +102,27 @@
}
// TODO(MZ-141): Support non-minimal strides.
- if (image_info->stride != image_info->width * bytes_per_pixel) {
+ if (host_image_info->stride != host_image_info->width * bytes_per_pixel) {
error_reporter->ERROR()
<< "Image::CreateFromMemory(): the stride must be minimal (MZ-141)";
return nullptr;
}
- auto escher_image = escher::image_utils::NewImageFromPixels(
- session->engine()->escher_image_factory(),
- session->engine()->escher_gpu_uploader(),
- static_cast<uint8_t*>(host_memory->memory_base()) + memory_offset,
- pixel_format, image_info->width, image_info->height);
+ auto escher_image = escher::image_utils::NewGpuImageFromPixels(
+ session->engine()->escher_image_factory(), gpu_image_pixel_format,
+ host_image_info->width, host_image_info->height);
return fxl::AdoptRef(new HostImage(session, id, std::move(host_memory),
- std::move(escher_image), memory_offset));
+ std::move(escher_image), memory_offset,
+ *host_image_info));
}
bool HostImage::UpdatePixels() {
if (session()->engine()->escher_gpu_uploader()) {
escher::image_utils::WritePixelsToImage(
session()->engine()->escher_gpu_uploader(),
- static_cast<uint8_t*>(memory_->memory_base()) + memory_offset_, image_);
+ static_cast<uint8_t*>(memory_->memory_base()) + memory_offset_, image_,
+ image_conversion_function_);
return true;
}
return false;
@@ -134,8 +135,10 @@
escher::ImagePtr escher_image = escher::Image::New(
image_owner, escher::ImageInfo(), vk::Image(), nullptr);
FXL_CHECK(escher_image);
- return fxl::AdoptRef(
- new HostImage(session, id, host_memory, escher_image, 0));
+ scenic::ImageInfo host_image_format;
+ host_image_format.pixel_format = scenic::ImageInfo::PixelFormat::BGRA_8;
+ return fxl::AdoptRef(new HostImage(session, id, host_memory, escher_image, 0,
+ host_image_format));
}
} // namespace scene_manager
diff --git a/lib/ui/scenic/resources/host_image.h b/lib/ui/scenic/resources/host_image.h
index 4be8111..3568980 100644
--- a/lib/ui/scenic/resources/host_image.h
+++ b/lib/ui/scenic/resources/host_image.h
@@ -15,6 +15,7 @@
class HostImage;
using HostImagePtr = fxl::RefPtr<Image>;
+using ImgConvertFunc = fbl::Function<void(void*, void*, uint32_t, uint32_t)>;
// An Image whose contents come from host-accessible memory.
class HostImage : public Image {
@@ -37,7 +38,7 @@
static ImagePtr New(Session* session,
scenic::ResourceId id,
HostMemoryPtr memory,
- const scenic::ImageInfoPtr& image_info,
+ const scenic::ImageInfoPtr& host_image_info,
uint64_t memory_offset,
mz::ErrorReporter* error_reporter);
@@ -57,18 +58,22 @@
// |session| is the Session that this image can be referenced from.
// |id| is the ID assigned to the resource.
// |memory| is the host memory that is associated with this image.
- // |image| is the escher::Image that is being wrapped.
+ // |gpu_image| is the escher::Image that is being wrapped.
// |host_memory_offset| specifies the offset into |memory| where the image is
// stored.
HostImage(Session* session,
scenic::ResourceId id,
HostMemoryPtr memory,
- escher::ImagePtr image,
- uint64_t host_memory_offset);
+ escher::ImagePtr gpu_image,
+ uint64_t host_memory_offset,
+ scenic::ImageInfo host_image_format);
HostMemoryPtr memory_;
// The offset into |memory_| where the image is stored, in bytes.
uint64_t memory_offset_;
+ // The format of the image stored in host memory
+ scenic::ImageInfo host_image_format_;
+ ImgConvertFunc image_conversion_function_ = nullptr;
};
} // namespace scene_manager
diff --git a/public/lib/escher/BUILD.gn b/public/lib/escher/BUILD.gn
index 4d2a469..c658431 100644
--- a/public/lib/escher/BUILD.gn
+++ b/public/lib/escher/BUILD.gn
@@ -229,6 +229,8 @@
"util/align.h",
"util/depth_to_color.cc",
"util/depth_to_color.h",
+ "util/image_formats.cc",
+ "util/image_formats.h",
"util/image_utils.cc",
"util/image_utils.h",
"util/stopwatch.h",
diff --git a/public/lib/escher/util/image_formats.cc b/public/lib/escher/util/image_formats.cc
new file mode 100644
index 0000000..53464c5
--- /dev/null
+++ b/public/lib/escher/util/image_formats.cc
@@ -0,0 +1,140 @@
+
+#include "lib/escher/util/image_formats.h"
+
+namespace escher {
+namespace image_formats {
+
+namespace {
+
+uint8_t clip(int in) {
+ uint32_t out = in < 0 ? 0 : (uint32_t)in;
+ return out > 255 ? 255 : (out & 0xff);
+}
+
+// Takes 4 bytes of YUY2 and writes 8 bytes of RGBA
+// TODO(garratt): do this better with a lookup table
+void Yuy2ToBgra(uint8_t* yuy2, uint8_t* bgra1, uint8_t* bgra2) {
+ int u = yuy2[1] - 128;
+ int y1 = 298 * (yuy2[0] - 16);
+ int v = yuy2[3] - 128;
+ int y2 = 298 * (yuy2[2] - 16);
+ bgra1[0] = clip(((y1 + 516 * u + 128) / 256)); // blue
+ bgra1[1] = clip(((y1 - 208 * v - 100 * u + 128) / 256)); // green
+ bgra1[2] = clip(((y1 + 409 * v + 128) / 256)); // red
+ bgra1[3] = 0xff; // alpha
+
+ bgra2[0] = clip(((y2 + 516 * u + 128) / 256)); // blue
+ bgra2[1] = clip(((y2 - 208 * v - 100 * u + 128) / 256)); // green
+ bgra2[2] = clip(((y2 + 409 * v + 128) / 256)); // red
+ bgra2[3] = 0xff; // alpha
+}
+
+void ConvertYuy2ToBgra(uint8_t* out_ptr,
+ uint8_t* in_ptr,
+ uint64_t buffer_size) {
+ // converts to BGRA
+ // uint8_t addresses:
+ // 0 1 2 3 4 5 6 7 8
+ // | Y | U | Y | V |
+ // | B | G | R | A | B | G | R | A
+ // We have 2 bytes per pixel, but we need to convert blocks of 4:
+ uint32_t num_double_pixels = buffer_size / 4;
+ // Since in_ptr and out_ptr are uint8_t, we step by 4 (bytes)
+ // in the incoming buffer, and 8 (bytes) in the output buffer.
+ for (unsigned int i = 0; i < num_double_pixels; i++) {
+ Yuy2ToBgra(&in_ptr[4 * i], &out_ptr[8 * i], &out_ptr[8 * i + 4]);
+ }
+}
+
+void ConvertYuy2ToBgraAndMirror(uint8_t* out_ptr,
+ uint8_t* in_ptr,
+ uint32_t out_width,
+ uint32_t out_height) {
+ uint32_t double_pixels_per_row = out_width / 2;
+ uint32_t in_stride = out_width * 2;
+ uint32_t out_stride = out_width * 4;
+ // converts to BGRA and mirrors left-right
+ for (uint32_t y = 0; y < out_height; ++y)
+ for (uint32_t x = 0; x < double_pixels_per_row; ++x) {
+ uint64_t out = 8 * ((double_pixels_per_row - 1 - x)) + y * out_stride;
+ Yuy2ToBgra(&in_ptr[4 * x + y * in_stride], &out_ptr[out + 4],
+ &out_ptr[out]);
+ }
+}
+
+void MirrorBgra(uint32_t* out_ptr,
+ uint32_t* in_ptr,
+ uint32_t width,
+ uint32_t height) {
+ // converts to BGRA and mirrors left-right
+ for (uint32_t y = 0; y < height; ++y)
+ for (uint32_t x = 0; x < width; ++x) {
+ uint64_t out = ((width - 1 - x)) + y * width;
+ out_ptr[out] = in_ptr[x + y * width];
+ }
+}
+
+} // anonymous namespace
+
+size_t BytesPerPixel(const scenic::ImageInfo::PixelFormat& pixel_format) {
+ switch (pixel_format) {
+ case scenic::ImageInfo::PixelFormat::BGRA_8:
+ return 4u;
+ case scenic::ImageInfo::PixelFormat::YUY2:
+ return 2u;
+ }
+ // TODO(garratt): throw fatal error. All formats should be enumerated here
+ return 0;
+}
+
+size_t PixelAlignment(const scenic::ImageInfo::PixelFormat& pixel_format) {
+ switch (pixel_format) {
+ case scenic::ImageInfo::PixelFormat::BGRA_8:
+ return 4u;
+ case scenic::ImageInfo::PixelFormat::YUY2:
+ return 2u;
+ }
+ // TODO(garratt): throw fatal error. All formats should be enumerated here
+ return 0;
+}
+
+ImgConvertFunc GetConversionFunction(const scenic::ImageInfo& image_info) {
+ size_t bpp = BytesPerPixel(image_info.pixel_format);
+ switch (image_info.pixel_format) {
+ case scenic::ImageInfo::PixelFormat::BGRA_8:
+ if (image_info.transform ==
+ scenic::ImageInfo::Transform::FLIP_HORIZONTAL) {
+ return [](void* out, void* in, uint32_t width, uint32_t height) {
+ MirrorBgra(reinterpret_cast<uint32_t*>(out),
+ reinterpret_cast<uint32_t*>(in), width, height);
+ };
+ } else {
+ // no conversion needed.
+ return [bpp](void* out, void* in, uint32_t width, uint32_t height) {
+ memcpy(out, in, width * height * bpp);
+ };
+ }
+ break;
+ // TODO(garratt): support vertical flipping
+ case scenic::ImageInfo::PixelFormat::YUY2:
+ if (image_info.transform ==
+ scenic::ImageInfo::Transform::FLIP_HORIZONTAL) {
+ return [](void* out, void* in, uint32_t width, uint32_t height) {
+ ConvertYuy2ToBgraAndMirror(reinterpret_cast<uint8_t*>(out),
+ reinterpret_cast<uint8_t*>(in), width,
+ height);
+ };
+ } else {
+ return [bpp](void* out, void* in, uint32_t width, uint32_t height) {
+ ConvertYuy2ToBgra(reinterpret_cast<uint8_t*>(out),
+ reinterpret_cast<uint8_t*>(in),
+ width * height * bpp);
+ };
+ }
+ break;
+ }
+ return nullptr;
+}
+
+} // namespace image_formats
+} // namespace escher
diff --git a/public/lib/escher/util/image_formats.h b/public/lib/escher/util/image_formats.h
new file mode 100644
index 0000000..558f837
--- /dev/null
+++ b/public/lib/escher/util/image_formats.h
@@ -0,0 +1,30 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#pragma once
+
+#include "lib/images/fidl/image_info.fidl.h"
+
+// Contains utilities for converting from various formats to BGRA_8, which is
+// what is needed to render.
+// TODO(garratt): Merge with existing image conversion libraries in media:
+// bin/media/video/video_converter.h
+
+namespace escher {
+namespace image_formats {
+
+// Returns the number of bytes per pixel for the given format.
+size_t BytesPerPixel(const scenic::ImageInfo::PixelFormat& pixel_format);
+
+// Returns the pixel alignment for the given format.
+size_t PixelAlignment(const scenic::ImageInfo::PixelFormat& pixel_format);
+
+using ImgConvertFunc = fbl::Function<void(void*, void*, uint32_t, uint32_t)>;
+
+// Returns a function that can be used to convert any format supported in
+// ImageInfo into a BGRA_8 image.
+ImgConvertFunc GetConversionFunction(const scenic::ImageInfo& image_info);
+
+} // namespace image_formats
+} // namespace escher
diff --git a/public/lib/escher/util/image_utils.cc b/public/lib/escher/util/image_utils.cc
index d9cb16f..e58fea8 100644
--- a/public/lib/escher/util/image_utils.cc
+++ b/public/lib/escher/util/image_utils.cc
@@ -10,6 +10,7 @@
#include "lib/escher/impl/vulkan_utils.h"
#include "lib/escher/vk/gpu_mem.h"
#include "lib/escher/vk/image_factory.h"
+#include "lib/escher/util/image_formats.h"
namespace {
struct RGBA {
@@ -99,15 +100,12 @@
return image_factory->NewImage(info);
}
-ImagePtr NewImageFromPixels(ImageFactory* image_factory,
- impl::GpuUploader* gpu_uploader,
- uint8_t* pixels,
- vk::Format format,
- uint32_t width,
- uint32_t height,
- vk::ImageUsageFlags additional_flags) {
+ImagePtr NewGpuImageFromPixels(ImageFactory* image_factory,
+ vk::Format format,
+ uint32_t width,
+ uint32_t height,
+ vk::ImageUsageFlags additional_flags) {
FXL_DCHECK(image_factory);
- FXL_DCHECK(gpu_uploader);
ImageInfo info;
info.format = format;
@@ -118,26 +116,30 @@
vk::ImageUsageFlagBits::eSampled;
// Create the new image.
- auto image = image_factory->NewImage(info);
+ auto gpu_image = image_factory->NewImage(info);
- WritePixelsToImage(gpu_uploader, pixels, image);
-
- return image;
+ return gpu_image;
}
-void WritePixelsToImage(impl::GpuUploader* gpu_uploader,
- uint8_t* pixels,
- ImagePtr image) {
+void WritePixelsToImage(
+ impl::GpuUploader* gpu_uploader,
+ uint8_t* pixels,
+ ImagePtr gpu_image,
+ const escher::image_formats::ImgConvertFunc& conversion_func) {
FXL_DCHECK(gpu_uploader);
- FXL_DCHECK(image);
+ FXL_DCHECK(gpu_image);
FXL_DCHECK(pixels);
- size_t bytes_per_pixel = BytesPerPixel(image->info().format);
- size_t width = image->info().width;
- size_t height = image->info().height;
+ size_t bytes_per_pixel = BytesPerPixel(gpu_image->info().format);
+ size_t width = gpu_image->info().width;
+ size_t height = gpu_image->info().height;
auto writer = gpu_uploader->GetWriter(width * height * bytes_per_pixel);
- memcpy(writer.ptr(), pixels, width * height * bytes_per_pixel);
+ if (!conversion_func) {
+ std::memcpy(writer.ptr(), pixels, width * height * bytes_per_pixel);
+ } else {
+ conversion_func(writer.ptr(), pixels, width, height);
+ }
vk::BufferImageCopy region;
region.imageSubresource.aspectMask = vk::ImageAspectFlagBits::eColor;
@@ -149,7 +151,7 @@
region.imageExtent.depth = 1;
region.bufferOffset = 0;
- writer.WriteImage(image, region, Semaphore::New(gpu_uploader->device()));
+ writer.WriteImage(gpu_image, region, Semaphore::New(gpu_uploader->device()));
writer.Submit();
}
@@ -161,8 +163,11 @@
FXL_DCHECK(image_factory);
FXL_DCHECK(gpu_uploader);
- return NewImageFromPixels(image_factory, gpu_uploader, pixels,
- vk::Format::eR8G8B8A8Unorm, width, height);
+ auto gpu_image = NewGpuImageFromPixels(
+ image_factory, vk::Format::eR8G8B8A8Unorm, width, height);
+
+ WritePixelsToImage(gpu_uploader, pixels, gpu_image);
+ return gpu_image;
}
ImagePtr NewCheckerboardImage(ImageFactory* image_factory,
@@ -172,9 +177,12 @@
FXL_DCHECK(image_factory);
FXL_DCHECK(gpu_uploader);
+ auto gpu_image = NewGpuImageFromPixels(
+ image_factory, vk::Format::eR8G8B8A8Unorm, width, height);
+
auto pixels = NewCheckerboardPixels(width, height);
- return NewImageFromPixels(image_factory, gpu_uploader, pixels.get(),
- vk::Format::eR8G8B8A8Unorm, width, height);
+ WritePixelsToImage(gpu_uploader, pixels.get(), gpu_image);
+ return gpu_image;
}
ImagePtr NewGradientImage(ImageFactory* image_factory,
@@ -185,8 +193,11 @@
FXL_DCHECK(gpu_uploader);
auto pixels = NewGradientPixels(width, height);
- return NewImageFromPixels(image_factory, gpu_uploader, pixels.get(),
- vk::Format::eR8G8B8A8Unorm, width, height);
+ auto gpu_image = NewGpuImageFromPixels(
+ image_factory, vk::Format::eR8G8B8A8Unorm, width, height);
+
+ WritePixelsToImage(gpu_uploader, pixels.get(), gpu_image);
+ return gpu_image;
}
ImagePtr NewNoiseImage(ImageFactory* image_factory,
@@ -198,9 +209,11 @@
FXL_DCHECK(gpu_uploader);
auto pixels = NewNoisePixels(width, height);
- return NewImageFromPixels(image_factory, gpu_uploader, pixels.get(),
- vk::Format::eR8Unorm, width, height,
- additional_flags);
+ auto gpu_image = NewGpuImageFromPixels(image_factory, vk::Format::eR8Unorm,
+ width, height, additional_flags);
+
+ WritePixelsToImage(gpu_uploader, pixels.get(), gpu_image);
+ return gpu_image;
}
std::unique_ptr<uint8_t[]> NewCheckerboardPixels(uint32_t width,
diff --git a/public/lib/escher/util/image_utils.h b/public/lib/escher/util/image_utils.h
index 1807a4c..e4875a0 100644
--- a/public/lib/escher/util/image_utils.h
+++ b/public/lib/escher/util/image_utils.h
@@ -6,6 +6,7 @@
#include "lib/escher/escher.h"
#include "lib/escher/forward_declarations.h"
+#include "lib/escher/util/image_formats.h"
#include "lib/escher/vk/image.h"
namespace escher {
@@ -47,21 +48,24 @@
// |image_factory| is a generic interface that could be an Image cache (in which
// case a new Image might be created, or an existing one reused). Alternatively
// the factory could allocate a new Image every time.
-ImagePtr NewImageFromPixels(
+ImagePtr NewGpuImageFromPixels(
ImageFactory* image_factory,
- impl::GpuUploader* gpu_uploader,
- uint8_t* pixels,
vk::Format format,
uint32_t width,
uint32_t height,
vk::ImageUsageFlags additional_flags = vk::ImageUsageFlags());
-// Write the contents of |pixels| into an existing |image|.
-// The VkFormat, width, and height of |pixels| is assumed to match that of
-// |image|.
-void WritePixelsToImage(impl::GpuUploader* gpu_uploader,
- uint8_t* pixels,
- ImagePtr image);
+// Write the contents of |pixels| into an existing |gpu_image|.
+// The width, and height of |pixels| is assumed to match that of
+// |gpu_image|.
+// If the format of |pixels| is different from |gpu_image|, a conversion
+// function that can convert from |pixels| to |gpu_image| should be
+// provided as |convertion_func|.
+void WritePixelsToImage(
+ impl::GpuUploader* gpu_uploader,
+ uint8_t* pixels,
+ ImagePtr gpu_image,
+ const escher::image_formats::ImgConvertFunc& convertion_func = nullptr);
// Return new Image containing the provided pixels. Uses transfer queue to
// efficiently transfer image data to GPU. If bytes is null, don't bother
diff --git a/public/lib/images/fidl/image_info.fidl b/public/lib/images/fidl/image_info.fidl
index 48bac43..b6b530f 100644
--- a/public/lib/images/fidl/image_info.fidl
+++ b/public/lib/images/fidl/image_info.fidl
@@ -9,6 +9,12 @@
// Equivalent to Skia |kBGRA_8888_SkColorType| color type.
// Equivalent to Zircon |ARGB_8888| pixel format on little-endian arch.
BGRA_8 = 0,
+ // A 32-bit component that contains information for 2 pixels:
+ // Byte order: Y1, U, Y2, V
+ // Unpacks to 2 RGB pixels, where RGB1 = func(Y1, U, V)
+ // and RGB2 = func(Y2, U, V)
+ // Equivalent to YUV422
+ YUY2 = 1,
};
// Specifies how pixel color information should be interpreted.
@@ -40,6 +46,23 @@
NON_PREMULTIPLIED = 2,
};
+ enum Transform {
+ // Pixels are displayed normally.
+ NORMAL = 0,
+
+ // Pixels are mirrored left-right.
+ FLIP_HORIZONTAL = 1,
+
+ // Pixels are flipped vertically.
+ FLIP_VERTICAL = 2,
+
+ // Pixels are flipped vertically and mirrored left-right.
+ FLIP_VERTICAL_AND_HORIZONTAL = 3,
+ };
+
+ // Specifies if the image should be mirrored before displaying.
+ Transform transform = Transform.NORMAL;
+
// The width and height of the image in pixels.
uint32 width;
uint32 height;
diff --git a/public/lib/ui/scenic/client/resources.cc b/public/lib/ui/scenic/client/resources.cc
index 5a9d777..4d9ec47 100644
--- a/public/lib/ui/scenic/client/resources.cc
+++ b/public/lib/ui/scenic/client/resources.cc
@@ -110,6 +110,8 @@
switch (image_info.pixel_format) {
case scenic::ImageInfo::PixelFormat::BGRA_8:
return image_info.height * image_info.stride;
+ case scenic::ImageInfo::PixelFormat::YUY2:
+ return image_info.height * image_info.stride;
}
FXL_NOTREACHED();