blob: 724f8e17376e34d11a96b3fbf5b593b4d489bf94 [file] [log] [blame]
// Copyright (C) 2024 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
extern "C" {
#include "drm_fourcc.h"
#include "virgl_hw.h"
} // extern "C"
namespace gfxstream {
namespace host {
#define VIRGL_FORMAT_NV12 166
#define VIRGL_FORMAT_YV12 163
#define VIRGL_FORMAT_P010 314
const uint32_t kGlBgra = 0x80e1;
const uint32_t kGlRgba = 0x1908;
const uint32_t kGlRgba16f = 0x881A;
const uint32_t kGlRgb565 = 0x8d62;
const uint32_t kGlRgba1010102 = 0x8059;
const uint32_t kGlR8 = 0x8229;
const uint32_t kGlR16 = 0x822A;
const uint32_t kGlRg8 = 0x822b;
const uint32_t kGlRgb8 = 0x8051;
const uint32_t kGlLuminance = 0x1909;
const uint32_t kGlLuminanceAlpha = 0x190a;
const uint32_t kGlUnsignedByte = 0x1401;
const uint32_t kGlUnsignedShort = 0x1403;
const uint32_t kGlUnsignedShort565 = 0x8363;
const uint32_t kGlDepth16 = 0x81A5;
const uint32_t kGlDepth24 = 0x81A6;
const uint32_t kGlDepth24Stencil8 = 0x88F0;
const uint32_t kGlDepth32f = 0x8CAC;
const uint32_t kGlDepth32fStencil8 = 0x8CAD;
constexpr uint32_t kFwkFormatGlCompat = 0;
constexpr uint32_t kFwkFormatYV12 = 1;
// constexpr uint32_t kFwkFormatYUV420888 = 2;
constexpr uint32_t kFwkFormatNV12 = 3;
constexpr uint32_t kFwkFormatP010 = 4;
static inline bool virgl_format_is_yuv(uint32_t format) {
switch (format) {
case VIRGL_FORMAT_B8G8R8X8_UNORM:
case VIRGL_FORMAT_B5G6R5_UNORM:
case VIRGL_FORMAT_B8G8R8A8_UNORM:
case VIRGL_FORMAT_R10G10B10A2_UNORM:
case VIRGL_FORMAT_R16_UNORM:
case VIRGL_FORMAT_R16G16B16A16_FLOAT:
case VIRGL_FORMAT_R8_UNORM:
case VIRGL_FORMAT_R8G8_UNORM:
case VIRGL_FORMAT_R8G8B8_UNORM:
case VIRGL_FORMAT_R8G8B8A8_UNORM:
case VIRGL_FORMAT_R8G8B8X8_UNORM:
case VIRGL_FORMAT_Z16_UNORM:
case VIRGL_FORMAT_Z24_UNORM_S8_UINT:
case VIRGL_FORMAT_Z24X8_UNORM:
case VIRGL_FORMAT_Z32_FLOAT_S8X24_UINT:
case VIRGL_FORMAT_Z32_FLOAT:
return false;
case VIRGL_FORMAT_NV12:
case VIRGL_FORMAT_P010:
case VIRGL_FORMAT_YV12:
return true;
default:
stream_renderer_error("Unknown virgl format 0x%x", format);
return false;
}
}
static inline uint32_t virgl_format_to_gl(uint32_t virgl_format) {
switch (virgl_format) {
case VIRGL_FORMAT_B8G8R8X8_UNORM:
case VIRGL_FORMAT_B8G8R8A8_UNORM:
return kGlBgra;
case VIRGL_FORMAT_R8G8B8X8_UNORM:
case VIRGL_FORMAT_R8G8B8A8_UNORM:
return kGlRgba;
case VIRGL_FORMAT_B5G6R5_UNORM:
return kGlRgb565;
case VIRGL_FORMAT_R16_UNORM:
return kGlR16;
case VIRGL_FORMAT_R16G16B16A16_FLOAT:
return kGlRgba16f;
case VIRGL_FORMAT_R8_UNORM:
return kGlR8;
case VIRGL_FORMAT_R8G8_UNORM:
return kGlRg8;
case VIRGL_FORMAT_R8G8B8_UNORM:
return kGlRgb8;
case VIRGL_FORMAT_NV12:
case VIRGL_FORMAT_P010:
case VIRGL_FORMAT_YV12:
// emulated as RGBA8888
return kGlRgba;
case VIRGL_FORMAT_R10G10B10A2_UNORM:
return kGlRgba1010102;
case VIRGL_FORMAT_Z16_UNORM:
return kGlDepth16;
case VIRGL_FORMAT_Z24X8_UNORM:
return kGlDepth24;
case VIRGL_FORMAT_Z24_UNORM_S8_UINT:
return kGlDepth24Stencil8;
case VIRGL_FORMAT_Z32_FLOAT:
return kGlDepth32f;
case VIRGL_FORMAT_Z32_FLOAT_S8X24_UINT:
return kGlDepth32fStencil8;
default:
return kGlRgba;
}
}
static inline uint32_t virgl_format_to_fwk_format(uint32_t virgl_format) {
switch (virgl_format) {
case VIRGL_FORMAT_NV12:
return kFwkFormatNV12;
case VIRGL_FORMAT_P010:
return kFwkFormatP010;
case VIRGL_FORMAT_YV12:
return kFwkFormatYV12;
case VIRGL_FORMAT_R8_UNORM:
case VIRGL_FORMAT_R16_UNORM:
case VIRGL_FORMAT_R16G16B16A16_FLOAT:
case VIRGL_FORMAT_R8G8_UNORM:
case VIRGL_FORMAT_R8G8B8_UNORM:
case VIRGL_FORMAT_B8G8R8X8_UNORM:
case VIRGL_FORMAT_B8G8R8A8_UNORM:
case VIRGL_FORMAT_R8G8B8X8_UNORM:
case VIRGL_FORMAT_R8G8B8A8_UNORM:
case VIRGL_FORMAT_B5G6R5_UNORM:
case VIRGL_FORMAT_R10G10B10A2_UNORM:
case VIRGL_FORMAT_Z16_UNORM:
case VIRGL_FORMAT_Z24X8_UNORM:
case VIRGL_FORMAT_Z24_UNORM_S8_UINT:
case VIRGL_FORMAT_Z32_FLOAT:
case VIRGL_FORMAT_Z32_FLOAT_S8X24_UINT:
default: // kFwkFormatGlCompat: No extra conversions needed
return kFwkFormatGlCompat;
}
}
static inline uint32_t gl_format_to_natural_type(uint32_t format) {
switch (format) {
case kGlBgra:
case kGlRgba:
case kGlLuminance:
case kGlLuminanceAlpha:
return kGlUnsignedByte;
case kGlRgb565:
return kGlUnsignedShort565;
case kGlDepth16:
return kGlUnsignedShort;
default:
return kGlUnsignedByte;
}
}
#ifndef DRM_FORMAT_DEPTH16
#define DRM_FORMAT_DEPTH16 fourcc_code('D', '1', '6', ' ')
#define DRM_FORMAT_DEPTH24 fourcc_code('D', '2', '4', 'X')
#define DRM_FORMAT_DEPTH24_STENCIL8 fourcc_code('D', '2', '4', 'S')
#define DRM_FORMAT_DEPTH32 fourcc_code('D', '3', '2', 'F')
#define DRM_FORMAT_DEPTH32_STENCIL8 fourcc_code('D', 'F', 'S', '8')
#endif
static inline uint32_t drm_format_to_virgl_format(uint32_t format) {
switch (format) {
case DRM_FORMAT_DEPTH16:
return VIRGL_FORMAT_Z16_UNORM;
case DRM_FORMAT_DEPTH24:
return VIRGL_FORMAT_Z24X8_UNORM;
case DRM_FORMAT_DEPTH24_STENCIL8:
return VIRGL_FORMAT_Z24_UNORM_S8_UINT;
case DRM_FORMAT_DEPTH32:
return VIRGL_FORMAT_Z32_FLOAT;
case DRM_FORMAT_DEPTH32_STENCIL8:
return VIRGL_FORMAT_Z32_FLOAT_S8X24_UINT;
default:
stream_renderer_error("Unknown drm format for virgl conversion 0x%x", format);
return 0;
}
}
static inline void set_virgl_format_supported(uint32_t* mask, uint32_t virgl_format,
bool supported) {
uint32_t index = virgl_format / 32;
uint32_t bit_offset = 1 << (virgl_format & 31);
if (supported) {
mask[index] |= bit_offset;
} else {
mask[index] &= ~bit_offset;
}
}
static inline void set_drm_format_supported(uint32_t* mask, uint32_t drm_format, bool supported) {
uint32_t virgl_format = drm_format_to_virgl_format(drm_format);
set_virgl_format_supported(mask, virgl_format, supported);
}
static inline bool is_drm_format_supported(uint32_t* mask, uint32_t drm_format) {
uint32_t virgl_format = drm_format_to_virgl_format(drm_format);
uint32_t index = virgl_format / 32;
uint32_t bit_offset = 1 << (virgl_format & 31);
return (mask[index] & bit_offset) ? true : false;
}
static inline size_t virgl_format_to_linear_base(uint32_t format, uint32_t totalWidth,
uint32_t totalHeight, uint32_t x, uint32_t y,
uint32_t w, uint32_t h) {
if (virgl_format_is_yuv(format)) {
return 0;
} else {
uint32_t bpp = 4;
switch (format) {
case VIRGL_FORMAT_R16G16B16A16_FLOAT:
case VIRGL_FORMAT_Z32_FLOAT_S8X24_UINT:
bpp = 8;
break;
case VIRGL_FORMAT_B8G8R8X8_UNORM:
case VIRGL_FORMAT_B8G8R8A8_UNORM:
case VIRGL_FORMAT_R8G8B8X8_UNORM:
case VIRGL_FORMAT_R8G8B8A8_UNORM:
case VIRGL_FORMAT_R10G10B10A2_UNORM:
case VIRGL_FORMAT_Z24X8_UNORM:
case VIRGL_FORMAT_Z24_UNORM_S8_UINT:
case VIRGL_FORMAT_Z32_FLOAT:
bpp = 4;
break;
case VIRGL_FORMAT_R8G8B8_UNORM:
bpp = 3;
break;
case VIRGL_FORMAT_B5G6R5_UNORM:
case VIRGL_FORMAT_R8G8_UNORM:
case VIRGL_FORMAT_R16_UNORM:
case VIRGL_FORMAT_Z16_UNORM:
bpp = 2;
break;
case VIRGL_FORMAT_R8_UNORM:
bpp = 1;
break;
default:
stream_renderer_error("Unknown virgl format: 0x%x", format);
return 0;
}
uint32_t stride = totalWidth * bpp;
return y * stride + x * bpp;
}
return 0;
}
static inline uint32_t align_up_power_of_2(uint32_t n, uint32_t a) {
return (n + (a - 1)) & ~(a - 1);
}
static inline size_t virgl_format_to_total_xfer_len(uint32_t format, uint32_t totalWidth,
uint32_t totalHeight, uint32_t x, uint32_t y,
uint32_t w, uint32_t h) {
if (virgl_format_is_yuv(format)) {
uint32_t bpp = format == VIRGL_FORMAT_P010 ? 2 : 1;
uint32_t yWidth = totalWidth;
uint32_t yHeight = totalHeight;
uint32_t yStridePixels;
if (format == VIRGL_FORMAT_NV12) {
yStridePixels = yWidth;
} else if (format == VIRGL_FORMAT_P010) {
yStridePixels = yWidth;
} else if (format == VIRGL_FORMAT_YV12) {
yStridePixels = align_up_power_of_2(yWidth, 32);
} else {
stream_renderer_error("Unknown virgl format: 0x%x", format);
return 0;
}
uint32_t yStrideBytes = yStridePixels * bpp;
uint32_t ySize = yStrideBytes * yHeight;
uint32_t uvStridePixels;
uint32_t uvPlaneCount;
if (format == VIRGL_FORMAT_NV12) {
uvStridePixels = yStridePixels;
uvPlaneCount = 1;
} else if (format == VIRGL_FORMAT_P010) {
uvStridePixels = yStridePixels;
uvPlaneCount = 1;
} else if (format == VIRGL_FORMAT_YV12) {
uvStridePixels = yStridePixels / 2;
uvPlaneCount = 2;
} else {
stream_renderer_error("Unknown virgl yuv format: 0x%x", format);
return 0;
}
uint32_t uvStrideBytes = uvStridePixels * bpp;
uint32_t uvHeight = totalHeight / 2;
uint32_t uvSize = uvStrideBytes * uvHeight * uvPlaneCount;
uint32_t dataSize = ySize + uvSize;
return dataSize;
} else {
uint32_t bpp = 4;
switch (format) {
case VIRGL_FORMAT_R16G16B16A16_FLOAT:
case VIRGL_FORMAT_Z32_FLOAT_S8X24_UINT:
bpp = 8;
break;
case VIRGL_FORMAT_B8G8R8X8_UNORM:
case VIRGL_FORMAT_B8G8R8A8_UNORM:
case VIRGL_FORMAT_R8G8B8X8_UNORM:
case VIRGL_FORMAT_R8G8B8A8_UNORM:
case VIRGL_FORMAT_R10G10B10A2_UNORM:
case VIRGL_FORMAT_Z24X8_UNORM:
case VIRGL_FORMAT_Z24_UNORM_S8_UINT:
case VIRGL_FORMAT_Z32_FLOAT:
bpp = 4;
break;
case VIRGL_FORMAT_R8G8B8_UNORM:
bpp = 3;
break;
case VIRGL_FORMAT_B5G6R5_UNORM:
case VIRGL_FORMAT_R16_UNORM:
case VIRGL_FORMAT_R8G8_UNORM:
case VIRGL_FORMAT_Z16_UNORM:
bpp = 2;
break;
case VIRGL_FORMAT_R8_UNORM:
bpp = 1;
break;
default:
stream_renderer_error("Unknown virgl format: 0x%x", format);
return 0;
}
uint32_t stride = totalWidth * bpp;
return (h - 1U) * stride + w * bpp;
}
return 0;
}
} // namespace host
} // namespace gfxstream