| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545 |
- /* SPDX-License-Identifier: GPL-2.0 OR MIT */
- /**********************************************************
- *
- * Copyright (c) 2021-2024 Broadcom. All Rights Reserved. The term
- * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
- *
- * Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation
- * files (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use, copy,
- * modify, merge, publish, distribute, sublicense, and/or sell copies
- * of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- **********************************************************/
- #ifndef VMW_SURFACE_CACHE_H
- #define VMW_SURFACE_CACHE_H
- #include "device_include/svga3d_surfacedefs.h"
- #include <drm/vmwgfx_drm.h>
- #define SVGA3D_FLAGS_UPPER_32(svga3d_flags) ((svga3d_flags) >> 32)
- #define SVGA3D_FLAGS_LOWER_32(svga3d_flags) \
- ((svga3d_flags) & ((uint64_t)U32_MAX))
- static inline u32 clamped_umul32(u32 a, u32 b)
- {
- uint64_t tmp = (uint64_t) a*b;
- return (tmp > (uint64_t) ((u32) -1)) ? (u32) -1 : tmp;
- }
- /**
- * vmw_surface_get_desc - Look up the appropriate SVGA3dSurfaceDesc for the
- * given format.
- */
- static inline const SVGA3dSurfaceDesc *
- vmw_surface_get_desc(SVGA3dSurfaceFormat format)
- {
- if (format < ARRAY_SIZE(g_SVGA3dSurfaceDescs))
- return &g_SVGA3dSurfaceDescs[format];
- return &g_SVGA3dSurfaceDescs[SVGA3D_FORMAT_INVALID];
- }
- /**
- * vmw_surface_get_mip_size - Given a base level size and the mip level,
- * compute the size of the mip level.
- */
- static inline struct drm_vmw_size
- vmw_surface_get_mip_size(struct drm_vmw_size base_level, u32 mip_level)
- {
- struct drm_vmw_size size = {
- .width = max_t(u32, base_level.width >> mip_level, 1),
- .height = max_t(u32, base_level.height >> mip_level, 1),
- .depth = max_t(u32, base_level.depth >> mip_level, 1)
- };
- return size;
- }
- static inline void
- vmw_surface_get_size_in_blocks(const SVGA3dSurfaceDesc *desc,
- const struct drm_vmw_size *pixel_size,
- SVGA3dSize *block_size)
- {
- block_size->width = __KERNEL_DIV_ROUND_UP(pixel_size->width,
- desc->blockSize.width);
- block_size->height = __KERNEL_DIV_ROUND_UP(pixel_size->height,
- desc->blockSize.height);
- block_size->depth = __KERNEL_DIV_ROUND_UP(pixel_size->depth,
- desc->blockSize.depth);
- }
- static inline bool
- vmw_surface_is_planar_surface(const SVGA3dSurfaceDesc *desc)
- {
- return (desc->blockDesc & SVGA3DBLOCKDESC_PLANAR_YUV) != 0;
- }
- static inline u32
- vmw_surface_calculate_pitch(const SVGA3dSurfaceDesc *desc,
- const struct drm_vmw_size *size)
- {
- u32 pitch;
- SVGA3dSize blocks;
- vmw_surface_get_size_in_blocks(desc, size, &blocks);
- pitch = blocks.width * desc->pitchBytesPerBlock;
- return pitch;
- }
- /**
- * vmw_surface_get_image_buffer_size - Calculates image buffer size.
- *
- * Return the number of bytes of buffer space required to store one image of a
- * surface, optionally using the specified pitch.
- *
- * If pitch is zero, it is assumed that rows are tightly packed.
- *
- * This function is overflow-safe. If the result would have overflowed, instead
- * we return MAX_UINT32.
- */
- static inline u32
- vmw_surface_get_image_buffer_size(const SVGA3dSurfaceDesc *desc,
- const struct drm_vmw_size *size,
- u32 pitch)
- {
- SVGA3dSize image_blocks;
- u32 slice_size, total_size;
- vmw_surface_get_size_in_blocks(desc, size, &image_blocks);
- if (vmw_surface_is_planar_surface(desc)) {
- total_size = clamped_umul32(image_blocks.width,
- image_blocks.height);
- total_size = clamped_umul32(total_size, image_blocks.depth);
- total_size = clamped_umul32(total_size, desc->bytesPerBlock);
- return total_size;
- }
- if (pitch == 0)
- pitch = vmw_surface_calculate_pitch(desc, size);
- slice_size = clamped_umul32(image_blocks.height, pitch);
- total_size = clamped_umul32(slice_size, image_blocks.depth);
- return total_size;
- }
- /**
- * vmw_surface_get_serialized_size - Get the serialized size for the image.
- */
- static inline u32
- vmw_surface_get_serialized_size(SVGA3dSurfaceFormat format,
- struct drm_vmw_size base_level_size,
- u32 num_mip_levels,
- u32 num_layers)
- {
- const SVGA3dSurfaceDesc *desc = vmw_surface_get_desc(format);
- u32 total_size = 0;
- u32 mip;
- for (mip = 0; mip < num_mip_levels; mip++) {
- struct drm_vmw_size size =
- vmw_surface_get_mip_size(base_level_size, mip);
- total_size += vmw_surface_get_image_buffer_size(desc,
- &size, 0);
- }
- return total_size * num_layers;
- }
- /**
- * vmw_surface_get_serialized_size_extended - Returns the number of bytes
- * required for a surface with given parameters. Support for sample count.
- */
- static inline u32
- vmw_surface_get_serialized_size_extended(SVGA3dSurfaceFormat format,
- struct drm_vmw_size base_level_size,
- u32 num_mip_levels,
- u32 num_layers,
- u32 num_samples)
- {
- uint64_t total_size =
- vmw_surface_get_serialized_size(format,
- base_level_size,
- num_mip_levels,
- num_layers);
- total_size *= max_t(u32, 1, num_samples);
- return min_t(uint64_t, total_size, (uint64_t)U32_MAX);
- }
- /**
- * vmw_surface_get_pixel_offset - Compute the offset (in bytes) to a pixel
- * in an image (or volume).
- *
- * @width: The image width in pixels.
- * @height: The image height in pixels
- */
- static inline u32
- vmw_surface_get_pixel_offset(SVGA3dSurfaceFormat format,
- u32 width, u32 height,
- u32 x, u32 y, u32 z)
- {
- const SVGA3dSurfaceDesc *desc = vmw_surface_get_desc(format);
- const u32 bw = desc->blockSize.width, bh = desc->blockSize.height;
- const u32 bd = desc->blockSize.depth;
- const u32 rowstride = __KERNEL_DIV_ROUND_UP(width, bw) *
- desc->bytesPerBlock;
- const u32 imgstride = __KERNEL_DIV_ROUND_UP(height, bh) * rowstride;
- const u32 offset = (z / bd * imgstride +
- y / bh * rowstride +
- x / bw * desc->bytesPerBlock);
- return offset;
- }
- static inline u32
- vmw_surface_get_image_offset(SVGA3dSurfaceFormat format,
- struct drm_vmw_size baseLevelSize,
- u32 numMipLevels,
- u32 face,
- u32 mip)
- {
- u32 offset;
- u32 mipChainBytes;
- u32 mipChainBytesToLevel;
- u32 i;
- const SVGA3dSurfaceDesc *desc;
- struct drm_vmw_size mipSize;
- u32 bytes;
- desc = vmw_surface_get_desc(format);
- mipChainBytes = 0;
- mipChainBytesToLevel = 0;
- for (i = 0; i < numMipLevels; i++) {
- mipSize = vmw_surface_get_mip_size(baseLevelSize, i);
- bytes = vmw_surface_get_image_buffer_size(desc, &mipSize, 0);
- mipChainBytes += bytes;
- if (i < mip)
- mipChainBytesToLevel += bytes;
- }
- offset = mipChainBytes * face + mipChainBytesToLevel;
- return offset;
- }
- /**
- * vmw_surface_is_gb_screen_target_format - Is the specified format usable as
- * a ScreenTarget?
- * (with just the GBObjects cap-bit
- * set)
- * @format: format to queried
- *
- * RETURNS:
- * true if queried format is valid for screen targets
- */
- static inline bool
- vmw_surface_is_gb_screen_target_format(SVGA3dSurfaceFormat format)
- {
- return (format == SVGA3D_X8R8G8B8 ||
- format == SVGA3D_A8R8G8B8 ||
- format == SVGA3D_R5G6B5 ||
- format == SVGA3D_X1R5G5B5 ||
- format == SVGA3D_A1R5G5B5 ||
- format == SVGA3D_P8);
- }
- /**
- * vmw_surface_is_dx_screen_target_format - Is the specified format usable as
- * a ScreenTarget?
- * (with DX10 enabled)
- *
- * @format: format to queried
- *
- * Results:
- * true if queried format is valid for screen targets
- */
- static inline bool
- vmw_surface_is_dx_screen_target_format(SVGA3dSurfaceFormat format)
- {
- return (format == SVGA3D_R8G8B8A8_UNORM ||
- format == SVGA3D_B8G8R8A8_UNORM ||
- format == SVGA3D_B8G8R8X8_UNORM);
- }
- /**
- * vmw_surface_is_screen_target_format - Is the specified format usable as a
- * ScreenTarget?
- * (for some combination of caps)
- *
- * @format: format to queried
- *
- * Results:
- * true if queried format is valid for screen targets
- */
- static inline bool
- vmw_surface_is_screen_target_format(SVGA3dSurfaceFormat format)
- {
- if (vmw_surface_is_gb_screen_target_format(format)) {
- return true;
- }
- return vmw_surface_is_dx_screen_target_format(format);
- }
- /**
- * struct vmw_surface_mip - Mimpmap level information
- * @bytes: Bytes required in the backing store of this mipmap level.
- * @img_stride: Byte stride per image.
- * @row_stride: Byte stride per block row.
- * @size: The size of the mipmap.
- */
- struct vmw_surface_mip {
- size_t bytes;
- size_t img_stride;
- size_t row_stride;
- struct drm_vmw_size size;
- };
- /**
- * struct vmw_surface_cache - Cached surface information
- * @desc: Pointer to the surface descriptor
- * @mip: Array of mipmap level information. Valid size is @num_mip_levels.
- * @mip_chain_bytes: Bytes required in the backing store for the whole chain
- * of mip levels.
- * @sheet_bytes: Bytes required in the backing store for a sheet
- * representing a single sample.
- * @num_mip_levels: Valid size of the @mip array. Number of mipmap levels in
- * a chain.
- * @num_layers: Number of slices in an array texture or number of faces in
- * a cubemap texture.
- */
- struct vmw_surface_cache {
- const SVGA3dSurfaceDesc *desc;
- struct vmw_surface_mip mip[DRM_VMW_MAX_MIP_LEVELS];
- size_t mip_chain_bytes;
- size_t sheet_bytes;
- u32 num_mip_levels;
- u32 num_layers;
- };
- /**
- * struct vmw_surface_loc - Surface location
- * @sheet: The multisample sheet.
- * @sub_resource: Surface subresource. Defined as layer * num_mip_levels +
- * mip_level.
- * @x: X coordinate.
- * @y: Y coordinate.
- * @z: Z coordinate.
- */
- struct vmw_surface_loc {
- u32 sheet;
- u32 sub_resource;
- u32 x, y, z;
- };
- /**
- * vmw_surface_subres - Compute the subresource from layer and mipmap.
- * @cache: Surface layout data.
- * @mip_level: The mipmap level.
- * @layer: The surface layer (face or array slice).
- *
- * Return: The subresource.
- */
- static inline u32 vmw_surface_subres(const struct vmw_surface_cache *cache,
- u32 mip_level, u32 layer)
- {
- return cache->num_mip_levels * layer + mip_level;
- }
- /**
- * vmw_surface_setup_cache - Build a surface cache entry
- * @size: The surface base level dimensions.
- * @format: The surface format.
- * @num_mip_levels: Number of mipmap levels.
- * @num_layers: Number of layers.
- * @cache: Pointer to a struct vmw_surface_cach object to be filled in.
- *
- * Return: Zero on success, -EINVAL on invalid surface layout.
- */
- static inline int vmw_surface_setup_cache(const struct drm_vmw_size *size,
- SVGA3dSurfaceFormat format,
- u32 num_mip_levels,
- u32 num_layers,
- u32 num_samples,
- struct vmw_surface_cache *cache)
- {
- const SVGA3dSurfaceDesc *desc;
- u32 i;
- memset(cache, 0, sizeof(*cache));
- cache->desc = desc = vmw_surface_get_desc(format);
- cache->num_mip_levels = num_mip_levels;
- cache->num_layers = num_layers;
- for (i = 0; i < cache->num_mip_levels; i++) {
- struct vmw_surface_mip *mip = &cache->mip[i];
- mip->size = vmw_surface_get_mip_size(*size, i);
- mip->bytes = vmw_surface_get_image_buffer_size
- (desc, &mip->size, 0);
- mip->row_stride =
- __KERNEL_DIV_ROUND_UP(mip->size.width,
- desc->blockSize.width) *
- desc->bytesPerBlock * num_samples;
- if (!mip->row_stride)
- goto invalid_dim;
- mip->img_stride =
- __KERNEL_DIV_ROUND_UP(mip->size.height,
- desc->blockSize.height) *
- mip->row_stride;
- if (!mip->img_stride)
- goto invalid_dim;
- cache->mip_chain_bytes += mip->bytes;
- }
- cache->sheet_bytes = cache->mip_chain_bytes * num_layers;
- if (!cache->sheet_bytes)
- goto invalid_dim;
- return 0;
- invalid_dim:
- VMW_DEBUG_USER("Invalid surface layout for dirty tracking.\n");
- return -EINVAL;
- }
- /**
- * vmw_surface_get_loc - Get a surface location from an offset into the
- * backing store
- * @cache: Surface layout data.
- * @loc: Pointer to a struct vmw_surface_loc to be filled in.
- * @offset: Offset into the surface backing store.
- */
- static inline void
- vmw_surface_get_loc(const struct vmw_surface_cache *cache,
- struct vmw_surface_loc *loc,
- size_t offset)
- {
- const struct vmw_surface_mip *mip = &cache->mip[0];
- const SVGA3dSurfaceDesc *desc = cache->desc;
- u32 layer;
- int i;
- loc->sheet = offset / cache->sheet_bytes;
- offset -= loc->sheet * cache->sheet_bytes;
- layer = offset / cache->mip_chain_bytes;
- offset -= layer * cache->mip_chain_bytes;
- for (i = 0; i < cache->num_mip_levels; ++i, ++mip) {
- if (mip->bytes > offset)
- break;
- offset -= mip->bytes;
- }
- loc->sub_resource = vmw_surface_subres(cache, i, layer);
- loc->z = offset / mip->img_stride;
- offset -= loc->z * mip->img_stride;
- loc->z *= desc->blockSize.depth;
- loc->y = offset / mip->row_stride;
- offset -= loc->y * mip->row_stride;
- loc->y *= desc->blockSize.height;
- loc->x = offset / desc->bytesPerBlock;
- loc->x *= desc->blockSize.width;
- }
- /**
- * vmw_surface_inc_loc - Clamp increment a surface location with one block
- * size
- * in each dimension.
- * @loc: Pointer to a struct vmw_surface_loc to be incremented.
- *
- * When computing the size of a range as size = end - start, the range does not
- * include the end element. However a location representing the last byte
- * of a touched region in the backing store *is* included in the range.
- * This function modifies such a location to match the end definition
- * given as start + size which is the one used in a SVGA3dBox.
- */
- static inline void
- vmw_surface_inc_loc(const struct vmw_surface_cache *cache,
- struct vmw_surface_loc *loc)
- {
- const SVGA3dSurfaceDesc *desc = cache->desc;
- u32 mip = loc->sub_resource % cache->num_mip_levels;
- const struct drm_vmw_size *size = &cache->mip[mip].size;
- loc->sub_resource++;
- loc->x += desc->blockSize.width;
- if (loc->x > size->width)
- loc->x = size->width;
- loc->y += desc->blockSize.height;
- if (loc->y > size->height)
- loc->y = size->height;
- loc->z += desc->blockSize.depth;
- if (loc->z > size->depth)
- loc->z = size->depth;
- }
- /**
- * vmw_surface_min_loc - The start location in a subresource
- * @cache: Surface layout data.
- * @sub_resource: The subresource.
- * @loc: Pointer to a struct vmw_surface_loc to be filled in.
- */
- static inline void
- vmw_surface_min_loc(const struct vmw_surface_cache *cache,
- u32 sub_resource,
- struct vmw_surface_loc *loc)
- {
- loc->sheet = 0;
- loc->sub_resource = sub_resource;
- loc->x = loc->y = loc->z = 0;
- }
- /**
- * vmw_surface_min_loc - The end location in a subresource
- * @cache: Surface layout data.
- * @sub_resource: The subresource.
- * @loc: Pointer to a struct vmw_surface_loc to be filled in.
- *
- * Following the end definition given in vmw_surface_inc_loc(),
- * Compute the end location of a surface subresource.
- */
- static inline void
- vmw_surface_max_loc(const struct vmw_surface_cache *cache,
- u32 sub_resource,
- struct vmw_surface_loc *loc)
- {
- const struct drm_vmw_size *size;
- u32 mip;
- loc->sheet = 0;
- loc->sub_resource = sub_resource + 1;
- mip = sub_resource % cache->num_mip_levels;
- size = &cache->mip[mip].size;
- loc->x = size->width;
- loc->y = size->height;
- loc->z = size->depth;
- }
- #endif /* VMW_SURFACE_CACHE_H */
|