1 /* SPDX-License-Identifier: GPL-2.0 OR MIT */ 2 /********************************************************** 3 * 4 * Copyright (c) 2021-2024 Broadcom. All Rights Reserved. The term 5 * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. 6 * 7 * Permission is hereby granted, free of charge, to any person 8 * obtaining a copy of this software and associated documentation 9 * files (the "Software"), to deal in the Software without 10 * restriction, including without limitation the rights to use, copy, 11 * modify, merge, publish, distribute, sublicense, and/or sell copies 12 * of the Software, and to permit persons to whom the Software is 13 * furnished to do so, subject to the following conditions: 14 * 15 * The above copyright notice and this permission notice shall be 16 * included in all copies or substantial portions of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 22 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 23 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 * SOFTWARE. 26 * 27 **********************************************************/ 28 29 #ifndef VMW_SURFACE_CACHE_H 30 #define VMW_SURFACE_CACHE_H 31 32 #include "device_include/svga3d_surfacedefs.h" 33 34 #include <drm/vmwgfx_drm.h> 35 36 #define SVGA3D_FLAGS_UPPER_32(svga3d_flags) ((svga3d_flags) >> 32) 37 #define SVGA3D_FLAGS_LOWER_32(svga3d_flags) \ 38 ((svga3d_flags) & ((uint64_t)U32_MAX)) 39 40 static inline u32 clamped_umul32(u32 a, u32 b) 41 { 42 uint64_t tmp = (uint64_t) a*b; 43 return (tmp > (uint64_t) ((u32) -1)) ? (u32) -1 : tmp; 44 } 45 46 /** 47 * vmw_surface_get_desc - Look up the appropriate SVGA3dSurfaceDesc for the 48 * given format. 49 */ 50 static inline const SVGA3dSurfaceDesc * 51 vmw_surface_get_desc(SVGA3dSurfaceFormat format) 52 { 53 if (format < ARRAY_SIZE(g_SVGA3dSurfaceDescs)) 54 return &g_SVGA3dSurfaceDescs[format]; 55 56 return &g_SVGA3dSurfaceDescs[SVGA3D_FORMAT_INVALID]; 57 } 58 59 /** 60 * vmw_surface_get_mip_size - Given a base level size and the mip level, 61 * compute the size of the mip level. 62 */ 63 static inline struct drm_vmw_size 64 vmw_surface_get_mip_size(struct drm_vmw_size base_level, u32 mip_level) 65 { 66 struct drm_vmw_size size = { 67 .width = max_t(u32, base_level.width >> mip_level, 1), 68 .height = max_t(u32, base_level.height >> mip_level, 1), 69 .depth = max_t(u32, base_level.depth >> mip_level, 1) 70 }; 71 72 return size; 73 } 74 75 static inline void 76 vmw_surface_get_size_in_blocks(const SVGA3dSurfaceDesc *desc, 77 const struct drm_vmw_size *pixel_size, 78 SVGA3dSize *block_size) 79 { 80 block_size->width = __KERNEL_DIV_ROUND_UP(pixel_size->width, 81 desc->blockSize.width); 82 block_size->height = __KERNEL_DIV_ROUND_UP(pixel_size->height, 83 desc->blockSize.height); 84 block_size->depth = __KERNEL_DIV_ROUND_UP(pixel_size->depth, 85 desc->blockSize.depth); 86 } 87 88 static inline bool 89 vmw_surface_is_planar_surface(const SVGA3dSurfaceDesc *desc) 90 { 91 return (desc->blockDesc & SVGA3DBLOCKDESC_PLANAR_YUV) != 0; 92 } 93 94 static inline u32 95 vmw_surface_calculate_pitch(const SVGA3dSurfaceDesc *desc, 96 const struct drm_vmw_size *size) 97 { 98 u32 pitch; 99 SVGA3dSize blocks; 100 101 vmw_surface_get_size_in_blocks(desc, size, &blocks); 102 103 pitch = blocks.width * desc->pitchBytesPerBlock; 104 105 return pitch; 106 } 107 108 /** 109 * vmw_surface_get_image_buffer_size - Calculates image buffer size. 110 * 111 * Return the number of bytes of buffer space required to store one image of a 112 * surface, optionally using the specified pitch. 113 * 114 * If pitch is zero, it is assumed that rows are tightly packed. 115 * 116 * This function is overflow-safe. If the result would have overflowed, instead 117 * we return MAX_UINT32. 118 */ 119 static inline u32 120 vmw_surface_get_image_buffer_size(const SVGA3dSurfaceDesc *desc, 121 const struct drm_vmw_size *size, 122 u32 pitch) 123 { 124 SVGA3dSize image_blocks; 125 u32 slice_size, total_size; 126 127 vmw_surface_get_size_in_blocks(desc, size, &image_blocks); 128 129 if (vmw_surface_is_planar_surface(desc)) { 130 total_size = clamped_umul32(image_blocks.width, 131 image_blocks.height); 132 total_size = clamped_umul32(total_size, image_blocks.depth); 133 total_size = clamped_umul32(total_size, desc->bytesPerBlock); 134 return total_size; 135 } 136 137 if (pitch == 0) 138 pitch = vmw_surface_calculate_pitch(desc, size); 139 140 slice_size = clamped_umul32(image_blocks.height, pitch); 141 total_size = clamped_umul32(slice_size, image_blocks.depth); 142 143 return total_size; 144 } 145 146 /** 147 * vmw_surface_get_serialized_size - Get the serialized size for the image. 148 */ 149 static inline u32 150 vmw_surface_get_serialized_size(SVGA3dSurfaceFormat format, 151 struct drm_vmw_size base_level_size, 152 u32 num_mip_levels, 153 u32 num_layers) 154 { 155 const SVGA3dSurfaceDesc *desc = vmw_surface_get_desc(format); 156 u32 total_size = 0; 157 u32 mip; 158 159 for (mip = 0; mip < num_mip_levels; mip++) { 160 struct drm_vmw_size size = 161 vmw_surface_get_mip_size(base_level_size, mip); 162 total_size += vmw_surface_get_image_buffer_size(desc, 163 &size, 0); 164 } 165 166 return total_size * num_layers; 167 } 168 169 /** 170 * vmw_surface_get_serialized_size_extended - Returns the number of bytes 171 * required for a surface with given parameters. Support for sample count. 172 */ 173 static inline u32 174 vmw_surface_get_serialized_size_extended(SVGA3dSurfaceFormat format, 175 struct drm_vmw_size base_level_size, 176 u32 num_mip_levels, 177 u32 num_layers, 178 u32 num_samples) 179 { 180 uint64_t total_size = 181 vmw_surface_get_serialized_size(format, 182 base_level_size, 183 num_mip_levels, 184 num_layers); 185 total_size *= max_t(u32, 1, num_samples); 186 187 return min_t(uint64_t, total_size, (uint64_t)U32_MAX); 188 } 189 190 /** 191 * vmw_surface_get_pixel_offset - Compute the offset (in bytes) to a pixel 192 * in an image (or volume). 193 * 194 * @width: The image width in pixels. 195 * @height: The image height in pixels 196 */ 197 static inline u32 198 vmw_surface_get_pixel_offset(SVGA3dSurfaceFormat format, 199 u32 width, u32 height, 200 u32 x, u32 y, u32 z) 201 { 202 const SVGA3dSurfaceDesc *desc = vmw_surface_get_desc(format); 203 const u32 bw = desc->blockSize.width, bh = desc->blockSize.height; 204 const u32 bd = desc->blockSize.depth; 205 const u32 rowstride = __KERNEL_DIV_ROUND_UP(width, bw) * 206 desc->bytesPerBlock; 207 const u32 imgstride = __KERNEL_DIV_ROUND_UP(height, bh) * rowstride; 208 const u32 offset = (z / bd * imgstride + 209 y / bh * rowstride + 210 x / bw * desc->bytesPerBlock); 211 return offset; 212 } 213 214 static inline u32 215 vmw_surface_get_image_offset(SVGA3dSurfaceFormat format, 216 struct drm_vmw_size baseLevelSize, 217 u32 numMipLevels, 218 u32 face, 219 u32 mip) 220 221 { 222 u32 offset; 223 u32 mipChainBytes; 224 u32 mipChainBytesToLevel; 225 u32 i; 226 const SVGA3dSurfaceDesc *desc; 227 struct drm_vmw_size mipSize; 228 u32 bytes; 229 230 desc = vmw_surface_get_desc(format); 231 232 mipChainBytes = 0; 233 mipChainBytesToLevel = 0; 234 for (i = 0; i < numMipLevels; i++) { 235 mipSize = vmw_surface_get_mip_size(baseLevelSize, i); 236 bytes = vmw_surface_get_image_buffer_size(desc, &mipSize, 0); 237 mipChainBytes += bytes; 238 if (i < mip) 239 mipChainBytesToLevel += bytes; 240 } 241 242 offset = mipChainBytes * face + mipChainBytesToLevel; 243 244 return offset; 245 } 246 247 248 /** 249 * vmw_surface_is_gb_screen_target_format - Is the specified format usable as 250 * a ScreenTarget? 251 * (with just the GBObjects cap-bit 252 * set) 253 * @format: format to queried 254 * 255 * RETURNS: 256 * true if queried format is valid for screen targets 257 */ 258 static inline bool 259 vmw_surface_is_gb_screen_target_format(SVGA3dSurfaceFormat format) 260 { 261 return (format == SVGA3D_X8R8G8B8 || 262 format == SVGA3D_A8R8G8B8 || 263 format == SVGA3D_R5G6B5 || 264 format == SVGA3D_X1R5G5B5 || 265 format == SVGA3D_A1R5G5B5 || 266 format == SVGA3D_P8); 267 } 268 269 270 /** 271 * vmw_surface_is_dx_screen_target_format - Is the specified format usable as 272 * a ScreenTarget? 273 * (with DX10 enabled) 274 * 275 * @format: format to queried 276 * 277 * Results: 278 * true if queried format is valid for screen targets 279 */ 280 static inline bool 281 vmw_surface_is_dx_screen_target_format(SVGA3dSurfaceFormat format) 282 { 283 return (format == SVGA3D_R8G8B8A8_UNORM || 284 format == SVGA3D_B8G8R8A8_UNORM || 285 format == SVGA3D_B8G8R8X8_UNORM); 286 } 287 288 289 /** 290 * vmw_surface_is_screen_target_format - Is the specified format usable as a 291 * ScreenTarget? 292 * (for some combination of caps) 293 * 294 * @format: format to queried 295 * 296 * Results: 297 * true if queried format is valid for screen targets 298 */ 299 static inline bool 300 vmw_surface_is_screen_target_format(SVGA3dSurfaceFormat format) 301 { 302 if (vmw_surface_is_gb_screen_target_format(format)) { 303 return true; 304 } 305 return vmw_surface_is_dx_screen_target_format(format); 306 } 307 308 /** 309 * struct vmw_surface_mip - Mimpmap level information 310 * @bytes: Bytes required in the backing store of this mipmap level. 311 * @img_stride: Byte stride per image. 312 * @row_stride: Byte stride per block row. 313 * @size: The size of the mipmap. 314 */ 315 struct vmw_surface_mip { 316 size_t bytes; 317 size_t img_stride; 318 size_t row_stride; 319 struct drm_vmw_size size; 320 321 }; 322 323 /** 324 * struct vmw_surface_cache - Cached surface information 325 * @desc: Pointer to the surface descriptor 326 * @mip: Array of mipmap level information. Valid size is @num_mip_levels. 327 * @mip_chain_bytes: Bytes required in the backing store for the whole chain 328 * of mip levels. 329 * @sheet_bytes: Bytes required in the backing store for a sheet 330 * representing a single sample. 331 * @num_mip_levels: Valid size of the @mip array. Number of mipmap levels in 332 * a chain. 333 * @num_layers: Number of slices in an array texture or number of faces in 334 * a cubemap texture. 335 */ 336 struct vmw_surface_cache { 337 const SVGA3dSurfaceDesc *desc; 338 struct vmw_surface_mip mip[DRM_VMW_MAX_MIP_LEVELS]; 339 size_t mip_chain_bytes; 340 size_t sheet_bytes; 341 u32 num_mip_levels; 342 u32 num_layers; 343 }; 344 345 /** 346 * struct vmw_surface_loc - Surface location 347 * @sheet: The multisample sheet. 348 * @sub_resource: Surface subresource. Defined as layer * num_mip_levels + 349 * mip_level. 350 * @x: X coordinate. 351 * @y: Y coordinate. 352 * @z: Z coordinate. 353 */ 354 struct vmw_surface_loc { 355 u32 sheet; 356 u32 sub_resource; 357 u32 x, y, z; 358 }; 359 360 /** 361 * vmw_surface_subres - Compute the subresource from layer and mipmap. 362 * @cache: Surface layout data. 363 * @mip_level: The mipmap level. 364 * @layer: The surface layer (face or array slice). 365 * 366 * Return: The subresource. 367 */ 368 static inline u32 vmw_surface_subres(const struct vmw_surface_cache *cache, 369 u32 mip_level, u32 layer) 370 { 371 return cache->num_mip_levels * layer + mip_level; 372 } 373 374 /** 375 * vmw_surface_setup_cache - Build a surface cache entry 376 * @size: The surface base level dimensions. 377 * @format: The surface format. 378 * @num_mip_levels: Number of mipmap levels. 379 * @num_layers: Number of layers. 380 * @cache: Pointer to a struct vmw_surface_cach object to be filled in. 381 * 382 * Return: Zero on success, -EINVAL on invalid surface layout. 383 */ 384 static inline int vmw_surface_setup_cache(const struct drm_vmw_size *size, 385 SVGA3dSurfaceFormat format, 386 u32 num_mip_levels, 387 u32 num_layers, 388 u32 num_samples, 389 struct vmw_surface_cache *cache) 390 { 391 const SVGA3dSurfaceDesc *desc; 392 u32 i; 393 394 memset(cache, 0, sizeof(*cache)); 395 cache->desc = desc = vmw_surface_get_desc(format); 396 cache->num_mip_levels = num_mip_levels; 397 cache->num_layers = num_layers; 398 for (i = 0; i < cache->num_mip_levels; i++) { 399 struct vmw_surface_mip *mip = &cache->mip[i]; 400 401 mip->size = vmw_surface_get_mip_size(*size, i); 402 mip->bytes = vmw_surface_get_image_buffer_size 403 (desc, &mip->size, 0); 404 mip->row_stride = 405 __KERNEL_DIV_ROUND_UP(mip->size.width, 406 desc->blockSize.width) * 407 desc->bytesPerBlock * num_samples; 408 if (!mip->row_stride) 409 goto invalid_dim; 410 411 mip->img_stride = 412 __KERNEL_DIV_ROUND_UP(mip->size.height, 413 desc->blockSize.height) * 414 mip->row_stride; 415 if (!mip->img_stride) 416 goto invalid_dim; 417 418 cache->mip_chain_bytes += mip->bytes; 419 } 420 cache->sheet_bytes = cache->mip_chain_bytes * num_layers; 421 if (!cache->sheet_bytes) 422 goto invalid_dim; 423 424 return 0; 425 426 invalid_dim: 427 VMW_DEBUG_USER("Invalid surface layout for dirty tracking.\n"); 428 return -EINVAL; 429 } 430 431 /** 432 * vmw_surface_get_loc - Get a surface location from an offset into the 433 * backing store 434 * @cache: Surface layout data. 435 * @loc: Pointer to a struct vmw_surface_loc to be filled in. 436 * @offset: Offset into the surface backing store. 437 */ 438 static inline void 439 vmw_surface_get_loc(const struct vmw_surface_cache *cache, 440 struct vmw_surface_loc *loc, 441 size_t offset) 442 { 443 const struct vmw_surface_mip *mip = &cache->mip[0]; 444 const SVGA3dSurfaceDesc *desc = cache->desc; 445 u32 layer; 446 int i; 447 448 loc->sheet = offset / cache->sheet_bytes; 449 offset -= loc->sheet * cache->sheet_bytes; 450 451 layer = offset / cache->mip_chain_bytes; 452 offset -= layer * cache->mip_chain_bytes; 453 for (i = 0; i < cache->num_mip_levels; ++i, ++mip) { 454 if (mip->bytes > offset) 455 break; 456 offset -= mip->bytes; 457 } 458 459 loc->sub_resource = vmw_surface_subres(cache, i, layer); 460 loc->z = offset / mip->img_stride; 461 offset -= loc->z * mip->img_stride; 462 loc->z *= desc->blockSize.depth; 463 loc->y = offset / mip->row_stride; 464 offset -= loc->y * mip->row_stride; 465 loc->y *= desc->blockSize.height; 466 loc->x = offset / desc->bytesPerBlock; 467 loc->x *= desc->blockSize.width; 468 } 469 470 /** 471 * vmw_surface_inc_loc - Clamp increment a surface location with one block 472 * size 473 * in each dimension. 474 * @loc: Pointer to a struct vmw_surface_loc to be incremented. 475 * 476 * When computing the size of a range as size = end - start, the range does not 477 * include the end element. However a location representing the last byte 478 * of a touched region in the backing store *is* included in the range. 479 * This function modifies such a location to match the end definition 480 * given as start + size which is the one used in a SVGA3dBox. 481 */ 482 static inline void 483 vmw_surface_inc_loc(const struct vmw_surface_cache *cache, 484 struct vmw_surface_loc *loc) 485 { 486 const SVGA3dSurfaceDesc *desc = cache->desc; 487 u32 mip = loc->sub_resource % cache->num_mip_levels; 488 const struct drm_vmw_size *size = &cache->mip[mip].size; 489 490 loc->sub_resource++; 491 loc->x += desc->blockSize.width; 492 if (loc->x > size->width) 493 loc->x = size->width; 494 loc->y += desc->blockSize.height; 495 if (loc->y > size->height) 496 loc->y = size->height; 497 loc->z += desc->blockSize.depth; 498 if (loc->z > size->depth) 499 loc->z = size->depth; 500 } 501 502 /** 503 * vmw_surface_min_loc - The start location in a subresource 504 * @cache: Surface layout data. 505 * @sub_resource: The subresource. 506 * @loc: Pointer to a struct vmw_surface_loc to be filled in. 507 */ 508 static inline void 509 vmw_surface_min_loc(const struct vmw_surface_cache *cache, 510 u32 sub_resource, 511 struct vmw_surface_loc *loc) 512 { 513 loc->sheet = 0; 514 loc->sub_resource = sub_resource; 515 loc->x = loc->y = loc->z = 0; 516 } 517 518 /** 519 * vmw_surface_min_loc - The end location in a subresource 520 * @cache: Surface layout data. 521 * @sub_resource: The subresource. 522 * @loc: Pointer to a struct vmw_surface_loc to be filled in. 523 * 524 * Following the end definition given in vmw_surface_inc_loc(), 525 * Compute the end location of a surface subresource. 526 */ 527 static inline void 528 vmw_surface_max_loc(const struct vmw_surface_cache *cache, 529 u32 sub_resource, 530 struct vmw_surface_loc *loc) 531 { 532 const struct drm_vmw_size *size; 533 u32 mip; 534 535 loc->sheet = 0; 536 loc->sub_resource = sub_resource + 1; 537 mip = sub_resource % cache->num_mip_levels; 538 size = &cache->mip[mip].size; 539 loc->x = size->width; 540 loc->y = size->height; 541 loc->z = size->depth; 542 } 543 544 545 #endif /* VMW_SURFACE_CACHE_H */ 546