1*ebc9ac7cSZack Rusin /**********************************************************
2*ebc9ac7cSZack Rusin  * Copyright 2021 VMware, Inc.
3*ebc9ac7cSZack Rusin  * SPDX-License-Identifier: GPL-2.0 OR MIT
4*ebc9ac7cSZack Rusin  *
5*ebc9ac7cSZack Rusin  * Permission is hereby granted, free of charge, to any person
6*ebc9ac7cSZack Rusin  * obtaining a copy of this software and associated documentation
7*ebc9ac7cSZack Rusin  * files (the "Software"), to deal in the Software without
8*ebc9ac7cSZack Rusin  * restriction, including without limitation the rights to use, copy,
9*ebc9ac7cSZack Rusin  * modify, merge, publish, distribute, sublicense, and/or sell copies
10*ebc9ac7cSZack Rusin  * of the Software, and to permit persons to whom the Software is
11*ebc9ac7cSZack Rusin  * furnished to do so, subject to the following conditions:
12*ebc9ac7cSZack Rusin  *
13*ebc9ac7cSZack Rusin  * The above copyright notice and this permission notice shall be
14*ebc9ac7cSZack Rusin  * included in all copies or substantial portions of the Software.
15*ebc9ac7cSZack Rusin  *
16*ebc9ac7cSZack Rusin  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17*ebc9ac7cSZack Rusin  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18*ebc9ac7cSZack Rusin  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19*ebc9ac7cSZack Rusin  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20*ebc9ac7cSZack Rusin  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21*ebc9ac7cSZack Rusin  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22*ebc9ac7cSZack Rusin  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23*ebc9ac7cSZack Rusin  * SOFTWARE.
24*ebc9ac7cSZack Rusin  *
25*ebc9ac7cSZack Rusin  **********************************************************/
26*ebc9ac7cSZack Rusin 
27*ebc9ac7cSZack Rusin #ifndef VMW_SURFACE_CACHE_H
28*ebc9ac7cSZack Rusin #define VMW_SURFACE_CACHE_H
29*ebc9ac7cSZack Rusin 
30*ebc9ac7cSZack Rusin #include "device_include/svga3d_surfacedefs.h"
31*ebc9ac7cSZack Rusin 
32*ebc9ac7cSZack Rusin #include <drm/vmwgfx_drm.h>
33*ebc9ac7cSZack Rusin 
clamped_umul32(u32 a,u32 b)34*ebc9ac7cSZack Rusin static inline u32 clamped_umul32(u32 a, u32 b)
35*ebc9ac7cSZack Rusin {
36*ebc9ac7cSZack Rusin 	uint64_t tmp = (uint64_t) a*b;
37*ebc9ac7cSZack Rusin 	return (tmp > (uint64_t) ((u32) -1)) ? (u32) -1 : tmp;
38*ebc9ac7cSZack Rusin }
39*ebc9ac7cSZack Rusin 
40*ebc9ac7cSZack Rusin /**
41*ebc9ac7cSZack Rusin  * vmw_surface_get_desc - Look up the appropriate SVGA3dSurfaceDesc for the
42*ebc9ac7cSZack Rusin  * given format.
43*ebc9ac7cSZack Rusin  */
44*ebc9ac7cSZack Rusin static inline const SVGA3dSurfaceDesc *
vmw_surface_get_desc(SVGA3dSurfaceFormat format)45*ebc9ac7cSZack Rusin vmw_surface_get_desc(SVGA3dSurfaceFormat format)
46*ebc9ac7cSZack Rusin {
47*ebc9ac7cSZack Rusin 	if (format < ARRAY_SIZE(g_SVGA3dSurfaceDescs))
48*ebc9ac7cSZack Rusin 		return &g_SVGA3dSurfaceDescs[format];
49*ebc9ac7cSZack Rusin 
50*ebc9ac7cSZack Rusin 	return &g_SVGA3dSurfaceDescs[SVGA3D_FORMAT_INVALID];
51*ebc9ac7cSZack Rusin }
52*ebc9ac7cSZack Rusin 
53*ebc9ac7cSZack Rusin /**
54*ebc9ac7cSZack Rusin  * vmw_surface_get_mip_size -  Given a base level size and the mip level,
55*ebc9ac7cSZack Rusin  * compute the size of the mip level.
56*ebc9ac7cSZack Rusin  */
57*ebc9ac7cSZack Rusin static inline struct drm_vmw_size
vmw_surface_get_mip_size(struct drm_vmw_size base_level,u32 mip_level)58*ebc9ac7cSZack Rusin vmw_surface_get_mip_size(struct drm_vmw_size base_level, u32 mip_level)
59*ebc9ac7cSZack Rusin {
60*ebc9ac7cSZack Rusin 	struct drm_vmw_size size = {
61*ebc9ac7cSZack Rusin 		.width = max_t(u32, base_level.width >> mip_level, 1),
62*ebc9ac7cSZack Rusin 		.height = max_t(u32, base_level.height >> mip_level, 1),
63*ebc9ac7cSZack Rusin 		.depth = max_t(u32, base_level.depth >> mip_level, 1)
64*ebc9ac7cSZack Rusin 	};
65*ebc9ac7cSZack Rusin 
66*ebc9ac7cSZack Rusin 	return size;
67*ebc9ac7cSZack Rusin }
68*ebc9ac7cSZack Rusin 
69*ebc9ac7cSZack Rusin static inline void
vmw_surface_get_size_in_blocks(const SVGA3dSurfaceDesc * desc,const struct drm_vmw_size * pixel_size,SVGA3dSize * block_size)70*ebc9ac7cSZack Rusin vmw_surface_get_size_in_blocks(const SVGA3dSurfaceDesc *desc,
71*ebc9ac7cSZack Rusin 				 const struct drm_vmw_size *pixel_size,
72*ebc9ac7cSZack Rusin 				 SVGA3dSize *block_size)
73*ebc9ac7cSZack Rusin {
74*ebc9ac7cSZack Rusin 	block_size->width = __KERNEL_DIV_ROUND_UP(pixel_size->width,
75*ebc9ac7cSZack Rusin 						  desc->blockSize.width);
76*ebc9ac7cSZack Rusin 	block_size->height = __KERNEL_DIV_ROUND_UP(pixel_size->height,
77*ebc9ac7cSZack Rusin 						   desc->blockSize.height);
78*ebc9ac7cSZack Rusin 	block_size->depth = __KERNEL_DIV_ROUND_UP(pixel_size->depth,
79*ebc9ac7cSZack Rusin 						  desc->blockSize.depth);
80*ebc9ac7cSZack Rusin }
81*ebc9ac7cSZack Rusin 
82*ebc9ac7cSZack Rusin static inline bool
vmw_surface_is_planar_surface(const SVGA3dSurfaceDesc * desc)83*ebc9ac7cSZack Rusin vmw_surface_is_planar_surface(const SVGA3dSurfaceDesc *desc)
84*ebc9ac7cSZack Rusin {
85*ebc9ac7cSZack Rusin 	return (desc->blockDesc & SVGA3DBLOCKDESC_PLANAR_YUV) != 0;
86*ebc9ac7cSZack Rusin }
87*ebc9ac7cSZack Rusin 
88*ebc9ac7cSZack Rusin static inline u32
vmw_surface_calculate_pitch(const SVGA3dSurfaceDesc * desc,const struct drm_vmw_size * size)89*ebc9ac7cSZack Rusin vmw_surface_calculate_pitch(const SVGA3dSurfaceDesc *desc,
90*ebc9ac7cSZack Rusin 			      const struct drm_vmw_size *size)
91*ebc9ac7cSZack Rusin {
92*ebc9ac7cSZack Rusin 	u32 pitch;
93*ebc9ac7cSZack Rusin 	SVGA3dSize blocks;
94*ebc9ac7cSZack Rusin 
95*ebc9ac7cSZack Rusin 	vmw_surface_get_size_in_blocks(desc, size, &blocks);
96*ebc9ac7cSZack Rusin 
97*ebc9ac7cSZack Rusin 	pitch = blocks.width * desc->pitchBytesPerBlock;
98*ebc9ac7cSZack Rusin 
99*ebc9ac7cSZack Rusin 	return pitch;
100*ebc9ac7cSZack Rusin }
101*ebc9ac7cSZack Rusin 
102*ebc9ac7cSZack Rusin /**
103*ebc9ac7cSZack Rusin  * vmw_surface_get_image_buffer_size - Calculates image buffer size.
104*ebc9ac7cSZack Rusin  *
105*ebc9ac7cSZack Rusin  * Return the number of bytes of buffer space required to store one image of a
106*ebc9ac7cSZack Rusin  * surface, optionally using the specified pitch.
107*ebc9ac7cSZack Rusin  *
108*ebc9ac7cSZack Rusin  * If pitch is zero, it is assumed that rows are tightly packed.
109*ebc9ac7cSZack Rusin  *
110*ebc9ac7cSZack Rusin  * This function is overflow-safe. If the result would have overflowed, instead
111*ebc9ac7cSZack Rusin  * we return MAX_UINT32.
112*ebc9ac7cSZack Rusin  */
113*ebc9ac7cSZack Rusin static inline u32
vmw_surface_get_image_buffer_size(const SVGA3dSurfaceDesc * desc,const struct drm_vmw_size * size,u32 pitch)114*ebc9ac7cSZack Rusin vmw_surface_get_image_buffer_size(const SVGA3dSurfaceDesc *desc,
115*ebc9ac7cSZack Rusin 				    const struct drm_vmw_size *size,
116*ebc9ac7cSZack Rusin 				    u32 pitch)
117*ebc9ac7cSZack Rusin {
118*ebc9ac7cSZack Rusin 	SVGA3dSize image_blocks;
119*ebc9ac7cSZack Rusin 	u32 slice_size, total_size;
120*ebc9ac7cSZack Rusin 
121*ebc9ac7cSZack Rusin 	vmw_surface_get_size_in_blocks(desc, size, &image_blocks);
122*ebc9ac7cSZack Rusin 
123*ebc9ac7cSZack Rusin 	if (vmw_surface_is_planar_surface(desc)) {
124*ebc9ac7cSZack Rusin 		total_size = clamped_umul32(image_blocks.width,
125*ebc9ac7cSZack Rusin 					    image_blocks.height);
126*ebc9ac7cSZack Rusin 		total_size = clamped_umul32(total_size, image_blocks.depth);
127*ebc9ac7cSZack Rusin 		total_size = clamped_umul32(total_size, desc->bytesPerBlock);
128*ebc9ac7cSZack Rusin 		return total_size;
129*ebc9ac7cSZack Rusin 	}
130*ebc9ac7cSZack Rusin 
131*ebc9ac7cSZack Rusin 	if (pitch == 0)
132*ebc9ac7cSZack Rusin 		pitch = vmw_surface_calculate_pitch(desc, size);
133*ebc9ac7cSZack Rusin 
134*ebc9ac7cSZack Rusin 	slice_size = clamped_umul32(image_blocks.height, pitch);
135*ebc9ac7cSZack Rusin 	total_size = clamped_umul32(slice_size, image_blocks.depth);
136*ebc9ac7cSZack Rusin 
137*ebc9ac7cSZack Rusin 	return total_size;
138*ebc9ac7cSZack Rusin }
139*ebc9ac7cSZack Rusin 
140*ebc9ac7cSZack Rusin /**
141*ebc9ac7cSZack Rusin  * vmw_surface_get_serialized_size - Get the serialized size for the image.
142*ebc9ac7cSZack Rusin  */
143*ebc9ac7cSZack Rusin static inline u32
vmw_surface_get_serialized_size(SVGA3dSurfaceFormat format,struct drm_vmw_size base_level_size,u32 num_mip_levels,u32 num_layers)144*ebc9ac7cSZack Rusin vmw_surface_get_serialized_size(SVGA3dSurfaceFormat format,
145*ebc9ac7cSZack Rusin 				  struct drm_vmw_size base_level_size,
146*ebc9ac7cSZack Rusin 				  u32 num_mip_levels,
147*ebc9ac7cSZack Rusin 				  u32 num_layers)
148*ebc9ac7cSZack Rusin {
149*ebc9ac7cSZack Rusin 	const SVGA3dSurfaceDesc *desc = vmw_surface_get_desc(format);
150*ebc9ac7cSZack Rusin 	u32 total_size = 0;
151*ebc9ac7cSZack Rusin 	u32 mip;
152*ebc9ac7cSZack Rusin 
153*ebc9ac7cSZack Rusin 	for (mip = 0; mip < num_mip_levels; mip++) {
154*ebc9ac7cSZack Rusin 		struct drm_vmw_size size =
155*ebc9ac7cSZack Rusin 			vmw_surface_get_mip_size(base_level_size, mip);
156*ebc9ac7cSZack Rusin 		total_size += vmw_surface_get_image_buffer_size(desc,
157*ebc9ac7cSZack Rusin 								  &size, 0);
158*ebc9ac7cSZack Rusin 	}
159*ebc9ac7cSZack Rusin 
160*ebc9ac7cSZack Rusin 	return total_size * num_layers;
161*ebc9ac7cSZack Rusin }
162*ebc9ac7cSZack Rusin 
163*ebc9ac7cSZack Rusin /**
164*ebc9ac7cSZack Rusin  * vmw_surface_get_serialized_size_extended - Returns the number of bytes
165*ebc9ac7cSZack Rusin  * required for a surface with given parameters. Support for sample count.
166*ebc9ac7cSZack Rusin  */
167*ebc9ac7cSZack Rusin 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)168*ebc9ac7cSZack Rusin vmw_surface_get_serialized_size_extended(SVGA3dSurfaceFormat format,
169*ebc9ac7cSZack Rusin 					   struct drm_vmw_size base_level_size,
170*ebc9ac7cSZack Rusin 					   u32 num_mip_levels,
171*ebc9ac7cSZack Rusin 					   u32 num_layers,
172*ebc9ac7cSZack Rusin 					   u32 num_samples)
173*ebc9ac7cSZack Rusin {
174*ebc9ac7cSZack Rusin 	uint64_t total_size =
175*ebc9ac7cSZack Rusin 		vmw_surface_get_serialized_size(format,
176*ebc9ac7cSZack Rusin 						  base_level_size,
177*ebc9ac7cSZack Rusin 						  num_mip_levels,
178*ebc9ac7cSZack Rusin 						  num_layers);
179*ebc9ac7cSZack Rusin 	total_size *= max_t(u32, 1, num_samples);
180*ebc9ac7cSZack Rusin 
181*ebc9ac7cSZack Rusin 	return min_t(uint64_t, total_size, (uint64_t)U32_MAX);
182*ebc9ac7cSZack Rusin }
183*ebc9ac7cSZack Rusin 
184*ebc9ac7cSZack Rusin /**
185*ebc9ac7cSZack Rusin  * vmw_surface_get_pixel_offset - Compute the offset (in bytes) to a pixel
186*ebc9ac7cSZack Rusin  * in an image (or volume).
187*ebc9ac7cSZack Rusin  *
188*ebc9ac7cSZack Rusin  * @width: The image width in pixels.
189*ebc9ac7cSZack Rusin  * @height: The image height in pixels
190*ebc9ac7cSZack Rusin  */
191*ebc9ac7cSZack Rusin static inline u32
vmw_surface_get_pixel_offset(SVGA3dSurfaceFormat format,u32 width,u32 height,u32 x,u32 y,u32 z)192*ebc9ac7cSZack Rusin vmw_surface_get_pixel_offset(SVGA3dSurfaceFormat format,
193*ebc9ac7cSZack Rusin 			       u32 width, u32 height,
194*ebc9ac7cSZack Rusin 			       u32 x, u32 y, u32 z)
195*ebc9ac7cSZack Rusin {
196*ebc9ac7cSZack Rusin 	const SVGA3dSurfaceDesc *desc = vmw_surface_get_desc(format);
197*ebc9ac7cSZack Rusin 	const u32 bw = desc->blockSize.width, bh = desc->blockSize.height;
198*ebc9ac7cSZack Rusin 	const u32 bd = desc->blockSize.depth;
199*ebc9ac7cSZack Rusin 	const u32 rowstride = __KERNEL_DIV_ROUND_UP(width, bw) *
200*ebc9ac7cSZack Rusin 			      desc->bytesPerBlock;
201*ebc9ac7cSZack Rusin 	const u32 imgstride = __KERNEL_DIV_ROUND_UP(height, bh) * rowstride;
202*ebc9ac7cSZack Rusin 	const u32 offset = (z / bd * imgstride +
203*ebc9ac7cSZack Rusin 			    y / bh * rowstride +
204*ebc9ac7cSZack Rusin 			    x / bw * desc->bytesPerBlock);
205*ebc9ac7cSZack Rusin 	return offset;
206*ebc9ac7cSZack Rusin }
207*ebc9ac7cSZack Rusin 
208*ebc9ac7cSZack Rusin static inline u32
vmw_surface_get_image_offset(SVGA3dSurfaceFormat format,struct drm_vmw_size baseLevelSize,u32 numMipLevels,u32 face,u32 mip)209*ebc9ac7cSZack Rusin vmw_surface_get_image_offset(SVGA3dSurfaceFormat format,
210*ebc9ac7cSZack Rusin 			       struct drm_vmw_size baseLevelSize,
211*ebc9ac7cSZack Rusin 			       u32 numMipLevels,
212*ebc9ac7cSZack Rusin 			       u32 face,
213*ebc9ac7cSZack Rusin 			       u32 mip)
214*ebc9ac7cSZack Rusin 
215*ebc9ac7cSZack Rusin {
216*ebc9ac7cSZack Rusin 	u32 offset;
217*ebc9ac7cSZack Rusin 	u32 mipChainBytes;
218*ebc9ac7cSZack Rusin 	u32 mipChainBytesToLevel;
219*ebc9ac7cSZack Rusin 	u32 i;
220*ebc9ac7cSZack Rusin 	const SVGA3dSurfaceDesc *desc;
221*ebc9ac7cSZack Rusin 	struct drm_vmw_size mipSize;
222*ebc9ac7cSZack Rusin 	u32 bytes;
223*ebc9ac7cSZack Rusin 
224*ebc9ac7cSZack Rusin 	desc = vmw_surface_get_desc(format);
225*ebc9ac7cSZack Rusin 
226*ebc9ac7cSZack Rusin 	mipChainBytes = 0;
227*ebc9ac7cSZack Rusin 	mipChainBytesToLevel = 0;
228*ebc9ac7cSZack Rusin 	for (i = 0; i < numMipLevels; i++) {
229*ebc9ac7cSZack Rusin 		mipSize = vmw_surface_get_mip_size(baseLevelSize, i);
230*ebc9ac7cSZack Rusin 		bytes = vmw_surface_get_image_buffer_size(desc, &mipSize, 0);
231*ebc9ac7cSZack Rusin 		mipChainBytes += bytes;
232*ebc9ac7cSZack Rusin 		if (i < mip)
233*ebc9ac7cSZack Rusin 			mipChainBytesToLevel += bytes;
234*ebc9ac7cSZack Rusin 	}
235*ebc9ac7cSZack Rusin 
236*ebc9ac7cSZack Rusin 	offset = mipChainBytes * face + mipChainBytesToLevel;
237*ebc9ac7cSZack Rusin 
238*ebc9ac7cSZack Rusin 	return offset;
239*ebc9ac7cSZack Rusin }
240*ebc9ac7cSZack Rusin 
241*ebc9ac7cSZack Rusin 
242*ebc9ac7cSZack Rusin /**
243*ebc9ac7cSZack Rusin  * vmw_surface_is_gb_screen_target_format - Is the specified format usable as
244*ebc9ac7cSZack Rusin  *                                            a ScreenTarget?
245*ebc9ac7cSZack Rusin  *                                            (with just the GBObjects cap-bit
246*ebc9ac7cSZack Rusin  *                                             set)
247*ebc9ac7cSZack Rusin  * @format: format to queried
248*ebc9ac7cSZack Rusin  *
249*ebc9ac7cSZack Rusin  * RETURNS:
250*ebc9ac7cSZack Rusin  * true if queried format is valid for screen targets
251*ebc9ac7cSZack Rusin  */
252*ebc9ac7cSZack Rusin static inline bool
vmw_surface_is_gb_screen_target_format(SVGA3dSurfaceFormat format)253*ebc9ac7cSZack Rusin vmw_surface_is_gb_screen_target_format(SVGA3dSurfaceFormat format)
254*ebc9ac7cSZack Rusin {
255*ebc9ac7cSZack Rusin 	return (format == SVGA3D_X8R8G8B8 ||
256*ebc9ac7cSZack Rusin 		format == SVGA3D_A8R8G8B8 ||
257*ebc9ac7cSZack Rusin 		format == SVGA3D_R5G6B5   ||
258*ebc9ac7cSZack Rusin 		format == SVGA3D_X1R5G5B5 ||
259*ebc9ac7cSZack Rusin 		format == SVGA3D_A1R5G5B5 ||
260*ebc9ac7cSZack Rusin 		format == SVGA3D_P8);
261*ebc9ac7cSZack Rusin }
262*ebc9ac7cSZack Rusin 
263*ebc9ac7cSZack Rusin 
264*ebc9ac7cSZack Rusin /**
265*ebc9ac7cSZack Rusin  * vmw_surface_is_dx_screen_target_format - Is the specified format usable as
266*ebc9ac7cSZack Rusin  *                                            a ScreenTarget?
267*ebc9ac7cSZack Rusin  *                                            (with DX10 enabled)
268*ebc9ac7cSZack Rusin  *
269*ebc9ac7cSZack Rusin  * @format: format to queried
270*ebc9ac7cSZack Rusin  *
271*ebc9ac7cSZack Rusin  * Results:
272*ebc9ac7cSZack Rusin  * true if queried format is valid for screen targets
273*ebc9ac7cSZack Rusin  */
274*ebc9ac7cSZack Rusin static inline bool
vmw_surface_is_dx_screen_target_format(SVGA3dSurfaceFormat format)275*ebc9ac7cSZack Rusin vmw_surface_is_dx_screen_target_format(SVGA3dSurfaceFormat format)
276*ebc9ac7cSZack Rusin {
277*ebc9ac7cSZack Rusin 	return (format == SVGA3D_R8G8B8A8_UNORM ||
278*ebc9ac7cSZack Rusin 		format == SVGA3D_B8G8R8A8_UNORM ||
279*ebc9ac7cSZack Rusin 		format == SVGA3D_B8G8R8X8_UNORM);
280*ebc9ac7cSZack Rusin }
281*ebc9ac7cSZack Rusin 
282*ebc9ac7cSZack Rusin 
283*ebc9ac7cSZack Rusin /**
284*ebc9ac7cSZack Rusin  * vmw_surface_is_screen_target_format - Is the specified format usable as a
285*ebc9ac7cSZack Rusin  *                                         ScreenTarget?
286*ebc9ac7cSZack Rusin  *                                         (for some combination of caps)
287*ebc9ac7cSZack Rusin  *
288*ebc9ac7cSZack Rusin  * @format: format to queried
289*ebc9ac7cSZack Rusin  *
290*ebc9ac7cSZack Rusin  * Results:
291*ebc9ac7cSZack Rusin  * true if queried format is valid for screen targets
292*ebc9ac7cSZack Rusin  */
293*ebc9ac7cSZack Rusin static inline bool
vmw_surface_is_screen_target_format(SVGA3dSurfaceFormat format)294*ebc9ac7cSZack Rusin vmw_surface_is_screen_target_format(SVGA3dSurfaceFormat format)
295*ebc9ac7cSZack Rusin {
296*ebc9ac7cSZack Rusin 	if (vmw_surface_is_gb_screen_target_format(format)) {
297*ebc9ac7cSZack Rusin 		return true;
298*ebc9ac7cSZack Rusin 	}
299*ebc9ac7cSZack Rusin 	return vmw_surface_is_dx_screen_target_format(format);
300*ebc9ac7cSZack Rusin }
301*ebc9ac7cSZack Rusin 
302*ebc9ac7cSZack Rusin /**
303*ebc9ac7cSZack Rusin  * struct vmw_surface_mip - Mimpmap level information
304*ebc9ac7cSZack Rusin  * @bytes: Bytes required in the backing store of this mipmap level.
305*ebc9ac7cSZack Rusin  * @img_stride: Byte stride per image.
306*ebc9ac7cSZack Rusin  * @row_stride: Byte stride per block row.
307*ebc9ac7cSZack Rusin  * @size: The size of the mipmap.
308*ebc9ac7cSZack Rusin  */
309*ebc9ac7cSZack Rusin struct vmw_surface_mip {
310*ebc9ac7cSZack Rusin 	size_t bytes;
311*ebc9ac7cSZack Rusin 	size_t img_stride;
312*ebc9ac7cSZack Rusin 	size_t row_stride;
313*ebc9ac7cSZack Rusin 	struct drm_vmw_size size;
314*ebc9ac7cSZack Rusin 
315*ebc9ac7cSZack Rusin };
316*ebc9ac7cSZack Rusin 
317*ebc9ac7cSZack Rusin /**
318*ebc9ac7cSZack Rusin  * struct vmw_surface_cache - Cached surface information
319*ebc9ac7cSZack Rusin  * @desc: Pointer to the surface descriptor
320*ebc9ac7cSZack Rusin  * @mip: Array of mipmap level information. Valid size is @num_mip_levels.
321*ebc9ac7cSZack Rusin  * @mip_chain_bytes: Bytes required in the backing store for the whole chain
322*ebc9ac7cSZack Rusin  * of mip levels.
323*ebc9ac7cSZack Rusin  * @sheet_bytes: Bytes required in the backing store for a sheet
324*ebc9ac7cSZack Rusin  * representing a single sample.
325*ebc9ac7cSZack Rusin  * @num_mip_levels: Valid size of the @mip array. Number of mipmap levels in
326*ebc9ac7cSZack Rusin  * a chain.
327*ebc9ac7cSZack Rusin  * @num_layers: Number of slices in an array texture or number of faces in
328*ebc9ac7cSZack Rusin  * a cubemap texture.
329*ebc9ac7cSZack Rusin  */
330*ebc9ac7cSZack Rusin struct vmw_surface_cache {
331*ebc9ac7cSZack Rusin 	const SVGA3dSurfaceDesc *desc;
332*ebc9ac7cSZack Rusin 	struct vmw_surface_mip mip[DRM_VMW_MAX_MIP_LEVELS];
333*ebc9ac7cSZack Rusin 	size_t mip_chain_bytes;
334*ebc9ac7cSZack Rusin 	size_t sheet_bytes;
335*ebc9ac7cSZack Rusin 	u32 num_mip_levels;
336*ebc9ac7cSZack Rusin 	u32 num_layers;
337*ebc9ac7cSZack Rusin };
338*ebc9ac7cSZack Rusin 
339*ebc9ac7cSZack Rusin /**
340*ebc9ac7cSZack Rusin  * struct vmw_surface_loc - Surface location
341*ebc9ac7cSZack Rusin  * @sheet: The multisample sheet.
342*ebc9ac7cSZack Rusin  * @sub_resource: Surface subresource. Defined as layer * num_mip_levels +
343*ebc9ac7cSZack Rusin  * mip_level.
344*ebc9ac7cSZack Rusin  * @x: X coordinate.
345*ebc9ac7cSZack Rusin  * @y: Y coordinate.
346*ebc9ac7cSZack Rusin  * @z: Z coordinate.
347*ebc9ac7cSZack Rusin  */
348*ebc9ac7cSZack Rusin struct vmw_surface_loc {
349*ebc9ac7cSZack Rusin 	u32 sheet;
350*ebc9ac7cSZack Rusin 	u32 sub_resource;
351*ebc9ac7cSZack Rusin 	u32 x, y, z;
352*ebc9ac7cSZack Rusin };
353*ebc9ac7cSZack Rusin 
354*ebc9ac7cSZack Rusin /**
355*ebc9ac7cSZack Rusin  * vmw_surface_subres - Compute the subresource from layer and mipmap.
356*ebc9ac7cSZack Rusin  * @cache: Surface layout data.
357*ebc9ac7cSZack Rusin  * @mip_level: The mipmap level.
358*ebc9ac7cSZack Rusin  * @layer: The surface layer (face or array slice).
359*ebc9ac7cSZack Rusin  *
360*ebc9ac7cSZack Rusin  * Return: The subresource.
361*ebc9ac7cSZack Rusin  */
vmw_surface_subres(const struct vmw_surface_cache * cache,u32 mip_level,u32 layer)362*ebc9ac7cSZack Rusin static inline u32 vmw_surface_subres(const struct vmw_surface_cache *cache,
363*ebc9ac7cSZack Rusin 				       u32 mip_level, u32 layer)
364*ebc9ac7cSZack Rusin {
365*ebc9ac7cSZack Rusin 	return cache->num_mip_levels * layer + mip_level;
366*ebc9ac7cSZack Rusin }
367*ebc9ac7cSZack Rusin 
368*ebc9ac7cSZack Rusin /**
369*ebc9ac7cSZack Rusin  * vmw_surface_setup_cache - Build a surface cache entry
370*ebc9ac7cSZack Rusin  * @size: The surface base level dimensions.
371*ebc9ac7cSZack Rusin  * @format: The surface format.
372*ebc9ac7cSZack Rusin  * @num_mip_levels: Number of mipmap levels.
373*ebc9ac7cSZack Rusin  * @num_layers: Number of layers.
374*ebc9ac7cSZack Rusin  * @cache: Pointer to a struct vmw_surface_cach object to be filled in.
375*ebc9ac7cSZack Rusin  *
376*ebc9ac7cSZack Rusin  * Return: Zero on success, -EINVAL on invalid surface layout.
377*ebc9ac7cSZack Rusin  */
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)378*ebc9ac7cSZack Rusin static inline int vmw_surface_setup_cache(const struct drm_vmw_size *size,
379*ebc9ac7cSZack Rusin 					    SVGA3dSurfaceFormat format,
380*ebc9ac7cSZack Rusin 					    u32 num_mip_levels,
381*ebc9ac7cSZack Rusin 					    u32 num_layers,
382*ebc9ac7cSZack Rusin 					    u32 num_samples,
383*ebc9ac7cSZack Rusin 					    struct vmw_surface_cache *cache)
384*ebc9ac7cSZack Rusin {
385*ebc9ac7cSZack Rusin 	const SVGA3dSurfaceDesc *desc;
386*ebc9ac7cSZack Rusin 	u32 i;
387*ebc9ac7cSZack Rusin 
388*ebc9ac7cSZack Rusin 	memset(cache, 0, sizeof(*cache));
389*ebc9ac7cSZack Rusin 	cache->desc = desc = vmw_surface_get_desc(format);
390*ebc9ac7cSZack Rusin 	cache->num_mip_levels = num_mip_levels;
391*ebc9ac7cSZack Rusin 	cache->num_layers = num_layers;
392*ebc9ac7cSZack Rusin 	for (i = 0; i < cache->num_mip_levels; i++) {
393*ebc9ac7cSZack Rusin 		struct vmw_surface_mip *mip = &cache->mip[i];
394*ebc9ac7cSZack Rusin 
395*ebc9ac7cSZack Rusin 		mip->size = vmw_surface_get_mip_size(*size, i);
396*ebc9ac7cSZack Rusin 		mip->bytes = vmw_surface_get_image_buffer_size
397*ebc9ac7cSZack Rusin 			(desc, &mip->size, 0);
398*ebc9ac7cSZack Rusin 		mip->row_stride =
399*ebc9ac7cSZack Rusin 			__KERNEL_DIV_ROUND_UP(mip->size.width,
400*ebc9ac7cSZack Rusin 					      desc->blockSize.width) *
401*ebc9ac7cSZack Rusin 			desc->bytesPerBlock * num_samples;
402*ebc9ac7cSZack Rusin 		if (!mip->row_stride)
403*ebc9ac7cSZack Rusin 			goto invalid_dim;
404*ebc9ac7cSZack Rusin 
405*ebc9ac7cSZack Rusin 		mip->img_stride =
406*ebc9ac7cSZack Rusin 			__KERNEL_DIV_ROUND_UP(mip->size.height,
407*ebc9ac7cSZack Rusin 					      desc->blockSize.height) *
408*ebc9ac7cSZack Rusin 			mip->row_stride;
409*ebc9ac7cSZack Rusin 		if (!mip->img_stride)
410*ebc9ac7cSZack Rusin 			goto invalid_dim;
411*ebc9ac7cSZack Rusin 
412*ebc9ac7cSZack Rusin 		cache->mip_chain_bytes += mip->bytes;
413*ebc9ac7cSZack Rusin 	}
414*ebc9ac7cSZack Rusin 	cache->sheet_bytes = cache->mip_chain_bytes * num_layers;
415*ebc9ac7cSZack Rusin 	if (!cache->sheet_bytes)
416*ebc9ac7cSZack Rusin 		goto invalid_dim;
417*ebc9ac7cSZack Rusin 
418*ebc9ac7cSZack Rusin 	return 0;
419*ebc9ac7cSZack Rusin 
420*ebc9ac7cSZack Rusin invalid_dim:
421*ebc9ac7cSZack Rusin 	VMW_DEBUG_USER("Invalid surface layout for dirty tracking.\n");
422*ebc9ac7cSZack Rusin 	return -EINVAL;
423*ebc9ac7cSZack Rusin }
424*ebc9ac7cSZack Rusin 
425*ebc9ac7cSZack Rusin /**
426*ebc9ac7cSZack Rusin  * vmw_surface_get_loc - Get a surface location from an offset into the
427*ebc9ac7cSZack Rusin  * backing store
428*ebc9ac7cSZack Rusin  * @cache: Surface layout data.
429*ebc9ac7cSZack Rusin  * @loc: Pointer to a struct vmw_surface_loc to be filled in.
430*ebc9ac7cSZack Rusin  * @offset: Offset into the surface backing store.
431*ebc9ac7cSZack Rusin  */
432*ebc9ac7cSZack Rusin static inline void
vmw_surface_get_loc(const struct vmw_surface_cache * cache,struct vmw_surface_loc * loc,size_t offset)433*ebc9ac7cSZack Rusin vmw_surface_get_loc(const struct vmw_surface_cache *cache,
434*ebc9ac7cSZack Rusin 		      struct vmw_surface_loc *loc,
435*ebc9ac7cSZack Rusin 		      size_t offset)
436*ebc9ac7cSZack Rusin {
437*ebc9ac7cSZack Rusin 	const struct vmw_surface_mip *mip = &cache->mip[0];
438*ebc9ac7cSZack Rusin 	const SVGA3dSurfaceDesc *desc = cache->desc;
439*ebc9ac7cSZack Rusin 	u32 layer;
440*ebc9ac7cSZack Rusin 	int i;
441*ebc9ac7cSZack Rusin 
442*ebc9ac7cSZack Rusin 	loc->sheet = offset / cache->sheet_bytes;
443*ebc9ac7cSZack Rusin 	offset -= loc->sheet * cache->sheet_bytes;
444*ebc9ac7cSZack Rusin 
445*ebc9ac7cSZack Rusin 	layer = offset / cache->mip_chain_bytes;
446*ebc9ac7cSZack Rusin 	offset -= layer * cache->mip_chain_bytes;
447*ebc9ac7cSZack Rusin 	for (i = 0; i < cache->num_mip_levels; ++i, ++mip) {
448*ebc9ac7cSZack Rusin 		if (mip->bytes > offset)
449*ebc9ac7cSZack Rusin 			break;
450*ebc9ac7cSZack Rusin 		offset -= mip->bytes;
451*ebc9ac7cSZack Rusin 	}
452*ebc9ac7cSZack Rusin 
453*ebc9ac7cSZack Rusin 	loc->sub_resource = vmw_surface_subres(cache, i, layer);
454*ebc9ac7cSZack Rusin 	loc->z = offset / mip->img_stride;
455*ebc9ac7cSZack Rusin 	offset -= loc->z * mip->img_stride;
456*ebc9ac7cSZack Rusin 	loc->z *= desc->blockSize.depth;
457*ebc9ac7cSZack Rusin 	loc->y = offset / mip->row_stride;
458*ebc9ac7cSZack Rusin 	offset -= loc->y * mip->row_stride;
459*ebc9ac7cSZack Rusin 	loc->y *= desc->blockSize.height;
460*ebc9ac7cSZack Rusin 	loc->x = offset / desc->bytesPerBlock;
461*ebc9ac7cSZack Rusin 	loc->x *= desc->blockSize.width;
462*ebc9ac7cSZack Rusin }
463*ebc9ac7cSZack Rusin 
464*ebc9ac7cSZack Rusin /**
465*ebc9ac7cSZack Rusin  * vmw_surface_inc_loc - Clamp increment a surface location with one block
466*ebc9ac7cSZack Rusin  * size
467*ebc9ac7cSZack Rusin  * in each dimension.
468*ebc9ac7cSZack Rusin  * @loc: Pointer to a struct vmw_surface_loc to be incremented.
469*ebc9ac7cSZack Rusin  *
470*ebc9ac7cSZack Rusin  * When computing the size of a range as size = end - start, the range does not
471*ebc9ac7cSZack Rusin  * include the end element. However a location representing the last byte
472*ebc9ac7cSZack Rusin  * of a touched region in the backing store *is* included in the range.
473*ebc9ac7cSZack Rusin  * This function modifies such a location to match the end definition
474*ebc9ac7cSZack Rusin  * given as start + size which is the one used in a SVGA3dBox.
475*ebc9ac7cSZack Rusin  */
476*ebc9ac7cSZack Rusin static inline void
vmw_surface_inc_loc(const struct vmw_surface_cache * cache,struct vmw_surface_loc * loc)477*ebc9ac7cSZack Rusin vmw_surface_inc_loc(const struct vmw_surface_cache *cache,
478*ebc9ac7cSZack Rusin 		      struct vmw_surface_loc *loc)
479*ebc9ac7cSZack Rusin {
480*ebc9ac7cSZack Rusin 	const SVGA3dSurfaceDesc *desc = cache->desc;
481*ebc9ac7cSZack Rusin 	u32 mip = loc->sub_resource % cache->num_mip_levels;
482*ebc9ac7cSZack Rusin 	const struct drm_vmw_size *size = &cache->mip[mip].size;
483*ebc9ac7cSZack Rusin 
484*ebc9ac7cSZack Rusin 	loc->sub_resource++;
485*ebc9ac7cSZack Rusin 	loc->x += desc->blockSize.width;
486*ebc9ac7cSZack Rusin 	if (loc->x > size->width)
487*ebc9ac7cSZack Rusin 		loc->x = size->width;
488*ebc9ac7cSZack Rusin 	loc->y += desc->blockSize.height;
489*ebc9ac7cSZack Rusin 	if (loc->y > size->height)
490*ebc9ac7cSZack Rusin 		loc->y = size->height;
491*ebc9ac7cSZack Rusin 	loc->z += desc->blockSize.depth;
492*ebc9ac7cSZack Rusin 	if (loc->z > size->depth)
493*ebc9ac7cSZack Rusin 		loc->z = size->depth;
494*ebc9ac7cSZack Rusin }
495*ebc9ac7cSZack Rusin 
496*ebc9ac7cSZack Rusin /**
497*ebc9ac7cSZack Rusin  * vmw_surface_min_loc - The start location in a subresource
498*ebc9ac7cSZack Rusin  * @cache: Surface layout data.
499*ebc9ac7cSZack Rusin  * @sub_resource: The subresource.
500*ebc9ac7cSZack Rusin  * @loc: Pointer to a struct vmw_surface_loc to be filled in.
501*ebc9ac7cSZack Rusin  */
502*ebc9ac7cSZack Rusin static inline void
vmw_surface_min_loc(const struct vmw_surface_cache * cache,u32 sub_resource,struct vmw_surface_loc * loc)503*ebc9ac7cSZack Rusin vmw_surface_min_loc(const struct vmw_surface_cache *cache,
504*ebc9ac7cSZack Rusin 		      u32 sub_resource,
505*ebc9ac7cSZack Rusin 		      struct vmw_surface_loc *loc)
506*ebc9ac7cSZack Rusin {
507*ebc9ac7cSZack Rusin 	loc->sheet = 0;
508*ebc9ac7cSZack Rusin 	loc->sub_resource = sub_resource;
509*ebc9ac7cSZack Rusin 	loc->x = loc->y = loc->z = 0;
510*ebc9ac7cSZack Rusin }
511*ebc9ac7cSZack Rusin 
512*ebc9ac7cSZack Rusin /**
513*ebc9ac7cSZack Rusin  * vmw_surface_min_loc - The end location in a subresource
514*ebc9ac7cSZack Rusin  * @cache: Surface layout data.
515*ebc9ac7cSZack Rusin  * @sub_resource: The subresource.
516*ebc9ac7cSZack Rusin  * @loc: Pointer to a struct vmw_surface_loc to be filled in.
517*ebc9ac7cSZack Rusin  *
518*ebc9ac7cSZack Rusin  * Following the end definition given in vmw_surface_inc_loc(),
519*ebc9ac7cSZack Rusin  * Compute the end location of a surface subresource.
520*ebc9ac7cSZack Rusin  */
521*ebc9ac7cSZack Rusin static inline void
vmw_surface_max_loc(const struct vmw_surface_cache * cache,u32 sub_resource,struct vmw_surface_loc * loc)522*ebc9ac7cSZack Rusin vmw_surface_max_loc(const struct vmw_surface_cache *cache,
523*ebc9ac7cSZack Rusin 		      u32 sub_resource,
524*ebc9ac7cSZack Rusin 		      struct vmw_surface_loc *loc)
525*ebc9ac7cSZack Rusin {
526*ebc9ac7cSZack Rusin 	const struct drm_vmw_size *size;
527*ebc9ac7cSZack Rusin 	u32 mip;
528*ebc9ac7cSZack Rusin 
529*ebc9ac7cSZack Rusin 	loc->sheet = 0;
530*ebc9ac7cSZack Rusin 	loc->sub_resource = sub_resource + 1;
531*ebc9ac7cSZack Rusin 	mip = sub_resource % cache->num_mip_levels;
532*ebc9ac7cSZack Rusin 	size = &cache->mip[mip].size;
533*ebc9ac7cSZack Rusin 	loc->x = size->width;
534*ebc9ac7cSZack Rusin 	loc->y = size->height;
535*ebc9ac7cSZack Rusin 	loc->z = size->depth;
536*ebc9ac7cSZack Rusin }
537*ebc9ac7cSZack Rusin 
538*ebc9ac7cSZack Rusin 
539*ebc9ac7cSZack Rusin #endif /* VMW_SURFACE_CACHE_H */
540