Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/vmwgfx: Add surface dirty-tracking callbacks

Add the callbacks necessary to implement emulated coherent memory for
surfaces. Add a flag to the gb_surface_create ioctl to indicate that
surface memory should be coherent.
Also bump the drm minor version to signal the availability of coherent
surfaces.

Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Rik van Riel <riel@surriel.com>
Cc: Minchan Kim <minchan@kernel.org>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Huang Ying <ying.huang@intel.com>
Cc: Jérôme Glisse <jglisse@redhat.com>
Cc: Kirill A. Shutemov <kirill@shutemov.name>
Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
Reviewed-by: Deepak Rawat <drawat@vmware.com>

+629 -7
+232 -1
drivers/gpu/drm/vmwgfx/device_include/svga3d_surfacedefs.h
··· 1280 1280 return offset; 1281 1281 } 1282 1282 1283 - 1284 1283 static inline u32 1285 1284 svga3dsurface_get_image_offset(SVGA3dSurfaceFormat format, 1286 1285 surf_size_struct baseLevelSize, ··· 1372 1373 return true; 1373 1374 } 1374 1375 return svga3dsurface_is_dx_screen_target_format(format); 1376 + } 1377 + 1378 + /** 1379 + * struct svga3dsurface_mip - Mimpmap level information 1380 + * @bytes: Bytes required in the backing store of this mipmap level. 1381 + * @img_stride: Byte stride per image. 1382 + * @row_stride: Byte stride per block row. 1383 + * @size: The size of the mipmap. 1384 + */ 1385 + struct svga3dsurface_mip { 1386 + size_t bytes; 1387 + size_t img_stride; 1388 + size_t row_stride; 1389 + struct drm_vmw_size size; 1390 + 1391 + }; 1392 + 1393 + /** 1394 + * struct svga3dsurface_cache - Cached surface information 1395 + * @desc: Pointer to the surface descriptor 1396 + * @mip: Array of mipmap level information. Valid size is @num_mip_levels. 1397 + * @mip_chain_bytes: Bytes required in the backing store for the whole chain 1398 + * of mip levels. 1399 + * @sheet_bytes: Bytes required in the backing store for a sheet 1400 + * representing a single sample. 1401 + * @num_mip_levels: Valid size of the @mip array. Number of mipmap levels in 1402 + * a chain. 1403 + * @num_layers: Number of slices in an array texture or number of faces in 1404 + * a cubemap texture. 1405 + */ 1406 + struct svga3dsurface_cache { 1407 + const struct svga3d_surface_desc *desc; 1408 + struct svga3dsurface_mip mip[DRM_VMW_MAX_MIP_LEVELS]; 1409 + size_t mip_chain_bytes; 1410 + size_t sheet_bytes; 1411 + u32 num_mip_levels; 1412 + u32 num_layers; 1413 + }; 1414 + 1415 + /** 1416 + * struct svga3dsurface_loc - Surface location 1417 + * @sub_resource: Surface subresource. Defined as layer * num_mip_levels + 1418 + * mip_level. 1419 + * @x: X coordinate. 1420 + * @y: Y coordinate. 1421 + * @z: Z coordinate. 1422 + */ 1423 + struct svga3dsurface_loc { 1424 + u32 sub_resource; 1425 + u32 x, y, z; 1426 + }; 1427 + 1428 + /** 1429 + * svga3dsurface_subres - Compute the subresource from layer and mipmap. 1430 + * @cache: Surface layout data. 1431 + * @mip_level: The mipmap level. 1432 + * @layer: The surface layer (face or array slice). 1433 + * 1434 + * Return: The subresource. 1435 + */ 1436 + static inline u32 svga3dsurface_subres(const struct svga3dsurface_cache *cache, 1437 + u32 mip_level, u32 layer) 1438 + { 1439 + return cache->num_mip_levels * layer + mip_level; 1440 + } 1441 + 1442 + /** 1443 + * svga3dsurface_setup_cache - Build a surface cache entry 1444 + * @size: The surface base level dimensions. 1445 + * @format: The surface format. 1446 + * @num_mip_levels: Number of mipmap levels. 1447 + * @num_layers: Number of layers. 1448 + * @cache: Pointer to a struct svga3dsurface_cach object to be filled in. 1449 + * 1450 + * Return: Zero on success, -EINVAL on invalid surface layout. 1451 + */ 1452 + static inline int svga3dsurface_setup_cache(const struct drm_vmw_size *size, 1453 + SVGA3dSurfaceFormat format, 1454 + u32 num_mip_levels, 1455 + u32 num_layers, 1456 + u32 num_samples, 1457 + struct svga3dsurface_cache *cache) 1458 + { 1459 + const struct svga3d_surface_desc *desc; 1460 + u32 i; 1461 + 1462 + memset(cache, 0, sizeof(*cache)); 1463 + cache->desc = desc = svga3dsurface_get_desc(format); 1464 + cache->num_mip_levels = num_mip_levels; 1465 + cache->num_layers = num_layers; 1466 + for (i = 0; i < cache->num_mip_levels; i++) { 1467 + struct svga3dsurface_mip *mip = &cache->mip[i]; 1468 + 1469 + mip->size = svga3dsurface_get_mip_size(*size, i); 1470 + mip->bytes = svga3dsurface_get_image_buffer_size 1471 + (desc, &mip->size, 0); 1472 + mip->row_stride = 1473 + __KERNEL_DIV_ROUND_UP(mip->size.width, 1474 + desc->block_size.width) * 1475 + desc->bytes_per_block * num_samples; 1476 + if (!mip->row_stride) 1477 + goto invalid_dim; 1478 + 1479 + mip->img_stride = 1480 + __KERNEL_DIV_ROUND_UP(mip->size.height, 1481 + desc->block_size.height) * 1482 + mip->row_stride; 1483 + if (!mip->img_stride) 1484 + goto invalid_dim; 1485 + 1486 + cache->mip_chain_bytes += mip->bytes; 1487 + } 1488 + cache->sheet_bytes = cache->mip_chain_bytes * num_layers; 1489 + if (!cache->sheet_bytes) 1490 + goto invalid_dim; 1491 + 1492 + return 0; 1493 + 1494 + invalid_dim: 1495 + VMW_DEBUG_USER("Invalid surface layout for dirty tracking.\n"); 1496 + return -EINVAL; 1497 + } 1498 + 1499 + /** 1500 + * svga3dsurface_get_loc - Get a surface location from an offset into the 1501 + * backing store 1502 + * @cache: Surface layout data. 1503 + * @loc: Pointer to a struct svga3dsurface_loc to be filled in. 1504 + * @offset: Offset into the surface backing store. 1505 + */ 1506 + static inline void 1507 + svga3dsurface_get_loc(const struct svga3dsurface_cache *cache, 1508 + struct svga3dsurface_loc *loc, 1509 + size_t offset) 1510 + { 1511 + const struct svga3dsurface_mip *mip = &cache->mip[0]; 1512 + const struct svga3d_surface_desc *desc = cache->desc; 1513 + u32 layer; 1514 + int i; 1515 + 1516 + if (offset >= cache->sheet_bytes) 1517 + offset %= cache->sheet_bytes; 1518 + 1519 + layer = offset / cache->mip_chain_bytes; 1520 + offset -= layer * cache->mip_chain_bytes; 1521 + for (i = 0; i < cache->num_mip_levels; ++i, ++mip) { 1522 + if (mip->bytes > offset) 1523 + break; 1524 + offset -= mip->bytes; 1525 + } 1526 + 1527 + loc->sub_resource = svga3dsurface_subres(cache, i, layer); 1528 + loc->z = offset / mip->img_stride; 1529 + offset -= loc->z * mip->img_stride; 1530 + loc->z *= desc->block_size.depth; 1531 + loc->y = offset / mip->row_stride; 1532 + offset -= loc->y * mip->row_stride; 1533 + loc->y *= desc->block_size.height; 1534 + loc->x = offset / desc->bytes_per_block; 1535 + loc->x *= desc->block_size.width; 1536 + } 1537 + 1538 + /** 1539 + * svga3dsurface_inc_loc - Clamp increment a surface location with one block 1540 + * size 1541 + * in each dimension. 1542 + * @loc: Pointer to a struct svga3dsurface_loc to be incremented. 1543 + * 1544 + * When computing the size of a range as size = end - start, the range does not 1545 + * include the end element. However a location representing the last byte 1546 + * of a touched region in the backing store *is* included in the range. 1547 + * This function modifies such a location to match the end definition 1548 + * given as start + size which is the one used in a SVGA3dBox. 1549 + */ 1550 + static inline void 1551 + svga3dsurface_inc_loc(const struct svga3dsurface_cache *cache, 1552 + struct svga3dsurface_loc *loc) 1553 + { 1554 + const struct svga3d_surface_desc *desc = cache->desc; 1555 + u32 mip = loc->sub_resource % cache->num_mip_levels; 1556 + const struct drm_vmw_size *size = &cache->mip[mip].size; 1557 + 1558 + loc->sub_resource++; 1559 + loc->x += desc->block_size.width; 1560 + if (loc->x > size->width) 1561 + loc->x = size->width; 1562 + loc->y += desc->block_size.height; 1563 + if (loc->y > size->height) 1564 + loc->y = size->height; 1565 + loc->z += desc->block_size.depth; 1566 + if (loc->z > size->depth) 1567 + loc->z = size->depth; 1568 + } 1569 + 1570 + /** 1571 + * svga3dsurface_min_loc - The start location in a subresource 1572 + * @cache: Surface layout data. 1573 + * @sub_resource: The subresource. 1574 + * @loc: Pointer to a struct svga3dsurface_loc to be filled in. 1575 + */ 1576 + static inline void 1577 + svga3dsurface_min_loc(const struct svga3dsurface_cache *cache, 1578 + u32 sub_resource, 1579 + struct svga3dsurface_loc *loc) 1580 + { 1581 + loc->sub_resource = sub_resource; 1582 + loc->x = loc->y = loc->z = 0; 1583 + } 1584 + 1585 + /** 1586 + * svga3dsurface_min_loc - The end location in a subresource 1587 + * @cache: Surface layout data. 1588 + * @sub_resource: The subresource. 1589 + * @loc: Pointer to a struct svga3dsurface_loc to be filled in. 1590 + * 1591 + * Following the end definition given in svga3dsurface_inc_loc(), 1592 + * Compute the end location of a surface subresource. 1593 + */ 1594 + static inline void 1595 + svga3dsurface_max_loc(const struct svga3dsurface_cache *cache, 1596 + u32 sub_resource, 1597 + struct svga3dsurface_loc *loc) 1598 + { 1599 + const struct drm_vmw_size *size; 1600 + u32 mip; 1601 + 1602 + loc->sub_resource = sub_resource + 1; 1603 + mip = sub_resource % cache->num_mip_levels; 1604 + size = &cache->mip[mip].size; 1605 + loc->x = size->width; 1606 + loc->y = size->height; 1607 + loc->z = size->depth; 1375 1608 } 1376 1609 1377 1610 #endif /* _SVGA3D_SURFACEDEFS_H_ */
+2 -2
drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
··· 56 56 57 57 58 58 #define VMWGFX_DRIVER_NAME "vmwgfx" 59 - #define VMWGFX_DRIVER_DATE "20180704" 59 + #define VMWGFX_DRIVER_DATE "20190328" 60 60 #define VMWGFX_DRIVER_MAJOR 2 61 - #define VMWGFX_DRIVER_MINOR 15 61 + #define VMWGFX_DRIVER_MINOR 16 62 62 #define VMWGFX_DRIVER_PATCHLEVEL 0 63 63 #define VMWGFX_FIFO_STATIC_SIZE (1024*1024) 64 64 #define VMWGFX_MAX_RELOCATIONS 2048
+392 -3
drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
··· 68 68 uint32_t bo_offset; 69 69 }; 70 70 71 + /** 72 + * vmw_surface_dirty - Surface dirty-tracker 73 + * @cache: Cached layout information of the surface. 74 + * @size: Accounting size for the struct vmw_surface_dirty. 75 + * @num_subres: Number of subresources. 76 + * @boxes: Array of SVGA3dBoxes indicating dirty regions. One per subresource. 77 + */ 78 + struct vmw_surface_dirty { 79 + struct svga3dsurface_cache cache; 80 + size_t size; 81 + u32 num_subres; 82 + SVGA3dBox boxes[0]; 83 + }; 84 + 71 85 static void vmw_user_surface_free(struct vmw_resource *res); 72 86 static struct vmw_resource * 73 87 vmw_user_surface_base_to_res(struct ttm_base_object *base); ··· 109 95 struct drm_vmw_surface_arg *req, 110 96 struct drm_vmw_gb_surface_ref_ext_rep *rep, 111 97 struct drm_file *file_priv); 98 + 99 + static void vmw_surface_dirty_free(struct vmw_resource *res); 100 + static int vmw_surface_dirty_alloc(struct vmw_resource *res); 101 + static int vmw_surface_dirty_sync(struct vmw_resource *res); 102 + static void vmw_surface_dirty_range_add(struct vmw_resource *res, size_t start, 103 + size_t end); 104 + static int vmw_surface_clean(struct vmw_resource *res); 112 105 113 106 static const struct vmw_user_resource_conv user_surface_conv = { 114 107 .object_type = VMW_RES_SURFACE, ··· 154 133 .create = vmw_gb_surface_create, 155 134 .destroy = vmw_gb_surface_destroy, 156 135 .bind = vmw_gb_surface_bind, 157 - .unbind = vmw_gb_surface_unbind 136 + .unbind = vmw_gb_surface_unbind, 137 + .dirty_alloc = vmw_surface_dirty_alloc, 138 + .dirty_free = vmw_surface_dirty_free, 139 + .dirty_sync = vmw_surface_dirty_sync, 140 + .dirty_range_add = vmw_surface_dirty_range_add, 141 + .clean = vmw_surface_clean, 158 142 }; 159 143 160 144 /** ··· 667 641 struct vmw_private *dev_priv = srf->res.dev_priv; 668 642 uint32_t size = user_srf->size; 669 643 644 + WARN_ON_ONCE(res->dirty); 670 645 if (user_srf->master) 671 646 drm_master_put(&user_srf->master); 672 647 kfree(srf->offsets); ··· 1195 1168 cmd2->header.id = SVGA_3D_CMD_UPDATE_GB_SURFACE; 1196 1169 cmd2->header.size = sizeof(cmd2->body); 1197 1170 cmd2->body.sid = res->id; 1198 - res->backup_dirty = false; 1199 1171 } 1200 1172 vmw_fifo_commit(dev_priv, submit_size); 1173 + 1174 + if (res->backup->dirty && res->backup_dirty) { 1175 + /* We've just made a full upload. Cear dirty regions. */ 1176 + vmw_bo_dirty_clear_res(res); 1177 + } 1178 + 1179 + res->backup_dirty = false; 1201 1180 1202 1181 return 0; 1203 1182 } ··· 1669 1636 } 1670 1637 } 1671 1638 } else if (req->base.drm_surface_flags & 1672 - drm_vmw_surface_flag_create_buffer) 1639 + (drm_vmw_surface_flag_create_buffer | 1640 + drm_vmw_surface_flag_coherent)) 1673 1641 ret = vmw_user_bo_alloc(dev_priv, tfile, 1674 1642 res->backup_size, 1675 1643 req->base.drm_surface_flags & ··· 1682 1648 if (unlikely(ret != 0)) { 1683 1649 vmw_resource_unreference(&res); 1684 1650 goto out_unlock; 1651 + } 1652 + 1653 + if (req->base.drm_surface_flags & drm_vmw_surface_flag_coherent) { 1654 + struct vmw_buffer_object *backup = res->backup; 1655 + 1656 + ttm_bo_reserve(&backup->base, false, false, NULL); 1657 + if (!res->func->dirty_alloc) 1658 + ret = -EINVAL; 1659 + if (!ret) 1660 + ret = vmw_bo_dirty_add(backup); 1661 + if (!ret) { 1662 + res->coherent = true; 1663 + ret = res->func->dirty_alloc(res); 1664 + } 1665 + ttm_bo_unreserve(&backup->base); 1666 + if (ret) { 1667 + vmw_resource_unreference(&res); 1668 + goto out_unlock; 1669 + } 1670 + 1685 1671 } 1686 1672 1687 1673 tmp = vmw_resource_reference(res); ··· 1811 1757 ttm_base_object_unref(&base); 1812 1758 1813 1759 return ret; 1760 + } 1761 + 1762 + /** 1763 + * vmw_subres_dirty_add - Add a dirty region to a subresource 1764 + * @dirty: The surfaces's dirty tracker. 1765 + * @loc_start: The location corresponding to the start of the region. 1766 + * @loc_end: The location corresponding to the end of the region. 1767 + * 1768 + * As we are assuming that @loc_start and @loc_end represent a sequential 1769 + * range of backing store memory, if the region spans multiple lines then 1770 + * regardless of the x coordinate, the full lines are dirtied. 1771 + * Correspondingly if the region spans multiple z slices, then full rather 1772 + * than partial z slices are dirtied. 1773 + */ 1774 + static void vmw_subres_dirty_add(struct vmw_surface_dirty *dirty, 1775 + const struct svga3dsurface_loc *loc_start, 1776 + const struct svga3dsurface_loc *loc_end) 1777 + { 1778 + const struct svga3dsurface_cache *cache = &dirty->cache; 1779 + SVGA3dBox *box = &dirty->boxes[loc_start->sub_resource]; 1780 + u32 mip = loc_start->sub_resource % cache->num_mip_levels; 1781 + const struct drm_vmw_size *size = &cache->mip[mip].size; 1782 + u32 box_c2 = box->z + box->d; 1783 + 1784 + if (WARN_ON(loc_start->sub_resource >= dirty->num_subres)) 1785 + return; 1786 + 1787 + if (box->d == 0 || box->z > loc_start->z) 1788 + box->z = loc_start->z; 1789 + if (box_c2 < loc_end->z) 1790 + box->d = loc_end->z - box->z; 1791 + 1792 + if (loc_start->z + 1 == loc_end->z) { 1793 + box_c2 = box->y + box->h; 1794 + if (box->h == 0 || box->y > loc_start->y) 1795 + box->y = loc_start->y; 1796 + if (box_c2 < loc_end->y) 1797 + box->h = loc_end->y - box->y; 1798 + 1799 + if (loc_start->y + 1 == loc_end->y) { 1800 + box_c2 = box->x + box->w; 1801 + if (box->w == 0 || box->x > loc_start->x) 1802 + box->x = loc_start->x; 1803 + if (box_c2 < loc_end->x) 1804 + box->w = loc_end->x - box->x; 1805 + } else { 1806 + box->x = 0; 1807 + box->w = size->width; 1808 + } 1809 + } else { 1810 + box->y = 0; 1811 + box->h = size->height; 1812 + box->x = 0; 1813 + box->w = size->width; 1814 + } 1815 + } 1816 + 1817 + /** 1818 + * vmw_subres_dirty_full - Mark a full subresource as dirty 1819 + * @dirty: The surface's dirty tracker. 1820 + * @subres: The subresource 1821 + */ 1822 + static void vmw_subres_dirty_full(struct vmw_surface_dirty *dirty, u32 subres) 1823 + { 1824 + const struct svga3dsurface_cache *cache = &dirty->cache; 1825 + u32 mip = subres % cache->num_mip_levels; 1826 + const struct drm_vmw_size *size = &cache->mip[mip].size; 1827 + SVGA3dBox *box = &dirty->boxes[subres]; 1828 + 1829 + box->x = 0; 1830 + box->y = 0; 1831 + box->z = 0; 1832 + box->w = size->width; 1833 + box->h = size->height; 1834 + box->d = size->depth; 1835 + } 1836 + 1837 + /* 1838 + * vmw_surface_tex_dirty_add_range - The dirty_add_range callback for texture 1839 + * surfaces. 1840 + */ 1841 + static void vmw_surface_tex_dirty_range_add(struct vmw_resource *res, 1842 + size_t start, size_t end) 1843 + { 1844 + struct vmw_surface_dirty *dirty = 1845 + (struct vmw_surface_dirty *) res->dirty; 1846 + size_t backup_end = res->backup_offset + res->backup_size; 1847 + struct svga3dsurface_loc loc1, loc2; 1848 + const struct svga3dsurface_cache *cache; 1849 + 1850 + start = max_t(size_t, start, res->backup_offset) - res->backup_offset; 1851 + end = min(end, backup_end) - res->backup_offset; 1852 + cache = &dirty->cache; 1853 + svga3dsurface_get_loc(cache, &loc1, start); 1854 + svga3dsurface_get_loc(cache, &loc2, end - 1); 1855 + svga3dsurface_inc_loc(cache, &loc2); 1856 + 1857 + if (loc1.sub_resource + 1 == loc2.sub_resource) { 1858 + /* Dirty range covers a single sub-resource */ 1859 + vmw_subres_dirty_add(dirty, &loc1, &loc2); 1860 + } else { 1861 + /* Dirty range covers multiple sub-resources */ 1862 + struct svga3dsurface_loc loc_min, loc_max; 1863 + u32 sub_res; 1864 + 1865 + svga3dsurface_max_loc(cache, loc1.sub_resource, &loc_max); 1866 + vmw_subres_dirty_add(dirty, &loc1, &loc_max); 1867 + svga3dsurface_min_loc(cache, loc2.sub_resource - 1, &loc_min); 1868 + vmw_subres_dirty_add(dirty, &loc_min, &loc2); 1869 + for (sub_res = loc1.sub_resource + 1; 1870 + sub_res < loc2.sub_resource - 1; ++sub_res) 1871 + vmw_subres_dirty_full(dirty, sub_res); 1872 + } 1873 + } 1874 + 1875 + /* 1876 + * vmw_surface_tex_dirty_add_range - The dirty_add_range callback for buffer 1877 + * surfaces. 1878 + */ 1879 + static void vmw_surface_buf_dirty_range_add(struct vmw_resource *res, 1880 + size_t start, size_t end) 1881 + { 1882 + struct vmw_surface_dirty *dirty = 1883 + (struct vmw_surface_dirty *) res->dirty; 1884 + const struct svga3dsurface_cache *cache = &dirty->cache; 1885 + size_t backup_end = res->backup_offset + cache->mip_chain_bytes; 1886 + SVGA3dBox *box = &dirty->boxes[0]; 1887 + u32 box_c2; 1888 + 1889 + box->h = box->d = 1; 1890 + start = max_t(size_t, start, res->backup_offset) - res->backup_offset; 1891 + end = min(end, backup_end) - res->backup_offset; 1892 + box_c2 = box->x + box->w; 1893 + if (box->w == 0 || box->x > start) 1894 + box->x = start; 1895 + if (box_c2 < end) 1896 + box->w = end - box->x; 1897 + } 1898 + 1899 + /* 1900 + * vmw_surface_tex_dirty_add_range - The dirty_add_range callback for surfaces 1901 + */ 1902 + static void vmw_surface_dirty_range_add(struct vmw_resource *res, size_t start, 1903 + size_t end) 1904 + { 1905 + struct vmw_surface *srf = vmw_res_to_srf(res); 1906 + 1907 + if (WARN_ON(end <= res->backup_offset || 1908 + start >= res->backup_offset + res->backup_size)) 1909 + return; 1910 + 1911 + if (srf->format == SVGA3D_BUFFER) 1912 + vmw_surface_buf_dirty_range_add(res, start, end); 1913 + else 1914 + vmw_surface_tex_dirty_range_add(res, start, end); 1915 + } 1916 + 1917 + /* 1918 + * vmw_surface_dirty_sync - The surface's dirty_sync callback. 1919 + */ 1920 + static int vmw_surface_dirty_sync(struct vmw_resource *res) 1921 + { 1922 + struct vmw_private *dev_priv = res->dev_priv; 1923 + bool has_dx = 0; 1924 + u32 i, num_dirty; 1925 + struct vmw_surface_dirty *dirty = 1926 + (struct vmw_surface_dirty *) res->dirty; 1927 + size_t alloc_size; 1928 + const struct svga3dsurface_cache *cache = &dirty->cache; 1929 + struct { 1930 + SVGA3dCmdHeader header; 1931 + SVGA3dCmdDXUpdateSubResource body; 1932 + } *cmd1; 1933 + struct { 1934 + SVGA3dCmdHeader header; 1935 + SVGA3dCmdUpdateGBImage body; 1936 + } *cmd2; 1937 + void *cmd; 1938 + 1939 + num_dirty = 0; 1940 + for (i = 0; i < dirty->num_subres; ++i) { 1941 + const SVGA3dBox *box = &dirty->boxes[i]; 1942 + 1943 + if (box->d) 1944 + num_dirty++; 1945 + } 1946 + 1947 + if (!num_dirty) 1948 + goto out; 1949 + 1950 + alloc_size = num_dirty * ((has_dx) ? sizeof(*cmd1) : sizeof(*cmd2)); 1951 + cmd = VMW_FIFO_RESERVE(dev_priv, alloc_size); 1952 + if (!cmd) 1953 + return -ENOMEM; 1954 + 1955 + cmd1 = cmd; 1956 + cmd2 = cmd; 1957 + 1958 + for (i = 0; i < dirty->num_subres; ++i) { 1959 + const SVGA3dBox *box = &dirty->boxes[i]; 1960 + 1961 + if (!box->d) 1962 + continue; 1963 + 1964 + /* 1965 + * DX_UPDATE_SUBRESOURCE is aware of array surfaces. 1966 + * UPDATE_GB_IMAGE is not. 1967 + */ 1968 + if (has_dx) { 1969 + cmd1->header.id = SVGA_3D_CMD_DX_UPDATE_SUBRESOURCE; 1970 + cmd1->header.size = sizeof(cmd1->body); 1971 + cmd1->body.sid = res->id; 1972 + cmd1->body.subResource = i; 1973 + cmd1->body.box = *box; 1974 + cmd1++; 1975 + } else { 1976 + cmd2->header.id = SVGA_3D_CMD_UPDATE_GB_IMAGE; 1977 + cmd2->header.size = sizeof(cmd2->body); 1978 + cmd2->body.image.sid = res->id; 1979 + cmd2->body.image.face = i / cache->num_mip_levels; 1980 + cmd2->body.image.mipmap = i - 1981 + (cache->num_mip_levels * cmd2->body.image.face); 1982 + cmd2->body.box = *box; 1983 + cmd2++; 1984 + } 1985 + 1986 + } 1987 + vmw_fifo_commit(dev_priv, alloc_size); 1988 + out: 1989 + memset(&dirty->boxes[0], 0, sizeof(dirty->boxes[0]) * 1990 + dirty->num_subres); 1991 + 1992 + return 0; 1993 + } 1994 + 1995 + /* 1996 + * vmw_surface_dirty_alloc - The surface's dirty_alloc callback. 1997 + */ 1998 + static int vmw_surface_dirty_alloc(struct vmw_resource *res) 1999 + { 2000 + struct vmw_surface *srf = vmw_res_to_srf(res); 2001 + struct vmw_surface_dirty *dirty; 2002 + u32 num_layers = 1; 2003 + u32 num_mip; 2004 + u32 num_subres; 2005 + u32 num_samples; 2006 + size_t dirty_size, acc_size; 2007 + static struct ttm_operation_ctx ctx = { 2008 + .interruptible = false, 2009 + .no_wait_gpu = false 2010 + }; 2011 + int ret; 2012 + 2013 + if (srf->array_size) 2014 + num_layers = srf->array_size; 2015 + else if (srf->flags & SVGA3D_SURFACE_CUBEMAP) 2016 + num_layers *= SVGA3D_MAX_SURFACE_FACES; 2017 + 2018 + num_mip = srf->mip_levels[0]; 2019 + if (!num_mip) 2020 + num_mip = 1; 2021 + 2022 + num_subres = num_layers * num_mip; 2023 + dirty_size = sizeof(*dirty) + num_subres * sizeof(dirty->boxes[0]); 2024 + acc_size = ttm_round_pot(dirty_size); 2025 + ret = ttm_mem_global_alloc(vmw_mem_glob(res->dev_priv), 2026 + acc_size, &ctx); 2027 + if (ret) { 2028 + VMW_DEBUG_USER("Out of graphics memory for surface " 2029 + "dirty tracker.\n"); 2030 + return ret; 2031 + } 2032 + 2033 + dirty = kvzalloc(dirty_size, GFP_KERNEL); 2034 + if (!dirty) { 2035 + ret = -ENOMEM; 2036 + goto out_no_dirty; 2037 + } 2038 + 2039 + num_samples = max_t(u32, 1, srf->multisample_count); 2040 + ret = svga3dsurface_setup_cache(&srf->base_size, srf->format, num_mip, 2041 + num_layers, num_samples, &dirty->cache); 2042 + if (ret) 2043 + goto out_no_cache; 2044 + 2045 + dirty->num_subres = num_subres; 2046 + dirty->size = acc_size; 2047 + res->dirty = (struct vmw_resource_dirty *) dirty; 2048 + 2049 + return 0; 2050 + 2051 + out_no_cache: 2052 + kvfree(dirty); 2053 + out_no_dirty: 2054 + ttm_mem_global_free(vmw_mem_glob(res->dev_priv), acc_size); 2055 + return ret; 2056 + } 2057 + 2058 + /* 2059 + * vmw_surface_dirty_free - The surface's dirty_free callback 2060 + */ 2061 + static void vmw_surface_dirty_free(struct vmw_resource *res) 2062 + { 2063 + struct vmw_surface_dirty *dirty = 2064 + (struct vmw_surface_dirty *) res->dirty; 2065 + size_t acc_size = dirty->size; 2066 + 2067 + kvfree(dirty); 2068 + ttm_mem_global_free(vmw_mem_glob(res->dev_priv), acc_size); 2069 + res->dirty = NULL; 2070 + } 2071 + 2072 + /* 2073 + * vmw_surface_clean - The surface's clean callback 2074 + */ 2075 + static int vmw_surface_clean(struct vmw_resource *res) 2076 + { 2077 + struct vmw_private *dev_priv = res->dev_priv; 2078 + size_t alloc_size; 2079 + struct { 2080 + SVGA3dCmdHeader header; 2081 + SVGA3dCmdReadbackGBSurface body; 2082 + } *cmd; 2083 + 2084 + alloc_size = sizeof(*cmd); 2085 + cmd = VMW_FIFO_RESERVE(dev_priv, alloc_size); 2086 + if (!cmd) 2087 + return -ENOMEM; 2088 + 2089 + cmd->header.id = SVGA_3D_CMD_READBACK_GB_SURFACE; 2090 + cmd->header.size = sizeof(cmd->body); 2091 + cmd->body.sid = res->id; 2092 + vmw_fifo_commit(dev_priv, alloc_size); 2093 + 2094 + return 0; 1814 2095 }
+3 -1
include/uapi/drm/vmwgfx_drm.h
··· 891 891 * surface. 892 892 * @drm_vmw_surface_flag_create_buffer: Create a backup buffer if none is 893 893 * given. 894 + * @drm_vmw_surface_flag_coherent: Back surface with coherent memory. 894 895 */ 895 896 enum drm_vmw_surface_flags { 896 897 drm_vmw_surface_flag_shareable = (1 << 0), 897 898 drm_vmw_surface_flag_scanout = (1 << 1), 898 - drm_vmw_surface_flag_create_buffer = (1 << 2) 899 + drm_vmw_surface_flag_create_buffer = (1 << 2), 900 + drm_vmw_surface_flag_coherent = (1 << 3), 899 901 }; 900 902 901 903 /**