brintos

brintos / linux-shallow public Read only

0
0
Text · 15.5 KiB · 1ac3cb1 Raw
546 lines · c
1/* SPDX-License-Identifier: GPL-2.0 OR MIT */2/**********************************************************3 *4 * Copyright (c) 2021-2024 Broadcom. All Rights Reserved. The term5 * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.6 *7 * Permission is hereby granted, free of charge, to any person8 * obtaining a copy of this software and associated documentation9 * files (the "Software"), to deal in the Software without10 * restriction, including without limitation the rights to use, copy,11 * modify, merge, publish, distribute, sublicense, and/or sell copies12 * of the Software, and to permit persons to whom the Software is13 * furnished to do so, subject to the following conditions:14 *15 * The above copyright notice and this permission notice shall be16 * 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 OF20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND21 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS22 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN23 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE25 * SOFTWARE.26 *27 **********************************************************/28 29#ifndef VMW_SURFACE_CACHE_H30#define VMW_SURFACE_CACHE_H31 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 40static 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 the48 * given format.49 */50static inline const SVGA3dSurfaceDesc *51vmw_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 */63static inline struct drm_vmw_size64vmw_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 75static inline void76vmw_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 88static inline bool89vmw_surface_is_planar_surface(const SVGA3dSurfaceDesc *desc)90{91	return (desc->blockDesc & SVGA3DBLOCKDESC_PLANAR_YUV) != 0;92}93 94static inline u3295vmw_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 a112 * 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, instead117 * we return MAX_UINT32.118 */119static inline u32120vmw_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 */149static inline u32150vmw_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 bytes171 * required for a surface with given parameters. Support for sample count.172 */173static inline u32174vmw_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 pixel192 * in an image (or volume).193 *194 * @width: The image width in pixels.195 * @height: The image height in pixels196 */197static inline u32198vmw_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 214static inline u32215vmw_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 as250 *                                            a ScreenTarget?251 *                                            (with just the GBObjects cap-bit252 *                                             set)253 * @format: format to queried254 *255 * RETURNS:256 * true if queried format is valid for screen targets257 */258static inline bool259vmw_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 as272 *                                            a ScreenTarget?273 *                                            (with DX10 enabled)274 *275 * @format: format to queried276 *277 * Results:278 * true if queried format is valid for screen targets279 */280static inline bool281vmw_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 a291 *                                         ScreenTarget?292 *                                         (for some combination of caps)293 *294 * @format: format to queried295 *296 * Results:297 * true if queried format is valid for screen targets298 */299static inline bool300vmw_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 information310 * @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 */315struct 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 information325 * @desc: Pointer to the surface descriptor326 * @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 chain328 * of mip levels.329 * @sheet_bytes: Bytes required in the backing store for a sheet330 * representing a single sample.331 * @num_mip_levels: Valid size of the @mip array. Number of mipmap levels in332 * a chain.333 * @num_layers: Number of slices in an array texture or number of faces in334 * a cubemap texture.335 */336struct 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 location347 * @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 */354struct 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 */368static 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 entry376 * @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 */384static 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_size403			(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 426invalid_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 the433 * backing store434 * @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 */438static inline void439vmw_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 block472 * size473 * 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 not477 * include the end element. However a location representing the last byte478 * of a touched region in the backing store *is* included in the range.479 * This function modifies such a location to match the end definition480 * given as start + size which is the one used in a SVGA3dBox.481 */482static inline void483vmw_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 subresource504 * @cache: Surface layout data.505 * @sub_resource: The subresource.506 * @loc: Pointer to a struct vmw_surface_loc to be filled in.507 */508static inline void509vmw_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 subresource520 * @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 */527static inline void528vmw_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