vmw_surface_cache.h 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545
  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. #ifndef VMW_SURFACE_CACHE_H
  29. #define VMW_SURFACE_CACHE_H
  30. #include "device_include/svga3d_surfacedefs.h"
  31. #include <drm/vmwgfx_drm.h>
  32. #define SVGA3D_FLAGS_UPPER_32(svga3d_flags) ((svga3d_flags) >> 32)
  33. #define SVGA3D_FLAGS_LOWER_32(svga3d_flags) \
  34. ((svga3d_flags) & ((uint64_t)U32_MAX))
  35. static inline u32 clamped_umul32(u32 a, u32 b)
  36. {
  37. uint64_t tmp = (uint64_t) a*b;
  38. return (tmp > (uint64_t) ((u32) -1)) ? (u32) -1 : tmp;
  39. }
  40. /**
  41. * vmw_surface_get_desc - Look up the appropriate SVGA3dSurfaceDesc for the
  42. * given format.
  43. */
  44. static inline const SVGA3dSurfaceDesc *
  45. vmw_surface_get_desc(SVGA3dSurfaceFormat format)
  46. {
  47. if (format < ARRAY_SIZE(g_SVGA3dSurfaceDescs))
  48. return &g_SVGA3dSurfaceDescs[format];
  49. return &g_SVGA3dSurfaceDescs[SVGA3D_FORMAT_INVALID];
  50. }
  51. /**
  52. * vmw_surface_get_mip_size - Given a base level size and the mip level,
  53. * compute the size of the mip level.
  54. */
  55. static inline struct drm_vmw_size
  56. vmw_surface_get_mip_size(struct drm_vmw_size base_level, u32 mip_level)
  57. {
  58. struct drm_vmw_size size = {
  59. .width = max_t(u32, base_level.width >> mip_level, 1),
  60. .height = max_t(u32, base_level.height >> mip_level, 1),
  61. .depth = max_t(u32, base_level.depth >> mip_level, 1)
  62. };
  63. return size;
  64. }
  65. static inline void
  66. vmw_surface_get_size_in_blocks(const SVGA3dSurfaceDesc *desc,
  67. const struct drm_vmw_size *pixel_size,
  68. SVGA3dSize *block_size)
  69. {
  70. block_size->width = __KERNEL_DIV_ROUND_UP(pixel_size->width,
  71. desc->blockSize.width);
  72. block_size->height = __KERNEL_DIV_ROUND_UP(pixel_size->height,
  73. desc->blockSize.height);
  74. block_size->depth = __KERNEL_DIV_ROUND_UP(pixel_size->depth,
  75. desc->blockSize.depth);
  76. }
  77. static inline bool
  78. vmw_surface_is_planar_surface(const SVGA3dSurfaceDesc *desc)
  79. {
  80. return (desc->blockDesc & SVGA3DBLOCKDESC_PLANAR_YUV) != 0;
  81. }
  82. static inline u32
  83. vmw_surface_calculate_pitch(const SVGA3dSurfaceDesc *desc,
  84. const struct drm_vmw_size *size)
  85. {
  86. u32 pitch;
  87. SVGA3dSize blocks;
  88. vmw_surface_get_size_in_blocks(desc, size, &blocks);
  89. pitch = blocks.width * desc->pitchBytesPerBlock;
  90. return pitch;
  91. }
  92. /**
  93. * vmw_surface_get_image_buffer_size - Calculates image buffer size.
  94. *
  95. * Return the number of bytes of buffer space required to store one image of a
  96. * surface, optionally using the specified pitch.
  97. *
  98. * If pitch is zero, it is assumed that rows are tightly packed.
  99. *
  100. * This function is overflow-safe. If the result would have overflowed, instead
  101. * we return MAX_UINT32.
  102. */
  103. static inline u32
  104. vmw_surface_get_image_buffer_size(const SVGA3dSurfaceDesc *desc,
  105. const struct drm_vmw_size *size,
  106. u32 pitch)
  107. {
  108. SVGA3dSize image_blocks;
  109. u32 slice_size, total_size;
  110. vmw_surface_get_size_in_blocks(desc, size, &image_blocks);
  111. if (vmw_surface_is_planar_surface(desc)) {
  112. total_size = clamped_umul32(image_blocks.width,
  113. image_blocks.height);
  114. total_size = clamped_umul32(total_size, image_blocks.depth);
  115. total_size = clamped_umul32(total_size, desc->bytesPerBlock);
  116. return total_size;
  117. }
  118. if (pitch == 0)
  119. pitch = vmw_surface_calculate_pitch(desc, size);
  120. slice_size = clamped_umul32(image_blocks.height, pitch);
  121. total_size = clamped_umul32(slice_size, image_blocks.depth);
  122. return total_size;
  123. }
  124. /**
  125. * vmw_surface_get_serialized_size - Get the serialized size for the image.
  126. */
  127. static inline u32
  128. vmw_surface_get_serialized_size(SVGA3dSurfaceFormat format,
  129. struct drm_vmw_size base_level_size,
  130. u32 num_mip_levels,
  131. u32 num_layers)
  132. {
  133. const SVGA3dSurfaceDesc *desc = vmw_surface_get_desc(format);
  134. u32 total_size = 0;
  135. u32 mip;
  136. for (mip = 0; mip < num_mip_levels; mip++) {
  137. struct drm_vmw_size size =
  138. vmw_surface_get_mip_size(base_level_size, mip);
  139. total_size += vmw_surface_get_image_buffer_size(desc,
  140. &size, 0);
  141. }
  142. return total_size * num_layers;
  143. }
  144. /**
  145. * vmw_surface_get_serialized_size_extended - Returns the number of bytes
  146. * required for a surface with given parameters. Support for sample count.
  147. */
  148. static inline u32
  149. vmw_surface_get_serialized_size_extended(SVGA3dSurfaceFormat format,
  150. struct drm_vmw_size base_level_size,
  151. u32 num_mip_levels,
  152. u32 num_layers,
  153. u32 num_samples)
  154. {
  155. uint64_t total_size =
  156. vmw_surface_get_serialized_size(format,
  157. base_level_size,
  158. num_mip_levels,
  159. num_layers);
  160. total_size *= max_t(u32, 1, num_samples);
  161. return min_t(uint64_t, total_size, (uint64_t)U32_MAX);
  162. }
  163. /**
  164. * vmw_surface_get_pixel_offset - Compute the offset (in bytes) to a pixel
  165. * in an image (or volume).
  166. *
  167. * @width: The image width in pixels.
  168. * @height: The image height in pixels
  169. */
  170. static inline u32
  171. vmw_surface_get_pixel_offset(SVGA3dSurfaceFormat format,
  172. u32 width, u32 height,
  173. u32 x, u32 y, u32 z)
  174. {
  175. const SVGA3dSurfaceDesc *desc = vmw_surface_get_desc(format);
  176. const u32 bw = desc->blockSize.width, bh = desc->blockSize.height;
  177. const u32 bd = desc->blockSize.depth;
  178. const u32 rowstride = __KERNEL_DIV_ROUND_UP(width, bw) *
  179. desc->bytesPerBlock;
  180. const u32 imgstride = __KERNEL_DIV_ROUND_UP(height, bh) * rowstride;
  181. const u32 offset = (z / bd * imgstride +
  182. y / bh * rowstride +
  183. x / bw * desc->bytesPerBlock);
  184. return offset;
  185. }
  186. static inline u32
  187. vmw_surface_get_image_offset(SVGA3dSurfaceFormat format,
  188. struct drm_vmw_size baseLevelSize,
  189. u32 numMipLevels,
  190. u32 face,
  191. u32 mip)
  192. {
  193. u32 offset;
  194. u32 mipChainBytes;
  195. u32 mipChainBytesToLevel;
  196. u32 i;
  197. const SVGA3dSurfaceDesc *desc;
  198. struct drm_vmw_size mipSize;
  199. u32 bytes;
  200. desc = vmw_surface_get_desc(format);
  201. mipChainBytes = 0;
  202. mipChainBytesToLevel = 0;
  203. for (i = 0; i < numMipLevels; i++) {
  204. mipSize = vmw_surface_get_mip_size(baseLevelSize, i);
  205. bytes = vmw_surface_get_image_buffer_size(desc, &mipSize, 0);
  206. mipChainBytes += bytes;
  207. if (i < mip)
  208. mipChainBytesToLevel += bytes;
  209. }
  210. offset = mipChainBytes * face + mipChainBytesToLevel;
  211. return offset;
  212. }
  213. /**
  214. * vmw_surface_is_gb_screen_target_format - Is the specified format usable as
  215. * a ScreenTarget?
  216. * (with just the GBObjects cap-bit
  217. * set)
  218. * @format: format to queried
  219. *
  220. * RETURNS:
  221. * true if queried format is valid for screen targets
  222. */
  223. static inline bool
  224. vmw_surface_is_gb_screen_target_format(SVGA3dSurfaceFormat format)
  225. {
  226. return (format == SVGA3D_X8R8G8B8 ||
  227. format == SVGA3D_A8R8G8B8 ||
  228. format == SVGA3D_R5G6B5 ||
  229. format == SVGA3D_X1R5G5B5 ||
  230. format == SVGA3D_A1R5G5B5 ||
  231. format == SVGA3D_P8);
  232. }
  233. /**
  234. * vmw_surface_is_dx_screen_target_format - Is the specified format usable as
  235. * a ScreenTarget?
  236. * (with DX10 enabled)
  237. *
  238. * @format: format to queried
  239. *
  240. * Results:
  241. * true if queried format is valid for screen targets
  242. */
  243. static inline bool
  244. vmw_surface_is_dx_screen_target_format(SVGA3dSurfaceFormat format)
  245. {
  246. return (format == SVGA3D_R8G8B8A8_UNORM ||
  247. format == SVGA3D_B8G8R8A8_UNORM ||
  248. format == SVGA3D_B8G8R8X8_UNORM);
  249. }
  250. /**
  251. * vmw_surface_is_screen_target_format - Is the specified format usable as a
  252. * ScreenTarget?
  253. * (for some combination of caps)
  254. *
  255. * @format: format to queried
  256. *
  257. * Results:
  258. * true if queried format is valid for screen targets
  259. */
  260. static inline bool
  261. vmw_surface_is_screen_target_format(SVGA3dSurfaceFormat format)
  262. {
  263. if (vmw_surface_is_gb_screen_target_format(format)) {
  264. return true;
  265. }
  266. return vmw_surface_is_dx_screen_target_format(format);
  267. }
  268. /**
  269. * struct vmw_surface_mip - Mimpmap level information
  270. * @bytes: Bytes required in the backing store of this mipmap level.
  271. * @img_stride: Byte stride per image.
  272. * @row_stride: Byte stride per block row.
  273. * @size: The size of the mipmap.
  274. */
  275. struct vmw_surface_mip {
  276. size_t bytes;
  277. size_t img_stride;
  278. size_t row_stride;
  279. struct drm_vmw_size size;
  280. };
  281. /**
  282. * struct vmw_surface_cache - Cached surface information
  283. * @desc: Pointer to the surface descriptor
  284. * @mip: Array of mipmap level information. Valid size is @num_mip_levels.
  285. * @mip_chain_bytes: Bytes required in the backing store for the whole chain
  286. * of mip levels.
  287. * @sheet_bytes: Bytes required in the backing store for a sheet
  288. * representing a single sample.
  289. * @num_mip_levels: Valid size of the @mip array. Number of mipmap levels in
  290. * a chain.
  291. * @num_layers: Number of slices in an array texture or number of faces in
  292. * a cubemap texture.
  293. */
  294. struct vmw_surface_cache {
  295. const SVGA3dSurfaceDesc *desc;
  296. struct vmw_surface_mip mip[DRM_VMW_MAX_MIP_LEVELS];
  297. size_t mip_chain_bytes;
  298. size_t sheet_bytes;
  299. u32 num_mip_levels;
  300. u32 num_layers;
  301. };
  302. /**
  303. * struct vmw_surface_loc - Surface location
  304. * @sheet: The multisample sheet.
  305. * @sub_resource: Surface subresource. Defined as layer * num_mip_levels +
  306. * mip_level.
  307. * @x: X coordinate.
  308. * @y: Y coordinate.
  309. * @z: Z coordinate.
  310. */
  311. struct vmw_surface_loc {
  312. u32 sheet;
  313. u32 sub_resource;
  314. u32 x, y, z;
  315. };
  316. /**
  317. * vmw_surface_subres - Compute the subresource from layer and mipmap.
  318. * @cache: Surface layout data.
  319. * @mip_level: The mipmap level.
  320. * @layer: The surface layer (face or array slice).
  321. *
  322. * Return: The subresource.
  323. */
  324. static inline u32 vmw_surface_subres(const struct vmw_surface_cache *cache,
  325. u32 mip_level, u32 layer)
  326. {
  327. return cache->num_mip_levels * layer + mip_level;
  328. }
  329. /**
  330. * vmw_surface_setup_cache - Build a surface cache entry
  331. * @size: The surface base level dimensions.
  332. * @format: The surface format.
  333. * @num_mip_levels: Number of mipmap levels.
  334. * @num_layers: Number of layers.
  335. * @cache: Pointer to a struct vmw_surface_cach object to be filled in.
  336. *
  337. * Return: Zero on success, -EINVAL on invalid surface layout.
  338. */
  339. static inline int vmw_surface_setup_cache(const struct drm_vmw_size *size,
  340. SVGA3dSurfaceFormat format,
  341. u32 num_mip_levels,
  342. u32 num_layers,
  343. u32 num_samples,
  344. struct vmw_surface_cache *cache)
  345. {
  346. const SVGA3dSurfaceDesc *desc;
  347. u32 i;
  348. memset(cache, 0, sizeof(*cache));
  349. cache->desc = desc = vmw_surface_get_desc(format);
  350. cache->num_mip_levels = num_mip_levels;
  351. cache->num_layers = num_layers;
  352. for (i = 0; i < cache->num_mip_levels; i++) {
  353. struct vmw_surface_mip *mip = &cache->mip[i];
  354. mip->size = vmw_surface_get_mip_size(*size, i);
  355. mip->bytes = vmw_surface_get_image_buffer_size
  356. (desc, &mip->size, 0);
  357. mip->row_stride =
  358. __KERNEL_DIV_ROUND_UP(mip->size.width,
  359. desc->blockSize.width) *
  360. desc->bytesPerBlock * num_samples;
  361. if (!mip->row_stride)
  362. goto invalid_dim;
  363. mip->img_stride =
  364. __KERNEL_DIV_ROUND_UP(mip->size.height,
  365. desc->blockSize.height) *
  366. mip->row_stride;
  367. if (!mip->img_stride)
  368. goto invalid_dim;
  369. cache->mip_chain_bytes += mip->bytes;
  370. }
  371. cache->sheet_bytes = cache->mip_chain_bytes * num_layers;
  372. if (!cache->sheet_bytes)
  373. goto invalid_dim;
  374. return 0;
  375. invalid_dim:
  376. VMW_DEBUG_USER("Invalid surface layout for dirty tracking.\n");
  377. return -EINVAL;
  378. }
  379. /**
  380. * vmw_surface_get_loc - Get a surface location from an offset into the
  381. * backing store
  382. * @cache: Surface layout data.
  383. * @loc: Pointer to a struct vmw_surface_loc to be filled in.
  384. * @offset: Offset into the surface backing store.
  385. */
  386. static inline void
  387. vmw_surface_get_loc(const struct vmw_surface_cache *cache,
  388. struct vmw_surface_loc *loc,
  389. size_t offset)
  390. {
  391. const struct vmw_surface_mip *mip = &cache->mip[0];
  392. const SVGA3dSurfaceDesc *desc = cache->desc;
  393. u32 layer;
  394. int i;
  395. loc->sheet = offset / cache->sheet_bytes;
  396. offset -= loc->sheet * cache->sheet_bytes;
  397. layer = offset / cache->mip_chain_bytes;
  398. offset -= layer * cache->mip_chain_bytes;
  399. for (i = 0; i < cache->num_mip_levels; ++i, ++mip) {
  400. if (mip->bytes > offset)
  401. break;
  402. offset -= mip->bytes;
  403. }
  404. loc->sub_resource = vmw_surface_subres(cache, i, layer);
  405. loc->z = offset / mip->img_stride;
  406. offset -= loc->z * mip->img_stride;
  407. loc->z *= desc->blockSize.depth;
  408. loc->y = offset / mip->row_stride;
  409. offset -= loc->y * mip->row_stride;
  410. loc->y *= desc->blockSize.height;
  411. loc->x = offset / desc->bytesPerBlock;
  412. loc->x *= desc->blockSize.width;
  413. }
  414. /**
  415. * vmw_surface_inc_loc - Clamp increment a surface location with one block
  416. * size
  417. * in each dimension.
  418. * @loc: Pointer to a struct vmw_surface_loc to be incremented.
  419. *
  420. * When computing the size of a range as size = end - start, the range does not
  421. * include the end element. However a location representing the last byte
  422. * of a touched region in the backing store *is* included in the range.
  423. * This function modifies such a location to match the end definition
  424. * given as start + size which is the one used in a SVGA3dBox.
  425. */
  426. static inline void
  427. vmw_surface_inc_loc(const struct vmw_surface_cache *cache,
  428. struct vmw_surface_loc *loc)
  429. {
  430. const SVGA3dSurfaceDesc *desc = cache->desc;
  431. u32 mip = loc->sub_resource % cache->num_mip_levels;
  432. const struct drm_vmw_size *size = &cache->mip[mip].size;
  433. loc->sub_resource++;
  434. loc->x += desc->blockSize.width;
  435. if (loc->x > size->width)
  436. loc->x = size->width;
  437. loc->y += desc->blockSize.height;
  438. if (loc->y > size->height)
  439. loc->y = size->height;
  440. loc->z += desc->blockSize.depth;
  441. if (loc->z > size->depth)
  442. loc->z = size->depth;
  443. }
  444. /**
  445. * vmw_surface_min_loc - The start location in a subresource
  446. * @cache: Surface layout data.
  447. * @sub_resource: The subresource.
  448. * @loc: Pointer to a struct vmw_surface_loc to be filled in.
  449. */
  450. static inline void
  451. vmw_surface_min_loc(const struct vmw_surface_cache *cache,
  452. u32 sub_resource,
  453. struct vmw_surface_loc *loc)
  454. {
  455. loc->sheet = 0;
  456. loc->sub_resource = sub_resource;
  457. loc->x = loc->y = loc->z = 0;
  458. }
  459. /**
  460. * vmw_surface_min_loc - The end location in a subresource
  461. * @cache: Surface layout data.
  462. * @sub_resource: The subresource.
  463. * @loc: Pointer to a struct vmw_surface_loc to be filled in.
  464. *
  465. * Following the end definition given in vmw_surface_inc_loc(),
  466. * Compute the end location of a surface subresource.
  467. */
  468. static inline void
  469. vmw_surface_max_loc(const struct vmw_surface_cache *cache,
  470. u32 sub_resource,
  471. struct vmw_surface_loc *loc)
  472. {
  473. const struct drm_vmw_size *size;
  474. u32 mip;
  475. loc->sheet = 0;
  476. loc->sub_resource = sub_resource + 1;
  477. mip = sub_resource % cache->num_mip_levels;
  478. size = &cache->mip[mip].size;
  479. loc->x = size->width;
  480. loc->y = size->height;
  481. loc->z = size->depth;
  482. }
  483. #endif /* VMW_SURFACE_CACHE_H */