1 // Copyright (C) 2024 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #pragma once
16 
17 extern "C" {
18 #include "drm_fourcc.h"
19 #include "virgl_hw.h"
20 }  // extern "C"
21 
22 namespace gfxstream {
23 namespace host {
24 
25 #define VIRGL_FORMAT_NV12 166
26 #define VIRGL_FORMAT_YV12 163
27 #define VIRGL_FORMAT_P010 314
28 
29 const uint32_t kGlBgra = 0x80e1;
30 const uint32_t kGlRgba = 0x1908;
31 const uint32_t kGlRgba16f = 0x881A;
32 const uint32_t kGlRgb565 = 0x8d62;
33 const uint32_t kGlRgba1010102 = 0x8059;
34 const uint32_t kGlR8 = 0x8229;
35 const uint32_t kGlR16 = 0x822A;
36 const uint32_t kGlRg8 = 0x822b;
37 const uint32_t kGlRgb8 = 0x8051;
38 const uint32_t kGlLuminance = 0x1909;
39 const uint32_t kGlLuminanceAlpha = 0x190a;
40 const uint32_t kGlUnsignedByte = 0x1401;
41 const uint32_t kGlUnsignedShort = 0x1403;
42 const uint32_t kGlUnsignedShort565 = 0x8363;
43 const uint32_t kGlDepth16 = 0x81A5;
44 const uint32_t kGlDepth24 = 0x81A6;
45 const uint32_t kGlDepth24Stencil8 = 0x88F0;
46 const uint32_t kGlDepth32f = 0x8CAC;
47 const uint32_t kGlDepth32fStencil8 = 0x8CAD;
48 
49 constexpr uint32_t kFwkFormatGlCompat = 0;
50 constexpr uint32_t kFwkFormatYV12 = 1;
51 // constexpr uint32_t kFwkFormatYUV420888 = 2;
52 constexpr uint32_t kFwkFormatNV12 = 3;
53 constexpr uint32_t kFwkFormatP010 = 4;
54 
virgl_format_is_yuv(uint32_t format)55 static inline bool virgl_format_is_yuv(uint32_t format) {
56     switch (format) {
57         case VIRGL_FORMAT_B8G8R8X8_UNORM:
58         case VIRGL_FORMAT_B5G6R5_UNORM:
59         case VIRGL_FORMAT_B8G8R8A8_UNORM:
60         case VIRGL_FORMAT_R10G10B10A2_UNORM:
61         case VIRGL_FORMAT_R16_UNORM:
62         case VIRGL_FORMAT_R16G16B16A16_FLOAT:
63         case VIRGL_FORMAT_R8_UNORM:
64         case VIRGL_FORMAT_R8G8_UNORM:
65         case VIRGL_FORMAT_R8G8B8_UNORM:
66         case VIRGL_FORMAT_R8G8B8A8_UNORM:
67         case VIRGL_FORMAT_R8G8B8X8_UNORM:
68         case VIRGL_FORMAT_Z16_UNORM:
69         case VIRGL_FORMAT_Z24_UNORM_S8_UINT:
70         case VIRGL_FORMAT_Z24X8_UNORM:
71         case VIRGL_FORMAT_Z32_FLOAT_S8X24_UINT:
72         case VIRGL_FORMAT_Z32_FLOAT:
73             return false;
74         case VIRGL_FORMAT_NV12:
75         case VIRGL_FORMAT_P010:
76         case VIRGL_FORMAT_YV12:
77             return true;
78         default:
79             stream_renderer_error("Unknown virgl format 0x%x", format);
80             return false;
81     }
82 }
83 
virgl_format_to_gl(uint32_t virgl_format)84 static inline uint32_t virgl_format_to_gl(uint32_t virgl_format) {
85     switch (virgl_format) {
86         case VIRGL_FORMAT_B8G8R8X8_UNORM:
87         case VIRGL_FORMAT_B8G8R8A8_UNORM:
88             return kGlBgra;
89         case VIRGL_FORMAT_R8G8B8X8_UNORM:
90         case VIRGL_FORMAT_R8G8B8A8_UNORM:
91             return kGlRgba;
92         case VIRGL_FORMAT_B5G6R5_UNORM:
93             return kGlRgb565;
94         case VIRGL_FORMAT_R16_UNORM:
95             return kGlR16;
96         case VIRGL_FORMAT_R16G16B16A16_FLOAT:
97             return kGlRgba16f;
98         case VIRGL_FORMAT_R8_UNORM:
99             return kGlR8;
100         case VIRGL_FORMAT_R8G8_UNORM:
101             return kGlRg8;
102         case VIRGL_FORMAT_R8G8B8_UNORM:
103             return kGlRgb8;
104         case VIRGL_FORMAT_NV12:
105         case VIRGL_FORMAT_P010:
106         case VIRGL_FORMAT_YV12:
107             // emulated as RGBA8888
108             return kGlRgba;
109         case VIRGL_FORMAT_R10G10B10A2_UNORM:
110             return kGlRgba1010102;
111         case VIRGL_FORMAT_Z16_UNORM:
112             return kGlDepth16;
113         case VIRGL_FORMAT_Z24X8_UNORM:
114             return kGlDepth24;
115         case VIRGL_FORMAT_Z24_UNORM_S8_UINT:
116             return kGlDepth24Stencil8;
117         case VIRGL_FORMAT_Z32_FLOAT:
118             return kGlDepth32f;
119         case VIRGL_FORMAT_Z32_FLOAT_S8X24_UINT:
120             return kGlDepth32fStencil8;
121         default:
122             return kGlRgba;
123     }
124 }
125 
virgl_format_to_fwk_format(uint32_t virgl_format)126 static inline uint32_t virgl_format_to_fwk_format(uint32_t virgl_format) {
127     switch (virgl_format) {
128         case VIRGL_FORMAT_NV12:
129             return kFwkFormatNV12;
130         case VIRGL_FORMAT_P010:
131             return kFwkFormatP010;
132         case VIRGL_FORMAT_YV12:
133             return kFwkFormatYV12;
134         case VIRGL_FORMAT_R8_UNORM:
135         case VIRGL_FORMAT_R16_UNORM:
136         case VIRGL_FORMAT_R16G16B16A16_FLOAT:
137         case VIRGL_FORMAT_R8G8_UNORM:
138         case VIRGL_FORMAT_R8G8B8_UNORM:
139         case VIRGL_FORMAT_B8G8R8X8_UNORM:
140         case VIRGL_FORMAT_B8G8R8A8_UNORM:
141         case VIRGL_FORMAT_R8G8B8X8_UNORM:
142         case VIRGL_FORMAT_R8G8B8A8_UNORM:
143         case VIRGL_FORMAT_B5G6R5_UNORM:
144         case VIRGL_FORMAT_R10G10B10A2_UNORM:
145         case VIRGL_FORMAT_Z16_UNORM:
146         case VIRGL_FORMAT_Z24X8_UNORM:
147         case VIRGL_FORMAT_Z24_UNORM_S8_UINT:
148         case VIRGL_FORMAT_Z32_FLOAT:
149         case VIRGL_FORMAT_Z32_FLOAT_S8X24_UINT:
150         default:  // kFwkFormatGlCompat: No extra conversions needed
151             return kFwkFormatGlCompat;
152     }
153 }
154 
gl_format_to_natural_type(uint32_t format)155 static inline uint32_t gl_format_to_natural_type(uint32_t format) {
156     switch (format) {
157         case kGlBgra:
158         case kGlRgba:
159         case kGlLuminance:
160         case kGlLuminanceAlpha:
161             return kGlUnsignedByte;
162         case kGlRgb565:
163             return kGlUnsignedShort565;
164         case kGlDepth16:
165             return kGlUnsignedShort;
166         default:
167             return kGlUnsignedByte;
168     }
169 }
170 
171 #ifndef DRM_FORMAT_DEPTH16
172 #define DRM_FORMAT_DEPTH16 fourcc_code('D', '1', '6', ' ')
173 #define DRM_FORMAT_DEPTH24 fourcc_code('D', '2', '4', 'X')
174 #define DRM_FORMAT_DEPTH24_STENCIL8 fourcc_code('D', '2', '4', 'S')
175 #define DRM_FORMAT_DEPTH32 fourcc_code('D', '3', '2', 'F')
176 #define DRM_FORMAT_DEPTH32_STENCIL8 fourcc_code('D', 'F', 'S', '8')
177 #endif
178 
drm_format_to_virgl_format(uint32_t format)179 static inline uint32_t drm_format_to_virgl_format(uint32_t format) {
180     switch (format) {
181         case DRM_FORMAT_DEPTH16:
182             return VIRGL_FORMAT_Z16_UNORM;
183         case DRM_FORMAT_DEPTH24:
184             return VIRGL_FORMAT_Z24X8_UNORM;
185         case DRM_FORMAT_DEPTH24_STENCIL8:
186             return VIRGL_FORMAT_Z24_UNORM_S8_UINT;
187         case DRM_FORMAT_DEPTH32:
188             return VIRGL_FORMAT_Z32_FLOAT;
189         case DRM_FORMAT_DEPTH32_STENCIL8:
190             return VIRGL_FORMAT_Z32_FLOAT_S8X24_UINT;
191         default:
192             stream_renderer_error("Unknown drm format for virgl conversion 0x%x", format);
193             return 0;
194     }
195 }
196 
set_virgl_format_supported(uint32_t * mask,uint32_t virgl_format,bool supported)197 static inline void set_virgl_format_supported(uint32_t* mask, uint32_t virgl_format,
198                                               bool supported) {
199     uint32_t index = virgl_format / 32;
200     uint32_t bit_offset = 1 << (virgl_format & 31);
201     if (supported) {
202         mask[index] |= bit_offset;
203     } else {
204         mask[index] &= ~bit_offset;
205     }
206 }
207 
set_drm_format_supported(uint32_t * mask,uint32_t drm_format,bool supported)208 static inline void set_drm_format_supported(uint32_t* mask, uint32_t drm_format, bool supported) {
209     uint32_t virgl_format = drm_format_to_virgl_format(drm_format);
210     set_virgl_format_supported(mask, virgl_format, supported);
211 }
212 
is_drm_format_supported(uint32_t * mask,uint32_t drm_format)213 static inline bool is_drm_format_supported(uint32_t* mask, uint32_t drm_format) {
214     uint32_t virgl_format = drm_format_to_virgl_format(drm_format);
215     uint32_t index = virgl_format / 32;
216     uint32_t bit_offset = 1 << (virgl_format & 31);
217     return (mask[index] & bit_offset) ? true : false;
218 }
219 
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)220 static inline size_t virgl_format_to_linear_base(uint32_t format, uint32_t totalWidth,
221                                                  uint32_t totalHeight, uint32_t x, uint32_t y,
222                                                  uint32_t w, uint32_t h) {
223     if (virgl_format_is_yuv(format)) {
224         return 0;
225     } else {
226         uint32_t bpp = 4;
227         switch (format) {
228             case VIRGL_FORMAT_R16G16B16A16_FLOAT:
229             case VIRGL_FORMAT_Z32_FLOAT_S8X24_UINT:
230                 bpp = 8;
231                 break;
232             case VIRGL_FORMAT_B8G8R8X8_UNORM:
233             case VIRGL_FORMAT_B8G8R8A8_UNORM:
234             case VIRGL_FORMAT_R8G8B8X8_UNORM:
235             case VIRGL_FORMAT_R8G8B8A8_UNORM:
236             case VIRGL_FORMAT_R10G10B10A2_UNORM:
237             case VIRGL_FORMAT_Z24X8_UNORM:
238             case VIRGL_FORMAT_Z24_UNORM_S8_UINT:
239             case VIRGL_FORMAT_Z32_FLOAT:
240                 bpp = 4;
241                 break;
242             case VIRGL_FORMAT_R8G8B8_UNORM:
243                 bpp = 3;
244                 break;
245             case VIRGL_FORMAT_B5G6R5_UNORM:
246             case VIRGL_FORMAT_R8G8_UNORM:
247             case VIRGL_FORMAT_R16_UNORM:
248             case VIRGL_FORMAT_Z16_UNORM:
249                 bpp = 2;
250                 break;
251             case VIRGL_FORMAT_R8_UNORM:
252                 bpp = 1;
253                 break;
254             default:
255                 stream_renderer_error("Unknown virgl format: 0x%x", format);
256                 return 0;
257         }
258 
259         uint32_t stride = totalWidth * bpp;
260         return y * stride + x * bpp;
261     }
262     return 0;
263 }
264 
align_up_power_of_2(uint32_t n,uint32_t a)265 static inline uint32_t align_up_power_of_2(uint32_t n, uint32_t a) {
266     return (n + (a - 1)) & ~(a - 1);
267 }
268 
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)269 static inline size_t virgl_format_to_total_xfer_len(uint32_t format, uint32_t totalWidth,
270                                                     uint32_t totalHeight, uint32_t x, uint32_t y,
271                                                     uint32_t w, uint32_t h) {
272     if (virgl_format_is_yuv(format)) {
273         uint32_t bpp = format == VIRGL_FORMAT_P010 ? 2 : 1;
274 
275         uint32_t yWidth = totalWidth;
276         uint32_t yHeight = totalHeight;
277         uint32_t yStridePixels;
278         if (format == VIRGL_FORMAT_NV12) {
279             yStridePixels = yWidth;
280         } else if (format == VIRGL_FORMAT_P010) {
281             yStridePixels = yWidth;
282         } else if (format == VIRGL_FORMAT_YV12) {
283             yStridePixels = align_up_power_of_2(yWidth, 32);
284         } else {
285             stream_renderer_error("Unknown virgl format: 0x%x", format);
286             return 0;
287         }
288         uint32_t yStrideBytes = yStridePixels * bpp;
289         uint32_t ySize = yStrideBytes * yHeight;
290 
291         uint32_t uvStridePixels;
292         uint32_t uvPlaneCount;
293         if (format == VIRGL_FORMAT_NV12) {
294             uvStridePixels = yStridePixels;
295             uvPlaneCount = 1;
296         } else if (format == VIRGL_FORMAT_P010) {
297             uvStridePixels = yStridePixels;
298             uvPlaneCount = 1;
299         } else if (format == VIRGL_FORMAT_YV12) {
300             uvStridePixels = yStridePixels / 2;
301             uvPlaneCount = 2;
302         } else {
303             stream_renderer_error("Unknown virgl yuv format: 0x%x", format);
304             return 0;
305         }
306         uint32_t uvStrideBytes = uvStridePixels * bpp;
307         uint32_t uvHeight = totalHeight / 2;
308         uint32_t uvSize = uvStrideBytes * uvHeight * uvPlaneCount;
309 
310         uint32_t dataSize = ySize + uvSize;
311         return dataSize;
312     } else {
313         uint32_t bpp = 4;
314         switch (format) {
315             case VIRGL_FORMAT_R16G16B16A16_FLOAT:
316             case VIRGL_FORMAT_Z32_FLOAT_S8X24_UINT:
317                 bpp = 8;
318                 break;
319             case VIRGL_FORMAT_B8G8R8X8_UNORM:
320             case VIRGL_FORMAT_B8G8R8A8_UNORM:
321             case VIRGL_FORMAT_R8G8B8X8_UNORM:
322             case VIRGL_FORMAT_R8G8B8A8_UNORM:
323             case VIRGL_FORMAT_R10G10B10A2_UNORM:
324             case VIRGL_FORMAT_Z24X8_UNORM:
325             case VIRGL_FORMAT_Z24_UNORM_S8_UINT:
326             case VIRGL_FORMAT_Z32_FLOAT:
327                 bpp = 4;
328                 break;
329             case VIRGL_FORMAT_R8G8B8_UNORM:
330                 bpp = 3;
331                 break;
332             case VIRGL_FORMAT_B5G6R5_UNORM:
333             case VIRGL_FORMAT_R16_UNORM:
334             case VIRGL_FORMAT_R8G8_UNORM:
335             case VIRGL_FORMAT_Z16_UNORM:
336                 bpp = 2;
337                 break;
338             case VIRGL_FORMAT_R8_UNORM:
339                 bpp = 1;
340                 break;
341             default:
342                 stream_renderer_error("Unknown virgl format: 0x%x", format);
343                 return 0;
344         }
345 
346         uint32_t stride = totalWidth * bpp;
347         return (h - 1U) * stride + w * bpp;
348     }
349     return 0;
350 }
351 
352 }  // namespace host
353 }  // namespace gfxstream