drm/i915: Wait on external rendering for GEM objects

When transitioning to the GTT or CPU domain we wait on all rendering
from i915 to complete (with the optimisation of allowing concurrent read
access by both the GPU and client). We don't yet ensure all rendering
from third parties (tracked by implicit fences on the dma-buf) is
complete. Since implicitly tracked rendering by third parties will
ignore our cache-domain tracking, we have to always wait upon rendering
from third-parties when transitioning to direct access to the backing
store. We still rely on clients notifying us of cache domain changes
(i.e. they need to move to the GTT read or write domain after doing a CPU
access before letting the third party render again).

v2:
This introduces a potential WARN_ON into i915_gem_object_free() as the
current i915_vma_unbind() calls i915_gem_object_wait_rendering(). To
hit this path we first need to render with the GPU, have a dma-buf
attached with an unsignaled fence and then interrupt the wait. It does
get fixed later in the series (when i915_vma_unbind() only waits on the
active VMA and not all, including third-party, rendering.

To offset that risk, use the __i915_vma_unbind_no_wait hack.

Testcase: igt/prime_vgem/basic-fence-read
Testcase: igt/prime_vgem/basic-fence-mmap
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1469002875-2335-8-git-send-email-chris@chris-wilson.co.uk
This commit is contained in:
Chris Wilson 2016-07-20 09:21:15 +01:00
parent 30bc06c0fa
commit c13d87ea53
1 changed files with 28 additions and 16 deletions

View File

@ -29,10 +29,12 @@
#include <drm/drm_vma_manager.h> #include <drm/drm_vma_manager.h>
#include <drm/i915_drm.h> #include <drm/i915_drm.h>
#include "i915_drv.h" #include "i915_drv.h"
#include "i915_gem_dmabuf.h"
#include "i915_vgpu.h" #include "i915_vgpu.h"
#include "i915_trace.h" #include "i915_trace.h"
#include "intel_drv.h" #include "intel_drv.h"
#include "intel_mocs.h" #include "intel_mocs.h"
#include <linux/reservation.h>
#include <linux/shmem_fs.h> #include <linux/shmem_fs.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/swap.h> #include <linux/swap.h>
@ -511,6 +513,10 @@ int i915_gem_obj_prepare_shmem_read(struct drm_i915_gem_object *obj,
if (WARN_ON(!i915_gem_object_has_struct_page(obj))) if (WARN_ON(!i915_gem_object_has_struct_page(obj)))
return -EINVAL; return -EINVAL;
ret = i915_gem_object_wait_rendering(obj, true);
if (ret)
return ret;
if (!(obj->base.read_domains & I915_GEM_DOMAIN_CPU)) { if (!(obj->base.read_domains & I915_GEM_DOMAIN_CPU)) {
/* If we're not in the cpu read domain, set ourself into the gtt /* If we're not in the cpu read domain, set ourself into the gtt
* read domain and manually flush cachelines (if required). This * read domain and manually flush cachelines (if required). This
@ -518,9 +524,6 @@ int i915_gem_obj_prepare_shmem_read(struct drm_i915_gem_object *obj,
* anyway again before the next pread happens. */ * anyway again before the next pread happens. */
*needs_clflush = !cpu_cache_is_coherent(obj->base.dev, *needs_clflush = !cpu_cache_is_coherent(obj->base.dev,
obj->cache_level); obj->cache_level);
ret = i915_gem_object_wait_rendering(obj, true);
if (ret)
return ret;
} }
ret = i915_gem_object_get_pages(obj); ret = i915_gem_object_get_pages(obj);
@ -1132,15 +1135,16 @@ i915_gem_shmem_pwrite(struct drm_device *dev,
obj_do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj); obj_do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj);
ret = i915_gem_object_wait_rendering(obj, false);
if (ret)
return ret;
if (obj->base.write_domain != I915_GEM_DOMAIN_CPU) { if (obj->base.write_domain != I915_GEM_DOMAIN_CPU) {
/* If we're not in the cpu write domain, set ourself into the gtt /* If we're not in the cpu write domain, set ourself into the gtt
* write domain and manually flush cachelines (if required). This * write domain and manually flush cachelines (if required). This
* optimizes for the case when the gpu will use the data * optimizes for the case when the gpu will use the data
* right away and we therefore have to clflush anyway. */ * right away and we therefore have to clflush anyway. */
needs_clflush_after = cpu_write_needs_clflush(obj); needs_clflush_after = cpu_write_needs_clflush(obj);
ret = i915_gem_object_wait_rendering(obj, false);
if (ret)
return ret;
} }
/* Same trick applies to invalidate partially written cachelines read /* Same trick applies to invalidate partially written cachelines read
* before writing. */ * before writing. */
@ -1335,11 +1339,9 @@ int
i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj, i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj,
bool readonly) bool readonly)
{ {
struct reservation_object *resv;
int ret, i; int ret, i;
if (!obj->active)
return 0;
if (readonly) { if (readonly) {
if (obj->last_write_req != NULL) { if (obj->last_write_req != NULL) {
ret = i915_wait_request(obj->last_write_req); ret = i915_wait_request(obj->last_write_req);
@ -1366,6 +1368,16 @@ i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj,
GEM_BUG_ON(obj->active); GEM_BUG_ON(obj->active);
} }
resv = i915_gem_object_get_dmabuf_resv(obj);
if (resv) {
long err;
err = reservation_object_wait_timeout_rcu(resv, !readonly, true,
MAX_SCHEDULE_TIMEOUT);
if (err < 0)
return err;
}
return 0; return 0;
} }
@ -3402,13 +3414,13 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write)
struct i915_vma *vma; struct i915_vma *vma;
int ret; int ret;
if (obj->base.write_domain == I915_GEM_DOMAIN_GTT)
return 0;
ret = i915_gem_object_wait_rendering(obj, !write); ret = i915_gem_object_wait_rendering(obj, !write);
if (ret) if (ret)
return ret; return ret;
if (obj->base.write_domain == I915_GEM_DOMAIN_GTT)
return 0;
/* Flush and acquire obj->pages so that we are coherent through /* Flush and acquire obj->pages so that we are coherent through
* direct access in memory with previous cached writes through * direct access in memory with previous cached writes through
* shmemfs and that our cache domain tracking remains valid. * shmemfs and that our cache domain tracking remains valid.
@ -3752,13 +3764,13 @@ i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *obj, bool write)
uint32_t old_write_domain, old_read_domains; uint32_t old_write_domain, old_read_domains;
int ret; int ret;
if (obj->base.write_domain == I915_GEM_DOMAIN_CPU)
return 0;
ret = i915_gem_object_wait_rendering(obj, !write); ret = i915_gem_object_wait_rendering(obj, !write);
if (ret) if (ret)
return ret; return ret;
if (obj->base.write_domain == I915_GEM_DOMAIN_CPU)
return 0;
i915_gem_object_flush_gtt_write_domain(obj); i915_gem_object_flush_gtt_write_domain(obj);
old_write_domain = obj->base.write_domain; old_write_domain = obj->base.write_domain;
@ -4238,7 +4250,7 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj)
int ret; int ret;
vma->pin_count = 0; vma->pin_count = 0;
ret = i915_vma_unbind(vma); ret = __i915_vma_unbind_no_wait(vma);
if (WARN_ON(ret == -ERESTARTSYS)) { if (WARN_ON(ret == -ERESTARTSYS)) {
bool was_interruptible; bool was_interruptible;