Linux Audio

Check our new training course

Linux debugging, profiling, tracing and performance analysis training

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