blob: 2c88031cb085eb2cb91c222ba95a972cc2d71051 [file] [log] [blame]
// Copyright 2019 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.
#include "src/ui/scenic/lib/utils/pixel.h"
#include <lib/syslog/cpp/macros.h>
#include <cstdint>
namespace utils {
namespace {
// List of supported pixel formats
std::vector<fuchsia::images2::PixelFormat> kSupportedPixelFormats = {
fuchsia::images2::PixelFormat::B8G8R8A8, fuchsia::images2::PixelFormat::R8G8B8A8,
fuchsia::images2::PixelFormat::R5G6B5};
} // namespace
uint8_t LinearToSrgb(const float val) {
// Function to convert from linear RGB to sRGB.
// (https://en.wikipedia.org/wiki/SRGB#From_CIE_XYZ_to_sRGB)
if (0.f <= val && val <= 0.0031308f) {
return static_cast<uint8_t>(roundf((val * 12.92f) * 255U));
}
return static_cast<uint8_t>(roundf(((powf(val, 1.0f / 2.4f) * 1.055f) - 0.055f) * 255U));
}
Pixel Pixel::FromUnormBgra(float blue, float green, float red, float alpha) {
return Pixel{LinearToSrgb(blue), LinearToSrgb(green), LinearToSrgb(red),
static_cast<uint8_t>(roundf(alpha * 255U))};
}
Pixel Pixel::FromVmo(const uint8_t* vmo_host, uint32_t stride, uint32_t x, uint32_t y,
fuchsia::images2::PixelFormat type) {
if (type == fuchsia::images2::PixelFormat::B8G8R8A8) {
return FromVmoBgra(vmo_host, stride, x, y);
}
if (type == fuchsia::images2::PixelFormat::R5G6B5) {
return FromVmoRgb565(vmo_host, stride, x, y);
}
FX_DCHECK(type == fuchsia::images2::PixelFormat::R8G8B8A8);
return FromVmoRgba(vmo_host, stride, x, y);
}
Pixel Pixel::FromVmo(const uint8_t* vmo_host, uint32_t stride, uint32_t x, uint32_t y,
fuchsia::sysmem::PixelFormatType type) {
if (type == fuchsia::sysmem::PixelFormatType::BGRA32) {
return FromVmoBgra(vmo_host, stride, x, y);
}
if (type == fuchsia::sysmem::PixelFormatType::RGB565) {
return FromVmoRgb565(vmo_host, stride, x, y);
}
FX_DCHECK(type == fuchsia::sysmem::PixelFormatType::R8G8B8A8);
return FromVmoRgba(vmo_host, stride, x, y);
}
Pixel Pixel::FromVmoRgb565(const uint8_t* vmo_host, uint32_t stride, uint32_t x, uint32_t y) {
uint16_t pixel;
memcpy(&pixel, vmo_host + (y * stride + x) * sizeof(uint16_t), sizeof(uint16_t));
uint8_t r5 = pixel >> 11;
uint8_t g6 = (pixel >> 5) & 0x3F;
uint8_t b5 = pixel & 0x1F;
uint8_t r8 = static_cast<uint8_t>(r5 * 255.0f / 31 + 0.5f);
uint8_t g8 = static_cast<uint8_t>(g6 * 255.0f / 63 + 0.5f);
uint8_t b8 = static_cast<uint8_t>(b5 * 255.0f / 31 + 0.5f);
return utils::Pixel(b8, g8, r8, 255);
}
Pixel Pixel::FromVmoRgba(const uint8_t* vmo_host, uint32_t stride, uint32_t x, uint32_t y) {
uint8_t r = vmo_host[y * stride * 4 + x * 4];
uint8_t g = vmo_host[y * stride * 4 + x * 4 + 1];
uint8_t b = vmo_host[y * stride * 4 + x * 4 + 2];
uint8_t a = vmo_host[y * stride * 4 + x * 4 + 3];
return utils::Pixel(b, g, r, a);
}
Pixel Pixel::FromVmoBgra(const uint8_t* vmo_host, uint32_t stride, uint32_t x, uint32_t y) {
uint8_t b = vmo_host[y * stride * 4 + x * 4];
uint8_t g = vmo_host[y * stride * 4 + x * 4 + 1];
uint8_t r = vmo_host[y * stride * 4 + x * 4 + 2];
uint8_t a = vmo_host[y * stride * 4 + x * 4 + 3];
return utils::Pixel(b, g, r, a);
}
std::vector<uint8_t> Pixel::ToFormat(fuchsia::images2::PixelFormat type) const {
std::vector<uint8_t> bytes;
ToFormat(type, bytes);
return bytes;
}
void Pixel::ToFormat(fuchsia::images2::PixelFormat type, std::vector<uint8_t>& bytes) const {
switch (type) {
case fuchsia::images2::PixelFormat::B8G8R8A8:
ToBgra(bytes);
break;
case fuchsia::images2::PixelFormat::R5G6B5:
ToRgb565(bytes);
break;
default:
FX_DCHECK(type == fuchsia::images2::PixelFormat::R8G8B8A8);
ToRgba(bytes);
}
}
std::vector<uint8_t> Pixel::ToFormat(fuchsia::sysmem::PixelFormatType type) const {
if (type == fuchsia::sysmem::PixelFormatType::BGRA32) {
return ToBgra();
}
if (type == fuchsia::sysmem::PixelFormatType::RGB565) {
return ToRgb565();
}
FX_DCHECK(type == fuchsia::sysmem::PixelFormatType::R8G8B8A8);
return ToRgba();
}
void Pixel::ToRgb565(std::vector<uint8_t>& bytes) const {
uint16_t color = static_cast<uint16_t>(((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3));
bytes.resize(sizeof(color));
memcpy(bytes.data(), &color, sizeof(color));
}
bool Pixel::IsFormatSupported(fuchsia::images2::PixelFormat type) {
return std::any_of(kSupportedPixelFormats.begin(), kSupportedPixelFormats.end(),
[type](fuchsia::images2::PixelFormat supported) { return supported == type; });
}
bool Pixel::IsFormatSupported(fuchsia::sysmem::PixelFormatType type) {
fuchsia::images2::PixelFormat v2_pixel_format =
static_cast<fuchsia::images2::PixelFormat>(static_cast<uint32_t>(type));
return IsFormatSupported(v2_pixel_format);
}
std::ostream& operator<<(std::ostream& stream, const Pixel& pixel) {
return stream << "{Pixel:"
<< " r:" << static_cast<unsigned int>(pixel.red)
<< " g:" << static_cast<unsigned int>(pixel.green)
<< " b:" << static_cast<unsigned int>(pixel.blue)
<< " a:" << static_cast<unsigned int>(pixel.alpha) << "}";
}
} // namespace utils