1 /* SPDX-License-Identifier: GPL-2.0 OR MIT */
2 /**********************************************************
3 *
4 * Copyright (c) 2024 Broadcom.
5 * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
6 *
7 **********************************************************/
8 #ifndef VMW_SURF_DEFS_H
9 #define VMW_SURF_DEFS_H
10
11 #include "util/macros.h"
12 #include "svga3d_surfacedefs.h"
13 #include "svga3d_types.h"
14
15 static inline uint32
clamped_umul32(uint32 a,uint32 b)16 clamped_umul32(uint32 a, uint32 b)
17 {
18 uint64_t tmp = (uint64_t)a * b;
19 return (tmp > (uint64_t)((uint32)-1)) ? (uint32)-1 : tmp;
20 }
21
22 static inline uint32
clamped_uadd32(uint32 a,uint32 b)23 clamped_uadd32(uint32 a, uint32 b)
24 {
25 uint32 c = a + b;
26 if (c < a || c < b) {
27 return MAX_UINT32;
28 }
29 return c;
30 }
31
32 static inline const struct SVGA3dSurfaceDesc *
vmw_surf_get_desc(SVGA3dSurfaceFormat format)33 vmw_surf_get_desc(SVGA3dSurfaceFormat format)
34 {
35 if (format < ARRAY_SIZE(g_SVGA3dSurfaceDescs))
36 return &g_SVGA3dSurfaceDescs[format];
37
38 return &g_SVGA3dSurfaceDescs[SVGA3D_FORMAT_INVALID];
39 }
40
41 static inline SVGA3dSize
vmw_surf_get_mip_size(SVGA3dSize base_level,uint32 mip_level)42 vmw_surf_get_mip_size(SVGA3dSize base_level, uint32 mip_level)
43 {
44 SVGA3dSize size;
45
46 size.width = MAX2(base_level.width >> mip_level, 1);
47 size.height = MAX2(base_level.height >> mip_level, 1);
48 size.depth = MAX2(base_level.depth >> mip_level, 1);
49 return size;
50 }
51
52 static inline void
vmw_surf_get_size_in_blocks(const struct SVGA3dSurfaceDesc * desc,const SVGA3dSize * pixel_size,SVGA3dSize * block_size)53 vmw_surf_get_size_in_blocks(const struct SVGA3dSurfaceDesc *desc,
54 const SVGA3dSize *pixel_size,
55 SVGA3dSize *block_size)
56 {
57 block_size->width = DIV_ROUND_UP(pixel_size->width, desc->blockSize.width);
58 block_size->height =
59 DIV_ROUND_UP(pixel_size->height, desc->blockSize.height);
60 block_size->depth = DIV_ROUND_UP(pixel_size->depth, desc->blockSize.depth);
61 }
62
63 static inline bool
vmw_surf_is_planar_surface(const struct SVGA3dSurfaceDesc * desc)64 vmw_surf_is_planar_surface(const struct SVGA3dSurfaceDesc *desc)
65 {
66 return (desc->blockDesc & SVGA3DBLOCKDESC_PLANAR_YUV) != 0;
67 }
68
69 static inline uint32
vmw_surf_calculate_pitch(const struct SVGA3dSurfaceDesc * desc,const SVGA3dSize * size)70 vmw_surf_calculate_pitch(const struct SVGA3dSurfaceDesc *desc,
71 const SVGA3dSize *size)
72 {
73 uint32 pitch;
74 SVGA3dSize blocks;
75
76 vmw_surf_get_size_in_blocks(desc, size, &blocks);
77
78 pitch = blocks.width * desc->pitchBytesPerBlock;
79
80 return pitch;
81 }
82
83 static inline uint32
vmw_surf_get_image_buffer_size(const struct SVGA3dSurfaceDesc * desc,const SVGA3dSize * size,uint32 pitch)84 vmw_surf_get_image_buffer_size(const struct SVGA3dSurfaceDesc *desc,
85 const SVGA3dSize *size, uint32 pitch)
86 {
87 SVGA3dSize image_blocks;
88 uint32 slice_size, total_size;
89
90 vmw_surf_get_size_in_blocks(desc, size, &image_blocks);
91
92 if (vmw_surf_is_planar_surface(desc)) {
93 total_size = clamped_umul32(image_blocks.width, image_blocks.height);
94 total_size = clamped_umul32(total_size, image_blocks.depth);
95 total_size = clamped_umul32(total_size, desc->bytesPerBlock);
96 return total_size;
97 }
98
99 if (pitch == 0)
100 pitch = vmw_surf_calculate_pitch(desc, size);
101
102 slice_size = clamped_umul32(image_blocks.height, pitch);
103 total_size = clamped_umul32(slice_size, image_blocks.depth);
104
105 return total_size;
106 }
107
108 static inline uint32
vmw_surf_get_serialized_size(SVGA3dSurfaceFormat format,SVGA3dSize base_level_size,uint32 num_mip_levels,uint32 num_layers)109 vmw_surf_get_serialized_size(SVGA3dSurfaceFormat format,
110 SVGA3dSize base_level_size, uint32 num_mip_levels,
111 uint32 num_layers)
112 {
113 const struct SVGA3dSurfaceDesc *desc = vmw_surf_get_desc(format);
114 uint64_t total_size = 0;
115 uint32 mip;
116
117 for (mip = 0; mip < num_mip_levels; mip++) {
118 SVGA3dSize size = vmw_surf_get_mip_size(base_level_size, mip);
119 total_size += vmw_surf_get_image_buffer_size(desc, &size, 0);
120 }
121
122 total_size *= num_layers;
123
124 return (total_size > (uint64_t)MAX_UINT32) ? MAX_UINT32 : (uint32)total_size;
125 }
126
127 /**
128 * vmw_surf_get_serialized_size_extended - Returns the number of bytes
129 * required for a surface with given parameters. Support for sample count.
130 *
131 */
132 static inline uint32
vmw_surf_get_serialized_size_extended(SVGA3dSurfaceFormat format,SVGA3dSize base_level_size,uint32 num_mip_levels,uint32 num_layers,uint32 num_samples)133 vmw_surf_get_serialized_size_extended(SVGA3dSurfaceFormat format,
134 SVGA3dSize base_level_size,
135 uint32 num_mip_levels, uint32 num_layers,
136 uint32 num_samples)
137 {
138 uint64_t total_size = vmw_surf_get_serialized_size(
139 format, base_level_size, num_mip_levels, num_layers);
140
141 total_size *= (num_samples > 1 ? num_samples : 1);
142
143 return (total_size > (uint64_t)MAX_UINT32) ? MAX_UINT32 : (uint32)total_size;
144 }
145
146 static inline uint32
vmw_surf_get_image_offset(SVGA3dSurfaceFormat format,SVGA3dSize baseLevelSize,uint32 numMipLevels,uint32 layer,uint32 mip)147 vmw_surf_get_image_offset(SVGA3dSurfaceFormat format, SVGA3dSize baseLevelSize,
148 uint32 numMipLevels, uint32 layer, uint32 mip)
149
150 {
151 uint32 offset;
152 uint32 mipChainBytes;
153 uint32 mipChainBytesToLevel;
154 uint32 i;
155 const struct SVGA3dSurfaceDesc *desc;
156 SVGA3dSize mipSize;
157 uint32 bytes;
158
159 desc = vmw_surf_get_desc(format);
160
161 mipChainBytes = 0;
162 mipChainBytesToLevel = 0;
163 for (i = 0; i < numMipLevels; i++) {
164 mipSize = vmw_surf_get_mip_size(baseLevelSize, i);
165 bytes = vmw_surf_get_image_buffer_size(desc, &mipSize, 0);
166 mipChainBytes += bytes;
167 if (i < mip) {
168 mipChainBytesToLevel += bytes;
169 }
170 }
171
172 offset = mipChainBytes * layer + mipChainBytesToLevel;
173
174 return offset;
175 }
176
177 /**
178 * Compute the offset (in bytes) to a pixel in an image (or volume).
179 * 'width' is the image width in pixels
180 * 'height' is the image height in pixels
181 */
182 static inline uint32
vmw_surf_get_pixel_offset(SVGA3dSurfaceFormat format,uint32 width,uint32 height,uint32 x,uint32 y,uint32 z)183 vmw_surf_get_pixel_offset(SVGA3dSurfaceFormat format, uint32 width,
184 uint32 height, uint32 x, uint32 y, uint32 z)
185 {
186 const struct SVGA3dSurfaceDesc *desc = vmw_surf_get_desc(format);
187 const uint32 bw = desc->blockSize.width, bh = desc->blockSize.height;
188 const uint32 bd = desc->blockSize.depth;
189 const uint32 rowstride = DIV_ROUND_UP(width, bw) * desc->bytesPerBlock;
190 const uint32 imgstride = DIV_ROUND_UP(height, bh) * rowstride;
191 const uint32 offset =
192 (z / bd * imgstride + y / bh * rowstride + x / bw * desc->bytesPerBlock);
193 return offset;
194 }
195
196 #endif /* VMW_SURF_DEFS_H */
197