Back to home page

OSCL-LXR

 
 

    


0001 /**********************************************************
0002  * Copyright 2021 VMware, Inc.
0003  * SPDX-License-Identifier: GPL-2.0 OR MIT
0004  *
0005  * Permission is hereby granted, free of charge, to any person
0006  * obtaining a copy of this software and associated documentation
0007  * files (the "Software"), to deal in the Software without
0008  * restriction, including without limitation the rights to use, copy,
0009  * modify, merge, publish, distribute, sublicense, and/or sell copies
0010  * of the Software, and to permit persons to whom the Software is
0011  * furnished to do so, subject to the following conditions:
0012  *
0013  * The above copyright notice and this permission notice shall be
0014  * included in all copies or substantial portions of the Software.
0015  *
0016  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
0017  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
0018  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
0019  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
0020  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
0021  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
0022  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
0023  * SOFTWARE.
0024  *
0025  **********************************************************/
0026 
0027 #ifndef VMW_SURFACE_CACHE_H
0028 #define VMW_SURFACE_CACHE_H
0029 
0030 #include "device_include/svga3d_surfacedefs.h"
0031 
0032 #include <drm/vmwgfx_drm.h>
0033 
0034 static inline u32 clamped_umul32(u32 a, u32 b)
0035 {
0036     uint64_t tmp = (uint64_t) a*b;
0037     return (tmp > (uint64_t) ((u32) -1)) ? (u32) -1 : tmp;
0038 }
0039 
0040 /**
0041  * vmw_surface_get_desc - Look up the appropriate SVGA3dSurfaceDesc for the
0042  * given format.
0043  */
0044 static inline const SVGA3dSurfaceDesc *
0045 vmw_surface_get_desc(SVGA3dSurfaceFormat format)
0046 {
0047     if (format < ARRAY_SIZE(g_SVGA3dSurfaceDescs))
0048         return &g_SVGA3dSurfaceDescs[format];
0049 
0050     return &g_SVGA3dSurfaceDescs[SVGA3D_FORMAT_INVALID];
0051 }
0052 
0053 /**
0054  * vmw_surface_get_mip_size -  Given a base level size and the mip level,
0055  * compute the size of the mip level.
0056  */
0057 static inline struct drm_vmw_size
0058 vmw_surface_get_mip_size(struct drm_vmw_size base_level, u32 mip_level)
0059 {
0060     struct drm_vmw_size size = {
0061         .width = max_t(u32, base_level.width >> mip_level, 1),
0062         .height = max_t(u32, base_level.height >> mip_level, 1),
0063         .depth = max_t(u32, base_level.depth >> mip_level, 1)
0064     };
0065 
0066     return size;
0067 }
0068 
0069 static inline void
0070 vmw_surface_get_size_in_blocks(const SVGA3dSurfaceDesc *desc,
0071                  const struct drm_vmw_size *pixel_size,
0072                  SVGA3dSize *block_size)
0073 {
0074     block_size->width = __KERNEL_DIV_ROUND_UP(pixel_size->width,
0075                           desc->blockSize.width);
0076     block_size->height = __KERNEL_DIV_ROUND_UP(pixel_size->height,
0077                            desc->blockSize.height);
0078     block_size->depth = __KERNEL_DIV_ROUND_UP(pixel_size->depth,
0079                           desc->blockSize.depth);
0080 }
0081 
0082 static inline bool
0083 vmw_surface_is_planar_surface(const SVGA3dSurfaceDesc *desc)
0084 {
0085     return (desc->blockDesc & SVGA3DBLOCKDESC_PLANAR_YUV) != 0;
0086 }
0087 
0088 static inline u32
0089 vmw_surface_calculate_pitch(const SVGA3dSurfaceDesc *desc,
0090                   const struct drm_vmw_size *size)
0091 {
0092     u32 pitch;
0093     SVGA3dSize blocks;
0094 
0095     vmw_surface_get_size_in_blocks(desc, size, &blocks);
0096 
0097     pitch = blocks.width * desc->pitchBytesPerBlock;
0098 
0099     return pitch;
0100 }
0101 
0102 /**
0103  * vmw_surface_get_image_buffer_size - Calculates image buffer size.
0104  *
0105  * Return the number of bytes of buffer space required to store one image of a
0106  * surface, optionally using the specified pitch.
0107  *
0108  * If pitch is zero, it is assumed that rows are tightly packed.
0109  *
0110  * This function is overflow-safe. If the result would have overflowed, instead
0111  * we return MAX_UINT32.
0112  */
0113 static inline u32
0114 vmw_surface_get_image_buffer_size(const SVGA3dSurfaceDesc *desc,
0115                     const struct drm_vmw_size *size,
0116                     u32 pitch)
0117 {
0118     SVGA3dSize image_blocks;
0119     u32 slice_size, total_size;
0120 
0121     vmw_surface_get_size_in_blocks(desc, size, &image_blocks);
0122 
0123     if (vmw_surface_is_planar_surface(desc)) {
0124         total_size = clamped_umul32(image_blocks.width,
0125                         image_blocks.height);
0126         total_size = clamped_umul32(total_size, image_blocks.depth);
0127         total_size = clamped_umul32(total_size, desc->bytesPerBlock);
0128         return total_size;
0129     }
0130 
0131     if (pitch == 0)
0132         pitch = vmw_surface_calculate_pitch(desc, size);
0133 
0134     slice_size = clamped_umul32(image_blocks.height, pitch);
0135     total_size = clamped_umul32(slice_size, image_blocks.depth);
0136 
0137     return total_size;
0138 }
0139 
0140 /**
0141  * vmw_surface_get_serialized_size - Get the serialized size for the image.
0142  */
0143 static inline u32
0144 vmw_surface_get_serialized_size(SVGA3dSurfaceFormat format,
0145                   struct drm_vmw_size base_level_size,
0146                   u32 num_mip_levels,
0147                   u32 num_layers)
0148 {
0149     const SVGA3dSurfaceDesc *desc = vmw_surface_get_desc(format);
0150     u32 total_size = 0;
0151     u32 mip;
0152 
0153     for (mip = 0; mip < num_mip_levels; mip++) {
0154         struct drm_vmw_size size =
0155             vmw_surface_get_mip_size(base_level_size, mip);
0156         total_size += vmw_surface_get_image_buffer_size(desc,
0157                                   &size, 0);
0158     }
0159 
0160     return total_size * num_layers;
0161 }
0162 
0163 /**
0164  * vmw_surface_get_serialized_size_extended - Returns the number of bytes
0165  * required for a surface with given parameters. Support for sample count.
0166  */
0167 static inline u32
0168 vmw_surface_get_serialized_size_extended(SVGA3dSurfaceFormat format,
0169                        struct drm_vmw_size base_level_size,
0170                        u32 num_mip_levels,
0171                        u32 num_layers,
0172                        u32 num_samples)
0173 {
0174     uint64_t total_size =
0175         vmw_surface_get_serialized_size(format,
0176                           base_level_size,
0177                           num_mip_levels,
0178                           num_layers);
0179     total_size *= max_t(u32, 1, num_samples);
0180 
0181     return min_t(uint64_t, total_size, (uint64_t)U32_MAX);
0182 }
0183 
0184 /**
0185  * vmw_surface_get_pixel_offset - Compute the offset (in bytes) to a pixel
0186  * in an image (or volume).
0187  *
0188  * @width: The image width in pixels.
0189  * @height: The image height in pixels
0190  */
0191 static inline u32
0192 vmw_surface_get_pixel_offset(SVGA3dSurfaceFormat format,
0193                    u32 width, u32 height,
0194                    u32 x, u32 y, u32 z)
0195 {
0196     const SVGA3dSurfaceDesc *desc = vmw_surface_get_desc(format);
0197     const u32 bw = desc->blockSize.width, bh = desc->blockSize.height;
0198     const u32 bd = desc->blockSize.depth;
0199     const u32 rowstride = __KERNEL_DIV_ROUND_UP(width, bw) *
0200                   desc->bytesPerBlock;
0201     const u32 imgstride = __KERNEL_DIV_ROUND_UP(height, bh) * rowstride;
0202     const u32 offset = (z / bd * imgstride +
0203                 y / bh * rowstride +
0204                 x / bw * desc->bytesPerBlock);
0205     return offset;
0206 }
0207 
0208 static inline u32
0209 vmw_surface_get_image_offset(SVGA3dSurfaceFormat format,
0210                    struct drm_vmw_size baseLevelSize,
0211                    u32 numMipLevels,
0212                    u32 face,
0213                    u32 mip)
0214 
0215 {
0216     u32 offset;
0217     u32 mipChainBytes;
0218     u32 mipChainBytesToLevel;
0219     u32 i;
0220     const SVGA3dSurfaceDesc *desc;
0221     struct drm_vmw_size mipSize;
0222     u32 bytes;
0223 
0224     desc = vmw_surface_get_desc(format);
0225 
0226     mipChainBytes = 0;
0227     mipChainBytesToLevel = 0;
0228     for (i = 0; i < numMipLevels; i++) {
0229         mipSize = vmw_surface_get_mip_size(baseLevelSize, i);
0230         bytes = vmw_surface_get_image_buffer_size(desc, &mipSize, 0);
0231         mipChainBytes += bytes;
0232         if (i < mip)
0233             mipChainBytesToLevel += bytes;
0234     }
0235 
0236     offset = mipChainBytes * face + mipChainBytesToLevel;
0237 
0238     return offset;
0239 }
0240 
0241 
0242 /**
0243  * vmw_surface_is_gb_screen_target_format - Is the specified format usable as
0244  *                                            a ScreenTarget?
0245  *                                            (with just the GBObjects cap-bit
0246  *                                             set)
0247  * @format: format to queried
0248  *
0249  * RETURNS:
0250  * true if queried format is valid for screen targets
0251  */
0252 static inline bool
0253 vmw_surface_is_gb_screen_target_format(SVGA3dSurfaceFormat format)
0254 {
0255     return (format == SVGA3D_X8R8G8B8 ||
0256         format == SVGA3D_A8R8G8B8 ||
0257         format == SVGA3D_R5G6B5   ||
0258         format == SVGA3D_X1R5G5B5 ||
0259         format == SVGA3D_A1R5G5B5 ||
0260         format == SVGA3D_P8);
0261 }
0262 
0263 
0264 /**
0265  * vmw_surface_is_dx_screen_target_format - Is the specified format usable as
0266  *                                            a ScreenTarget?
0267  *                                            (with DX10 enabled)
0268  *
0269  * @format: format to queried
0270  *
0271  * Results:
0272  * true if queried format is valid for screen targets
0273  */
0274 static inline bool
0275 vmw_surface_is_dx_screen_target_format(SVGA3dSurfaceFormat format)
0276 {
0277     return (format == SVGA3D_R8G8B8A8_UNORM ||
0278         format == SVGA3D_B8G8R8A8_UNORM ||
0279         format == SVGA3D_B8G8R8X8_UNORM);
0280 }
0281 
0282 
0283 /**
0284  * vmw_surface_is_screen_target_format - Is the specified format usable as a
0285  *                                         ScreenTarget?
0286  *                                         (for some combination of caps)
0287  *
0288  * @format: format to queried
0289  *
0290  * Results:
0291  * true if queried format is valid for screen targets
0292  */
0293 static inline bool
0294 vmw_surface_is_screen_target_format(SVGA3dSurfaceFormat format)
0295 {
0296     if (vmw_surface_is_gb_screen_target_format(format)) {
0297         return true;
0298     }
0299     return vmw_surface_is_dx_screen_target_format(format);
0300 }
0301 
0302 /**
0303  * struct vmw_surface_mip - Mimpmap level information
0304  * @bytes: Bytes required in the backing store of this mipmap level.
0305  * @img_stride: Byte stride per image.
0306  * @row_stride: Byte stride per block row.
0307  * @size: The size of the mipmap.
0308  */
0309 struct vmw_surface_mip {
0310     size_t bytes;
0311     size_t img_stride;
0312     size_t row_stride;
0313     struct drm_vmw_size size;
0314 
0315 };
0316 
0317 /**
0318  * struct vmw_surface_cache - Cached surface information
0319  * @desc: Pointer to the surface descriptor
0320  * @mip: Array of mipmap level information. Valid size is @num_mip_levels.
0321  * @mip_chain_bytes: Bytes required in the backing store for the whole chain
0322  * of mip levels.
0323  * @sheet_bytes: Bytes required in the backing store for a sheet
0324  * representing a single sample.
0325  * @num_mip_levels: Valid size of the @mip array. Number of mipmap levels in
0326  * a chain.
0327  * @num_layers: Number of slices in an array texture or number of faces in
0328  * a cubemap texture.
0329  */
0330 struct vmw_surface_cache {
0331     const SVGA3dSurfaceDesc *desc;
0332     struct vmw_surface_mip mip[DRM_VMW_MAX_MIP_LEVELS];
0333     size_t mip_chain_bytes;
0334     size_t sheet_bytes;
0335     u32 num_mip_levels;
0336     u32 num_layers;
0337 };
0338 
0339 /**
0340  * struct vmw_surface_loc - Surface location
0341  * @sheet: The multisample sheet.
0342  * @sub_resource: Surface subresource. Defined as layer * num_mip_levels +
0343  * mip_level.
0344  * @x: X coordinate.
0345  * @y: Y coordinate.
0346  * @z: Z coordinate.
0347  */
0348 struct vmw_surface_loc {
0349     u32 sheet;
0350     u32 sub_resource;
0351     u32 x, y, z;
0352 };
0353 
0354 /**
0355  * vmw_surface_subres - Compute the subresource from layer and mipmap.
0356  * @cache: Surface layout data.
0357  * @mip_level: The mipmap level.
0358  * @layer: The surface layer (face or array slice).
0359  *
0360  * Return: The subresource.
0361  */
0362 static inline u32 vmw_surface_subres(const struct vmw_surface_cache *cache,
0363                        u32 mip_level, u32 layer)
0364 {
0365     return cache->num_mip_levels * layer + mip_level;
0366 }
0367 
0368 /**
0369  * vmw_surface_setup_cache - Build a surface cache entry
0370  * @size: The surface base level dimensions.
0371  * @format: The surface format.
0372  * @num_mip_levels: Number of mipmap levels.
0373  * @num_layers: Number of layers.
0374  * @cache: Pointer to a struct vmw_surface_cach object to be filled in.
0375  *
0376  * Return: Zero on success, -EINVAL on invalid surface layout.
0377  */
0378 static inline int vmw_surface_setup_cache(const struct drm_vmw_size *size,
0379                         SVGA3dSurfaceFormat format,
0380                         u32 num_mip_levels,
0381                         u32 num_layers,
0382                         u32 num_samples,
0383                         struct vmw_surface_cache *cache)
0384 {
0385     const SVGA3dSurfaceDesc *desc;
0386     u32 i;
0387 
0388     memset(cache, 0, sizeof(*cache));
0389     cache->desc = desc = vmw_surface_get_desc(format);
0390     cache->num_mip_levels = num_mip_levels;
0391     cache->num_layers = num_layers;
0392     for (i = 0; i < cache->num_mip_levels; i++) {
0393         struct vmw_surface_mip *mip = &cache->mip[i];
0394 
0395         mip->size = vmw_surface_get_mip_size(*size, i);
0396         mip->bytes = vmw_surface_get_image_buffer_size
0397             (desc, &mip->size, 0);
0398         mip->row_stride =
0399             __KERNEL_DIV_ROUND_UP(mip->size.width,
0400                           desc->blockSize.width) *
0401             desc->bytesPerBlock * num_samples;
0402         if (!mip->row_stride)
0403             goto invalid_dim;
0404 
0405         mip->img_stride =
0406             __KERNEL_DIV_ROUND_UP(mip->size.height,
0407                           desc->blockSize.height) *
0408             mip->row_stride;
0409         if (!mip->img_stride)
0410             goto invalid_dim;
0411 
0412         cache->mip_chain_bytes += mip->bytes;
0413     }
0414     cache->sheet_bytes = cache->mip_chain_bytes * num_layers;
0415     if (!cache->sheet_bytes)
0416         goto invalid_dim;
0417 
0418     return 0;
0419 
0420 invalid_dim:
0421     VMW_DEBUG_USER("Invalid surface layout for dirty tracking.\n");
0422     return -EINVAL;
0423 }
0424 
0425 /**
0426  * vmw_surface_get_loc - Get a surface location from an offset into the
0427  * backing store
0428  * @cache: Surface layout data.
0429  * @loc: Pointer to a struct vmw_surface_loc to be filled in.
0430  * @offset: Offset into the surface backing store.
0431  */
0432 static inline void
0433 vmw_surface_get_loc(const struct vmw_surface_cache *cache,
0434               struct vmw_surface_loc *loc,
0435               size_t offset)
0436 {
0437     const struct vmw_surface_mip *mip = &cache->mip[0];
0438     const SVGA3dSurfaceDesc *desc = cache->desc;
0439     u32 layer;
0440     int i;
0441 
0442     loc->sheet = offset / cache->sheet_bytes;
0443     offset -= loc->sheet * cache->sheet_bytes;
0444 
0445     layer = offset / cache->mip_chain_bytes;
0446     offset -= layer * cache->mip_chain_bytes;
0447     for (i = 0; i < cache->num_mip_levels; ++i, ++mip) {
0448         if (mip->bytes > offset)
0449             break;
0450         offset -= mip->bytes;
0451     }
0452 
0453     loc->sub_resource = vmw_surface_subres(cache, i, layer);
0454     loc->z = offset / mip->img_stride;
0455     offset -= loc->z * mip->img_stride;
0456     loc->z *= desc->blockSize.depth;
0457     loc->y = offset / mip->row_stride;
0458     offset -= loc->y * mip->row_stride;
0459     loc->y *= desc->blockSize.height;
0460     loc->x = offset / desc->bytesPerBlock;
0461     loc->x *= desc->blockSize.width;
0462 }
0463 
0464 /**
0465  * vmw_surface_inc_loc - Clamp increment a surface location with one block
0466  * size
0467  * in each dimension.
0468  * @loc: Pointer to a struct vmw_surface_loc to be incremented.
0469  *
0470  * When computing the size of a range as size = end - start, the range does not
0471  * include the end element. However a location representing the last byte
0472  * of a touched region in the backing store *is* included in the range.
0473  * This function modifies such a location to match the end definition
0474  * given as start + size which is the one used in a SVGA3dBox.
0475  */
0476 static inline void
0477 vmw_surface_inc_loc(const struct vmw_surface_cache *cache,
0478               struct vmw_surface_loc *loc)
0479 {
0480     const SVGA3dSurfaceDesc *desc = cache->desc;
0481     u32 mip = loc->sub_resource % cache->num_mip_levels;
0482     const struct drm_vmw_size *size = &cache->mip[mip].size;
0483 
0484     loc->sub_resource++;
0485     loc->x += desc->blockSize.width;
0486     if (loc->x > size->width)
0487         loc->x = size->width;
0488     loc->y += desc->blockSize.height;
0489     if (loc->y > size->height)
0490         loc->y = size->height;
0491     loc->z += desc->blockSize.depth;
0492     if (loc->z > size->depth)
0493         loc->z = size->depth;
0494 }
0495 
0496 /**
0497  * vmw_surface_min_loc - The start location in a subresource
0498  * @cache: Surface layout data.
0499  * @sub_resource: The subresource.
0500  * @loc: Pointer to a struct vmw_surface_loc to be filled in.
0501  */
0502 static inline void
0503 vmw_surface_min_loc(const struct vmw_surface_cache *cache,
0504               u32 sub_resource,
0505               struct vmw_surface_loc *loc)
0506 {
0507     loc->sheet = 0;
0508     loc->sub_resource = sub_resource;
0509     loc->x = loc->y = loc->z = 0;
0510 }
0511 
0512 /**
0513  * vmw_surface_min_loc - The end location in a subresource
0514  * @cache: Surface layout data.
0515  * @sub_resource: The subresource.
0516  * @loc: Pointer to a struct vmw_surface_loc to be filled in.
0517  *
0518  * Following the end definition given in vmw_surface_inc_loc(),
0519  * Compute the end location of a surface subresource.
0520  */
0521 static inline void
0522 vmw_surface_max_loc(const struct vmw_surface_cache *cache,
0523               u32 sub_resource,
0524               struct vmw_surface_loc *loc)
0525 {
0526     const struct drm_vmw_size *size;
0527     u32 mip;
0528 
0529     loc->sheet = 0;
0530     loc->sub_resource = sub_resource + 1;
0531     mip = sub_resource % cache->num_mip_levels;
0532     size = &cache->mip[mip].size;
0533     loc->x = size->width;
0534     loc->y = size->height;
0535     loc->z = size->depth;
0536 }
0537 
0538 
0539 #endif /* VMW_SURFACE_CACHE_H */