Add YUV format utils and validation code

1. Add YuvFormatInfo struct and a few YUV format helpers
2. Update ES3 validation code to account for YUV formats

Bug: angleproject:5773
Change-Id: I82ababe8bf2a065e7d5c4f868e4a512ba8c9d7d2
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2947766
Commit-Queue: Mohan Maiya <m.maiya@samsung.com>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
This commit is contained in:
Mohan Maiya 2021-06-08 13:36:38 -07:00 коммит произвёл Angle LUCI CQ
Родитель 4264138a69
Коммит 669acb00b2
3 изменённых файлов: 249 добавлений и 7 удалений

Просмотреть файл

@ -597,6 +597,152 @@ void InsertFormatInfo(InternalFormatInfoMap *map, const InternalFormat &formatIn
(*map)[formatInfo.internalFormat][formatInfo.type] = formatInfo;
}
// YuvFormatInfo implementation
YuvFormatInfo::YuvFormatInfo(GLenum internalFormat, const Extents &yPlaneExtent)
{
ASSERT(gl::IsYuvFormat(internalFormat));
ASSERT((gl::GetPlaneCount(internalFormat) > 0) && (gl::GetPlaneCount(internalFormat) <= 3));
glInternalFormat = internalFormat;
planeCount = gl::GetPlaneCount(internalFormat);
// Chroma planes of a YUV format can be subsampled
int horizontalSubsampleFactor = 0;
int verticalSubsampleFactor = 0;
gl::GetSubSampleFactor(internalFormat, &horizontalSubsampleFactor, &verticalSubsampleFactor);
// Compute plane Bpp
planeBpp[0] = gl::GetYPlaneBpp(internalFormat);
planeBpp[1] = gl::GetChromaPlaneBpp(internalFormat);
planeBpp[2] = (planeCount > 2) ? planeBpp[1] : 0;
// Compute plane extent
planeExtent[0] = yPlaneExtent;
planeExtent[1] = {(yPlaneExtent.width / horizontalSubsampleFactor),
(yPlaneExtent.height / verticalSubsampleFactor), yPlaneExtent.depth};
planeExtent[2] = (planeCount > 2) ? planeExtent[1] : Extents();
// Compute plane pitch
planePitch[0] = planeExtent[0].width * planeBpp[0];
planePitch[1] = planeExtent[1].width * planeBpp[1];
planePitch[2] = planeExtent[2].width * planeBpp[2];
// Compute plane size
planeSize[0] = planePitch[0] * planeExtent[0].height;
planeSize[1] = planePitch[1] * planeExtent[1].height;
planeSize[2] = planePitch[2] * planeExtent[2].height;
// Compute plane offset
planeOffset[0] = 0;
planeOffset[1] = planeSize[0];
planeOffset[2] = planeSize[0] + planeSize[1];
}
// YUV format related helpers
bool IsYuvFormat(GLenum format)
{
switch (format)
{
case GL_G8_B8R8_2PLANE_420_UNORM_ANGLE:
case GL_G8_B8_R8_3PLANE_420_UNORM_ANGLE:
case GL_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16_ANGLE:
case GL_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16_ANGLE:
case GL_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16_ANGLE:
case GL_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16_ANGLE:
case GL_G16_B16R16_2PLANE_420_UNORM_ANGLE:
case GL_G16_B16_R16_3PLANE_420_UNORM_ANGLE:
return true;
default:
return false;
}
}
uint32_t GetPlaneCount(GLenum format)
{
switch (format)
{
case GL_G8_B8R8_2PLANE_420_UNORM_ANGLE:
case GL_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16_ANGLE:
case GL_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16_ANGLE:
case GL_G16_B16R16_2PLANE_420_UNORM_ANGLE:
return 2;
case GL_G8_B8_R8_3PLANE_420_UNORM_ANGLE:
case GL_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16_ANGLE:
case GL_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16_ANGLE:
case GL_G16_B16_R16_3PLANE_420_UNORM_ANGLE:
return 3;
default:
UNREACHABLE();
return 0;
}
}
uint32_t GetYPlaneBpp(GLenum format)
{
switch (format)
{
case GL_G8_B8R8_2PLANE_420_UNORM_ANGLE:
case GL_G8_B8_R8_3PLANE_420_UNORM_ANGLE:
return 1;
case GL_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16_ANGLE:
case GL_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16_ANGLE:
case GL_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16_ANGLE:
case GL_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16_ANGLE:
case GL_G16_B16R16_2PLANE_420_UNORM_ANGLE:
case GL_G16_B16_R16_3PLANE_420_UNORM_ANGLE:
return 2;
default:
UNREACHABLE();
return 0;
}
}
uint32_t GetChromaPlaneBpp(GLenum format)
{
// 2 plane 420 YUV formats have CbCr channels interleaved.
// 3 plane 420 YUV formats have separate Cb and Cr planes.
switch (format)
{
case GL_G8_B8_R8_3PLANE_420_UNORM_ANGLE:
return 1;
case GL_G8_B8R8_2PLANE_420_UNORM_ANGLE:
case GL_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16_ANGLE:
case GL_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16_ANGLE:
case GL_G16_B16_R16_3PLANE_420_UNORM_ANGLE:
return 2;
case GL_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16_ANGLE:
case GL_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16_ANGLE:
case GL_G16_B16R16_2PLANE_420_UNORM_ANGLE:
return 4;
default:
UNREACHABLE();
return 0;
}
}
void GetSubSampleFactor(GLenum format, int *horizontalSubsampleFactor, int *verticalSubsampleFactor)
{
ASSERT(horizontalSubsampleFactor && verticalSubsampleFactor);
switch (format)
{
case GL_G8_B8R8_2PLANE_420_UNORM_ANGLE:
case GL_G8_B8_R8_3PLANE_420_UNORM_ANGLE:
case GL_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16_ANGLE:
case GL_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16_ANGLE:
case GL_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16_ANGLE:
case GL_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16_ANGLE:
case GL_G16_B16R16_2PLANE_420_UNORM_ANGLE:
case GL_G16_B16_R16_3PLANE_420_UNORM_ANGLE:
*horizontalSubsampleFactor = 2;
*verticalSubsampleFactor = 2;
break;
default:
UNREACHABLE();
break;
}
}
void AddRGBAFormat(InternalFormatInfoMap *map,
GLenum internalFormat,
bool sized,

Просмотреть файл

@ -486,6 +486,32 @@ ANGLE_INLINE ComponentType GetVertexAttributeComponentType(bool pureInteger, Ver
return ComponentType::Float;
}
}
constexpr std::size_t kMaxYuvPlaneCount = 3;
template <typename T>
using YuvPlaneArray = std::array<T, kMaxYuvPlaneCount>;
struct YuvFormatInfo
{
// Sized types only.
YuvFormatInfo(GLenum internalFormat, const Extents &yPlaneExtent);
GLenum glInternalFormat;
uint32_t planeCount;
YuvPlaneArray<uint32_t> planeBpp;
YuvPlaneArray<Extents> planeExtent;
YuvPlaneArray<uint32_t> planePitch;
YuvPlaneArray<uint32_t> planeSize;
YuvPlaneArray<uint32_t> planeOffset;
};
bool IsYuvFormat(GLenum format);
uint32_t GetPlaneCount(GLenum format);
uint32_t GetYPlaneBpp(GLenum format);
uint32_t GetChromaPlaneBpp(GLenum format);
void GetSubSampleFactor(GLenum format,
int *horizontalSubsampleFactor,
int *verticalSubsampleFactor);
} // namespace gl
#endif // LIBANGLE_FORMATUTILS_H_

