0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027 #ifndef VMW_SURFACE_CACHE_H
0028 #define VMW_SURFACE_CACHE_H
0029
0030 #include "device_include/svga3d_surfacedefs.h"
0031
0032 #include <drm/vmwgfx_drm.h>
0033
0034 static inline u32 clamped_umul32(u32 a, u32 b)
0035 {
0036 uint64_t tmp = (uint64_t) a*b;
0037 return (tmp > (uint64_t) ((u32) -1)) ? (u32) -1 : tmp;
0038 }
0039
0040
0041
0042
0043
0044 static inline const SVGA3dSurfaceDesc *
0045 vmw_surface_get_desc(SVGA3dSurfaceFormat format)
0046 {
0047 if (format < ARRAY_SIZE(g_SVGA3dSurfaceDescs))
0048 return &g_SVGA3dSurfaceDescs[format];
0049
0050 return &g_SVGA3dSurfaceDescs[SVGA3D_FORMAT_INVALID];
0051 }
0052
0053
0054
0055
0056
0057 static inline struct drm_vmw_size
0058 vmw_surface_get_mip_size(struct drm_vmw_size base_level, u32 mip_level)
0059 {
0060 struct drm_vmw_size size = {
0061 .width = max_t(u32, base_level.width >> mip_level, 1),
0062 .height = max_t(u32, base_level.height >> mip_level, 1),
0063 .depth = max_t(u32, base_level.depth >> mip_level, 1)
0064 };
0065
0066 return size;
0067 }
0068
0069 static inline void
0070 vmw_surface_get_size_in_blocks(const SVGA3dSurfaceDesc *desc,
0071 const struct drm_vmw_size *pixel_size,
0072 SVGA3dSize *block_size)
0073 {
0074 block_size->width = __KERNEL_DIV_ROUND_UP(pixel_size->width,
0075 desc->blockSize.width);
0076 block_size->height = __KERNEL_DIV_ROUND_UP(pixel_size->height,
0077 desc->blockSize.height);
0078 block_size->depth = __KERNEL_DIV_ROUND_UP(pixel_size->depth,
0079 desc->blockSize.depth);
0080 }
0081
0082 static inline bool
0083 vmw_surface_is_planar_surface(const SVGA3dSurfaceDesc *desc)
0084 {
0085 return (desc->blockDesc & SVGA3DBLOCKDESC_PLANAR_YUV) != 0;
0086 }
0087
0088 static inline u32
0089 vmw_surface_calculate_pitch(const SVGA3dSurfaceDesc *desc,
0090 const struct drm_vmw_size *size)
0091 {
0092 u32 pitch;
0093 SVGA3dSize blocks;
0094
0095 vmw_surface_get_size_in_blocks(desc, size, &blocks);
0096
0097 pitch = blocks.width * desc->pitchBytesPerBlock;
0098
0099 return pitch;
0100 }
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113 static inline u32
0114 vmw_surface_get_image_buffer_size(const SVGA3dSurfaceDesc *desc,
0115 const struct drm_vmw_size *size,
0116 u32 pitch)
0117 {
0118 SVGA3dSize image_blocks;
0119 u32 slice_size, total_size;
0120
0121 vmw_surface_get_size_in_blocks(desc, size, &image_blocks);
0122
0123 if (vmw_surface_is_planar_surface(desc)) {
0124 total_size = clamped_umul32(image_blocks.width,
0125 image_blocks.height);
0126 total_size = clamped_umul32(total_size, image_blocks.depth);
0127 total_size = clamped_umul32(total_size, desc->bytesPerBlock);
0128 return total_size;
0129 }
0130
0131 if (pitch == 0)
0132 pitch = vmw_surface_calculate_pitch(desc, size);
0133
0134 slice_size = clamped_umul32(image_blocks.height, pitch);
0135 total_size = clamped_umul32(slice_size, image_blocks.depth);
0136
0137 return total_size;
0138 }
0139
0140
0141
0142
0143 static inline u32
0144 vmw_surface_get_serialized_size(SVGA3dSurfaceFormat format,
0145 struct drm_vmw_size base_level_size,
0146 u32 num_mip_levels,
0147 u32 num_layers)
0148 {
0149 const SVGA3dSurfaceDesc *desc = vmw_surface_get_desc(format);
0150 u32 total_size = 0;
0151 u32 mip;
0152
0153 for (mip = 0; mip < num_mip_levels; mip++) {
0154 struct drm_vmw_size size =
0155 vmw_surface_get_mip_size(base_level_size, mip);
0156 total_size += vmw_surface_get_image_buffer_size(desc,
0157 &size, 0);
0158 }
0159
0160 return total_size * num_layers;
0161 }
0162
0163
0164
0165
0166
0167 static inline u32
0168 vmw_surface_get_serialized_size_extended(SVGA3dSurfaceFormat format,
0169 struct drm_vmw_size base_level_size,
0170 u32 num_mip_levels,
0171 u32 num_layers,
0172 u32 num_samples)
0173 {
0174 uint64_t total_size =
0175 vmw_surface_get_serialized_size(format,
0176 base_level_size,
0177 num_mip_levels,
0178 num_layers);
0179 total_size *= max_t(u32, 1, num_samples);
0180
0181 return min_t(uint64_t, total_size, (uint64_t)U32_MAX);
0182 }
0183
0184
0185
0186
0187
0188
0189
0190
0191 static inline u32
0192 vmw_surface_get_pixel_offset(SVGA3dSurfaceFormat format,
0193 u32 width, u32 height,
0194 u32 x, u32 y, u32 z)
0195 {
0196 const SVGA3dSurfaceDesc *desc = vmw_surface_get_desc(format);
0197 const u32 bw = desc->blockSize.width, bh = desc->blockSize.height;
0198 const u32 bd = desc->blockSize.depth;
0199 const u32 rowstride = __KERNEL_DIV_ROUND_UP(width, bw) *
0200 desc->bytesPerBlock;
0201 const u32 imgstride = __KERNEL_DIV_ROUND_UP(height, bh) * rowstride;
0202 const u32 offset = (z / bd * imgstride +
0203 y / bh * rowstride +
0204 x / bw * desc->bytesPerBlock);
0205 return offset;
0206 }
0207
0208 static inline u32
0209 vmw_surface_get_image_offset(SVGA3dSurfaceFormat format,
0210 struct drm_vmw_size baseLevelSize,
0211 u32 numMipLevels,
0212 u32 face,
0213 u32 mip)
0214
0215 {
0216 u32 offset;
0217 u32 mipChainBytes;
0218 u32 mipChainBytesToLevel;
0219 u32 i;
0220 const SVGA3dSurfaceDesc *desc;
0221 struct drm_vmw_size mipSize;
0222 u32 bytes;
0223
0224 desc = vmw_surface_get_desc(format);
0225
0226 mipChainBytes = 0;
0227 mipChainBytesToLevel = 0;
0228 for (i = 0; i < numMipLevels; i++) {
0229 mipSize = vmw_surface_get_mip_size(baseLevelSize, i);
0230 bytes = vmw_surface_get_image_buffer_size(desc, &mipSize, 0);
0231 mipChainBytes += bytes;
0232 if (i < mip)
0233 mipChainBytesToLevel += bytes;
0234 }
0235
0236 offset = mipChainBytes * face + mipChainBytesToLevel;
0237
0238 return offset;
0239 }
0240
0241
0242
0243
0244
0245
0246
0247
0248
0249
0250
0251
0252 static inline bool
0253 vmw_surface_is_gb_screen_target_format(SVGA3dSurfaceFormat format)
0254 {
0255 return (format == SVGA3D_X8R8G8B8 ||
0256 format == SVGA3D_A8R8G8B8 ||
0257 format == SVGA3D_R5G6B5 ||
0258 format == SVGA3D_X1R5G5B5 ||
0259 format == SVGA3D_A1R5G5B5 ||
0260 format == SVGA3D_P8);
0261 }
0262
0263
0264
0265
0266
0267
0268
0269
0270
0271
0272
0273
0274 static inline bool
0275 vmw_surface_is_dx_screen_target_format(SVGA3dSurfaceFormat format)
0276 {
0277 return (format == SVGA3D_R8G8B8A8_UNORM ||
0278 format == SVGA3D_B8G8R8A8_UNORM ||
0279 format == SVGA3D_B8G8R8X8_UNORM);
0280 }
0281
0282
0283
0284
0285
0286
0287
0288
0289
0290
0291
0292
0293 static inline bool
0294 vmw_surface_is_screen_target_format(SVGA3dSurfaceFormat format)
0295 {
0296 if (vmw_surface_is_gb_screen_target_format(format)) {
0297 return true;
0298 }
0299 return vmw_surface_is_dx_screen_target_format(format);
0300 }
0301
0302
0303
0304
0305
0306
0307
0308
0309 struct vmw_surface_mip {
0310 size_t bytes;
0311 size_t img_stride;
0312 size_t row_stride;
0313 struct drm_vmw_size size;
0314
0315 };
0316
0317
0318
0319
0320
0321
0322
0323
0324
0325
0326
0327
0328
0329
0330 struct vmw_surface_cache {
0331 const SVGA3dSurfaceDesc *desc;
0332 struct vmw_surface_mip mip[DRM_VMW_MAX_MIP_LEVELS];
0333 size_t mip_chain_bytes;
0334 size_t sheet_bytes;
0335 u32 num_mip_levels;
0336 u32 num_layers;
0337 };
0338
0339
0340
0341
0342
0343
0344
0345
0346
0347
0348 struct vmw_surface_loc {
0349 u32 sheet;
0350 u32 sub_resource;
0351 u32 x, y, z;
0352 };
0353
0354
0355
0356
0357
0358
0359
0360
0361
0362 static inline u32 vmw_surface_subres(const struct vmw_surface_cache *cache,
0363 u32 mip_level, u32 layer)
0364 {
0365 return cache->num_mip_levels * layer + mip_level;
0366 }
0367
0368
0369
0370
0371
0372
0373
0374
0375
0376
0377
0378 static inline int vmw_surface_setup_cache(const struct drm_vmw_size *size,
0379 SVGA3dSurfaceFormat format,
0380 u32 num_mip_levels,
0381 u32 num_layers,
0382 u32 num_samples,
0383 struct vmw_surface_cache *cache)
0384 {
0385 const SVGA3dSurfaceDesc *desc;
0386 u32 i;
0387
0388 memset(cache, 0, sizeof(*cache));
0389 cache->desc = desc = vmw_surface_get_desc(format);
0390 cache->num_mip_levels = num_mip_levels;
0391 cache->num_layers = num_layers;
0392 for (i = 0; i < cache->num_mip_levels; i++) {
0393 struct vmw_surface_mip *mip = &cache->mip[i];
0394
0395 mip->size = vmw_surface_get_mip_size(*size, i);
0396 mip->bytes = vmw_surface_get_image_buffer_size
0397 (desc, &mip->size, 0);
0398 mip->row_stride =
0399 __KERNEL_DIV_ROUND_UP(mip->size.width,
0400 desc->blockSize.width) *
0401 desc->bytesPerBlock * num_samples;
0402 if (!mip->row_stride)
0403 goto invalid_dim;
0404
0405 mip->img_stride =
0406 __KERNEL_DIV_ROUND_UP(mip->size.height,
0407 desc->blockSize.height) *
0408 mip->row_stride;
0409 if (!mip->img_stride)
0410 goto invalid_dim;
0411
0412 cache->mip_chain_bytes += mip->bytes;
0413 }
0414 cache->sheet_bytes = cache->mip_chain_bytes * num_layers;
0415 if (!cache->sheet_bytes)
0416 goto invalid_dim;
0417
0418 return 0;
0419
0420 invalid_dim:
0421 VMW_DEBUG_USER("Invalid surface layout for dirty tracking.\n");
0422 return -EINVAL;
0423 }
0424
0425
0426
0427
0428
0429
0430
0431
0432 static inline void
0433 vmw_surface_get_loc(const struct vmw_surface_cache *cache,
0434 struct vmw_surface_loc *loc,
0435 size_t offset)
0436 {
0437 const struct vmw_surface_mip *mip = &cache->mip[0];
0438 const SVGA3dSurfaceDesc *desc = cache->desc;
0439 u32 layer;
0440 int i;
0441
0442 loc->sheet = offset / cache->sheet_bytes;
0443 offset -= loc->sheet * cache->sheet_bytes;
0444
0445 layer = offset / cache->mip_chain_bytes;
0446 offset -= layer * cache->mip_chain_bytes;
0447 for (i = 0; i < cache->num_mip_levels; ++i, ++mip) {
0448 if (mip->bytes > offset)
0449 break;
0450 offset -= mip->bytes;
0451 }
0452
0453 loc->sub_resource = vmw_surface_subres(cache, i, layer);
0454 loc->z = offset / mip->img_stride;
0455 offset -= loc->z * mip->img_stride;
0456 loc->z *= desc->blockSize.depth;
0457 loc->y = offset / mip->row_stride;
0458 offset -= loc->y * mip->row_stride;
0459 loc->y *= desc->blockSize.height;
0460 loc->x = offset / desc->bytesPerBlock;
0461 loc->x *= desc->blockSize.width;
0462 }
0463
0464
0465
0466
0467
0468
0469
0470
0471
0472
0473
0474
0475
0476 static inline void
0477 vmw_surface_inc_loc(const struct vmw_surface_cache *cache,
0478 struct vmw_surface_loc *loc)
0479 {
0480 const SVGA3dSurfaceDesc *desc = cache->desc;
0481 u32 mip = loc->sub_resource % cache->num_mip_levels;
0482 const struct drm_vmw_size *size = &cache->mip[mip].size;
0483
0484 loc->sub_resource++;
0485 loc->x += desc->blockSize.width;
0486 if (loc->x > size->width)
0487 loc->x = size->width;
0488 loc->y += desc->blockSize.height;
0489 if (loc->y > size->height)
0490 loc->y = size->height;
0491 loc->z += desc->blockSize.depth;
0492 if (loc->z > size->depth)
0493 loc->z = size->depth;
0494 }
0495
0496
0497
0498
0499
0500
0501
0502 static inline void
0503 vmw_surface_min_loc(const struct vmw_surface_cache *cache,
0504 u32 sub_resource,
0505 struct vmw_surface_loc *loc)
0506 {
0507 loc->sheet = 0;
0508 loc->sub_resource = sub_resource;
0509 loc->x = loc->y = loc->z = 0;
0510 }
0511
0512
0513
0514
0515
0516
0517
0518
0519
0520
0521 static inline void
0522 vmw_surface_max_loc(const struct vmw_surface_cache *cache,
0523 u32 sub_resource,
0524 struct vmw_surface_loc *loc)
0525 {
0526 const struct drm_vmw_size *size;
0527 u32 mip;
0528
0529 loc->sheet = 0;
0530 loc->sub_resource = sub_resource + 1;
0531 mip = sub_resource % cache->num_mip_levels;
0532 size = &cache->mip[mip].size;
0533 loc->x = size->width;
0534 loc->y = size->height;
0535 loc->z = size->depth;
0536 }
0537
0538
0539 #endif