diff options
author | Deepak Rawat <drawat@vmware.com> | 2018-06-20 17:48:35 -0400 |
---|---|---|
committer | Thomas Hellstrom <thellstrom@vmware.com> | 2018-07-06 14:16:09 -0400 |
commit | 14b1c33e84295693c3b1a1d7c6ac82b3f384cd17 (patch) | |
tree | ed9718f7f57d58e20f92aa194181ab4a982b4abc /drivers/gpu | |
parent | 397a11175f830e1ceb82b608a1c7adbacfbe39b0 (diff) |
drm/vmwgfx: Add new ioctl for GB surface create and reference
New ioctls DRM_VMW_GB_SURFACE_CREATE_EXT and DRM_VMW_GB_SURFACE_REF_EXT
are added which support 64-bit wide svga device surface flags, quality
level and multisample pattern.
Signed-off-by: Deepak Rawat <drawat@vmware.com>
Reviewed-by: Sinclair Yeh <syeh@vmware.com>
Reviewed-by: Brian Paul <brianp@vmware.com>
Reviewed-by: Thomas Hellstrom <thellstrom@vmware.com>
Reviewed-by: Charmaine Lee <charmainel@vmware.com>
Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 12 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 20 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_surface.c | 468 |
5 files changed, 335 insertions, 175 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 6cf81e19182f..59229111f303 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | |||
@@ -137,6 +137,12 @@ | |||
137 | #define DRM_IOCTL_VMW_CREATE_EXTENDED_CONTEXT \ | 137 | #define DRM_IOCTL_VMW_CREATE_EXTENDED_CONTEXT \ |
138 | DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_CREATE_EXTENDED_CONTEXT, \ | 138 | DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_CREATE_EXTENDED_CONTEXT, \ |
139 | struct drm_vmw_context_arg) | 139 | struct drm_vmw_context_arg) |
140 | #define DRM_IOCTL_VMW_GB_SURFACE_CREATE_EXT \ | ||
141 | DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_GB_SURFACE_CREATE_EXT, \ | ||
142 | union drm_vmw_gb_surface_create_ext_arg) | ||
143 | #define DRM_IOCTL_VMW_GB_SURFACE_REF_EXT \ | ||
144 | DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_GB_SURFACE_REF_EXT, \ | ||
145 | union drm_vmw_gb_surface_reference_ext_arg) | ||
140 | 146 | ||
141 | /** | 147 | /** |
142 | * The core DRM version of this macro doesn't account for | 148 | * The core DRM version of this macro doesn't account for |
@@ -224,6 +230,12 @@ static const struct drm_ioctl_desc vmw_ioctls[] = { | |||
224 | VMW_IOCTL_DEF(VMW_CREATE_EXTENDED_CONTEXT, | 230 | VMW_IOCTL_DEF(VMW_CREATE_EXTENDED_CONTEXT, |
225 | vmw_extended_context_define_ioctl, | 231 | vmw_extended_context_define_ioctl, |
226 | DRM_AUTH | DRM_RENDER_ALLOW), | 232 | DRM_AUTH | DRM_RENDER_ALLOW), |
233 | VMW_IOCTL_DEF(VMW_GB_SURFACE_CREATE_EXT, | ||
234 | vmw_gb_surface_define_ext_ioctl, | ||
235 | DRM_AUTH | DRM_RENDER_ALLOW), | ||
236 | VMW_IOCTL_DEF(VMW_GB_SURFACE_REF_EXT, | ||
237 | vmw_gb_surface_reference_ext_ioctl, | ||
238 | DRM_AUTH | DRM_RENDER_ALLOW), | ||
227 | }; | 239 | }; |
228 | 240 | ||
229 | static const struct pci_device_id vmw_pci_id_list[] = { | 241 | static const struct pci_device_id vmw_pci_id_list[] = { |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 7e5c93083036..59af14714797 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | |||
@@ -1087,7 +1087,15 @@ int vmw_surface_gb_priv_define(struct drm_device *dev, | |||
1087 | uint32_t multisample_count, | 1087 | uint32_t multisample_count, |
1088 | uint32_t array_size, | 1088 | uint32_t array_size, |
1089 | struct drm_vmw_size size, | 1089 | struct drm_vmw_size size, |
1090 | SVGA3dMSPattern multisample_pattern, | ||
1091 | SVGA3dMSQualityLevel quality_level, | ||
1090 | struct vmw_surface **srf_out); | 1092 | struct vmw_surface **srf_out); |
1093 | extern int vmw_gb_surface_define_ext_ioctl(struct drm_device *dev, | ||
1094 | void *data, | ||
1095 | struct drm_file *file_priv); | ||
1096 | extern int vmw_gb_surface_reference_ext_ioctl(struct drm_device *dev, | ||
1097 | void *data, | ||
1098 | struct drm_file *file_priv); | ||
1091 | 1099 | ||
1092 | /* | 1100 | /* |
1093 | * Shader management - vmwgfx_shader.c | 1101 | * Shader management - vmwgfx_shader.c |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 0fb363458ab5..3201b0a51d10 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | |||
@@ -1238,15 +1238,17 @@ static int vmw_create_bo_proxy(struct drm_device *dev, | |||
1238 | content_base_size.depth = 1; | 1238 | content_base_size.depth = 1; |
1239 | 1239 | ||
1240 | ret = vmw_surface_gb_priv_define(dev, | 1240 | ret = vmw_surface_gb_priv_define(dev, |
1241 | 0, /* kernel visible only */ | 1241 | 0, /* kernel visible only */ |
1242 | 0, /* flags */ | 1242 | 0, /* flags */ |
1243 | format, | 1243 | format, |
1244 | true, /* can be a scanout buffer */ | 1244 | true, /* can be a scanout buffer */ |
1245 | 1, /* num of mip levels */ | 1245 | 1, /* num of mip levels */ |
1246 | 0, | 1246 | 0, |
1247 | 0, | 1247 | 0, |
1248 | content_base_size, | 1248 | content_base_size, |
1249 | srf_out); | 1249 | SVGA3D_MS_PATTERN_NONE, |
1250 | SVGA3D_MS_QUALITY_NONE, | ||
1251 | srf_out); | ||
1250 | if (ret) { | 1252 | if (ret) { |
1251 | DRM_ERROR("Failed to allocate proxy content buffer\n"); | 1253 | DRM_ERROR("Failed to allocate proxy content buffer\n"); |
1252 | return ret; | 1254 | return ret; |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index 6630abf3a95c..f9872c9e60c4 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | |||
@@ -1188,6 +1188,8 @@ vmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane, | |||
1188 | content_srf.multisample_count, | 1188 | content_srf.multisample_count, |
1189 | 0, | 1189 | 0, |
1190 | display_base_size, | 1190 | display_base_size, |
1191 | content_srf.multisample_pattern, | ||
1192 | content_srf.quality_level, | ||
1191 | &vps->surf); | 1193 | &vps->surf); |
1192 | if (ret != 0) { | 1194 | if (ret != 0) { |
1193 | DRM_ERROR("Couldn't allocate STDU surface.\n"); | 1195 | DRM_ERROR("Couldn't allocate STDU surface.\n"); |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c index a5f93f62c7fa..1d4c010a0e48 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c | |||
@@ -33,6 +33,10 @@ | |||
33 | #include "vmwgfx_binding.h" | 33 | #include "vmwgfx_binding.h" |
34 | #include "device_include/svga3d_surfacedefs.h" | 34 | #include "device_include/svga3d_surfacedefs.h" |
35 | 35 | ||
36 | #define SVGA3D_FLAGS_64(upper32, lower32) (((uint64_t)upper32 << 32) | lower32) | ||
37 | #define SVGA3D_FLAGS_UPPER_32(svga3d_flags) (svga3d_flags >> 32) | ||
38 | #define SVGA3D_FLAGS_LOWER_32(svga3d_flags) \ | ||
39 | (svga3d_flags & ((uint64_t)U32_MAX)) | ||
36 | 40 | ||
37 | /** | 41 | /** |
38 | * struct vmw_user_surface - User-space visible surface resource | 42 | * struct vmw_user_surface - User-space visible surface resource |
@@ -81,7 +85,16 @@ static int vmw_gb_surface_unbind(struct vmw_resource *res, | |||
81 | bool readback, | 85 | bool readback, |
82 | struct ttm_validate_buffer *val_buf); | 86 | struct ttm_validate_buffer *val_buf); |
83 | static int vmw_gb_surface_destroy(struct vmw_resource *res); | 87 | static int vmw_gb_surface_destroy(struct vmw_resource *res); |
84 | 88 | static int | |
89 | vmw_gb_surface_define_internal(struct drm_device *dev, | ||
90 | struct drm_vmw_gb_surface_create_ext_req *req, | ||
91 | struct drm_vmw_gb_surface_create_rep *rep, | ||
92 | struct drm_file *file_priv); | ||
93 | static int | ||
94 | vmw_gb_surface_reference_internal(struct drm_device *dev, | ||
95 | struct drm_vmw_surface_arg *req, | ||
96 | struct drm_vmw_gb_surface_ref_ext_rep *rep, | ||
97 | struct drm_file *file_priv); | ||
85 | 98 | ||
86 | static const struct vmw_user_resource_conv user_surface_conv = { | 99 | static const struct vmw_user_resource_conv user_surface_conv = { |
87 | .object_type = VMW_RES_SURFACE, | 100 | .object_type = VMW_RES_SURFACE, |
@@ -1289,193 +1302,55 @@ static int vmw_gb_surface_destroy(struct vmw_resource *res) | |||
1289 | 1302 | ||
1290 | /** | 1303 | /** |
1291 | * vmw_gb_surface_define_ioctl - Ioctl function implementing | 1304 | * vmw_gb_surface_define_ioctl - Ioctl function implementing |
1292 | * the user surface define functionality. | 1305 | * the user surface define functionality. |
1293 | * | 1306 | * |
1294 | * @dev: Pointer to a struct drm_device. | 1307 | * @dev: Pointer to a struct drm_device. |
1295 | * @data: Pointer to data copied from / to user-space. | 1308 | * @data: Pointer to data copied from / to user-space. |
1296 | * @file_priv: Pointer to a drm file private structure. | 1309 | * @file_priv: Pointer to a drm file private structure. |
1297 | */ | 1310 | */ |
1298 | int vmw_gb_surface_define_ioctl(struct drm_device *dev, void *data, | 1311 | int vmw_gb_surface_define_ioctl(struct drm_device *dev, void *data, |
1299 | struct drm_file *file_priv) | 1312 | struct drm_file *file_priv) |
1300 | { | 1313 | { |
1301 | struct vmw_private *dev_priv = vmw_priv(dev); | ||
1302 | struct vmw_user_surface *user_srf; | ||
1303 | struct vmw_surface *srf; | ||
1304 | struct vmw_resource *res; | ||
1305 | struct vmw_resource *tmp; | ||
1306 | union drm_vmw_gb_surface_create_arg *arg = | 1314 | union drm_vmw_gb_surface_create_arg *arg = |
1307 | (union drm_vmw_gb_surface_create_arg *)data; | 1315 | (union drm_vmw_gb_surface_create_arg *)data; |
1308 | struct drm_vmw_gb_surface_create_req *req = &arg->req; | ||
1309 | struct drm_vmw_gb_surface_create_rep *rep = &arg->rep; | 1316 | struct drm_vmw_gb_surface_create_rep *rep = &arg->rep; |
1310 | struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; | 1317 | struct drm_vmw_gb_surface_create_ext_req req_ext; |
1311 | int ret; | ||
1312 | uint32_t size; | ||
1313 | uint32_t backup_handle = 0; | ||
1314 | |||
1315 | if (req->multisample_count != 0) | ||
1316 | return -EINVAL; | ||
1317 | |||
1318 | if (req->mip_levels > DRM_VMW_MAX_MIP_LEVELS) | ||
1319 | return -EINVAL; | ||
1320 | |||
1321 | if (unlikely(vmw_user_surface_size == 0)) | ||
1322 | vmw_user_surface_size = ttm_round_pot(sizeof(*user_srf)) + | ||
1323 | 128; | ||
1324 | |||
1325 | size = vmw_user_surface_size + 128; | ||
1326 | |||
1327 | /* Define a surface based on the parameters. */ | ||
1328 | ret = vmw_surface_gb_priv_define(dev, | ||
1329 | size, | ||
1330 | (SVGA3dSurfaceAllFlags)req->svga3d_flags, | ||
1331 | req->format, | ||
1332 | req->drm_surface_flags & drm_vmw_surface_flag_scanout, | ||
1333 | req->mip_levels, | ||
1334 | req->multisample_count, | ||
1335 | req->array_size, | ||
1336 | req->base_size, | ||
1337 | &srf); | ||
1338 | if (unlikely(ret != 0)) | ||
1339 | return ret; | ||
1340 | |||
1341 | user_srf = container_of(srf, struct vmw_user_surface, srf); | ||
1342 | if (drm_is_primary_client(file_priv)) | ||
1343 | user_srf->master = drm_master_get(file_priv->master); | ||
1344 | |||
1345 | ret = ttm_read_lock(&dev_priv->reservation_sem, true); | ||
1346 | if (unlikely(ret != 0)) | ||
1347 | return ret; | ||
1348 | |||
1349 | res = &user_srf->srf.res; | ||
1350 | |||
1351 | |||
1352 | if (req->buffer_handle != SVGA3D_INVALID_ID) { | ||
1353 | ret = vmw_user_bo_lookup(tfile, req->buffer_handle, | ||
1354 | &res->backup, | ||
1355 | &user_srf->backup_base); | ||
1356 | if (ret == 0) { | ||
1357 | if (res->backup->base.num_pages * PAGE_SIZE < | ||
1358 | res->backup_size) { | ||
1359 | DRM_ERROR("Surface backup buffer is too small.\n"); | ||
1360 | vmw_bo_unreference(&res->backup); | ||
1361 | ret = -EINVAL; | ||
1362 | goto out_unlock; | ||
1363 | } else { | ||
1364 | backup_handle = req->buffer_handle; | ||
1365 | } | ||
1366 | } | ||
1367 | } else if (req->drm_surface_flags & drm_vmw_surface_flag_create_buffer) | ||
1368 | ret = vmw_user_bo_alloc(dev_priv, tfile, | ||
1369 | res->backup_size, | ||
1370 | req->drm_surface_flags & | ||
1371 | drm_vmw_surface_flag_shareable, | ||
1372 | &backup_handle, | ||
1373 | &res->backup, | ||
1374 | &user_srf->backup_base); | ||
1375 | |||
1376 | if (unlikely(ret != 0)) { | ||
1377 | vmw_resource_unreference(&res); | ||
1378 | goto out_unlock; | ||
1379 | } | ||
1380 | |||
1381 | tmp = vmw_resource_reference(res); | ||
1382 | ret = ttm_prime_object_init(tfile, res->backup_size, &user_srf->prime, | ||
1383 | req->drm_surface_flags & | ||
1384 | drm_vmw_surface_flag_shareable, | ||
1385 | VMW_RES_SURFACE, | ||
1386 | &vmw_user_surface_base_release, NULL); | ||
1387 | |||
1388 | if (unlikely(ret != 0)) { | ||
1389 | vmw_resource_unreference(&tmp); | ||
1390 | vmw_resource_unreference(&res); | ||
1391 | goto out_unlock; | ||
1392 | } | ||
1393 | |||
1394 | rep->handle = user_srf->prime.base.hash.key; | ||
1395 | rep->backup_size = res->backup_size; | ||
1396 | if (res->backup) { | ||
1397 | rep->buffer_map_handle = | ||
1398 | drm_vma_node_offset_addr(&res->backup->base.vma_node); | ||
1399 | rep->buffer_size = res->backup->base.num_pages * PAGE_SIZE; | ||
1400 | rep->buffer_handle = backup_handle; | ||
1401 | } else { | ||
1402 | rep->buffer_map_handle = 0; | ||
1403 | rep->buffer_size = 0; | ||
1404 | rep->buffer_handle = SVGA3D_INVALID_ID; | ||
1405 | } | ||
1406 | 1318 | ||
1407 | vmw_resource_unreference(&res); | 1319 | req_ext.base = arg->req; |
1320 | req_ext.version = drm_vmw_gb_surface_v1; | ||
1321 | req_ext.svga3d_flags_upper_32_bits = 0; | ||
1322 | req_ext.multisample_pattern = SVGA3D_MS_PATTERN_NONE; | ||
1323 | req_ext.quality_level = SVGA3D_MS_QUALITY_NONE; | ||
1324 | req_ext.must_be_zero = 0; | ||
1408 | 1325 | ||
1409 | out_unlock: | 1326 | return vmw_gb_surface_define_internal(dev, &req_ext, rep, file_priv); |
1410 | ttm_read_unlock(&dev_priv->reservation_sem); | ||
1411 | return ret; | ||
1412 | } | 1327 | } |
1413 | 1328 | ||
1414 | /** | 1329 | /** |
1415 | * vmw_gb_surface_reference_ioctl - Ioctl function implementing | 1330 | * vmw_gb_surface_reference_ioctl - Ioctl function implementing |
1416 | * the user surface reference functionality. | 1331 | * the user surface reference functionality. |
1417 | * | 1332 | * |
1418 | * @dev: Pointer to a struct drm_device. | 1333 | * @dev: Pointer to a struct drm_device. |
1419 | * @data: Pointer to data copied from / to user-space. | 1334 | * @data: Pointer to data copied from / to user-space. |
1420 | * @file_priv: Pointer to a drm file private structure. | 1335 | * @file_priv: Pointer to a drm file private structure. |
1421 | */ | 1336 | */ |
1422 | int vmw_gb_surface_reference_ioctl(struct drm_device *dev, void *data, | 1337 | int vmw_gb_surface_reference_ioctl(struct drm_device *dev, void *data, |
1423 | struct drm_file *file_priv) | 1338 | struct drm_file *file_priv) |
1424 | { | 1339 | { |
1425 | struct vmw_private *dev_priv = vmw_priv(dev); | ||
1426 | union drm_vmw_gb_surface_reference_arg *arg = | 1340 | union drm_vmw_gb_surface_reference_arg *arg = |
1427 | (union drm_vmw_gb_surface_reference_arg *)data; | 1341 | (union drm_vmw_gb_surface_reference_arg *)data; |
1428 | struct drm_vmw_surface_arg *req = &arg->req; | 1342 | struct drm_vmw_surface_arg *req = &arg->req; |
1429 | struct drm_vmw_gb_surface_ref_rep *rep = &arg->rep; | 1343 | struct drm_vmw_gb_surface_ref_rep *rep = &arg->rep; |
1430 | struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; | 1344 | struct drm_vmw_gb_surface_ref_ext_rep rep_ext; |
1431 | struct vmw_surface *srf; | 1345 | int ret; |
1432 | struct vmw_user_surface *user_srf; | 1346 | |
1433 | struct ttm_base_object *base; | 1347 | ret = vmw_gb_surface_reference_internal(dev, req, &rep_ext, file_priv); |
1434 | uint32_t backup_handle; | ||
1435 | int ret = -EINVAL; | ||
1436 | 1348 | ||
1437 | ret = vmw_surface_handle_reference(dev_priv, file_priv, req->sid, | ||
1438 | req->handle_type, &base); | ||
1439 | if (unlikely(ret != 0)) | 1349 | if (unlikely(ret != 0)) |
1440 | return ret; | 1350 | return ret; |
1441 | 1351 | ||
1442 | user_srf = container_of(base, struct vmw_user_surface, prime.base); | 1352 | rep->creq = rep_ext.creq.base; |
1443 | srf = &user_srf->srf; | 1353 | rep->crep = rep_ext.crep; |
1444 | if (!srf->res.backup) { | ||
1445 | DRM_ERROR("Shared GB surface is missing a backup buffer.\n"); | ||
1446 | goto out_bad_resource; | ||
1447 | } | ||
1448 | |||
1449 | mutex_lock(&dev_priv->cmdbuf_mutex); /* Protect res->backup */ | ||
1450 | ret = vmw_user_bo_reference(tfile, srf->res.backup, &backup_handle); | ||
1451 | mutex_unlock(&dev_priv->cmdbuf_mutex); | ||
1452 | |||
1453 | if (unlikely(ret != 0)) { | ||
1454 | DRM_ERROR("Could not add a reference to a GB surface " | ||
1455 | "backup buffer.\n"); | ||
1456 | (void) ttm_ref_object_base_unref(tfile, base->hash.key, | ||
1457 | TTM_REF_USAGE); | ||
1458 | goto out_bad_resource; | ||
1459 | } | ||
1460 | |||
1461 | rep->creq.svga3d_flags = (uint32_t)srf->flags; | ||
1462 | rep->creq.format = srf->format; | ||
1463 | rep->creq.mip_levels = srf->mip_levels[0]; | ||
1464 | rep->creq.drm_surface_flags = 0; | ||
1465 | rep->creq.multisample_count = srf->multisample_count; | ||
1466 | rep->creq.autogen_filter = srf->autogen_filter; | ||
1467 | rep->creq.array_size = srf->array_size; | ||
1468 | rep->creq.buffer_handle = backup_handle; | ||
1469 | rep->creq.base_size = srf->base_size; | ||
1470 | rep->crep.handle = user_srf->prime.base.hash.key; | ||
1471 | rep->crep.backup_size = srf->res.backup_size; | ||
1472 | rep->crep.buffer_handle = backup_handle; | ||
1473 | rep->crep.buffer_map_handle = | ||
1474 | drm_vma_node_offset_addr(&srf->res.backup->base.vma_node); | ||
1475 | rep->crep.buffer_size = srf->res.backup->base.num_pages * PAGE_SIZE; | ||
1476 | |||
1477 | out_bad_resource: | ||
1478 | ttm_base_object_unref(&base); | ||
1479 | 1354 | ||
1480 | return ret; | 1355 | return ret; |
1481 | } | 1356 | } |
@@ -1493,6 +1368,8 @@ out_bad_resource: | |||
1493 | * @multisample_count: | 1368 | * @multisample_count: |
1494 | * @array_size: Surface array size. | 1369 | * @array_size: Surface array size. |
1495 | * @size: width, heigh, depth of the surface requested | 1370 | * @size: width, heigh, depth of the surface requested |
1371 | * @multisample_pattern: Multisampling pattern when msaa is supported | ||
1372 | * @quality_level: Precision settings | ||
1496 | * @user_srf_out: allocated user_srf. Set to NULL on failure. | 1373 | * @user_srf_out: allocated user_srf. Set to NULL on failure. |
1497 | * | 1374 | * |
1498 | * GB surfaces allocated by this function will not have a user mode handle, and | 1375 | * GB surfaces allocated by this function will not have a user mode handle, and |
@@ -1509,6 +1386,8 @@ int vmw_surface_gb_priv_define(struct drm_device *dev, | |||
1509 | uint32_t multisample_count, | 1386 | uint32_t multisample_count, |
1510 | uint32_t array_size, | 1387 | uint32_t array_size, |
1511 | struct drm_vmw_size size, | 1388 | struct drm_vmw_size size, |
1389 | SVGA3dMSPattern multisample_pattern, | ||
1390 | SVGA3dMSQualityLevel quality_level, | ||
1512 | struct vmw_surface **srf_out) | 1391 | struct vmw_surface **srf_out) |
1513 | { | 1392 | { |
1514 | struct vmw_private *dev_priv = vmw_priv(dev); | 1393 | struct vmw_private *dev_priv = vmw_priv(dev); |
@@ -1519,7 +1398,7 @@ int vmw_surface_gb_priv_define(struct drm_device *dev, | |||
1519 | }; | 1398 | }; |
1520 | struct vmw_surface *srf; | 1399 | struct vmw_surface *srf; |
1521 | int ret; | 1400 | int ret; |
1522 | u32 num_layers; | 1401 | u32 num_layers = 1; |
1523 | 1402 | ||
1524 | *srf_out = NULL; | 1403 | *srf_out = NULL; |
1525 | 1404 | ||
@@ -1594,15 +1473,13 @@ int vmw_surface_gb_priv_define(struct drm_device *dev, | |||
1594 | srf->autogen_filter = SVGA3D_TEX_FILTER_NONE; | 1473 | srf->autogen_filter = SVGA3D_TEX_FILTER_NONE; |
1595 | srf->array_size = array_size; | 1474 | srf->array_size = array_size; |
1596 | srf->multisample_count = multisample_count; | 1475 | srf->multisample_count = multisample_count; |
1597 | srf->multisample_pattern = SVGA3D_MS_PATTERN_NONE; | 1476 | srf->multisample_pattern = multisample_pattern; |
1598 | srf->quality_level = SVGA3D_MS_QUALITY_NONE; | 1477 | srf->quality_level = quality_level; |
1599 | 1478 | ||
1600 | if (array_size) | 1479 | if (array_size) |
1601 | num_layers = array_size; | 1480 | num_layers = array_size; |
1602 | else if (svga3d_flags & SVGA3D_SURFACE_CUBEMAP) | 1481 | else if (svga3d_flags & SVGA3D_SURFACE_CUBEMAP) |
1603 | num_layers = SVGA3D_MAX_SURFACE_FACES; | 1482 | num_layers = SVGA3D_MAX_SURFACE_FACES; |
1604 | else | ||
1605 | num_layers = 1; | ||
1606 | 1483 | ||
1607 | srf->res.backup_size = | 1484 | srf->res.backup_size = |
1608 | svga3dsurface_get_serialized_size(srf->format, | 1485 | svga3dsurface_get_serialized_size(srf->format, |
@@ -1633,3 +1510,262 @@ out_unlock: | |||
1633 | ttm_read_unlock(&dev_priv->reservation_sem); | 1510 | ttm_read_unlock(&dev_priv->reservation_sem); |
1634 | return ret; | 1511 | return ret; |
1635 | } | 1512 | } |
1513 | |||
1514 | /** | ||
1515 | * vmw_gb_surface_define_ext_ioctl - Ioctl function implementing | ||
1516 | * the user surface define functionality. | ||
1517 | * | ||
1518 | * @dev: Pointer to a struct drm_device. | ||
1519 | * @data: Pointer to data copied from / to user-space. | ||
1520 | * @file_priv: Pointer to a drm file private structure. | ||
1521 | */ | ||
1522 | int vmw_gb_surface_define_ext_ioctl(struct drm_device *dev, void *data, | ||
1523 | struct drm_file *file_priv) | ||
1524 | { | ||
1525 | union drm_vmw_gb_surface_create_ext_arg *arg = | ||
1526 | (union drm_vmw_gb_surface_create_ext_arg *)data; | ||
1527 | struct drm_vmw_gb_surface_create_ext_req *req = &arg->req; | ||
1528 | struct drm_vmw_gb_surface_create_rep *rep = &arg->rep; | ||
1529 | |||
1530 | return vmw_gb_surface_define_internal(dev, req, rep, file_priv); | ||
1531 | } | ||
1532 | |||
1533 | /** | ||
1534 | * vmw_gb_surface_reference_ext_ioctl - Ioctl function implementing | ||
1535 | * the user surface reference functionality. | ||
1536 | * | ||
1537 | * @dev: Pointer to a struct drm_device. | ||
1538 | * @data: Pointer to data copied from / to user-space. | ||
1539 | * @file_priv: Pointer to a drm file private structure. | ||
1540 | */ | ||
1541 | int vmw_gb_surface_reference_ext_ioctl(struct drm_device *dev, void *data, | ||
1542 | struct drm_file *file_priv) | ||
1543 | { | ||
1544 | union drm_vmw_gb_surface_reference_ext_arg *arg = | ||
1545 | (union drm_vmw_gb_surface_reference_ext_arg *)data; | ||
1546 | struct drm_vmw_surface_arg *req = &arg->req; | ||
1547 | struct drm_vmw_gb_surface_ref_ext_rep *rep = &arg->rep; | ||
1548 | |||
1549 | return vmw_gb_surface_reference_internal(dev, req, rep, file_priv); | ||
1550 | } | ||
1551 | |||
1552 | /** | ||
1553 | * vmw_gb_surface_define_internal - Ioctl function implementing | ||
1554 | * the user surface define functionality. | ||
1555 | * | ||
1556 | * @dev: Pointer to a struct drm_device. | ||
1557 | * @req: Request argument from user-space. | ||
1558 | * @rep: Response argument to user-space. | ||
1559 | * @file_priv: Pointer to a drm file private structure. | ||
1560 | */ | ||
1561 | static int | ||
1562 | vmw_gb_surface_define_internal(struct drm_device *dev, | ||
1563 | struct drm_vmw_gb_surface_create_ext_req *req, | ||
1564 | struct drm_vmw_gb_surface_create_rep *rep, | ||
1565 | struct drm_file *file_priv) | ||
1566 | { | ||
1567 | struct vmw_private *dev_priv = vmw_priv(dev); | ||
1568 | struct vmw_user_surface *user_srf; | ||
1569 | struct vmw_surface *srf; | ||
1570 | struct vmw_resource *res; | ||
1571 | struct vmw_resource *tmp; | ||
1572 | struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; | ||
1573 | int ret; | ||
1574 | uint32_t size; | ||
1575 | uint32_t backup_handle = 0; | ||
1576 | SVGA3dSurfaceAllFlags svga3d_flags_64 = | ||
1577 | SVGA3D_FLAGS_64(req->svga3d_flags_upper_32_bits, | ||
1578 | req->base.svga3d_flags); | ||
1579 | |||
1580 | if (!dev_priv->has_sm4_1) { | ||
1581 | /* | ||
1582 | * If SM4_1 is not support then cannot send 64-bit flag to | ||
1583 | * device. | ||
1584 | */ | ||
1585 | if (req->svga3d_flags_upper_32_bits != 0) | ||
1586 | return -EINVAL; | ||
1587 | |||
1588 | if (req->base.multisample_count != 0) | ||
1589 | return -EINVAL; | ||
1590 | |||
1591 | if (req->multisample_pattern != SVGA3D_MS_PATTERN_NONE) | ||
1592 | return -EINVAL; | ||
1593 | |||
1594 | if (req->quality_level != SVGA3D_MS_QUALITY_NONE) | ||
1595 | return -EINVAL; | ||
1596 | } | ||
1597 | |||
1598 | if (req->base.mip_levels > DRM_VMW_MAX_MIP_LEVELS) | ||
1599 | return -EINVAL; | ||
1600 | |||
1601 | if (unlikely(vmw_user_surface_size == 0)) | ||
1602 | vmw_user_surface_size = ttm_round_pot(sizeof(*user_srf)) + | ||
1603 | 128; | ||
1604 | |||
1605 | size = vmw_user_surface_size + 128; | ||
1606 | |||
1607 | /* Define a surface based on the parameters. */ | ||
1608 | ret = vmw_surface_gb_priv_define(dev, | ||
1609 | size, | ||
1610 | svga3d_flags_64, | ||
1611 | req->base.format, | ||
1612 | req->base.drm_surface_flags & | ||
1613 | drm_vmw_surface_flag_scanout, | ||
1614 | req->base.mip_levels, | ||
1615 | req->base.multisample_count, | ||
1616 | req->base.array_size, | ||
1617 | req->base.base_size, | ||
1618 | req->multisample_pattern, | ||
1619 | req->quality_level, | ||
1620 | &srf); | ||
1621 | if (unlikely(ret != 0)) | ||
1622 | return ret; | ||
1623 | |||
1624 | user_srf = container_of(srf, struct vmw_user_surface, srf); | ||
1625 | if (drm_is_primary_client(file_priv)) | ||
1626 | user_srf->master = drm_master_get(file_priv->master); | ||
1627 | |||
1628 | ret = ttm_read_lock(&dev_priv->reservation_sem, true); | ||
1629 | if (unlikely(ret != 0)) | ||
1630 | return ret; | ||
1631 | |||
1632 | res = &user_srf->srf.res; | ||
1633 | |||
1634 | if (req->base.buffer_handle != SVGA3D_INVALID_ID) { | ||
1635 | ret = vmw_user_bo_lookup(tfile, req->base.buffer_handle, | ||
1636 | &res->backup, | ||
1637 | &user_srf->backup_base); | ||
1638 | if (ret == 0) { | ||
1639 | if (res->backup->base.num_pages * PAGE_SIZE < | ||
1640 | res->backup_size) { | ||
1641 | DRM_ERROR("Surface backup buffer too small.\n"); | ||
1642 | vmw_bo_unreference(&res->backup); | ||
1643 | ret = -EINVAL; | ||
1644 | goto out_unlock; | ||
1645 | } else { | ||
1646 | backup_handle = req->base.buffer_handle; | ||
1647 | } | ||
1648 | } | ||
1649 | } else if (req->base.drm_surface_flags & | ||
1650 | drm_vmw_surface_flag_create_buffer) | ||
1651 | ret = vmw_user_bo_alloc(dev_priv, tfile, | ||
1652 | res->backup_size, | ||
1653 | req->base.drm_surface_flags & | ||
1654 | drm_vmw_surface_flag_shareable, | ||
1655 | &backup_handle, | ||
1656 | &res->backup, | ||
1657 | &user_srf->backup_base); | ||
1658 | |||
1659 | if (unlikely(ret != 0)) { | ||
1660 | vmw_resource_unreference(&res); | ||
1661 | goto out_unlock; | ||
1662 | } | ||
1663 | |||
1664 | tmp = vmw_resource_reference(res); | ||
1665 | ret = ttm_prime_object_init(tfile, res->backup_size, &user_srf->prime, | ||
1666 | req->base.drm_surface_flags & | ||
1667 | drm_vmw_surface_flag_shareable, | ||
1668 | VMW_RES_SURFACE, | ||
1669 | &vmw_user_surface_base_release, NULL); | ||
1670 | |||
1671 | if (unlikely(ret != 0)) { | ||
1672 | vmw_resource_unreference(&tmp); | ||
1673 | vmw_resource_unreference(&res); | ||
1674 | goto out_unlock; | ||
1675 | } | ||
1676 | |||
1677 | rep->handle = user_srf->prime.base.hash.key; | ||
1678 | rep->backup_size = res->backup_size; | ||
1679 | if (res->backup) { | ||
1680 | rep->buffer_map_handle = | ||
1681 | drm_vma_node_offset_addr(&res->backup->base.vma_node); | ||
1682 | rep->buffer_size = res->backup->base.num_pages * PAGE_SIZE; | ||
1683 | rep->buffer_handle = backup_handle; | ||
1684 | } else { | ||
1685 | rep->buffer_map_handle = 0; | ||
1686 | rep->buffer_size = 0; | ||
1687 | rep->buffer_handle = SVGA3D_INVALID_ID; | ||
1688 | } | ||
1689 | |||
1690 | vmw_resource_unreference(&res); | ||
1691 | |||
1692 | out_unlock: | ||
1693 | ttm_read_unlock(&dev_priv->reservation_sem); | ||
1694 | return ret; | ||
1695 | } | ||
1696 | |||
1697 | /** | ||
1698 | * vmw_gb_surface_reference_internal - Ioctl function implementing | ||
1699 | * the user surface reference functionality. | ||
1700 | * | ||
1701 | * @dev: Pointer to a struct drm_device. | ||
1702 | * @req: Pointer to user-space request surface arg. | ||
1703 | * @rep: Pointer to response to user-space. | ||
1704 | * @file_priv: Pointer to a drm file private structure. | ||
1705 | */ | ||
1706 | static int | ||
1707 | vmw_gb_surface_reference_internal(struct drm_device *dev, | ||
1708 | struct drm_vmw_surface_arg *req, | ||
1709 | struct drm_vmw_gb_surface_ref_ext_rep *rep, | ||
1710 | struct drm_file *file_priv) | ||
1711 | { | ||
1712 | struct vmw_private *dev_priv = vmw_priv(dev); | ||
1713 | struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; | ||
1714 | struct vmw_surface *srf; | ||
1715 | struct vmw_user_surface *user_srf; | ||
1716 | struct ttm_base_object *base; | ||
1717 | uint32_t backup_handle; | ||
1718 | int ret = -EINVAL; | ||
1719 | |||
1720 | ret = vmw_surface_handle_reference(dev_priv, file_priv, req->sid, | ||
1721 | req->handle_type, &base); | ||
1722 | if (unlikely(ret != 0)) | ||
1723 | return ret; | ||
1724 | |||
1725 | user_srf = container_of(base, struct vmw_user_surface, prime.base); | ||
1726 | srf = &user_srf->srf; | ||
1727 | if (!srf->res.backup) { | ||
1728 | DRM_ERROR("Shared GB surface is missing a backup buffer.\n"); | ||
1729 | goto out_bad_resource; | ||
1730 | } | ||
1731 | |||
1732 | mutex_lock(&dev_priv->cmdbuf_mutex); /* Protect res->backup */ | ||
1733 | ret = vmw_user_bo_reference(tfile, srf->res.backup, &backup_handle); | ||
1734 | mutex_unlock(&dev_priv->cmdbuf_mutex); | ||
1735 | |||
1736 | if (unlikely(ret != 0)) { | ||
1737 | DRM_ERROR("Could not add a reference to a GB surface " | ||
1738 | "backup buffer.\n"); | ||
1739 | (void) ttm_ref_object_base_unref(tfile, base->hash.key, | ||
1740 | TTM_REF_USAGE); | ||
1741 | goto out_bad_resource; | ||
1742 | } | ||
1743 | |||
1744 | rep->creq.base.svga3d_flags = SVGA3D_FLAGS_LOWER_32(srf->flags); | ||
1745 | rep->creq.base.format = srf->format; | ||
1746 | rep->creq.base.mip_levels = srf->mip_levels[0]; | ||
1747 | rep->creq.base.drm_surface_flags = 0; | ||
1748 | rep->creq.base.multisample_count = srf->multisample_count; | ||
1749 | rep->creq.base.autogen_filter = srf->autogen_filter; | ||
1750 | rep->creq.base.array_size = srf->array_size; | ||
1751 | rep->creq.base.buffer_handle = backup_handle; | ||
1752 | rep->creq.base.base_size = srf->base_size; | ||
1753 | rep->crep.handle = user_srf->prime.base.hash.key; | ||
1754 | rep->crep.backup_size = srf->res.backup_size; | ||
1755 | rep->crep.buffer_handle = backup_handle; | ||
1756 | rep->crep.buffer_map_handle = | ||
1757 | drm_vma_node_offset_addr(&srf->res.backup->base.vma_node); | ||
1758 | rep->crep.buffer_size = srf->res.backup->base.num_pages * PAGE_SIZE; | ||
1759 | |||
1760 | rep->creq.version = drm_vmw_gb_surface_v1; | ||
1761 | rep->creq.svga3d_flags_upper_32_bits = | ||
1762 | SVGA3D_FLAGS_UPPER_32(srf->flags); | ||
1763 | rep->creq.multisample_pattern = srf->multisample_pattern; | ||
1764 | rep->creq.quality_level = srf->quality_level; | ||
1765 | rep->creq.must_be_zero = 0; | ||
1766 | |||
1767 | out_bad_resource: | ||
1768 | ttm_base_object_unref(&base); | ||
1769 | |||
1770 | return ret; | ||
1771 | } | ||