Просмотреть файл

@ -285,11 +285,23 @@ static bool ValidateTexImageFormatCombination(const Context *context,
}
else
{
// The type and format are valid if any supported internal format has that type and format
if (!ValidES3Format(format))
// The type and format are valid if any supported internal format has that type and format.
// ANGLE_texture_external_yuv_sampling extension adds support for YUV formats
if (gl::IsYuvFormat(format))
{
context->validationError(GL_INVALID_ENUM, kInvalidFormat);
return false;
if (!context->getExtensions().yuvInternalFormatANGLE)
{
context->validationError(GL_INVALID_ENUM, kInvalidFormat);
return false;
}
}
else
{
if (!ValidES3Format(format))
{
context->validationError(GL_INVALID_ENUM, kInvalidFormat);
return false;
}
}
if (!ValidES3Type(type))
@ -332,10 +344,22 @@ static bool ValidateTexImageFormatCombination(const Context *context,
else
{
// Check if this is a valid format combination to load texture data
if (!ValidES3FormatCombination(format, type, internalFormat))
// ANGLE_texture_external_yuv_sampling extension adds support for YUV formats
if (gl::IsYuvFormat(format))
{
context->validationError(GL_INVALID_OPERATION, kInvalidFormatCombination);
return false;
if (type != GL_UNSIGNED_BYTE)
{
context->validationError(GL_INVALID_OPERATION, kInvalidFormatCombination);
return false;
}
}
else
{
if (!ValidES3FormatCombination(format, type, internalFormat))
{
context->validationError(GL_INVALID_OPERATION, kInvalidFormatCombination);
return false;
}
}
}
@ -402,6 +426,29 @@ bool ValidateES3TexImageParametersBase(const Context *context,
{
TextureType texType = TextureTargetToType(target);
if (gl::IsYuvFormat(format))
{
// According to ANGLE_yuv_internal_format, the texture needs to be an immutable
// texture, texture target can only be TEXTURE_2D and there is no mipmap support
if (!context->getExtensions().yuvInternalFormatANGLE || !isSubImage)
{
context->validationError(GL_INVALID_ENUM, kInvalidFormat);
return false;
}
if (target != TextureTarget::_2D)
{
context->validationError(GL_INVALID_ENUM, kInvalidTextureTarget);
return false;
}
if (level != 0)
{
context->validationError(GL_INVALID_VALUE, kInvalidMipLevel);
return false;
}
}
// Validate image size
if (!ValidImageSizeParameters(context, texType, level, width, height, depth, isSubImage))
{
@ -1211,6 +1258,29 @@ bool ValidateES3TexStorageParametersBase(const Context *context,
return false;
}
// From ANGLE_texture_external_yuv_sampling:
// Texture target can only be TEXTURE_2D, there is no mipmap support
if (gl::IsYuvFormat(internalformat))
{
if (!context->getExtensions().yuvInternalFormatANGLE)
{
context->validationError(GL_INVALID_ENUM, kInvalidFormat);
return false;
}
if (target != TextureType::_2D)
{
context->validationError(GL_INVALID_ENUM, kInvalidTextureTarget);
return false;
}
if (levels != 1)
{
context->validationError(GL_INVALID_VALUE, kInvalidMipLevel);
return false;
}
}
const Caps &caps = context->getCaps();
switch (target)