1 /* SPDX-License-Identifier: GPL-2.0 OR MIT */
2 /**********************************************************
4 * Copyright (c) 2021-2024 Broadcom. All Rights Reserved. The term
5 * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
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:
15 * The above copyright notice and this permission notice shall be
16 * included in all copies or substantial portions of the Software.
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
27 **********************************************************/
29 #ifndef VMW_SURFACE_CACHE_H
30 #define VMW_SURFACE_CACHE_H
32 #include "device_include/svga3d_surfacedefs.h"
34 #include <drm/vmwgfx_drm.h>
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))
40 static inline u32 clamped_umul32(u32 a, u32 b)
42 uint64_t tmp = (uint64_t) a*b;
43 return (tmp > (uint64_t) ((u32) -1)) ? (u32) -1 : tmp;
47 * vmw_surface_get_desc - Look up the appropriate SVGA3dSurfaceDesc for the
50 static inline const SVGA3dSurfaceDesc *
51 vmw_surface_get_desc(SVGA3dSurfaceFormat format)
53 if (format < ARRAY_SIZE(g_SVGA3dSurfaceDescs))
54 return &g_SVGA3dSurfaceDescs[format];
56 return &g_SVGA3dSurfaceDescs[SVGA3D_FORMAT_INVALID];
60 * vmw_surface_get_mip_size - Given a base level size and the mip level,
61 * compute the size of the mip level.
63 static inline struct drm_vmw_size
64 vmw_surface_get_mip_size(struct drm_vmw_size base_level, u32 mip_level)
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)
76 vmw_surface_get_size_in_blocks(const SVGA3dSurfaceDesc *desc,
77 const struct drm_vmw_size *pixel_size,
78 SVGA3dSize *block_size)
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);
89 vmw_surface_is_planar_surface(const SVGA3dSurfaceDesc *desc)
91 return (desc->blockDesc & SVGA3DBLOCKDESC_PLANAR_YUV) != 0;
95 vmw_surface_calculate_pitch(const SVGA3dSurfaceDesc *desc,
96 const struct drm_vmw_size *size)
101 vmw_surface_get_size_in_blocks(desc, size, &blocks);
103 pitch = blocks.width * desc->pitchBytesPerBlock;
109 * vmw_surface_get_image_buffer_size - Calculates image buffer size.
111 * Return the number of bytes of buffer space required to store one image of a
112 * surface, optionally using the specified pitch.
114 * If pitch is zero, it is assumed that rows are tightly packed.
116 * This function is overflow-safe. If the result would have overflowed, instead
117 * we return MAX_UINT32.
120 vmw_surface_get_image_buffer_size(const SVGA3dSurfaceDesc *desc,
121 const struct drm_vmw_size *size,
124 SVGA3dSize image_blocks;
125 u32 slice_size, total_size;
127 vmw_surface_get_size_in_blocks(desc, size, &image_blocks);
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);
138 pitch = vmw_surface_calculate_pitch(desc, size);
140 slice_size = clamped_umul32(image_blocks.height, pitch);
141 total_size = clamped_umul32(slice_size, image_blocks.depth);
147 * vmw_surface_get_serialized_size - Get the serialized size for the image.
150 vmw_surface_get_serialized_size(SVGA3dSurfaceFormat format,
151 struct drm_vmw_size base_level_size,
155 const SVGA3dSurfaceDesc *desc = vmw_surface_get_desc(format);
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,
166 return total_size * num_layers;
170 * vmw_surface_get_serialized_size_extended - Returns the number of bytes
171 * required for a surface with given parameters. Support for sample count.
174 vmw_surface_get_serialized_size_extended(SVGA3dSurfaceFormat format,
175 struct drm_vmw_size base_level_size,
180 uint64_t total_size =
181 vmw_surface_get_serialized_size(format,
185 total_size *= max_t(u32, 1, num_samples);
187 return min_t(uint64_t, total_size, (uint64_t)U32_MAX);
191 * vmw_surface_get_pixel_offset - Compute the offset (in bytes) to a pixel
192 * in an image (or volume).
194 * @width: The image width in pixels.
195 * @height: The image height in pixels
198 vmw_surface_get_pixel_offset(SVGA3dSurfaceFormat format,
199 u32 width, u32 height,
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) *
207 const u32 imgstride = __KERNEL_DIV_ROUND_UP(height, bh) * rowstride;
208 const u32 offset = (z / bd * imgstride +
210 x / bw * desc->bytesPerBlock);
215 vmw_surface_get_image_offset(SVGA3dSurfaceFormat format,
216 struct drm_vmw_size baseLevelSize,
224 u32 mipChainBytesToLevel;
226 const SVGA3dSurfaceDesc *desc;
227 struct drm_vmw_size mipSize;
230 desc = vmw_surface_get_desc(format);
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;
239 mipChainBytesToLevel += bytes;
242 offset = mipChainBytes * face + mipChainBytesToLevel;
249 * vmw_surface_is_gb_screen_target_format - Is the specified format usable as
251 * (with just the GBObjects cap-bit
253 * @format: format to queried
256 * true if queried format is valid for screen targets
259 vmw_surface_is_gb_screen_target_format(SVGA3dSurfaceFormat format)
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);
271 * vmw_surface_is_dx_screen_target_format - Is the specified format usable as
273 * (with DX10 enabled)
275 * @format: format to queried
278 * true if queried format is valid for screen targets
281 vmw_surface_is_dx_screen_target_format(SVGA3dSurfaceFormat format)
283 return (format == SVGA3D_R8G8B8A8_UNORM ||
284 format == SVGA3D_B8G8R8A8_UNORM ||
285 format == SVGA3D_B8G8R8X8_UNORM);
290 * vmw_surface_is_screen_target_format - Is the specified format usable as a
292 * (for some combination of caps)
294 * @format: format to queried
297 * true if queried format is valid for screen targets
300 vmw_surface_is_screen_target_format(SVGA3dSurfaceFormat format)
302 if (vmw_surface_is_gb_screen_target_format(format)) {
305 return vmw_surface_is_dx_screen_target_format(format);
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.
315 struct vmw_surface_mip {
319 struct drm_vmw_size size;
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
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
333 * @num_layers: Number of slices in an array texture or number of faces in
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;
346 * struct vmw_surface_loc - Surface location
347 * @sheet: The multisample sheet.
348 * @sub_resource: Surface subresource. Defined as layer * num_mip_levels +
354 struct vmw_surface_loc {
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).
366 * Return: The subresource.
368 static inline u32 vmw_surface_subres(const struct vmw_surface_cache *cache,
369 u32 mip_level, u32 layer)
371 return cache->num_mip_levels * layer + mip_level;
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.
382 * Return: Zero on success, -EINVAL on invalid surface layout.
384 static inline int vmw_surface_setup_cache(const struct drm_vmw_size *size,
385 SVGA3dSurfaceFormat format,
389 struct vmw_surface_cache *cache)
391 const SVGA3dSurfaceDesc *desc;
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];
401 mip->size = vmw_surface_get_mip_size(*size, i);
402 mip->bytes = vmw_surface_get_image_buffer_size
403 (desc, &mip->size, 0);
405 __KERNEL_DIV_ROUND_UP(mip->size.width,
406 desc->blockSize.width) *
407 desc->bytesPerBlock * num_samples;
408 if (!mip->row_stride)
412 __KERNEL_DIV_ROUND_UP(mip->size.height,
413 desc->blockSize.height) *
415 if (!mip->img_stride)
418 cache->mip_chain_bytes += mip->bytes;
420 cache->sheet_bytes = cache->mip_chain_bytes * num_layers;
421 if (!cache->sheet_bytes)
427 VMW_DEBUG_USER("Invalid surface layout for dirty tracking.\n");
432 * vmw_surface_get_loc - Get a surface location from an offset into the
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.
439 vmw_surface_get_loc(const struct vmw_surface_cache *cache,
440 struct vmw_surface_loc *loc,
443 const struct vmw_surface_mip *mip = &cache->mip[0];
444 const SVGA3dSurfaceDesc *desc = cache->desc;
448 loc->sheet = offset / cache->sheet_bytes;
449 offset -= loc->sheet * cache->sheet_bytes;
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)
456 offset -= mip->bytes;
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;
471 * vmw_surface_inc_loc - Clamp increment a surface location with one block
474 * @loc: Pointer to a struct vmw_surface_loc to be incremented.
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.
483 vmw_surface_inc_loc(const struct vmw_surface_cache *cache,
484 struct vmw_surface_loc *loc)
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;
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;
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.
509 vmw_surface_min_loc(const struct vmw_surface_cache *cache,
511 struct vmw_surface_loc *loc)
514 loc->sub_resource = sub_resource;
515 loc->x = loc->y = loc->z = 0;
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.
524 * Following the end definition given in vmw_surface_inc_loc(),
525 * Compute the end location of a surface subresource.
528 vmw_surface_max_loc(const struct vmw_surface_cache *cache,
530 struct vmw_surface_loc *loc)
532 const struct drm_vmw_size *size;
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;
545 #endif /* VMW_SURFACE_CACHE_H */