| // 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 |