aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2010-10-07 12:28:15 -0400
committerChris Wilson <chris@chris-wilson.co.uk>2010-10-07 14:10:09 -0400
commite59f2bac15042eb744851bcf866f18dadc3091c6 (patch)
treea0534aea9beab6f65489d171e6dff2b3c992c13d
parentc2873e9633fe908dccd36dbb1d370e9c59a1ca62 (diff)
drm/i915: Wait for pending flips on the GPU
Currently, if a batch buffer refers to an object with a pending flip, then we sleep until that pending flip is completed (unpinned and signalled). This is so that a flip can be queued and the user can continue rendering to the backbuffer oblivious to whether the buffer is still pinned as the scan out. (The kernel arbitrating at the last moment to stall the batch and wait until the buffer is unpinned and replaced as the front buffer.) As we only have a queue depth of 1, we can simply wait for the current pending flip to complete and continue rendering. We can achieve this with a single WAIT_FOR_EVENT command inserted into the ring buffer prior to executing the batch, *without* stalling the client. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c75
-rw-r--r--drivers/gpu/drm/i915/intel_display.c7
2 files changed, 34 insertions, 48 deletions
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 100a7537980..72ab3032300 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -3647,41 +3647,6 @@ i915_gem_check_execbuffer (struct drm_i915_gem_execbuffer2 *exec,
3647} 3647}
3648 3648
3649static int 3649static int
3650i915_gem_wait_for_pending_flip(struct drm_device *dev,
3651 struct drm_gem_object **object_list,
3652 int count)
3653{
3654 drm_i915_private_t *dev_priv = dev->dev_private;
3655 struct drm_i915_gem_object *obj_priv;
3656 DEFINE_WAIT(wait);
3657 int i, ret = 0;
3658
3659 for (;;) {
3660 prepare_to_wait(&dev_priv->pending_flip_queue,
3661 &wait, TASK_INTERRUPTIBLE);
3662 for (i = 0; i < count; i++) {
3663 obj_priv = to_intel_bo(object_list[i]);
3664 if (atomic_read(&obj_priv->pending_flip) > 0)
3665 break;
3666 }
3667 if (i == count)
3668 break;
3669
3670 if (!signal_pending(current)) {
3671 mutex_unlock(&dev->struct_mutex);
3672 schedule();
3673 mutex_lock(&dev->struct_mutex);
3674 continue;
3675 }
3676 ret = -ERESTARTSYS;
3677 break;
3678 }
3679 finish_wait(&dev_priv->pending_flip_queue, &wait);
3680
3681 return ret;
3682}
3683
3684static int
3685i915_gem_do_execbuffer(struct drm_device *dev, void *data, 3650i915_gem_do_execbuffer(struct drm_device *dev, void *data,
3686 struct drm_file *file_priv, 3651 struct drm_file *file_priv,
3687 struct drm_i915_gem_execbuffer2 *args, 3652 struct drm_i915_gem_execbuffer2 *args,
@@ -3773,7 +3738,6 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
3773 } 3738 }
3774 3739
3775 /* Look up object handles */ 3740 /* Look up object handles */
3776 flips = 0;
3777 for (i = 0; i < args->buffer_count; i++) { 3741 for (i = 0; i < args->buffer_count; i++) {
3778 object_list[i] = drm_gem_object_lookup(dev, file_priv, 3742 object_list[i] = drm_gem_object_lookup(dev, file_priv,
3779 exec_list[i].handle); 3743 exec_list[i].handle);
@@ -3796,14 +3760,6 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
3796 goto err; 3760 goto err;
3797 } 3761 }
3798 obj_priv->in_execbuffer = true; 3762 obj_priv->in_execbuffer = true;
3799 flips += atomic_read(&obj_priv->pending_flip);
3800 }
3801
3802 if (flips > 0) {
3803 ret = i915_gem_wait_for_pending_flip(dev, object_list,
3804 args->buffer_count);
3805 if (ret)
3806 goto err;
3807 } 3763 }
3808 3764
3809 /* Pin and relocate */ 3765 /* Pin and relocate */
@@ -3943,9 +3899,38 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
3943 ~0); 3899 ~0);
3944#endif 3900#endif
3945 3901
3902 /* Check for any pending flips. As we only maintain a flip queue depth
3903 * of 1, we can simply insert a WAIT for the next display flip prior
3904 * to executing the batch and avoid stalling the CPU.
3905 */
3906 flips = 0;
3907 for (i = 0; i < args->buffer_count; i++) {
3908 if (object_list[i]->write_domain)
3909 flips |= atomic_read(&to_intel_bo(object_list[i])->pending_flip);
3910 }
3911 if (flips) {
3912 int plane, flip_mask;
3913
3914 for (plane = 0; flips >> plane; plane++) {
3915 if (((flips >> plane) & 1) == 0)
3916 continue;
3917
3918 if (plane)
3919 flip_mask = MI_WAIT_FOR_PLANE_B_FLIP;
3920 else
3921 flip_mask = MI_WAIT_FOR_PLANE_A_FLIP;
3922
3923 intel_ring_begin(dev, ring, 2);
3924 intel_ring_emit(dev, ring,
3925 MI_WAIT_FOR_EVENT | flip_mask);
3926 intel_ring_emit(dev, ring, MI_NOOP);
3927 intel_ring_advance(dev, ring);
3928 }
3929 }
3930
3946 /* Exec the batchbuffer */ 3931 /* Exec the batchbuffer */
3947 ret = ring->dispatch_gem_execbuffer(dev, ring, args, 3932 ret = ring->dispatch_gem_execbuffer(dev, ring, args,
3948 cliprects, exec_offset); 3933 cliprects, exec_offset);
3949 if (ret) { 3934 if (ret) {
3950 DRM_ERROR("dispatch failed %d\n", ret); 3935 DRM_ERROR("dispatch failed %d\n", ret);
3951 goto err; 3936 goto err;
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 9109c00f3ea..7fe92d06eb2 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -4994,8 +4994,9 @@ static void do_intel_finish_page_flip(struct drm_device *dev,
4994 obj_priv = to_intel_bo(work->pending_flip_obj); 4994 obj_priv = to_intel_bo(work->pending_flip_obj);
4995 4995
4996 /* Initial scanout buffer will have a 0 pending flip count */ 4996 /* Initial scanout buffer will have a 0 pending flip count */
4997 if ((atomic_read(&obj_priv->pending_flip) == 0) || 4997 atomic_clear_mask(1 << intel_crtc->plane,
4998 atomic_dec_and_test(&obj_priv->pending_flip)) 4998 &obj_priv->pending_flip.counter);
4999 if (atomic_read(&obj_priv->pending_flip) == 0)
4999 wake_up(&dev_priv->pending_flip_queue); 5000 wake_up(&dev_priv->pending_flip_queue);
5000 schedule_work(&work->work); 5001 schedule_work(&work->work);
5001 5002
@@ -5092,7 +5093,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
5092 goto cleanup_objs; 5093 goto cleanup_objs;
5093 5094
5094 obj_priv = to_intel_bo(obj); 5095 obj_priv = to_intel_bo(obj);
5095 atomic_inc(&obj_priv->pending_flip); 5096 atomic_add(1 << intel_crtc->plane, &obj_priv->pending_flip);
5096 work->pending_flip_obj = obj; 5097 work->pending_flip_obj = obj;
5097 5098
5098 if (IS_GEN3(dev) || IS_GEN2(dev)) { 5099 if (IS_GEN3(dev) || IS_GEN2(dev)) {