blob: 430ab569af619c24371ce34c21c7a6e606172fe3 [file] [log] [blame]
// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/buffer_format_util.h"
#include "base/check_op.h"
#include "base/notreached.h"
#include "base/numerics/safe_math.h"
#include "ui/gfx/switches.h"
namespace gfx {
namespace {
const BufferFormat kBufferFormats[] = {
BufferFormat::R_8, BufferFormat::R_16,
BufferFormat::RG_88, BufferFormat::RG_1616,
BufferFormat::BGR_565, BufferFormat::RGBA_4444,
BufferFormat::RGBX_8888, BufferFormat::RGBA_8888,
BufferFormat::BGRX_8888, BufferFormat::BGRA_1010102,
BufferFormat::RGBA_1010102, BufferFormat::BGRA_8888,
BufferFormat::RGBA_F16, BufferFormat::YUV_420_BIPLANAR,
BufferFormat::YVU_420, BufferFormat::YUVA_420_TRIPLANAR,
BufferFormat::P010};
static_assert(std::size(kBufferFormats) ==
(static_cast<int>(BufferFormat::LAST) + 1),
"BufferFormat::LAST must be last value of kBufferFormats");
} // namespace
std::vector<BufferFormat> GetBufferFormatsForTesting() {
return std::vector<BufferFormat>(kBufferFormats,
kBufferFormats + std::size(kBufferFormats));
}
size_t AlphaBitsForBufferFormat(BufferFormat format) {
switch (format) {
case BufferFormat::RGBA_4444:
return 4;
case BufferFormat::RGBA_8888:
return 8;
case BufferFormat::BGRA_1010102:
case BufferFormat::RGBA_1010102:
return 2;
case BufferFormat::BGRA_8888:
case BufferFormat::YUVA_420_TRIPLANAR:
return 8;
case BufferFormat::RGBA_F16:
return 16;
case BufferFormat::R_8:
case BufferFormat::R_16:
case BufferFormat::RG_88:
case BufferFormat::RG_1616:
case BufferFormat::BGR_565:
case BufferFormat::RGBX_8888:
case BufferFormat::BGRX_8888:
case BufferFormat::YVU_420:
case BufferFormat::YUV_420_BIPLANAR:
case BufferFormat::P010:
return 0;
}
NOTREACHED();
return 0;
}
size_t NumberOfPlanesForLinearBufferFormat(BufferFormat format) {
switch (format) {
case BufferFormat::R_8:
case BufferFormat::R_16:
case BufferFormat::RG_88:
case BufferFormat::RG_1616:
case BufferFormat::BGR_565:
case BufferFormat::RGBA_4444:
case BufferFormat::RGBX_8888:
case BufferFormat::RGBA_8888:
case BufferFormat::BGRX_8888:
case BufferFormat::BGRA_1010102:
case BufferFormat::RGBA_1010102:
case BufferFormat::BGRA_8888:
case BufferFormat::RGBA_F16:
return 1;
case BufferFormat::YUV_420_BIPLANAR:
case BufferFormat::P010:
return 2;
case BufferFormat::YVU_420:
case BufferFormat::YUVA_420_TRIPLANAR:
return 3;
}
NOTREACHED();
return 0;
}
size_t SubsamplingFactorForBufferFormat(BufferFormat format, size_t plane) {
switch (format) {
case BufferFormat::R_8:
case BufferFormat::R_16:
case BufferFormat::RG_88:
case BufferFormat::RG_1616:
case BufferFormat::BGR_565:
case BufferFormat::RGBA_4444:
case BufferFormat::RGBX_8888:
case BufferFormat::RGBA_8888:
case BufferFormat::BGRX_8888:
case BufferFormat::BGRA_1010102:
case BufferFormat::RGBA_1010102:
case BufferFormat::BGRA_8888:
case BufferFormat::RGBA_F16:
return 1;
case BufferFormat::YVU_420: {
constexpr size_t factor[] = {1, 2, 2};
DCHECK_LT(plane, std::size(factor));
return factor[plane];
}
case BufferFormat::YUV_420_BIPLANAR:
case BufferFormat::P010: {
constexpr size_t factor[] = {1, 2};
DCHECK_LT(plane, std::size(factor));
return factor[plane];
}
case BufferFormat::YUVA_420_TRIPLANAR: {
constexpr size_t factor[] = {1, 2, 1};
DCHECK_LT(plane, std::size(factor));
return factor[plane];
}
}
NOTREACHED();
return 0;
}
base::CheckedNumeric<size_t> PlaneWidthForBufferFormatChecked(
size_t width,
BufferFormat format,
size_t plane) {
const size_t subsample = SubsamplingFactorForBufferFormat(format, plane);
return base::CheckDiv(base::CheckAdd(width, base::CheckSub(subsample, 1)),
subsample);
}
base::CheckedNumeric<size_t> PlaneHeightForBufferFormatChecked(
size_t height,
BufferFormat format,
size_t plane) {
const size_t subsample = SubsamplingFactorForBufferFormat(format, plane);
return base::CheckDiv(base::CheckAdd(height, base::CheckSub(subsample, 1)),
subsample);
}
size_t BytesPerPixelForBufferFormat(BufferFormat format, size_t plane) {
switch (format) {
case BufferFormat::R_8:
return 1;
case BufferFormat::R_16:
case BufferFormat::RG_88:
case BufferFormat::BGR_565:
case BufferFormat::RGBA_4444:
return 2;
case BufferFormat::RG_1616:
case BufferFormat::BGRX_8888:
case BufferFormat::BGRA_1010102:
case BufferFormat::RGBA_1010102:
case BufferFormat::RGBX_8888:
case BufferFormat::RGBA_8888:
case BufferFormat::BGRA_8888:
return 4;
case BufferFormat::RGBA_F16:
return 8;
case BufferFormat::YVU_420:
return 1;
case BufferFormat::YUV_420_BIPLANAR:
case BufferFormat::YUVA_420_TRIPLANAR:
return SubsamplingFactorForBufferFormat(format, plane);
case BufferFormat::P010:
return 2 * SubsamplingFactorForBufferFormat(format, plane);
}
NOTREACHED();
return 0;
}
size_t RowByteAlignmentForBufferFormat(BufferFormat format, size_t plane) {
switch (format) {
case BufferFormat::R_8:
case BufferFormat::R_16:
case BufferFormat::RG_88:
case BufferFormat::BGR_565:
case BufferFormat::RGBA_4444:
case BufferFormat::RG_1616:
case BufferFormat::BGRX_8888:
case BufferFormat::BGRA_1010102:
case BufferFormat::RGBA_1010102:
case BufferFormat::RGBX_8888:
case BufferFormat::RGBA_8888:
case BufferFormat::BGRA_8888:
return 4;
case BufferFormat::RGBA_F16:
return 8;
case BufferFormat::YVU_420:
return 1;
case BufferFormat::YUV_420_BIPLANAR:
case BufferFormat::YUVA_420_TRIPLANAR:
case BufferFormat::P010:
return BytesPerPixelForBufferFormat(format, plane);
}
NOTREACHED();
return 0;
}
size_t RowSizeForBufferFormat(size_t width, BufferFormat format, size_t plane) {
size_t row_size = 0;
bool valid = RowSizeForBufferFormatChecked(width, format, plane, &row_size);
DCHECK(valid);
return row_size;
}
bool RowSizeForBufferFormatChecked(size_t width,
BufferFormat format,
size_t plane,
size_t* size_in_bytes) {
base::CheckedNumeric<size_t> checked_size =
PlaneWidthForBufferFormatChecked(width, format, plane);
checked_size *= BytesPerPixelForBufferFormat(format, plane);
const size_t alignment = RowByteAlignmentForBufferFormat(format, plane);
checked_size = (checked_size + alignment - 1) & ~(alignment - 1);
if (!checked_size.IsValid())
return false;
*size_in_bytes = checked_size.ValueOrDie();
return true;
}
size_t PlaneSizeForBufferFormat(const Size& size,
BufferFormat format,
size_t plane) {
size_t plane_size = 0;
bool valid =
PlaneSizeForBufferFormatChecked(size, format, plane, &plane_size);
DCHECK(valid);
return plane_size;
}
bool PlaneSizeForBufferFormatChecked(const Size& size,
BufferFormat format,
size_t plane,
size_t* size_in_bytes) {
size_t row_size = 0;
if (!RowSizeForBufferFormatChecked(base::checked_cast<size_t>(size.width()),
format, plane, &row_size)) {
return false;
}
base::CheckedNumeric<size_t> checked_plane_size = row_size;
checked_plane_size *= PlaneHeightForBufferFormatChecked(
base::checked_cast<size_t>(size.height()), format, plane);
if (!checked_plane_size.IsValid())
return false;
*size_in_bytes = checked_plane_size.ValueOrDie();
return true;
}
size_t BufferSizeForBufferFormat(const Size& size, BufferFormat format) {
size_t buffer_size = 0;
bool valid = BufferSizeForBufferFormatChecked(size, format, &buffer_size);
DCHECK(valid);
return buffer_size;
}
bool BufferSizeForBufferFormatChecked(const Size& size,
BufferFormat format,
size_t* size_in_bytes) {
base::CheckedNumeric<size_t> checked_size = 0;
size_t num_planes = NumberOfPlanesForLinearBufferFormat(format);
for (size_t i = 0; i < num_planes; ++i) {
size_t plane_size = 0;
if (!PlaneSizeForBufferFormatChecked(size, format, i, &plane_size))
return false;
checked_size += plane_size;
if (!checked_size.IsValid())
return false;
}
*size_in_bytes = checked_size.ValueOrDie();
return true;
}
size_t BufferOffsetForBufferFormat(const Size& size,
BufferFormat format,
size_t plane) {
DCHECK_LT(plane, gfx::NumberOfPlanesForLinearBufferFormat(format));
switch (format) {
case BufferFormat::R_8:
case BufferFormat::R_16:
case BufferFormat::RG_88:
case BufferFormat::RG_1616:
case BufferFormat::BGR_565:
case BufferFormat::RGBA_4444:
case BufferFormat::RGBX_8888:
case BufferFormat::RGBA_8888:
case BufferFormat::BGRX_8888:
case BufferFormat::BGRA_1010102:
case BufferFormat::RGBA_1010102:
case BufferFormat::BGRA_8888:
case BufferFormat::RGBA_F16:
return 0;
case BufferFormat::YVU_420:
case BufferFormat::YUV_420_BIPLANAR:
case BufferFormat::YUVA_420_TRIPLANAR:
case BufferFormat::P010: {
size_t offset = 0;
for (size_t i = 0; i < plane; i++) {
offset += PlaneSizeForBufferFormat(size, format, i);
}
return offset;
}
}
NOTREACHED();
return 0;
}
const char* BufferFormatToString(BufferFormat format) {
switch (format) {
case BufferFormat::R_8:
return "R_8";
case BufferFormat::R_16:
return "R_16";
case BufferFormat::RG_88:
return "RG_88";
case BufferFormat::RG_1616:
return "RG_1616";
case BufferFormat::BGR_565:
return "BGR_565";
case BufferFormat::RGBA_4444:
return "RGBA_4444";
case BufferFormat::RGBX_8888:
return "RGBX_8888";
case BufferFormat::RGBA_8888:
return "RGBA_8888";
case BufferFormat::BGRX_8888:
return "BGRX_8888";
case BufferFormat::BGRA_1010102:
return "BGRA_1010102";
case BufferFormat::RGBA_1010102:
return "RGBA_1010102";
case BufferFormat::BGRA_8888:
return "BGRA_8888";
case BufferFormat::RGBA_F16:
return "RGBA_F16";
case BufferFormat::YVU_420:
return "YVU_420";
case BufferFormat::YUV_420_BIPLANAR:
return "YUV_420_BIPLANAR";
case BufferFormat::YUVA_420_TRIPLANAR:
return "YUVA_420_TRIPLANAR";
case BufferFormat::P010:
return "P010";
}
NOTREACHED()
<< "Invalid BufferFormat: "
<< static_cast<typename std::underlying_type<BufferFormat>::type>(format);
return "Invalid Format";
}
const char* BufferPlaneToString(BufferPlane format) {
switch (format) {
case BufferPlane::DEFAULT:
return "DEFAULT";
case BufferPlane::Y:
return "Y";
case BufferPlane::UV:
return "UV";
case BufferPlane::U:
return "U";
case BufferPlane::V:
return "V";
case BufferPlane::A:
return "A";
}
NOTREACHED() << "Invalid BufferPlane: "
<< static_cast<typename std::underlying_type<BufferPlane>::type>(
format);
return "Invalid Plane";
}
bool IsOddHeightMultiPlanarBuffersAllowed() {
return base::FeatureList::IsEnabled(features::kOddHeightMultiPlanarBuffers);
}
bool IsOddWidthMultiPlanarBuffersAllowed() {
return base::FeatureList::IsEnabled(features::kOddWidthMultiPlanarBuffers);
}
} // namespace gfx