162306a36Sopenharmony_ci/**********************************************************
262306a36Sopenharmony_ci * Copyright 2021 VMware, Inc.
362306a36Sopenharmony_ci * SPDX-License-Identifier: GPL-2.0 OR MIT
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person
662306a36Sopenharmony_ci * obtaining a copy of this software and associated documentation
762306a36Sopenharmony_ci * files (the "Software"), to deal in the Software without
862306a36Sopenharmony_ci * restriction, including without limitation the rights to use, copy,
962306a36Sopenharmony_ci * modify, merge, publish, distribute, sublicense, and/or sell copies
1062306a36Sopenharmony_ci * of the Software, and to permit persons to whom the Software is
1162306a36Sopenharmony_ci * furnished to do so, subject to the following conditions:
1262306a36Sopenharmony_ci *
1362306a36Sopenharmony_ci * The above copyright notice and this permission notice shall be
1462306a36Sopenharmony_ci * included in all copies or substantial portions of the Software.
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
1762306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1862306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
1962306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
2062306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
2162306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
2262306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2362306a36Sopenharmony_ci * SOFTWARE.
2462306a36Sopenharmony_ci *
2562306a36Sopenharmony_ci **********************************************************/
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#ifndef VMW_SURFACE_CACHE_H
2862306a36Sopenharmony_ci#define VMW_SURFACE_CACHE_H
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#include "device_include/svga3d_surfacedefs.h"
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#include <drm/vmwgfx_drm.h>
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistatic inline u32 clamped_umul32(u32 a, u32 b)
3562306a36Sopenharmony_ci{
3662306a36Sopenharmony_ci	uint64_t tmp = (uint64_t) a*b;
3762306a36Sopenharmony_ci	return (tmp > (uint64_t) ((u32) -1)) ? (u32) -1 : tmp;
3862306a36Sopenharmony_ci}
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci/**
4162306a36Sopenharmony_ci * vmw_surface_get_desc - Look up the appropriate SVGA3dSurfaceDesc for the
4262306a36Sopenharmony_ci * given format.
4362306a36Sopenharmony_ci */
4462306a36Sopenharmony_cistatic inline const SVGA3dSurfaceDesc *
4562306a36Sopenharmony_civmw_surface_get_desc(SVGA3dSurfaceFormat format)
4662306a36Sopenharmony_ci{
4762306a36Sopenharmony_ci	if (format < ARRAY_SIZE(g_SVGA3dSurfaceDescs))
4862306a36Sopenharmony_ci		return &g_SVGA3dSurfaceDescs[format];
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	return &g_SVGA3dSurfaceDescs[SVGA3D_FORMAT_INVALID];
5162306a36Sopenharmony_ci}
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci/**
5462306a36Sopenharmony_ci * vmw_surface_get_mip_size -  Given a base level size and the mip level,
5562306a36Sopenharmony_ci * compute the size of the mip level.
5662306a36Sopenharmony_ci */
5762306a36Sopenharmony_cistatic inline struct drm_vmw_size
5862306a36Sopenharmony_civmw_surface_get_mip_size(struct drm_vmw_size base_level, u32 mip_level)
5962306a36Sopenharmony_ci{
6062306a36Sopenharmony_ci	struct drm_vmw_size size = {
6162306a36Sopenharmony_ci		.width = max_t(u32, base_level.width >> mip_level, 1),
6262306a36Sopenharmony_ci		.height = max_t(u32, base_level.height >> mip_level, 1),
6362306a36Sopenharmony_ci		.depth = max_t(u32, base_level.depth >> mip_level, 1)
6462306a36Sopenharmony_ci	};
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	return size;
6762306a36Sopenharmony_ci}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistatic inline void
7062306a36Sopenharmony_civmw_surface_get_size_in_blocks(const SVGA3dSurfaceDesc *desc,
7162306a36Sopenharmony_ci				 const struct drm_vmw_size *pixel_size,
7262306a36Sopenharmony_ci				 SVGA3dSize *block_size)
7362306a36Sopenharmony_ci{
7462306a36Sopenharmony_ci	block_size->width = __KERNEL_DIV_ROUND_UP(pixel_size->width,
7562306a36Sopenharmony_ci						  desc->blockSize.width);
7662306a36Sopenharmony_ci	block_size->height = __KERNEL_DIV_ROUND_UP(pixel_size->height,
7762306a36Sopenharmony_ci						   desc->blockSize.height);
7862306a36Sopenharmony_ci	block_size->depth = __KERNEL_DIV_ROUND_UP(pixel_size->depth,
7962306a36Sopenharmony_ci						  desc->blockSize.depth);
8062306a36Sopenharmony_ci}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cistatic inline bool
8362306a36Sopenharmony_civmw_surface_is_planar_surface(const SVGA3dSurfaceDesc *desc)
8462306a36Sopenharmony_ci{
8562306a36Sopenharmony_ci	return (desc->blockDesc & SVGA3DBLOCKDESC_PLANAR_YUV) != 0;
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic inline u32
8962306a36Sopenharmony_civmw_surface_calculate_pitch(const SVGA3dSurfaceDesc *desc,
9062306a36Sopenharmony_ci			      const struct drm_vmw_size *size)
9162306a36Sopenharmony_ci{
9262306a36Sopenharmony_ci	u32 pitch;
9362306a36Sopenharmony_ci	SVGA3dSize blocks;
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	vmw_surface_get_size_in_blocks(desc, size, &blocks);
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	pitch = blocks.width * desc->pitchBytesPerBlock;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	return pitch;
10062306a36Sopenharmony_ci}
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci/**
10362306a36Sopenharmony_ci * vmw_surface_get_image_buffer_size - Calculates image buffer size.
10462306a36Sopenharmony_ci *
10562306a36Sopenharmony_ci * Return the number of bytes of buffer space required to store one image of a
10662306a36Sopenharmony_ci * surface, optionally using the specified pitch.
10762306a36Sopenharmony_ci *
10862306a36Sopenharmony_ci * If pitch is zero, it is assumed that rows are tightly packed.
10962306a36Sopenharmony_ci *
11062306a36Sopenharmony_ci * This function is overflow-safe. If the result would have overflowed, instead
11162306a36Sopenharmony_ci * we return MAX_UINT32.
11262306a36Sopenharmony_ci */
11362306a36Sopenharmony_cistatic inline u32
11462306a36Sopenharmony_civmw_surface_get_image_buffer_size(const SVGA3dSurfaceDesc *desc,
11562306a36Sopenharmony_ci				    const struct drm_vmw_size *size,
11662306a36Sopenharmony_ci				    u32 pitch)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci	SVGA3dSize image_blocks;
11962306a36Sopenharmony_ci	u32 slice_size, total_size;
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	vmw_surface_get_size_in_blocks(desc, size, &image_blocks);
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	if (vmw_surface_is_planar_surface(desc)) {
12462306a36Sopenharmony_ci		total_size = clamped_umul32(image_blocks.width,
12562306a36Sopenharmony_ci					    image_blocks.height);
12662306a36Sopenharmony_ci		total_size = clamped_umul32(total_size, image_blocks.depth);
12762306a36Sopenharmony_ci		total_size = clamped_umul32(total_size, desc->bytesPerBlock);
12862306a36Sopenharmony_ci		return total_size;
12962306a36Sopenharmony_ci	}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	if (pitch == 0)
13262306a36Sopenharmony_ci		pitch = vmw_surface_calculate_pitch(desc, size);
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	slice_size = clamped_umul32(image_blocks.height, pitch);
13562306a36Sopenharmony_ci	total_size = clamped_umul32(slice_size, image_blocks.depth);
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	return total_size;
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci/**
14162306a36Sopenharmony_ci * vmw_surface_get_serialized_size - Get the serialized size for the image.
14262306a36Sopenharmony_ci */
14362306a36Sopenharmony_cistatic inline u32
14462306a36Sopenharmony_civmw_surface_get_serialized_size(SVGA3dSurfaceFormat format,
14562306a36Sopenharmony_ci				  struct drm_vmw_size base_level_size,
14662306a36Sopenharmony_ci				  u32 num_mip_levels,
14762306a36Sopenharmony_ci				  u32 num_layers)
14862306a36Sopenharmony_ci{
14962306a36Sopenharmony_ci	const SVGA3dSurfaceDesc *desc = vmw_surface_get_desc(format);
15062306a36Sopenharmony_ci	u32 total_size = 0;
15162306a36Sopenharmony_ci	u32 mip;
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	for (mip = 0; mip < num_mip_levels; mip++) {
15462306a36Sopenharmony_ci		struct drm_vmw_size size =
15562306a36Sopenharmony_ci			vmw_surface_get_mip_size(base_level_size, mip);
15662306a36Sopenharmony_ci		total_size += vmw_surface_get_image_buffer_size(desc,
15762306a36Sopenharmony_ci								  &size, 0);
15862306a36Sopenharmony_ci	}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	return total_size * num_layers;
16162306a36Sopenharmony_ci}
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci/**
16462306a36Sopenharmony_ci * vmw_surface_get_serialized_size_extended - Returns the number of bytes
16562306a36Sopenharmony_ci * required for a surface with given parameters. Support for sample count.
16662306a36Sopenharmony_ci */
16762306a36Sopenharmony_cistatic inline u32
16862306a36Sopenharmony_civmw_surface_get_serialized_size_extended(SVGA3dSurfaceFormat format,
16962306a36Sopenharmony_ci					   struct drm_vmw_size base_level_size,
17062306a36Sopenharmony_ci					   u32 num_mip_levels,
17162306a36Sopenharmony_ci					   u32 num_layers,
17262306a36Sopenharmony_ci					   u32 num_samples)
17362306a36Sopenharmony_ci{
17462306a36Sopenharmony_ci	uint64_t total_size =
17562306a36Sopenharmony_ci		vmw_surface_get_serialized_size(format,
17662306a36Sopenharmony_ci						  base_level_size,
17762306a36Sopenharmony_ci						  num_mip_levels,
17862306a36Sopenharmony_ci						  num_layers);
17962306a36Sopenharmony_ci	total_size *= max_t(u32, 1, num_samples);
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	return min_t(uint64_t, total_size, (uint64_t)U32_MAX);
18262306a36Sopenharmony_ci}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci/**
18562306a36Sopenharmony_ci * vmw_surface_get_pixel_offset - Compute the offset (in bytes) to a pixel
18662306a36Sopenharmony_ci * in an image (or volume).
18762306a36Sopenharmony_ci *
18862306a36Sopenharmony_ci * @width: The image width in pixels.
18962306a36Sopenharmony_ci * @height: The image height in pixels
19062306a36Sopenharmony_ci */
19162306a36Sopenharmony_cistatic inline u32
19262306a36Sopenharmony_civmw_surface_get_pixel_offset(SVGA3dSurfaceFormat format,
19362306a36Sopenharmony_ci			       u32 width, u32 height,
19462306a36Sopenharmony_ci			       u32 x, u32 y, u32 z)
19562306a36Sopenharmony_ci{
19662306a36Sopenharmony_ci	const SVGA3dSurfaceDesc *desc = vmw_surface_get_desc(format);
19762306a36Sopenharmony_ci	const u32 bw = desc->blockSize.width, bh = desc->blockSize.height;
19862306a36Sopenharmony_ci	const u32 bd = desc->blockSize.depth;
19962306a36Sopenharmony_ci	const u32 rowstride = __KERNEL_DIV_ROUND_UP(width, bw) *
20062306a36Sopenharmony_ci			      desc->bytesPerBlock;
20162306a36Sopenharmony_ci	const u32 imgstride = __KERNEL_DIV_ROUND_UP(height, bh) * rowstride;
20262306a36Sopenharmony_ci	const u32 offset = (z / bd * imgstride +
20362306a36Sopenharmony_ci			    y / bh * rowstride +
20462306a36Sopenharmony_ci			    x / bw * desc->bytesPerBlock);
20562306a36Sopenharmony_ci	return offset;
20662306a36Sopenharmony_ci}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_cistatic inline u32
20962306a36Sopenharmony_civmw_surface_get_image_offset(SVGA3dSurfaceFormat format,
21062306a36Sopenharmony_ci			       struct drm_vmw_size baseLevelSize,
21162306a36Sopenharmony_ci			       u32 numMipLevels,
21262306a36Sopenharmony_ci			       u32 face,
21362306a36Sopenharmony_ci			       u32 mip)
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci{
21662306a36Sopenharmony_ci	u32 offset;
21762306a36Sopenharmony_ci	u32 mipChainBytes;
21862306a36Sopenharmony_ci	u32 mipChainBytesToLevel;
21962306a36Sopenharmony_ci	u32 i;
22062306a36Sopenharmony_ci	const SVGA3dSurfaceDesc *desc;
22162306a36Sopenharmony_ci	struct drm_vmw_size mipSize;
22262306a36Sopenharmony_ci	u32 bytes;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	desc = vmw_surface_get_desc(format);
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	mipChainBytes = 0;
22762306a36Sopenharmony_ci	mipChainBytesToLevel = 0;
22862306a36Sopenharmony_ci	for (i = 0; i < numMipLevels; i++) {
22962306a36Sopenharmony_ci		mipSize = vmw_surface_get_mip_size(baseLevelSize, i);
23062306a36Sopenharmony_ci		bytes = vmw_surface_get_image_buffer_size(desc, &mipSize, 0);
23162306a36Sopenharmony_ci		mipChainBytes += bytes;
23262306a36Sopenharmony_ci		if (i < mip)
23362306a36Sopenharmony_ci			mipChainBytesToLevel += bytes;
23462306a36Sopenharmony_ci	}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	offset = mipChainBytes * face + mipChainBytesToLevel;
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	return offset;
23962306a36Sopenharmony_ci}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci/**
24362306a36Sopenharmony_ci * vmw_surface_is_gb_screen_target_format - Is the specified format usable as
24462306a36Sopenharmony_ci *                                            a ScreenTarget?
24562306a36Sopenharmony_ci *                                            (with just the GBObjects cap-bit
24662306a36Sopenharmony_ci *                                             set)
24762306a36Sopenharmony_ci * @format: format to queried
24862306a36Sopenharmony_ci *
24962306a36Sopenharmony_ci * RETURNS:
25062306a36Sopenharmony_ci * true if queried format is valid for screen targets
25162306a36Sopenharmony_ci */
25262306a36Sopenharmony_cistatic inline bool
25362306a36Sopenharmony_civmw_surface_is_gb_screen_target_format(SVGA3dSurfaceFormat format)
25462306a36Sopenharmony_ci{
25562306a36Sopenharmony_ci	return (format == SVGA3D_X8R8G8B8 ||
25662306a36Sopenharmony_ci		format == SVGA3D_A8R8G8B8 ||
25762306a36Sopenharmony_ci		format == SVGA3D_R5G6B5   ||
25862306a36Sopenharmony_ci		format == SVGA3D_X1R5G5B5 ||
25962306a36Sopenharmony_ci		format == SVGA3D_A1R5G5B5 ||
26062306a36Sopenharmony_ci		format == SVGA3D_P8);
26162306a36Sopenharmony_ci}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci/**
26562306a36Sopenharmony_ci * vmw_surface_is_dx_screen_target_format - Is the specified format usable as
26662306a36Sopenharmony_ci *                                            a ScreenTarget?
26762306a36Sopenharmony_ci *                                            (with DX10 enabled)
26862306a36Sopenharmony_ci *
26962306a36Sopenharmony_ci * @format: format to queried
27062306a36Sopenharmony_ci *
27162306a36Sopenharmony_ci * Results:
27262306a36Sopenharmony_ci * true if queried format is valid for screen targets
27362306a36Sopenharmony_ci */
27462306a36Sopenharmony_cistatic inline bool
27562306a36Sopenharmony_civmw_surface_is_dx_screen_target_format(SVGA3dSurfaceFormat format)
27662306a36Sopenharmony_ci{
27762306a36Sopenharmony_ci	return (format == SVGA3D_R8G8B8A8_UNORM ||
27862306a36Sopenharmony_ci		format == SVGA3D_B8G8R8A8_UNORM ||
27962306a36Sopenharmony_ci		format == SVGA3D_B8G8R8X8_UNORM);
28062306a36Sopenharmony_ci}
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci/**
28462306a36Sopenharmony_ci * vmw_surface_is_screen_target_format - Is the specified format usable as a
28562306a36Sopenharmony_ci *                                         ScreenTarget?
28662306a36Sopenharmony_ci *                                         (for some combination of caps)
28762306a36Sopenharmony_ci *
28862306a36Sopenharmony_ci * @format: format to queried
28962306a36Sopenharmony_ci *
29062306a36Sopenharmony_ci * Results:
29162306a36Sopenharmony_ci * true if queried format is valid for screen targets
29262306a36Sopenharmony_ci */
29362306a36Sopenharmony_cistatic inline bool
29462306a36Sopenharmony_civmw_surface_is_screen_target_format(SVGA3dSurfaceFormat format)
29562306a36Sopenharmony_ci{
29662306a36Sopenharmony_ci	if (vmw_surface_is_gb_screen_target_format(format)) {
29762306a36Sopenharmony_ci		return true;
29862306a36Sopenharmony_ci	}
29962306a36Sopenharmony_ci	return vmw_surface_is_dx_screen_target_format(format);
30062306a36Sopenharmony_ci}
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci/**
30362306a36Sopenharmony_ci * struct vmw_surface_mip - Mimpmap level information
30462306a36Sopenharmony_ci * @bytes: Bytes required in the backing store of this mipmap level.
30562306a36Sopenharmony_ci * @img_stride: Byte stride per image.
30662306a36Sopenharmony_ci * @row_stride: Byte stride per block row.
30762306a36Sopenharmony_ci * @size: The size of the mipmap.
30862306a36Sopenharmony_ci */
30962306a36Sopenharmony_cistruct vmw_surface_mip {
31062306a36Sopenharmony_ci	size_t bytes;
31162306a36Sopenharmony_ci	size_t img_stride;
31262306a36Sopenharmony_ci	size_t row_stride;
31362306a36Sopenharmony_ci	struct drm_vmw_size size;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci};
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci/**
31862306a36Sopenharmony_ci * struct vmw_surface_cache - Cached surface information
31962306a36Sopenharmony_ci * @desc: Pointer to the surface descriptor
32062306a36Sopenharmony_ci * @mip: Array of mipmap level information. Valid size is @num_mip_levels.
32162306a36Sopenharmony_ci * @mip_chain_bytes: Bytes required in the backing store for the whole chain
32262306a36Sopenharmony_ci * of mip levels.
32362306a36Sopenharmony_ci * @sheet_bytes: Bytes required in the backing store for a sheet
32462306a36Sopenharmony_ci * representing a single sample.
32562306a36Sopenharmony_ci * @num_mip_levels: Valid size of the @mip array. Number of mipmap levels in
32662306a36Sopenharmony_ci * a chain.
32762306a36Sopenharmony_ci * @num_layers: Number of slices in an array texture or number of faces in
32862306a36Sopenharmony_ci * a cubemap texture.
32962306a36Sopenharmony_ci */
33062306a36Sopenharmony_cistruct vmw_surface_cache {
33162306a36Sopenharmony_ci	const SVGA3dSurfaceDesc *desc;
33262306a36Sopenharmony_ci	struct vmw_surface_mip mip[DRM_VMW_MAX_MIP_LEVELS];
33362306a36Sopenharmony_ci	size_t mip_chain_bytes;
33462306a36Sopenharmony_ci	size_t sheet_bytes;
33562306a36Sopenharmony_ci	u32 num_mip_levels;
33662306a36Sopenharmony_ci	u32 num_layers;
33762306a36Sopenharmony_ci};
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci/**
34062306a36Sopenharmony_ci * struct vmw_surface_loc - Surface location
34162306a36Sopenharmony_ci * @sheet: The multisample sheet.
34262306a36Sopenharmony_ci * @sub_resource: Surface subresource. Defined as layer * num_mip_levels +
34362306a36Sopenharmony_ci * mip_level.
34462306a36Sopenharmony_ci * @x: X coordinate.
34562306a36Sopenharmony_ci * @y: Y coordinate.
34662306a36Sopenharmony_ci * @z: Z coordinate.
34762306a36Sopenharmony_ci */
34862306a36Sopenharmony_cistruct vmw_surface_loc {
34962306a36Sopenharmony_ci	u32 sheet;
35062306a36Sopenharmony_ci	u32 sub_resource;
35162306a36Sopenharmony_ci	u32 x, y, z;
35262306a36Sopenharmony_ci};
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci/**
35562306a36Sopenharmony_ci * vmw_surface_subres - Compute the subresource from layer and mipmap.
35662306a36Sopenharmony_ci * @cache: Surface layout data.
35762306a36Sopenharmony_ci * @mip_level: The mipmap level.
35862306a36Sopenharmony_ci * @layer: The surface layer (face or array slice).
35962306a36Sopenharmony_ci *
36062306a36Sopenharmony_ci * Return: The subresource.
36162306a36Sopenharmony_ci */
36262306a36Sopenharmony_cistatic inline u32 vmw_surface_subres(const struct vmw_surface_cache *cache,
36362306a36Sopenharmony_ci				       u32 mip_level, u32 layer)
36462306a36Sopenharmony_ci{
36562306a36Sopenharmony_ci	return cache->num_mip_levels * layer + mip_level;
36662306a36Sopenharmony_ci}
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci/**
36962306a36Sopenharmony_ci * vmw_surface_setup_cache - Build a surface cache entry
37062306a36Sopenharmony_ci * @size: The surface base level dimensions.
37162306a36Sopenharmony_ci * @format: The surface format.
37262306a36Sopenharmony_ci * @num_mip_levels: Number of mipmap levels.
37362306a36Sopenharmony_ci * @num_layers: Number of layers.
37462306a36Sopenharmony_ci * @cache: Pointer to a struct vmw_surface_cach object to be filled in.
37562306a36Sopenharmony_ci *
37662306a36Sopenharmony_ci * Return: Zero on success, -EINVAL on invalid surface layout.
37762306a36Sopenharmony_ci */
37862306a36Sopenharmony_cistatic inline int vmw_surface_setup_cache(const struct drm_vmw_size *size,
37962306a36Sopenharmony_ci					    SVGA3dSurfaceFormat format,
38062306a36Sopenharmony_ci					    u32 num_mip_levels,
38162306a36Sopenharmony_ci					    u32 num_layers,
38262306a36Sopenharmony_ci					    u32 num_samples,
38362306a36Sopenharmony_ci					    struct vmw_surface_cache *cache)
38462306a36Sopenharmony_ci{
38562306a36Sopenharmony_ci	const SVGA3dSurfaceDesc *desc;
38662306a36Sopenharmony_ci	u32 i;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	memset(cache, 0, sizeof(*cache));
38962306a36Sopenharmony_ci	cache->desc = desc = vmw_surface_get_desc(format);
39062306a36Sopenharmony_ci	cache->num_mip_levels = num_mip_levels;
39162306a36Sopenharmony_ci	cache->num_layers = num_layers;
39262306a36Sopenharmony_ci	for (i = 0; i < cache->num_mip_levels; i++) {
39362306a36Sopenharmony_ci		struct vmw_surface_mip *mip = &cache->mip[i];
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci		mip->size = vmw_surface_get_mip_size(*size, i);
39662306a36Sopenharmony_ci		mip->bytes = vmw_surface_get_image_buffer_size
39762306a36Sopenharmony_ci			(desc, &mip->size, 0);
39862306a36Sopenharmony_ci		mip->row_stride =
39962306a36Sopenharmony_ci			__KERNEL_DIV_ROUND_UP(mip->size.width,
40062306a36Sopenharmony_ci					      desc->blockSize.width) *
40162306a36Sopenharmony_ci			desc->bytesPerBlock * num_samples;
40262306a36Sopenharmony_ci		if (!mip->row_stride)
40362306a36Sopenharmony_ci			goto invalid_dim;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci		mip->img_stride =
40662306a36Sopenharmony_ci			__KERNEL_DIV_ROUND_UP(mip->size.height,
40762306a36Sopenharmony_ci					      desc->blockSize.height) *
40862306a36Sopenharmony_ci			mip->row_stride;
40962306a36Sopenharmony_ci		if (!mip->img_stride)
41062306a36Sopenharmony_ci			goto invalid_dim;
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci		cache->mip_chain_bytes += mip->bytes;
41362306a36Sopenharmony_ci	}
41462306a36Sopenharmony_ci	cache->sheet_bytes = cache->mip_chain_bytes * num_layers;
41562306a36Sopenharmony_ci	if (!cache->sheet_bytes)
41662306a36Sopenharmony_ci		goto invalid_dim;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	return 0;
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ciinvalid_dim:
42162306a36Sopenharmony_ci	VMW_DEBUG_USER("Invalid surface layout for dirty tracking.\n");
42262306a36Sopenharmony_ci	return -EINVAL;
42362306a36Sopenharmony_ci}
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci/**
42662306a36Sopenharmony_ci * vmw_surface_get_loc - Get a surface location from an offset into the
42762306a36Sopenharmony_ci * backing store
42862306a36Sopenharmony_ci * @cache: Surface layout data.
42962306a36Sopenharmony_ci * @loc: Pointer to a struct vmw_surface_loc to be filled in.
43062306a36Sopenharmony_ci * @offset: Offset into the surface backing store.
43162306a36Sopenharmony_ci */
43262306a36Sopenharmony_cistatic inline void
43362306a36Sopenharmony_civmw_surface_get_loc(const struct vmw_surface_cache *cache,
43462306a36Sopenharmony_ci		      struct vmw_surface_loc *loc,
43562306a36Sopenharmony_ci		      size_t offset)
43662306a36Sopenharmony_ci{
43762306a36Sopenharmony_ci	const struct vmw_surface_mip *mip = &cache->mip[0];
43862306a36Sopenharmony_ci	const SVGA3dSurfaceDesc *desc = cache->desc;
43962306a36Sopenharmony_ci	u32 layer;
44062306a36Sopenharmony_ci	int i;
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	loc->sheet = offset / cache->sheet_bytes;
44362306a36Sopenharmony_ci	offset -= loc->sheet * cache->sheet_bytes;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	layer = offset / cache->mip_chain_bytes;
44662306a36Sopenharmony_ci	offset -= layer * cache->mip_chain_bytes;
44762306a36Sopenharmony_ci	for (i = 0; i < cache->num_mip_levels; ++i, ++mip) {
44862306a36Sopenharmony_ci		if (mip->bytes > offset)
44962306a36Sopenharmony_ci			break;
45062306a36Sopenharmony_ci		offset -= mip->bytes;
45162306a36Sopenharmony_ci	}
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	loc->sub_resource = vmw_surface_subres(cache, i, layer);
45462306a36Sopenharmony_ci	loc->z = offset / mip->img_stride;
45562306a36Sopenharmony_ci	offset -= loc->z * mip->img_stride;
45662306a36Sopenharmony_ci	loc->z *= desc->blockSize.depth;
45762306a36Sopenharmony_ci	loc->y = offset / mip->row_stride;
45862306a36Sopenharmony_ci	offset -= loc->y * mip->row_stride;
45962306a36Sopenharmony_ci	loc->y *= desc->blockSize.height;
46062306a36Sopenharmony_ci	loc->x = offset / desc->bytesPerBlock;
46162306a36Sopenharmony_ci	loc->x *= desc->blockSize.width;
46262306a36Sopenharmony_ci}
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci/**
46562306a36Sopenharmony_ci * vmw_surface_inc_loc - Clamp increment a surface location with one block
46662306a36Sopenharmony_ci * size
46762306a36Sopenharmony_ci * in each dimension.
46862306a36Sopenharmony_ci * @loc: Pointer to a struct vmw_surface_loc to be incremented.
46962306a36Sopenharmony_ci *
47062306a36Sopenharmony_ci * When computing the size of a range as size = end - start, the range does not
47162306a36Sopenharmony_ci * include the end element. However a location representing the last byte
47262306a36Sopenharmony_ci * of a touched region in the backing store *is* included in the range.
47362306a36Sopenharmony_ci * This function modifies such a location to match the end definition
47462306a36Sopenharmony_ci * given as start + size which is the one used in a SVGA3dBox.
47562306a36Sopenharmony_ci */
47662306a36Sopenharmony_cistatic inline void
47762306a36Sopenharmony_civmw_surface_inc_loc(const struct vmw_surface_cache *cache,
47862306a36Sopenharmony_ci		      struct vmw_surface_loc *loc)
47962306a36Sopenharmony_ci{
48062306a36Sopenharmony_ci	const SVGA3dSurfaceDesc *desc = cache->desc;
48162306a36Sopenharmony_ci	u32 mip = loc->sub_resource % cache->num_mip_levels;
48262306a36Sopenharmony_ci	const struct drm_vmw_size *size = &cache->mip[mip].size;
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	loc->sub_resource++;
48562306a36Sopenharmony_ci	loc->x += desc->blockSize.width;
48662306a36Sopenharmony_ci	if (loc->x > size->width)
48762306a36Sopenharmony_ci		loc->x = size->width;
48862306a36Sopenharmony_ci	loc->y += desc->blockSize.height;
48962306a36Sopenharmony_ci	if (loc->y > size->height)
49062306a36Sopenharmony_ci		loc->y = size->height;
49162306a36Sopenharmony_ci	loc->z += desc->blockSize.depth;
49262306a36Sopenharmony_ci	if (loc->z > size->depth)
49362306a36Sopenharmony_ci		loc->z = size->depth;
49462306a36Sopenharmony_ci}
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci/**
49762306a36Sopenharmony_ci * vmw_surface_min_loc - The start location in a subresource
49862306a36Sopenharmony_ci * @cache: Surface layout data.
49962306a36Sopenharmony_ci * @sub_resource: The subresource.
50062306a36Sopenharmony_ci * @loc: Pointer to a struct vmw_surface_loc to be filled in.
50162306a36Sopenharmony_ci */
50262306a36Sopenharmony_cistatic inline void
50362306a36Sopenharmony_civmw_surface_min_loc(const struct vmw_surface_cache *cache,
50462306a36Sopenharmony_ci		      u32 sub_resource,
50562306a36Sopenharmony_ci		      struct vmw_surface_loc *loc)
50662306a36Sopenharmony_ci{
50762306a36Sopenharmony_ci	loc->sheet = 0;
50862306a36Sopenharmony_ci	loc->sub_resource = sub_resource;
50962306a36Sopenharmony_ci	loc->x = loc->y = loc->z = 0;
51062306a36Sopenharmony_ci}
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci/**
51362306a36Sopenharmony_ci * vmw_surface_min_loc - The end location in a subresource
51462306a36Sopenharmony_ci * @cache: Surface layout data.
51562306a36Sopenharmony_ci * @sub_resource: The subresource.
51662306a36Sopenharmony_ci * @loc: Pointer to a struct vmw_surface_loc to be filled in.
51762306a36Sopenharmony_ci *
51862306a36Sopenharmony_ci * Following the end definition given in vmw_surface_inc_loc(),
51962306a36Sopenharmony_ci * Compute the end location of a surface subresource.
52062306a36Sopenharmony_ci */
52162306a36Sopenharmony_cistatic inline void
52262306a36Sopenharmony_civmw_surface_max_loc(const struct vmw_surface_cache *cache,
52362306a36Sopenharmony_ci		      u32 sub_resource,
52462306a36Sopenharmony_ci		      struct vmw_surface_loc *loc)
52562306a36Sopenharmony_ci{
52662306a36Sopenharmony_ci	const struct drm_vmw_size *size;
52762306a36Sopenharmony_ci	u32 mip;
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	loc->sheet = 0;
53062306a36Sopenharmony_ci	loc->sub_resource = sub_resource + 1;
53162306a36Sopenharmony_ci	mip = sub_resource % cache->num_mip_levels;
53262306a36Sopenharmony_ci	size = &cache->mip[mip].size;
53362306a36Sopenharmony_ci	loc->x = size->width;
53462306a36Sopenharmony_ci	loc->y = size->height;
53562306a36Sopenharmony_ci	loc->z = size->depth;
53662306a36Sopenharmony_ci}
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci#endif /* VMW_SURFACE_CACHE_H */
540