more clean-up in intelDisplayBuffer()
[mesa.git] / src / mesa / drivers / dri / intel_winsys / intel_swapbuffers.c
1 /**************************************************************************
2 *
3 * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28 #include "intel_screen.h"
29 #include "intel_context.h"
30 #include "intel_swapbuffers.h"
31 #include "intel_batchbuffer.h"
32 #include "intel_reg.h"
33 #include "intel_winsys.h"
34 #include "context.h"
35 #include "utils.h"
36 #include "drirenderbuffer.h"
37 #include "vblank.h"
38
39 #include "pipe/p_context.h"
40 #include "state_tracker/st_context.h"
41 #include "state_tracker/st_cb_fbo.h"
42
43
44 /* This block can be removed when libdrm >= 2.3.1 is required */
45
46 #ifndef DRM_VBLANK_FLIP
47
48 #define DRM_VBLANK_FLIP 0x8000000
49
50 typedef struct drm_i915_flip {
51 int pipes;
52 } drm_i915_flip_t;
53
54 #undef DRM_IOCTL_I915_FLIP
55 #define DRM_IOCTL_I915_FLIP DRM_IOW(DRM_COMMAND_BASE + DRM_I915_FLIP, \
56 drm_i915_flip_t)
57
58 #endif
59
60
61 /**
62 * Return the pipe_surface for the given renderbuffer.
63 */
64 static struct pipe_surface *
65 get_color_surface(struct intel_framebuffer *intel_fb,
66 GLuint bufferIndex)
67 {
68 struct st_renderbuffer *strb
69 = st_renderbuffer(intel_fb->Base.Attachment[bufferIndex].Renderbuffer);
70 if (strb)
71 return strb->surface;
72 return NULL;
73 }
74
75
76 /**
77 * Display a colorbuffer surface in an X window.
78 * Used for SwapBuffers and flushing front buffer rendering.
79 *
80 * \param dPriv the window/drawable to display into
81 * \param surf the surface to display
82 * \param rect optional subrect of surface to display (may be NULL).
83 */
84 void
85 intelDisplayBuffer(__DRIdrawablePrivate * dPriv,
86 struct pipe_surface *surf,
87 const drm_clip_rect_t * rect)
88 {
89 struct intel_context *intel;
90 const intelScreenPrivate *intelScreen
91 = (intelScreenPrivate *) dPriv->driScreenPriv->private;
92
93 DBG(SWAP, "%s\n", __FUNCTION__);
94
95 assert(dPriv);
96
97 intel = intelScreenContext(dPriv->driScreenPriv->private);
98 if (!intel)
99 return;
100
101 if (intel->last_swap_fence) {
102 driFenceFinish(intel->last_swap_fence, DRM_FENCE_TYPE_EXE, GL_TRUE);
103 driFenceUnReference(intel->last_swap_fence);
104 intel->last_swap_fence = NULL;
105 }
106 intel->last_swap_fence = intel->first_swap_fence;
107 intel->first_swap_fence = NULL;
108
109 /* The LOCK_HARDWARE is required for the cliprects. Buffer offsets
110 * should work regardless.
111 */
112 LOCK_HARDWARE(intel);
113 /* if this drawable isn't currently bound the LOCK_HARDWARE done on the
114 current context (which is what intelScreenContext should return) might
115 not get a contended lock and thus cliprects not updated (tests/manywin) */
116 if ((struct intel_context *)dPriv->driContextPriv->driverPrivate != intel)
117 DRI_VALIDATE_DRAWABLE_INFO(intel->driScreen, dPriv);
118
119
120 if (dPriv && dPriv->numClipRects) {
121 const int srcWidth = surf->width;
122 const int srcHeight = surf->height;
123 const int nbox = dPriv->numClipRects;
124 const drm_clip_rect_t *pbox = dPriv->pClipRects;
125 const int pitch = intelScreen->front.pitch / intelScreen->front.cpp;
126 const int cpp = intelScreen->front.cpp;
127 int BR13, CMD;
128 int i;
129 const struct pipe_region *srcRegion = surf->region;
130 const int srcpitch= srcRegion->pitch;
131
132 ASSERT(srcRegion);
133 ASSERT(srcRegion->cpp == cpp);
134
135 DBG(SWAP, "screen pitch %d src surface pitch %d\n",
136 pitch, srcRegion->pitch);
137
138 if (cpp == 2) {
139 BR13 = (pitch * cpp) | (0xCC << 16) | (1 << 24);
140 CMD = XY_SRC_COPY_BLT_CMD;
141 }
142 else {
143 BR13 = (pitch * cpp) | (0xCC << 16) | (1 << 24) | (1 << 25);
144 CMD = (XY_SRC_COPY_BLT_CMD | XY_SRC_COPY_BLT_WRITE_ALPHA |
145 XY_SRC_COPY_BLT_WRITE_RGB);
146 }
147
148 for (i = 0; i < nbox; i++, pbox++) {
149 drm_clip_rect_t box;
150 drm_clip_rect_t sbox;
151
152 if (pbox->x1 > pbox->x2 ||
153 pbox->y1 > pbox->y2 ||
154 pbox->x2 > intelScreen->front.width ||
155 pbox->y2 > intelScreen->front.height) {
156 /* invalid cliprect, skip it */
157 continue;
158 }
159
160 box = *pbox;
161
162 if (rect) {
163 /* intersect cliprect with user-provided src rect */
164 drm_clip_rect_t rrect;
165
166 rrect.x1 = dPriv->x + rect->x1;
167 rrect.y1 = (dPriv->h - rect->y1 - rect->y2) + dPriv->y;
168 rrect.x2 = rect->x2 + rrect.x1;
169 rrect.y2 = rect->y2 + rrect.y1;
170 if (rrect.x1 > box.x1)
171 box.x1 = rrect.x1;
172 if (rrect.y1 > box.y1)
173 box.y1 = rrect.y1;
174 if (rrect.x2 < box.x2)
175 box.x2 = rrect.x2;
176 if (rrect.y2 < box.y2)
177 box.y2 = rrect.y2;
178
179 if (box.x1 > box.x2 || box.y1 > box.y2)
180 continue;
181 }
182
183 /* restrict blit to size of actually rendered area */
184 if (box.x2 - box.x1 > srcWidth)
185 box.x2 = srcWidth + box.x1;
186 if (box.y2 - box.y1 > srcHeight)
187 box.y2 = srcHeight + box.y1;
188
189 DBG(SWAP, "box x1 x2 y1 y2 %d %d %d %d\n",
190 box.x1, box.x2, box.y1, box.y2);
191
192 sbox.x1 = box.x1 - dPriv->x;
193 sbox.y1 = box.y1 - dPriv->y;
194
195 BEGIN_BATCH(8, INTEL_BATCH_NO_CLIPRECTS);
196 OUT_BATCH(CMD);
197 OUT_BATCH(BR13);
198 OUT_BATCH((box.y1 << 16) | box.x1);
199 OUT_BATCH((box.y2 << 16) | box.x2);
200
201 OUT_RELOC(intelScreen->front.buffer,
202 DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_WRITE,
203 DRM_BO_MASK_MEM | DRM_BO_FLAG_WRITE, 0);
204 OUT_BATCH((sbox.y1 << 16) | sbox.x1);
205 OUT_BATCH((srcpitch * cpp) & 0xffff);
206 OUT_RELOC(dri_bo(srcRegion->buffer),
207 DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_READ,
208 DRM_BO_MASK_MEM | DRM_BO_FLAG_READ, 0);
209
210 ADVANCE_BATCH();
211 }
212
213 if (intel->first_swap_fence)
214 driFenceUnReference(intel->first_swap_fence);
215 intel->first_swap_fence = intel_batchbuffer_flush(intel->batch);
216 driFenceReference(intel->first_swap_fence);
217 }
218
219 UNLOCK_HARDWARE(intel);
220
221 /* XXX this is bogus. The context here may not even be bound to this drawable! */
222 if (intel->lastStamp != dPriv->lastStamp) {
223 GET_CURRENT_CONTEXT(currctx);
224 struct intel_context *intelcurrent = intel_context(currctx);
225 if (intelcurrent == intel && intelcurrent->driDrawable == dPriv) {
226 intelWindowMoved(intel);
227 intel->lastStamp = dPriv->lastStamp;
228 }
229 }
230
231 }
232
233
234
235 /**
236 * This will be called whenever the currently bound window is moved/resized.
237 * XXX: actually, it seems to NOT be called when the window is only moved (BP).
238 */
239 void
240 intelWindowMoved(struct intel_context *intel)
241 {
242 GLcontext *ctx = intel->st->ctx;
243 __DRIdrawablePrivate *dPriv = intel->driDrawable;
244 struct intel_framebuffer *intel_fb = dPriv->driverPrivate;
245
246 if (!intel->st->ctx->DrawBuffer) {
247 /* when would this happen? -BP */
248 assert(0);
249 intel->numClipRects = 0;
250 }
251
252 /* Update Mesa's notion of window size */
253 intelUpdateFramebufferSize(ctx, dPriv);
254 intel_fb->Base.Initialized = GL_TRUE; /* XXX remove someday */
255
256 {
257 drmI830Sarea *sarea = intel->sarea;
258 drm_clip_rect_t drw_rect = { .x1 = dPriv->x, .x2 = dPriv->x + dPriv->w,
259 .y1 = dPriv->y, .y2 = dPriv->y + dPriv->h };
260 drm_clip_rect_t pipeA_rect = { .x1 = sarea->pipeA_x, .y1 = sarea->pipeA_y,
261 .x2 = sarea->pipeA_x + sarea->pipeA_w,
262 .y2 = sarea->pipeA_y + sarea->pipeA_h };
263 drm_clip_rect_t pipeB_rect = { .x1 = sarea->pipeB_x, .y1 = sarea->pipeB_y,
264 .x2 = sarea->pipeB_x + sarea->pipeB_w,
265 .y2 = sarea->pipeB_y + sarea->pipeB_h };
266 GLint areaA = driIntersectArea( drw_rect, pipeA_rect );
267 GLint areaB = driIntersectArea( drw_rect, pipeB_rect );
268 GLuint flags = intel_fb->vblank_flags;
269 GLboolean pf_active;
270 GLint pf_planes;
271
272 /* Update page flipping info
273 */
274 pf_planes = 0;
275
276 if (areaA > 0)
277 pf_planes |= 1;
278
279 if (areaB > 0)
280 pf_planes |= 2;
281
282 intel_fb->pf_current_page = (intel->sarea->pf_current_page >>
283 (intel_fb->pf_planes & 0x2)) & 0x3;
284
285 intel_fb->pf_num_pages = 2 /*intel->intelScreen->third.handle ? 3 : 2*/;
286
287 pf_active = pf_planes && (pf_planes & intel->sarea->pf_active) == pf_planes;
288
289 if (pf_active != intel_fb->pf_active)
290 DBG(LOCK, "%s - Page flipping %sactive\n",
291 __progname, pf_active ? "" : "in");
292
293 if (pf_active) {
294 /* Sync pages between planes if we're flipping on both at the same time */
295 if (pf_planes == 0x3 && pf_planes != intel_fb->pf_planes &&
296 (intel->sarea->pf_current_page & 0x3) !=
297 (((intel->sarea->pf_current_page) >> 2) & 0x3)) {
298 drm_i915_flip_t flip;
299
300 if (intel_fb->pf_current_page ==
301 (intel->sarea->pf_current_page & 0x3)) {
302 /* XXX: This is ugly, but emitting two flips 'in a row' can cause
303 * lockups for unknown reasons.
304 */
305 intel->sarea->pf_current_page =
306 intel->sarea->pf_current_page & 0x3;
307 intel->sarea->pf_current_page |=
308 ((intel_fb->pf_current_page + intel_fb->pf_num_pages - 1) %
309 intel_fb->pf_num_pages) << 2;
310
311 flip.pipes = 0x2;
312 } else {
313 intel->sarea->pf_current_page =
314 intel->sarea->pf_current_page & (0x3 << 2);
315 intel->sarea->pf_current_page |=
316 (intel_fb->pf_current_page + intel_fb->pf_num_pages - 1) %
317 intel_fb->pf_num_pages;
318
319 flip.pipes = 0x1;
320 }
321
322 drmCommandWrite(intel->driFd, DRM_I915_FLIP, &flip, sizeof(flip));
323 }
324
325 intel_fb->pf_planes = pf_planes;
326 }
327
328 intel_fb->pf_active = pf_active;
329 #if 0
330 intel_flip_renderbuffers(intel_fb);
331 intel_draw_buffer(&intel->ctx, intel->ctx.DrawBuffer);
332 #endif
333
334 /* Update vblank info
335 */
336 if (areaB > areaA || (areaA == areaB && areaB > 0)) {
337 flags = intel_fb->vblank_flags | VBLANK_FLAG_SECONDARY;
338 } else {
339 flags = intel_fb->vblank_flags & ~VBLANK_FLAG_SECONDARY;
340 }
341
342 if (flags != intel_fb->vblank_flags && intel_fb->vblank_flags &&
343 !(intel_fb->vblank_flags & VBLANK_FLAG_NO_IRQ)) {
344 drmVBlank vbl;
345 int i;
346
347 vbl.request.type = DRM_VBLANK_ABSOLUTE;
348
349 if ( intel_fb->vblank_flags & VBLANK_FLAG_SECONDARY ) {
350 vbl.request.type |= DRM_VBLANK_SECONDARY;
351 }
352
353 for (i = 0; i < intel_fb->pf_num_pages; i++) {
354 if ((intel_fb->vbl_waited - intel_fb->vbl_pending[i]) <= (1<<23))
355 continue;
356
357 vbl.request.sequence = intel_fb->vbl_pending[i];
358 drmWaitVBlank(intel->driFd, &vbl);
359 }
360
361 intel_fb->vblank_flags = flags;
362 driGetCurrentVBlank(dPriv, intel_fb->vblank_flags, &intel_fb->vbl_seq);
363 intel_fb->vbl_waited = intel_fb->vbl_seq;
364
365 for (i = 0; i < intel_fb->pf_num_pages; i++) {
366 intel_fb->vbl_pending[i] = intel_fb->vbl_waited;
367 }
368 }
369 }
370
371 /* This will be picked up by looking at the dirty state flags:
372 */
373
374 /* Update hardware scissor */
375 // ctx->Driver.Scissor(ctx, ctx->Scissor.X, ctx->Scissor.Y,
376 // ctx->Scissor.Width, ctx->Scissor.Height);
377
378 /* Re-calculate viewport related state */
379 // ctx->Driver.DepthRange( ctx, ctx->Viewport.Near, ctx->Viewport.Far );
380 }
381
382
383
384
385
386 /* Emit wait for pending flips */
387 #if 0
388 void
389 intel_wait_flips(struct intel_context *intel, GLuint batch_flags)
390 {
391 struct intel_framebuffer *intel_fb =
392 (struct intel_framebuffer *) intel->ctx.DrawBuffer;
393 struct intel_renderbuffer *intel_rb =
394 intel_get_renderbuffer(&intel_fb->Base,
395 intel_fb->Base._ColorDrawBufferMask[0] ==
396 BUFFER_BIT_FRONT_LEFT ? BUFFER_FRONT_LEFT :
397 BUFFER_BACK_LEFT);
398
399 if (intel_fb->Base.Name == 0 && intel_rb->pf_pending == intel_fb->pf_seq) {
400 GLint pf_planes = intel_fb->pf_planes;
401 BATCH_LOCALS;
402
403 /* Wait for pending flips to take effect */
404 BEGIN_BATCH(2, batch_flags);
405 OUT_BATCH(pf_planes & 0x1 ? (MI_WAIT_FOR_EVENT | MI_WAIT_FOR_PLANE_A_FLIP)
406 : 0);
407 OUT_BATCH(pf_planes & 0x2 ? (MI_WAIT_FOR_EVENT | MI_WAIT_FOR_PLANE_B_FLIP)
408 : 0);
409 ADVANCE_BATCH();
410
411 intel_rb->pf_pending--;
412 }
413 }
414 #endif
415
416 #if 0
417 /* Flip the front & back buffers
418 */
419 static GLboolean
420 intelPageFlip(const __DRIdrawablePrivate * dPriv)
421 {
422 struct intel_context *intel;
423 int ret;
424 struct intel_framebuffer *intel_fb = dPriv->driverPrivate;
425
426 DBG(SWAP, "%s\n", __FUNCTION__);
427
428 assert(dPriv);
429 assert(dPriv->driContextPriv);
430 assert(dPriv->driContextPriv->driverPrivate);
431
432 intel = (struct intel_context *) dPriv->driContextPriv->driverPrivate;
433
434 if (intel->intelScreen->drmMinor < 9)
435 return GL_FALSE;
436
437 intelFlush(&intel->ctx);
438
439 ret = 0;
440
441 LOCK_HARDWARE(intel);
442
443 if (dPriv->numClipRects && intel_fb->pf_active) {
444 drm_i915_flip_t flip;
445
446 flip.pipes = intel_fb->pf_planes;
447
448 ret = drmCommandWrite(intel->driFd, DRM_I915_FLIP, &flip, sizeof(flip));
449 }
450
451 UNLOCK_HARDWARE(intel);
452
453 if (ret || !intel_fb->pf_active)
454 return GL_FALSE;
455
456 if (!dPriv->numClipRects) {
457 usleep(10000); /* throttle invisible client 10ms */
458 }
459
460 intel_fb->pf_current_page = (intel->sarea->pf_current_page >>
461 (intel_fb->pf_planes & 0x2)) & 0x3;
462
463 if (dPriv->numClipRects != 0) {
464 intel_get_renderbuffer(&intel_fb->Base, BUFFER_FRONT_LEFT)->pf_pending =
465 intel_get_renderbuffer(&intel_fb->Base, BUFFER_BACK_LEFT)->pf_pending =
466 ++intel_fb->pf_seq;
467 }
468
469 #if 0
470 intel_flip_renderbuffers(intel_fb);
471 intel_draw_buffer(&intel->ctx, &intel_fb->Base);
472 #endif
473
474 DBG(SWAP, "%s: success\n", __FUNCTION__);
475
476 return GL_TRUE;
477 }
478 #endif
479
480
481 static GLboolean
482 intelScheduleSwap(const __DRIdrawablePrivate * dPriv, GLboolean *missed_target)
483 {
484 struct intel_framebuffer *intel_fb = dPriv->driverPrivate;
485 unsigned int interval = driGetVBlankInterval(dPriv, intel_fb->vblank_flags);
486 struct intel_context *intel =
487 intelScreenContext(dPriv->driScreenPriv->private);
488 const intelScreenPrivate *intelScreen = intel->intelScreen;
489 unsigned int target;
490 drm_i915_vblank_swap_t swap;
491 GLboolean ret;
492
493 /* XXX: Scheduled buffer swaps don't work with private back buffers yet */
494 if (1 || !intel_fb->vblank_flags ||
495 (intel_fb->vblank_flags & VBLANK_FLAG_NO_IRQ) ||
496 intelScreen->drmMinor < (intel_fb->pf_active ? 9 : 6))
497 return GL_FALSE;
498
499 swap.seqtype = DRM_VBLANK_ABSOLUTE;
500
501 if (intel_fb->vblank_flags & VBLANK_FLAG_SYNC) {
502 swap.seqtype |= DRM_VBLANK_NEXTONMISS;
503 } else if (interval == 0) {
504 return GL_FALSE;
505 }
506
507 swap.drawable = dPriv->hHWDrawable;
508 target = swap.sequence = intel_fb->vbl_seq + interval;
509
510 if ( intel_fb->vblank_flags & VBLANK_FLAG_SECONDARY ) {
511 swap.seqtype |= DRM_VBLANK_SECONDARY;
512 }
513
514 LOCK_HARDWARE(intel);
515
516 intel_batchbuffer_flush(intel->batch);
517
518 if ( intel_fb->pf_active ) {
519 swap.seqtype |= DRM_VBLANK_FLIP;
520
521 intel_fb->pf_current_page = (((intel->sarea->pf_current_page >>
522 (intel_fb->pf_planes & 0x2)) & 0x3) + 1) %
523 intel_fb->pf_num_pages;
524 }
525
526 if (!drmCommandWriteRead(intel->driFd, DRM_I915_VBLANK_SWAP, &swap,
527 sizeof(swap))) {
528 intel_fb->vbl_seq = swap.sequence;
529 swap.sequence -= target;
530 *missed_target = swap.sequence > 0 && swap.sequence <= (1 << 23);
531
532 #if 1
533 intel_fb->vbl_pending[1] = intel_fb->vbl_pending[0] = intel_fb->vbl_seq;
534 #else
535 intel_get_renderbuffer(&intel_fb->Base, BUFFER_BACK_LEFT)->vbl_pending =
536 intel_get_renderbuffer(&intel_fb->Base,
537 BUFFER_FRONT_LEFT)->vbl_pending =
538 intel_fb->vbl_seq;
539 #endif
540
541 if (swap.seqtype & DRM_VBLANK_FLIP) {
542 #if 0
543 intel_flip_renderbuffers(intel_fb);
544 intel_draw_buffer(&intel->ctx, intel->ctx.DrawBuffer);
545 #endif
546 }
547
548 ret = GL_TRUE;
549 } else {
550 if (swap.seqtype & DRM_VBLANK_FLIP) {
551 intel_fb->pf_current_page = ((intel->sarea->pf_current_page >>
552 (intel_fb->pf_planes & 0x2)) & 0x3) %
553 intel_fb->pf_num_pages;
554 }
555
556 ret = GL_FALSE;
557 }
558
559 UNLOCK_HARDWARE(intel);
560
561 return ret;
562 }
563
564 void
565 intelSwapBuffers(__DRIdrawablePrivate * dPriv)
566 {
567 if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) {
568 GET_CURRENT_CONTEXT(ctx);
569 struct intel_context *intel;
570
571 if (ctx == NULL)
572 return;
573
574 intel = intel_context(ctx);
575
576 if (ctx->Visual.doubleBufferMode) {
577 GLboolean missed_target;
578 struct intel_framebuffer *intel_fb = dPriv->driverPrivate;
579 int64_t ust;
580
581 _mesa_notifySwapBuffers(ctx); /* flush pending rendering comands */
582
583 if (!intelScheduleSwap(dPriv, &missed_target)) {
584 struct pipe_surface *back_surf
585 = get_color_surface(intel_fb, BUFFER_BACK_LEFT);
586
587 driWaitForVBlank(dPriv, &intel_fb->vbl_seq, intel_fb->vblank_flags,
588 &missed_target);
589
590 intelDisplayBuffer(dPriv, back_surf, NULL);
591 }
592
593 intel_fb->swap_count++;
594 (*dri_interface->getUST) (&ust);
595 if (missed_target) {
596 intel_fb->swap_missed_count++;
597 intel_fb->swap_missed_ust = ust - intel_fb->swap_ust;
598 }
599
600 intel_fb->swap_ust = ust;
601 }
602 }
603 else {
604 /* XXX this shouldn't be an error but we can't handle it for now */
605 fprintf(stderr, "%s: drawable has no context!\n", __FUNCTION__);
606 }
607 }
608
609
610 /**
611 * Called via glXCopySubBufferMESA() to copy a subrect of the back
612 * buffer to the front buffer/screen.
613 */
614 void
615 intelCopySubBuffer(__DRIdrawablePrivate * dPriv, int x, int y, int w, int h)
616 {
617 if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) {
618 struct intel_context *intel =
619 (struct intel_context *) dPriv->driContextPriv->driverPrivate;
620 GLcontext *ctx = intel->st->ctx;
621
622 if (ctx->Visual.doubleBufferMode) {
623 struct intel_framebuffer *intel_fb = dPriv->driverPrivate;
624 struct pipe_surface *back_surf
625 = get_color_surface(intel_fb, BUFFER_BACK_LEFT);
626
627 drm_clip_rect_t rect;
628 /* fixup cliprect (driDrawable may have changed?) later */
629 rect.x1 = x;
630 rect.y1 = y;
631 rect.x2 = w;
632 rect.y2 = h;
633 _mesa_notifySwapBuffers(ctx); /* flush pending rendering comands */
634 intelDisplayBuffer(dPriv, back_surf, &rect);
635 }
636 }
637 else {
638 /* XXX this shouldn't be an error but we can't handle it for now */
639 fprintf(stderr, "%s: drawable has no context!\n", __FUNCTION__);
640 }
641 }