Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

dri2: Fix corner case crash for swaplimit > 1

If a swaplimit > 1 is set on a server which
supports the swaplimit api (XOrg 1.12.0+),
the following can happen:

1. Client calls glXSwapBuffersMscOML() with a
   swap target > 1 vblank in the future, or a
   client calls glXSwapbuffers() while the swap
   interval is set to > 1 (unusual but possible).

2. nouveau_dri2_finish_swap() is therefore called
   only at the target vblank, instead of immediately.

3. Because of the deferred execution of
   nouveu_dri2_finish_swap(), the OpenGL client
   can call x-servers DRI2GetBuffersWithFormat()
   before nouveau_dri2_finish_swap() executes and
   it deletes pixmaps that would be needed by
   nouveau_dri2_finish_swap() --> Segfault --> Crash.

Prevent this: When a swap is scheduled into the
future, we temporarily reduce the swaplimit to 1
until nouveau_dri2_finish_swap() is done, then
restore it to its original value. This throttles
the client inside the server in DRI2ThrottleClient()
before it can call the evil DRI2GetbuffersWithFormat().

The client will still be released one video refresh
interval before swap completion, so there is still
some potential win.

This doesn't affect the common case of swapping at
the next vblank, where this throttling is not needed
or done.

Signed-off-by: Mario Kleiner <mario.kleiner@tuebingen.mpg.de>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
  • Loading branch information...
commit 248de8cdbd6d0bc062633b49896fa4791148cd3b 1 parent 247465e
Mario Kleiner authored February 16, 2012 Ben Skeggs committed March 06, 2012

Showing 1 changed file with 26 additions and 0 deletions. Show diff stats Hide diff stats

  1. 26  src/nouveau_dri2.c
26  src/nouveau_dri2.c
@@ -445,6 +445,26 @@ nouveau_dri2_schedule_swap(ClientPtr client, DrawablePtr draw,
445 445
 		if (*target_msc == 0)
446 446
 			*target_msc = 1;
447 447
 
  448
+#if DRI2INFOREC_VERSION >= 6
  449
+		/* Is this a swap in the future, ie. the vblank event will
  450
+		 * not be immediately dispatched, but only at a future vblank?
  451
+		 * If so, we need to temporarily lower the swaplimit to 1, so
  452
+		 * that DRI2GetBuffersWithFormat() requests from the client get
  453
+		 * deferred in the x-server until the vblank event has been
  454
+		 * dispatched to us and nouveau_dri2_finish_swap() is done. If
  455
+		 * we wouldn't do this, DRI2GetBuffersWithFormat() would operate
  456
+		 * on wrong (pre-swap) buffers, and cause a segfault later on in
  457
+		 * nouveau_dri2_finish_swap(). Our vblank event handler restores
  458
+		 * the old swaplimit immediately after nouveau_dri2_finish_swap()
  459
+		 * is done, so we still get 1 video refresh cycle worth of
  460
+		 * triple-buffering. For a swap at next vblank, dispatch of the
  461
+		 * vblank event happens immediately, so there isn't any need
  462
+		 * for this lowered swaplimit.
  463
+		 */
  464
+		if (current_msc < *target_msc - 1)
  465
+			DRI2SwapLimit(draw, 1);
  466
+#endif
  467
+
448 468
 		/* Request a vblank event one frame before the target */
449 469
 		ret = nouveau_wait_vblank(draw, DRM_VBLANK_ABSOLUTE |
450 470
 					  DRM_VBLANK_EVENT,
@@ -557,6 +577,12 @@ nouveau_dri2_vblank_handler(int fd, unsigned int frame,
557 577
 	switch (s->action) {
558 578
 	case SWAP:
559 579
 		nouveau_dri2_finish_swap(draw, frame, tv_sec, tv_usec, s);
  580
+#if DRI2INFOREC_VERSION >= 6
  581
+		/* Restore real swap limit on drawable, now that it is safe. */
  582
+		ScrnInfoPtr scrn = xf86Screens[draw->pScreen->myNum];
  583
+		DRI2SwapLimit(draw, NVPTR(scrn)->swap_limit);
  584
+#endif
  585
+
560 586
 		break;
561 587
 
562 588
 	case WAIT:

0 notes on commit 248de8c

Please sign in to comment.
Something went wrong with that request. Please try again.