diff options
author | Eric Anholt <eric@anholt.net> | 2008-11-10 13:53:25 -0500 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2008-12-03 20:21:52 -0500 |
commit | 2ef7eeaa553d88e78d9a4520271f26a7bc0e2968 (patch) | |
tree | 7a46a23d4fcc57ae03131c106d21fdac721dfce1 | |
parent | b670d8158283c35842ae1c650f75c375d8710607 (diff) |
drm/i915: Make a single set-to-gtt-domain path.
This fixes failure to flush caches in the relocation update path, and
failure to wait in the set_domain ioctl, each of which could lead to incorrect
rendering.
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem.c | 115 |
1 files changed, 96 insertions, 19 deletions
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 3fe108b7e2fa..62a059dce85f 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c | |||
@@ -48,6 +48,8 @@ i915_gem_set_domain(struct drm_gem_object *obj, | |||
48 | struct drm_file *file_priv, | 48 | struct drm_file *file_priv, |
49 | uint32_t read_domains, | 49 | uint32_t read_domains, |
50 | uint32_t write_domain); | 50 | uint32_t write_domain); |
51 | static int i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, | ||
52 | int write); | ||
51 | static int i915_gem_object_get_page_list(struct drm_gem_object *obj); | 53 | static int i915_gem_object_get_page_list(struct drm_gem_object *obj); |
52 | static void i915_gem_object_free_page_list(struct drm_gem_object *obj); | 54 | static void i915_gem_object_free_page_list(struct drm_gem_object *obj); |
53 | static int i915_gem_object_wait_rendering(struct drm_gem_object *obj); | 55 | static int i915_gem_object_wait_rendering(struct drm_gem_object *obj); |
@@ -260,8 +262,7 @@ i915_gem_gtt_pwrite(struct drm_device *dev, struct drm_gem_object *obj, | |||
260 | mutex_unlock(&dev->struct_mutex); | 262 | mutex_unlock(&dev->struct_mutex); |
261 | return ret; | 263 | return ret; |
262 | } | 264 | } |
263 | ret = i915_gem_set_domain(obj, file_priv, | 265 | ret = i915_gem_object_set_to_gtt_domain(obj, 1); |
264 | I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT); | ||
265 | if (ret) | 266 | if (ret) |
266 | goto fail; | 267 | goto fail; |
267 | 268 | ||
@@ -397,7 +398,8 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, | |||
397 | } | 398 | } |
398 | 399 | ||
399 | /** | 400 | /** |
400 | * Called when user space prepares to use an object | 401 | * Called when user space prepares to use an object with the CPU, either |
402 | * through the mmap ioctl's mapping or a GTT mapping. | ||
401 | */ | 403 | */ |
402 | int | 404 | int |
403 | i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, | 405 | i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, |
@@ -405,11 +407,26 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, | |||
405 | { | 407 | { |
406 | struct drm_i915_gem_set_domain *args = data; | 408 | struct drm_i915_gem_set_domain *args = data; |
407 | struct drm_gem_object *obj; | 409 | struct drm_gem_object *obj; |
410 | uint32_t read_domains = args->read_domains; | ||
411 | uint32_t write_domain = args->write_domain; | ||
408 | int ret; | 412 | int ret; |
409 | 413 | ||
410 | if (!(dev->driver->driver_features & DRIVER_GEM)) | 414 | if (!(dev->driver->driver_features & DRIVER_GEM)) |
411 | return -ENODEV; | 415 | return -ENODEV; |
412 | 416 | ||
417 | /* Only handle setting domains to types used by the CPU. */ | ||
418 | if (write_domain & ~(I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT)) | ||
419 | return -EINVAL; | ||
420 | |||
421 | if (read_domains & ~(I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT)) | ||
422 | return -EINVAL; | ||
423 | |||
424 | /* Having something in the write domain implies it's in the read | ||
425 | * domain, and only that read domain. Enforce that in the request. | ||
426 | */ | ||
427 | if (write_domain != 0 && read_domains != write_domain) | ||
428 | return -EINVAL; | ||
429 | |||
413 | obj = drm_gem_object_lookup(dev, file_priv, args->handle); | 430 | obj = drm_gem_object_lookup(dev, file_priv, args->handle); |
414 | if (obj == NULL) | 431 | if (obj == NULL) |
415 | return -EBADF; | 432 | return -EBADF; |
@@ -417,10 +434,15 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, | |||
417 | mutex_lock(&dev->struct_mutex); | 434 | mutex_lock(&dev->struct_mutex); |
418 | #if WATCH_BUF | 435 | #if WATCH_BUF |
419 | DRM_INFO("set_domain_ioctl %p(%d), %08x %08x\n", | 436 | DRM_INFO("set_domain_ioctl %p(%d), %08x %08x\n", |
420 | obj, obj->size, args->read_domains, args->write_domain); | 437 | obj, obj->size, read_domains, write_domain); |
421 | #endif | 438 | #endif |
422 | ret = i915_gem_set_domain(obj, file_priv, | 439 | if (read_domains & I915_GEM_DOMAIN_GTT) { |
423 | args->read_domains, args->write_domain); | 440 | ret = i915_gem_object_set_to_gtt_domain(obj, write_domain != 0); |
441 | } else { | ||
442 | ret = i915_gem_set_domain(obj, file_priv, | ||
443 | read_domains, write_domain); | ||
444 | } | ||
445 | |||
424 | drm_gem_object_unreference(obj); | 446 | drm_gem_object_unreference(obj); |
425 | mutex_unlock(&dev->struct_mutex); | 447 | mutex_unlock(&dev->struct_mutex); |
426 | return ret; | 448 | return ret; |
@@ -1237,6 +1259,69 @@ i915_gem_clflush_object(struct drm_gem_object *obj) | |||
1237 | drm_clflush_pages(obj_priv->page_list, obj->size / PAGE_SIZE); | 1259 | drm_clflush_pages(obj_priv->page_list, obj->size / PAGE_SIZE); |
1238 | } | 1260 | } |
1239 | 1261 | ||
1262 | /** | ||
1263 | * Moves a single object to the GTT read, and possibly write domain. | ||
1264 | * | ||
1265 | * This function returns when the move is complete, including waiting on | ||
1266 | * flushes to occur. | ||
1267 | */ | ||
1268 | static int | ||
1269 | i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, int write) | ||
1270 | { | ||
1271 | struct drm_device *dev = obj->dev; | ||
1272 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | ||
1273 | uint32_t flush_domains; | ||
1274 | |||
1275 | /* Figure out what GPU domains we need to flush or invalidate for | ||
1276 | * moving to GTT. | ||
1277 | */ | ||
1278 | flush_domains = obj->write_domain & I915_GEM_GPU_DOMAINS; | ||
1279 | |||
1280 | /* Queue the GPU write cache flushing we need. */ | ||
1281 | if (flush_domains != 0) { | ||
1282 | uint32_t seqno; | ||
1283 | |||
1284 | obj->write_domain &= ~I915_GEM_GPU_DOMAINS; | ||
1285 | i915_gem_flush(dev, 0, flush_domains); | ||
1286 | seqno = i915_add_request(dev, flush_domains); | ||
1287 | i915_gem_object_move_to_active(obj, seqno); | ||
1288 | } | ||
1289 | |||
1290 | /* Wait on any GPU rendering and flushing to occur. */ | ||
1291 | if (obj_priv->active) { | ||
1292 | int ret; | ||
1293 | |||
1294 | ret = i915_wait_request(dev, obj_priv->last_rendering_seqno); | ||
1295 | if (ret != 0) | ||
1296 | return ret; | ||
1297 | } | ||
1298 | |||
1299 | /* If we're writing through the GTT domain, then CPU and GPU caches | ||
1300 | * will need to be invalidated at next use. | ||
1301 | */ | ||
1302 | if (write) | ||
1303 | obj->read_domains &= ~(I915_GEM_GPU_DOMAINS | | ||
1304 | I915_GEM_DOMAIN_CPU); | ||
1305 | |||
1306 | /* Flush the CPU domain if it's dirty. */ | ||
1307 | if (obj->write_domain & I915_GEM_DOMAIN_CPU) { | ||
1308 | i915_gem_clflush_object(obj); | ||
1309 | drm_agp_chipset_flush(dev); | ||
1310 | |||
1311 | obj->write_domain &= ~I915_GEM_DOMAIN_CPU; | ||
1312 | } | ||
1313 | |||
1314 | /* It should now be out of any other write domains, and we can update | ||
1315 | * the domain values for our changes. | ||
1316 | */ | ||
1317 | BUG_ON((obj->write_domain & ~I915_GEM_DOMAIN_GTT) != 0); | ||
1318 | obj->read_domains |= I915_GEM_DOMAIN_GTT; | ||
1319 | if (write) | ||
1320 | obj->write_domain = I915_GEM_DOMAIN_GTT; | ||
1321 | |||
1322 | return 0; | ||
1323 | } | ||
1324 | |||
1240 | /* | 1325 | /* |
1241 | * Set the next domain for the specified object. This | 1326 | * Set the next domain for the specified object. This |
1242 | * may not actually perform the necessary flushing/invaliding though, | 1327 | * may not actually perform the necessary flushing/invaliding though, |
@@ -1634,19 +1719,11 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj, | |||
1634 | continue; | 1719 | continue; |
1635 | } | 1720 | } |
1636 | 1721 | ||
1637 | /* Now that we're going to actually write some data in, | 1722 | ret = i915_gem_object_set_to_gtt_domain(obj, 1); |
1638 | * make sure that any rendering using this buffer's contents | 1723 | if (ret != 0) { |
1639 | * is completed. | 1724 | drm_gem_object_unreference(target_obj); |
1640 | */ | 1725 | i915_gem_object_unpin(obj); |
1641 | i915_gem_object_wait_rendering(obj); | 1726 | return -EINVAL; |
1642 | |||
1643 | /* As we're writing through the gtt, flush | ||
1644 | * any CPU writes before we write the relocations | ||
1645 | */ | ||
1646 | if (obj->write_domain & I915_GEM_DOMAIN_CPU) { | ||
1647 | i915_gem_clflush_object(obj); | ||
1648 | drm_agp_chipset_flush(dev); | ||
1649 | obj->write_domain = 0; | ||
1650 | } | 1727 | } |
1651 | 1728 | ||
1652 | /* Map the page containing the relocation we're going to | 1729 | /* Map the page containing the relocation we're going to |