Merge branch 'mesa_7_6_branch'
[mesa.git] / src / mesa / drivers / dri / unichrome / via_ioctl.c
1 /*
2 * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
3 * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sub license,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial portions
14 * of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
19 * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 */
24 #include <stdio.h>
25 #include <unistd.h>
26
27 #include "main/glheader.h"
28 #include "main/mtypes.h"
29 #include "main/macros.h"
30 #include "main/dd.h"
31 #include "swrast/swrast.h"
32
33 #include "main/mm.h"
34 #include "via_context.h"
35 #include "via_tris.h"
36 #include "via_ioctl.h"
37 #include "via_state.h"
38 #include "via_fb.h"
39 #include "via_3d_reg.h"
40
41 #include "vblank.h"
42 #include "drm.h"
43 #include "xf86drm.h"
44 #include <sys/ioctl.h>
45 #include <errno.h>
46
47
48 #define VIA_REG_STATUS 0x400
49 #define VIA_REG_GEMODE 0x004
50 #define VIA_REG_SRCBASE 0x030
51 #define VIA_REG_DSTBASE 0x034
52 #define VIA_REG_PITCH 0x038
53 #define VIA_REG_SRCCOLORKEY 0x01C
54 #define VIA_REG_KEYCONTROL 0x02C
55 #define VIA_REG_SRCPOS 0x008
56 #define VIA_REG_DSTPOS 0x00C
57 #define VIA_REG_GECMD 0x000
58 #define VIA_REG_DIMENSION 0x010 /* width and height */
59 #define VIA_REG_FGCOLOR 0x018
60
61 #define VIA_GEM_8bpp 0x00000000
62 #define VIA_GEM_16bpp 0x00000100
63 #define VIA_GEM_32bpp 0x00000300
64 #define VIA_GEC_BLT 0x00000001
65 #define VIA_PITCH_ENABLE 0x80000000
66 #define VIA_GEC_INCX 0x00000000
67 #define VIA_GEC_DECY 0x00004000
68 #define VIA_GEC_INCY 0x00000000
69 #define VIA_GEC_DECX 0x00008000
70 #define VIA_GEC_FIXCOLOR_PAT 0x00002000
71
72
73 #define VIA_BLIT_CLEAR 0x00
74 #define VIA_BLIT_COPY 0xCC
75 #define VIA_BLIT_FILL 0xF0
76 #define VIA_BLIT_SET 0xFF
77
78 static void dump_dma( struct via_context *vmesa )
79 {
80 GLuint i;
81 GLuint *data = (GLuint *)vmesa->dma;
82 for (i = 0; i < vmesa->dmaLow; i += 16) {
83 fprintf(stderr, "%04x: ", i);
84 fprintf(stderr, "%08x ", *data++);
85 fprintf(stderr, "%08x ", *data++);
86 fprintf(stderr, "%08x ", *data++);
87 fprintf(stderr, "%08x\n", *data++);
88 }
89 fprintf(stderr, "******************************************\n");
90 }
91
92
93
94 void viaCheckDma(struct via_context *vmesa, GLuint bytes)
95 {
96 VIA_FINISH_PRIM( vmesa );
97 if (vmesa->dmaLow + bytes > VIA_DMA_HIGHWATER) {
98 viaFlushDma(vmesa);
99 }
100 }
101
102
103
104 #define SetReg2DAGP(nReg, nData) do { \
105 OUT_RING( ((nReg) >> 2) | 0xF0000000 ); \
106 OUT_RING( nData ); \
107 } while (0)
108
109
110 static void viaBlit(struct via_context *vmesa, GLuint bpp,
111 GLuint srcBase, GLuint srcPitch,
112 GLuint dstBase, GLuint dstPitch,
113 GLuint w, GLuint h,
114 GLuint blitMode,
115 GLuint color, GLuint nMask )
116 {
117
118 GLuint dwGEMode, srcX, dstX, cmd;
119 RING_VARS;
120
121 if (VIA_DEBUG & DEBUG_2D)
122 fprintf(stderr,
123 "%s bpp %d src %x/%x dst %x/%x w %d h %d "
124 " mode: %x color: 0x%08x mask 0x%08x\n",
125 __FUNCTION__, bpp, srcBase, srcPitch, dstBase,
126 dstPitch, w,h, blitMode, color, nMask);
127
128
129 if (!w || !h)
130 return;
131
132 switch (bpp) {
133 case 16:
134 dwGEMode = VIA_GEM_16bpp;
135 srcX = (srcBase & 0x1f) >> 1;
136 dstX = (dstBase & 0x1f) >> 1;
137 break;
138 case 32:
139 dwGEMode = VIA_GEM_32bpp;
140 srcX = (srcBase & 0x1f) >> 2;
141 dstX = (dstBase & 0x1f) >> 2;
142 break;
143 default:
144 return;
145 }
146
147 switch(blitMode) {
148 case VIA_BLIT_FILL:
149 cmd = VIA_GEC_BLT | VIA_GEC_FIXCOLOR_PAT | (VIA_BLIT_FILL << 24);
150 break;
151 case VIA_BLIT_COPY:
152 cmd = VIA_GEC_BLT | (VIA_BLIT_COPY << 24);
153 break;
154 default:
155 return;
156 }
157
158 BEGIN_RING(22);
159 SetReg2DAGP( VIA_REG_GEMODE, dwGEMode);
160 SetReg2DAGP( VIA_REG_FGCOLOR, color);
161 SetReg2DAGP( 0x2C, nMask);
162 SetReg2DAGP( VIA_REG_SRCBASE, (srcBase & ~0x1f) >> 3);
163 SetReg2DAGP( VIA_REG_DSTBASE, (dstBase & ~0x1f) >> 3);
164 SetReg2DAGP( VIA_REG_PITCH, VIA_PITCH_ENABLE |
165 (srcPitch >> 3) | ((dstPitch >> 3) << 16));
166 SetReg2DAGP( VIA_REG_SRCPOS, srcX);
167 SetReg2DAGP( VIA_REG_DSTPOS, dstX);
168 SetReg2DAGP( VIA_REG_DIMENSION, (((h - 1) << 16) | (w - 1)));
169 SetReg2DAGP( VIA_REG_GECMD, cmd);
170 SetReg2DAGP( 0x2C, 0x00000000);
171 ADVANCE_RING();
172 }
173
174 static void viaFillBuffer(struct via_context *vmesa,
175 struct via_renderbuffer *buffer,
176 drm_clip_rect_t *pbox,
177 int nboxes,
178 GLuint pixel,
179 GLuint mask)
180 {
181 GLuint bytePerPixel = buffer->bpp >> 3;
182 GLuint i;
183
184 for (i = 0; i < nboxes ; i++) {
185 int x = pbox[i].x1 - buffer->drawX;
186 int y = pbox[i].y1 - buffer->drawY;
187 int w = pbox[i].x2 - pbox[i].x1;
188 int h = pbox[i].y2 - pbox[i].y1;
189
190 int offset = (buffer->offset +
191 y * buffer->pitch +
192 x * bytePerPixel);
193
194 viaBlit(vmesa,
195 buffer->bpp,
196 offset, buffer->pitch,
197 offset, buffer->pitch,
198 w, h,
199 VIA_BLIT_FILL, pixel, mask);
200 }
201 }
202
203
204
205 static void viaClear(GLcontext *ctx, GLbitfield mask)
206 {
207 struct via_context *vmesa = VIA_CONTEXT(ctx);
208 __DRIdrawablePrivate *dPriv = vmesa->driDrawable;
209 struct via_renderbuffer *const vrb =
210 (struct via_renderbuffer *) dPriv->driverPrivate;
211 int flag = 0;
212 GLuint i = 0;
213 GLuint clear_depth_mask = 0xf << 28;
214 GLuint clear_depth = 0;
215
216 VIA_FLUSH_DMA(vmesa);
217
218 if (mask & BUFFER_BIT_FRONT_LEFT) {
219 flag |= VIA_FRONT;
220 mask &= ~BUFFER_BIT_FRONT_LEFT;
221 }
222
223 if (mask & BUFFER_BIT_BACK_LEFT) {
224 flag |= VIA_BACK;
225 mask &= ~BUFFER_BIT_BACK_LEFT;
226 }
227
228 if (mask & BUFFER_BIT_DEPTH) {
229 flag |= VIA_DEPTH;
230 clear_depth = (GLuint)(ctx->Depth.Clear * vmesa->ClearDepth);
231 clear_depth_mask &= ~vmesa->depth_clear_mask;
232 mask &= ~BUFFER_BIT_DEPTH;
233 }
234
235 if (mask & BUFFER_BIT_STENCIL) {
236 if (vmesa->have_hw_stencil) {
237 if ((ctx->Stencil.WriteMask[0] & 0xff) == 0xff) {
238 flag |= VIA_DEPTH;
239 clear_depth &= ~0xff;
240 clear_depth |= (ctx->Stencil.Clear & 0xff);
241 clear_depth_mask &= ~vmesa->stencil_clear_mask;
242 mask &= ~BUFFER_BIT_STENCIL;
243 }
244 else {
245 if (VIA_DEBUG & DEBUG_2D)
246 fprintf(stderr, "Clear stencil writemask %x\n",
247 ctx->Stencil.WriteMask[0]);
248 }
249 }
250 }
251
252 /* 16bpp doesn't support masked clears */
253 if (vmesa->viaScreen->bytesPerPixel == 2 &&
254 vmesa->ClearMask & 0xf0000000) {
255 if (flag & VIA_FRONT)
256 mask |= BUFFER_BIT_FRONT_LEFT;
257 if (flag & VIA_BACK)
258 mask |= BUFFER_BIT_BACK_LEFT;
259 flag &= ~(VIA_FRONT | VIA_BACK);
260 }
261
262 if (flag) {
263 drm_clip_rect_t *boxes, *tmp_boxes = 0;
264 int nr = 0;
265 GLint cx, cy, cw, ch;
266 GLboolean all;
267
268 LOCK_HARDWARE(vmesa);
269
270 /* get region after locking: */
271 cx = ctx->DrawBuffer->_Xmin;
272 cy = ctx->DrawBuffer->_Ymin;
273 cw = ctx->DrawBuffer->_Xmax - cx;
274 ch = ctx->DrawBuffer->_Ymax - cy;
275 all = (cw == ctx->DrawBuffer->Width && ch == ctx->DrawBuffer->Height);
276
277 /* flip top to bottom */
278 cy = dPriv->h - cy - ch;
279 cx += vrb->drawX;
280 cy += vrb->drawY;
281
282 if (!all) {
283 drm_clip_rect_t *b = vmesa->pClipRects;
284
285 boxes = tmp_boxes =
286 (drm_clip_rect_t *)malloc(vmesa->numClipRects *
287 sizeof(drm_clip_rect_t));
288 if (!boxes) {
289 UNLOCK_HARDWARE(vmesa);
290 return;
291 }
292
293 for (; i < vmesa->numClipRects; i++) {
294 GLint x = b[i].x1;
295 GLint y = b[i].y1;
296 GLint w = b[i].x2 - x;
297 GLint h = b[i].y2 - y;
298
299 if (x < cx) w -= cx - x, x = cx;
300 if (y < cy) h -= cy - y, y = cy;
301 if (x + w > cx + cw) w = cx + cw - x;
302 if (y + h > cy + ch) h = cy + ch - y;
303 if (w <= 0) continue;
304 if (h <= 0) continue;
305
306 boxes[nr].x1 = x;
307 boxes[nr].y1 = y;
308 boxes[nr].x2 = x + w;
309 boxes[nr].y2 = y + h;
310 nr++;
311 }
312 }
313 else {
314 boxes = vmesa->pClipRects;
315 nr = vmesa->numClipRects;
316 }
317
318 if (flag & VIA_FRONT) {
319 viaFillBuffer(vmesa, &vmesa->front, boxes, nr, vmesa->ClearColor,
320 vmesa->ClearMask);
321 }
322
323 if (flag & VIA_BACK) {
324 viaFillBuffer(vmesa, &vmesa->back, boxes, nr, vmesa->ClearColor,
325 vmesa->ClearMask);
326 }
327
328 if (flag & VIA_DEPTH) {
329 viaFillBuffer(vmesa, &vmesa->depth, boxes, nr, clear_depth,
330 clear_depth_mask);
331 }
332
333 viaFlushDmaLocked(vmesa, VIA_NO_CLIPRECTS);
334 UNLOCK_HARDWARE(vmesa);
335
336 if (tmp_boxes)
337 free(tmp_boxes);
338 }
339
340 if (mask)
341 _swrast_Clear(ctx, mask);
342 }
343
344
345
346
347 static void viaDoSwapBuffers(struct via_context *vmesa,
348 drm_clip_rect_t *b,
349 GLuint nbox)
350 {
351 GLuint bytePerPixel = vmesa->viaScreen->bitsPerPixel >> 3;
352 struct via_renderbuffer *front = &vmesa->front;
353 struct via_renderbuffer *back = &vmesa->back;
354 GLuint i;
355
356 for (i = 0; i < nbox; i++, b++) {
357 GLint x = b->x1 - back->drawX;
358 GLint y = b->y1 - back->drawY;
359 GLint w = b->x2 - b->x1;
360 GLint h = b->y2 - b->y1;
361
362 GLuint src = back->offset + y * back->pitch + x * bytePerPixel;
363 GLuint dest = front->offset + y * front->pitch + x * bytePerPixel;
364
365 viaBlit(vmesa,
366 bytePerPixel << 3,
367 src, back->pitch,
368 dest, front->pitch,
369 w, h,
370 VIA_BLIT_COPY, 0, 0);
371 }
372
373 viaFlushDmaLocked(vmesa, VIA_NO_CLIPRECTS); /* redundant */
374 }
375
376
377 static void viaEmitBreadcrumbLocked( struct via_context *vmesa )
378 {
379 struct via_renderbuffer *buffer = &vmesa->breadcrumb;
380 GLuint value = vmesa->lastBreadcrumbWrite + 1;
381
382 if (VIA_DEBUG & DEBUG_IOCTL)
383 fprintf(stderr, "%s %d\n", __FUNCTION__, value);
384
385 assert(!vmesa->dmaLow);
386
387 viaBlit(vmesa,
388 buffer->bpp,
389 buffer->offset, buffer->pitch,
390 buffer->offset, buffer->pitch,
391 1, 1,
392 VIA_BLIT_FILL, value, 0);
393
394 viaFlushDmaLocked(vmesa, VIA_NO_CLIPRECTS); /* often redundant */
395 vmesa->lastBreadcrumbWrite = value;
396 }
397
398 void viaEmitBreadcrumb( struct via_context *vmesa )
399 {
400 LOCK_HARDWARE(vmesa);
401 if (vmesa->dmaLow)
402 viaFlushDmaLocked(vmesa, 0);
403
404 viaEmitBreadcrumbLocked( vmesa );
405 UNLOCK_HARDWARE(vmesa);
406 }
407
408 static GLboolean viaCheckIdle( struct via_context *vmesa )
409 {
410 if ((vmesa->regEngineStatus[0] & 0xFFFEFFFF) == 0x00020000) {
411 return GL_TRUE;
412 }
413 return GL_FALSE;
414 }
415
416
417 GLboolean viaCheckBreadcrumb( struct via_context *vmesa, GLuint value )
418 {
419 GLuint *buf = (GLuint *)vmesa->breadcrumb.map;
420 vmesa->lastBreadcrumbRead = *buf;
421
422 if (VIA_DEBUG & DEBUG_IOCTL)
423 fprintf(stderr, "%s %d < %d: %d\n", __FUNCTION__, value,
424 vmesa->lastBreadcrumbRead,
425 !VIA_GEQ_WRAP(value, vmesa->lastBreadcrumbRead));
426
427 return !VIA_GEQ_WRAP(value, vmesa->lastBreadcrumbRead);
428 }
429
430 static void viaWaitBreadcrumb( struct via_context *vmesa, GLuint value )
431 {
432 if (VIA_DEBUG & DEBUG_IOCTL)
433 fprintf(stderr, "%s %d\n", __FUNCTION__, value);
434
435 assert(!VIA_GEQ_WRAP(value, vmesa->lastBreadcrumbWrite));
436
437 while (!viaCheckBreadcrumb( vmesa, value )) {
438 viaSwapOutWork( vmesa );
439 via_release_pending_textures( vmesa );
440 }
441 }
442
443
444 void viaWaitIdle( struct via_context *vmesa, GLboolean light )
445 {
446 VIA_FLUSH_DMA(vmesa);
447
448 if (VIA_DEBUG & DEBUG_IOCTL)
449 fprintf(stderr, "%s lastDma %d lastBreadcrumbWrite %d\n",
450 __FUNCTION__, vmesa->lastDma, vmesa->lastBreadcrumbWrite);
451
452 /* Need to emit a new breadcrumb?
453 */
454 if (vmesa->lastDma == vmesa->lastBreadcrumbWrite) {
455 LOCK_HARDWARE(vmesa);
456 viaEmitBreadcrumbLocked( vmesa );
457 UNLOCK_HARDWARE(vmesa);
458 }
459
460 /* Need to wait?
461 */
462 if (VIA_GEQ_WRAP(vmesa->lastDma, vmesa->lastBreadcrumbRead))
463 viaWaitBreadcrumb( vmesa, vmesa->lastDma );
464
465 if (light) return;
466
467 LOCK_HARDWARE(vmesa);
468 while(!viaCheckIdle(vmesa))
469 ;
470 UNLOCK_HARDWARE(vmesa);
471 via_release_pending_textures(vmesa);
472 }
473
474
475 void viaWaitIdleLocked( struct via_context *vmesa, GLboolean light )
476 {
477 if (vmesa->dmaLow)
478 viaFlushDmaLocked(vmesa, 0);
479
480 if (VIA_DEBUG & DEBUG_IOCTL)
481 fprintf(stderr, "%s lastDma %d lastBreadcrumbWrite %d\n",
482 __FUNCTION__, vmesa->lastDma, vmesa->lastBreadcrumbWrite);
483
484 /* Need to emit a new breadcrumb?
485 */
486 if (vmesa->lastDma == vmesa->lastBreadcrumbWrite) {
487 viaEmitBreadcrumbLocked( vmesa );
488 }
489
490 /* Need to wait?
491 */
492 if (vmesa->lastDma >= vmesa->lastBreadcrumbRead)
493 viaWaitBreadcrumb( vmesa, vmesa->lastDma );
494
495 if (light) return;
496
497 while(!viaCheckIdle(vmesa))
498 ;
499
500 via_release_pending_textures(vmesa);
501 }
502
503
504
505 /* Wait for command stream to be processed *and* the next vblank to
506 * occur. Equivalent to calling WAIT_IDLE() and then WaitVBlank,
507 * except that WAIT_IDLE() will spin the CPU polling, while this is
508 * IRQ driven.
509 */
510 static void viaWaitIdleVBlank( __DRIdrawablePrivate *dPriv,
511 struct via_context *vmesa,
512 GLuint value )
513 {
514 GLboolean missed_target;
515 __DRIscreenPrivate *psp = dPriv->driScreenPriv;
516
517 VIA_FLUSH_DMA(vmesa);
518
519 if (!value)
520 return;
521
522 do {
523 if (value < vmesa->lastBreadcrumbRead ||
524 vmesa->thrashing)
525 viaSwapOutWork(vmesa);
526
527 driWaitForVBlank( dPriv, & missed_target );
528 if ( missed_target ) {
529 vmesa->swap_missed_count++;
530 (*psp->systemTime->getUST)( &vmesa->swap_missed_ust );
531 }
532 }
533 while (!viaCheckBreadcrumb(vmesa, value));
534
535 vmesa->thrashing = 0; /* reset flag on swap */
536 vmesa->swap_count++;
537 via_release_pending_textures( vmesa );
538 }
539
540
541
542 static void viaDoPageFlipLocked(struct via_context *vmesa, GLuint offset)
543 {
544 RING_VARS;
545
546 if (VIA_DEBUG & DEBUG_2D)
547 fprintf(stderr, "%s %x\n", __FUNCTION__, offset);
548
549 if (!vmesa->nDoneFirstFlip) {
550 vmesa->nDoneFirstFlip = GL_TRUE;
551 BEGIN_RING(4);
552 OUT_RING(HALCYON_HEADER2);
553 OUT_RING(0x00fe0000);
554 OUT_RING(0x0000000e);
555 OUT_RING(0x0000000e);
556 ADVANCE_RING();
557 }
558
559 BEGIN_RING(4);
560 OUT_RING( HALCYON_HEADER2 );
561 OUT_RING( 0x00fe0000 );
562 OUT_RING((HC_SubA_HFBBasL << 24) | (offset & 0xFFFFF8) | 0x2);
563 OUT_RING((HC_SubA_HFBDrawFirst << 24) |
564 ((offset & 0xFF000000) >> 24) | 0x0100);
565 ADVANCE_RING();
566
567 vmesa->pfCurrentOffset = vmesa->sarea->pfCurrentOffset = offset;
568
569 viaFlushDmaLocked(vmesa, VIA_NO_CLIPRECTS); /* often redundant */
570 }
571
572 void viaResetPageFlippingLocked(struct via_context *vmesa)
573 {
574 if (VIA_DEBUG & DEBUG_2D)
575 fprintf(stderr, "%s\n", __FUNCTION__);
576
577 viaDoPageFlipLocked( vmesa, 0 );
578
579 if (vmesa->front.offset != 0) {
580 struct via_renderbuffer buffer_tmp;
581 memcpy(&buffer_tmp, &vmesa->back, sizeof(struct via_renderbuffer));
582 memcpy(&vmesa->back, &vmesa->front, sizeof(struct via_renderbuffer));
583 memcpy(&vmesa->front, &buffer_tmp, sizeof(struct via_renderbuffer));
584 }
585
586 assert(vmesa->front.offset == 0);
587 vmesa->doPageFlip = vmesa->allowPageFlip = 0;
588 }
589
590
591 /*
592 * Copy the back buffer to the front buffer.
593 */
594 void viaCopyBuffer(__DRIdrawablePrivate *dPriv)
595 {
596 struct via_context *vmesa =
597 (struct via_context *)dPriv->driContextPriv->driverPrivate;
598 __DRIscreenPrivate *psp = dPriv->driScreenPriv;
599
600 if (VIA_DEBUG & DEBUG_IOCTL)
601 fprintf(stderr,
602 "%s: lastSwap[1] %d lastSwap[0] %d lastWrite %d lastRead %d\n",
603 __FUNCTION__,
604 vmesa->lastSwap[1],
605 vmesa->lastSwap[0],
606 vmesa->lastBreadcrumbWrite,
607 vmesa->lastBreadcrumbRead);
608
609 VIA_FLUSH_DMA(vmesa);
610
611 if (dPriv->vblFlags == VBLANK_FLAG_SYNC &&
612 vmesa->lastBreadcrumbWrite > 1)
613 viaWaitIdleVBlank(dPriv, vmesa, vmesa->lastBreadcrumbWrite-1);
614 else
615 viaWaitIdleVBlank(dPriv, vmesa, vmesa->lastSwap[1]);
616
617 LOCK_HARDWARE(vmesa);
618
619 /* Catch and cleanup situation where we were pageflipping but have
620 * stopped.
621 */
622 if (dPriv->numClipRects && vmesa->sarea->pfCurrentOffset != 0) {
623 viaResetPageFlippingLocked(vmesa);
624 UNLOCK_HARDWARE(vmesa);
625 return;
626 }
627
628 viaDoSwapBuffers(vmesa, dPriv->pClipRects, dPriv->numClipRects);
629 vmesa->lastSwap[1] = vmesa->lastSwap[0];
630 vmesa->lastSwap[0] = vmesa->lastBreadcrumbWrite;
631 viaEmitBreadcrumbLocked(vmesa);
632 UNLOCK_HARDWARE(vmesa);
633
634 (*psp->systemTime->getUST)( &vmesa->swap_ust );
635 }
636
637
638 void viaPageFlip(__DRIdrawablePrivate *dPriv)
639 {
640 struct via_context *vmesa =
641 (struct via_context *)dPriv->driContextPriv->driverPrivate;
642 struct via_renderbuffer buffer_tmp;
643 __DRIscreenPrivate *psp = dPriv->driScreenPriv;
644
645 VIA_FLUSH_DMA(vmesa);
646 if (dPriv->vblFlags == VBLANK_FLAG_SYNC &&
647 vmesa->lastBreadcrumbWrite > 1)
648 viaWaitIdleVBlank(dPriv, vmesa, vmesa->lastBreadcrumbWrite - 1);
649 else
650 viaWaitIdleVBlank(dPriv, vmesa, vmesa->lastSwap[0]);
651
652 LOCK_HARDWARE(vmesa);
653 viaDoPageFlipLocked(vmesa, vmesa->back.offset);
654 vmesa->lastSwap[1] = vmesa->lastSwap[0];
655 vmesa->lastSwap[0] = vmesa->lastBreadcrumbWrite;
656 viaEmitBreadcrumbLocked(vmesa);
657 UNLOCK_HARDWARE(vmesa);
658
659 (*psp->systemTime->getUST)( &vmesa->swap_ust );
660
661
662 /* KW: FIXME: When buffers are freed, could free frontbuffer by
663 * accident:
664 */
665 memcpy(&buffer_tmp, &vmesa->back, sizeof(struct via_renderbuffer));
666 memcpy(&vmesa->back, &vmesa->front, sizeof(struct via_renderbuffer));
667 memcpy(&vmesa->front, &buffer_tmp, sizeof(struct via_renderbuffer));
668 }
669
670
671
672
673 #define VIA_CMDBUF_MAX_LAG 50000
674
675 static int fire_buffer(struct via_context *vmesa)
676 {
677 drm_via_cmdbuffer_t bufI;
678 int ret;
679
680 bufI.buf = (char *)vmesa->dma;
681 bufI.size = vmesa->dmaLow;
682
683 if (vmesa->useAgp) {
684 drm_via_cmdbuf_size_t bSiz;
685
686 /* Do the CMDBUF_SIZE ioctl:
687 */
688 bSiz.func = VIA_CMDBUF_LAG;
689 bSiz.wait = 1;
690 bSiz.size = VIA_CMDBUF_MAX_LAG;
691 do {
692 ret = drmCommandWriteRead(vmesa->driFd, DRM_VIA_CMDBUF_SIZE,
693 &bSiz, sizeof(bSiz));
694 } while (ret == -EAGAIN);
695 if (ret) {
696 UNLOCK_HARDWARE(vmesa);
697 fprintf(stderr, "%s: DRM_VIA_CMDBUF_SIZE returned %d\n",
698 __FUNCTION__, ret);
699 abort();
700 return ret;
701 }
702
703 /* Actually fire the buffer:
704 */
705 do {
706 ret = drmCommandWrite(vmesa->driFd, DRM_VIA_CMDBUFFER,
707 &bufI, sizeof(bufI));
708 } while (ret == -EAGAIN);
709 if (ret) {
710 UNLOCK_HARDWARE(vmesa);
711 fprintf(stderr, "%s: DRM_VIA_CMDBUFFER returned %d\n",
712 __FUNCTION__, ret);
713 abort();
714 /* If this fails, the original code fell back to the PCI path.
715 */
716 }
717 else
718 return 0;
719
720 /* Fall through to PCI handling?!?
721 */
722 viaWaitIdleLocked(vmesa, GL_FALSE);
723 }
724
725 ret = drmCommandWrite(vmesa->driFd, DRM_VIA_PCICMD, &bufI, sizeof(bufI));
726 if (ret) {
727 UNLOCK_HARDWARE(vmesa);
728 dump_dma(vmesa);
729 fprintf(stderr, "%s: DRM_VIA_PCICMD returned %d\n", __FUNCTION__, ret);
730 abort();
731 }
732
733 return ret;
734 }
735
736
737 /* Inserts the surface addresss and active cliprects one at a time
738 * into the head of the DMA buffer being flushed. Fires the buffer
739 * for each cliprect.
740 */
741 static void via_emit_cliprect(struct via_context *vmesa,
742 drm_clip_rect_t *b)
743 {
744 struct via_renderbuffer *buffer = vmesa->drawBuffer;
745 GLuint *vb = (GLuint *)(vmesa->dma + vmesa->dmaCliprectAddr);
746
747 GLuint format = (vmesa->viaScreen->bitsPerPixel == 0x20
748 ? HC_HDBFM_ARGB8888
749 : HC_HDBFM_RGB565);
750
751 GLuint pitch = buffer->pitch;
752 GLuint offset = buffer->offset;
753
754 if (0)
755 fprintf(stderr, "emit cliprect for box %d,%d %d,%d\n",
756 b->x1, b->y1, b->x2, b->y2);
757
758 vb[0] = HC_HEADER2;
759 vb[1] = (HC_ParaType_NotTex << 16);
760
761 if (vmesa->driDrawable->w == 0 || vmesa->driDrawable->h == 0) {
762 vb[2] = (HC_SubA_HClipTB << 24) | 0x0;
763 vb[3] = (HC_SubA_HClipLR << 24) | 0x0;
764 }
765 else {
766 vb[2] = (HC_SubA_HClipTB << 24) | (b->y1 << 12) | b->y2;
767 vb[3] = (HC_SubA_HClipLR << 24) | (b->x1 << 12) | b->x2;
768 }
769
770 vb[4] = (HC_SubA_HDBBasL << 24) | (offset & 0xFFFFFF);
771 vb[5] = (HC_SubA_HDBBasH << 24) | ((offset & 0xFF000000) >> 24);
772
773 vb[6] = (HC_SubA_HSPXYOS << 24);
774 vb[7] = (HC_SubA_HDBFM << 24) | HC_HDBLoc_Local | format | pitch;
775 }
776
777
778
779 static int intersect_rect(drm_clip_rect_t *out,
780 drm_clip_rect_t *a,
781 drm_clip_rect_t *b)
782 {
783 *out = *a;
784
785 if (0)
786 fprintf(stderr, "intersect %d,%d %d,%d and %d,%d %d,%d\n",
787 a->x1, a->y1, a->x2, a->y2,
788 b->x1, b->y1, b->x2, b->y2);
789
790 if (b->x1 > out->x1) out->x1 = b->x1;
791 if (b->x2 < out->x2) out->x2 = b->x2;
792 if (out->x1 >= out->x2) return 0;
793
794 if (b->y1 > out->y1) out->y1 = b->y1;
795 if (b->y2 < out->y2) out->y2 = b->y2;
796 if (out->y1 >= out->y2) return 0;
797
798 return 1;
799 }
800
801 void viaFlushDmaLocked(struct via_context *vmesa, GLuint flags)
802 {
803 int i;
804 RING_VARS;
805
806 if (VIA_DEBUG & (DEBUG_IOCTL|DEBUG_DMA))
807 fprintf(stderr, "%s\n", __FUNCTION__);
808
809 if (*(GLuint *)vmesa->driHwLock != (DRM_LOCK_HELD|vmesa->hHWContext) &&
810 *(GLuint *)vmesa->driHwLock !=
811 (DRM_LOCK_HELD|DRM_LOCK_CONT|vmesa->hHWContext)) {
812 fprintf(stderr, "%s called without lock held\n", __FUNCTION__);
813 abort();
814 }
815
816 if (vmesa->dmaLow == 0) {
817 return;
818 }
819
820 assert(vmesa->dmaLastPrim == 0);
821
822 /* viaFinishPrimitive can add up to 8 bytes beyond VIA_DMA_HIGHWATER:
823 */
824 if (vmesa->dmaLow > VIA_DMA_HIGHWATER + 8) {
825 fprintf(stderr, "buffer overflow in Flush Prims = %d\n",vmesa->dmaLow);
826 abort();
827 }
828
829 switch (vmesa->dmaLow & 0x1F) {
830 case 8:
831 BEGIN_RING_NOCHECK( 6 );
832 OUT_RING( HC_HEADER2 );
833 OUT_RING( (HC_ParaType_NotTex << 16) );
834 OUT_RING( HC_DUMMY );
835 OUT_RING( HC_DUMMY );
836 OUT_RING( HC_DUMMY );
837 OUT_RING( HC_DUMMY );
838 ADVANCE_RING();
839 break;
840 case 16:
841 BEGIN_RING_NOCHECK( 4 );
842 OUT_RING( HC_HEADER2 );
843 OUT_RING( (HC_ParaType_NotTex << 16) );
844 OUT_RING( HC_DUMMY );
845 OUT_RING( HC_DUMMY );
846 ADVANCE_RING();
847 break;
848 case 24:
849 BEGIN_RING_NOCHECK( 10 );
850 OUT_RING( HC_HEADER2 );
851 OUT_RING( (HC_ParaType_NotTex << 16) );
852 OUT_RING( HC_DUMMY );
853 OUT_RING( HC_DUMMY );
854 OUT_RING( HC_DUMMY );
855 OUT_RING( HC_DUMMY );
856 OUT_RING( HC_DUMMY );
857 OUT_RING( HC_DUMMY );
858 OUT_RING( HC_DUMMY );
859 OUT_RING( HC_DUMMY );
860 ADVANCE_RING();
861 break;
862 case 0:
863 break;
864 default:
865 if (VIA_DEBUG & DEBUG_IOCTL)
866 fprintf(stderr, "%s: unaligned value for vmesa->dmaLow: %x\n",
867 __FUNCTION__, vmesa->dmaLow);
868 }
869
870 vmesa->lastDma = vmesa->lastBreadcrumbWrite;
871
872 if (VIA_DEBUG & DEBUG_DMA)
873 dump_dma( vmesa );
874
875 if (flags & VIA_NO_CLIPRECTS) {
876 if (0) fprintf(stderr, "%s VIA_NO_CLIPRECTS\n", __FUNCTION__);
877 assert(vmesa->dmaCliprectAddr == ~0);
878 fire_buffer( vmesa );
879 }
880 else if (vmesa->dmaCliprectAddr == ~0) {
881 /* Contains only state. Could just dump the packet?
882 */
883 if (0) fprintf(stderr, "%s: no dmaCliprectAddr\n", __FUNCTION__);
884 if (0) fire_buffer( vmesa );
885 }
886 else if (vmesa->numClipRects) {
887 drm_clip_rect_t *pbox = vmesa->pClipRects;
888 __DRIdrawablePrivate *dPriv = vmesa->driDrawable;
889
890 for (i = 0; i < vmesa->numClipRects; i++) {
891 drm_clip_rect_t b;
892
893 b.x1 = pbox[i].x1;
894 b.x2 = pbox[i].x2;
895 b.y1 = pbox[i].y1;
896 b.y2 = pbox[i].y2;
897
898 if (vmesa->scissor &&
899 !intersect_rect(&b, &b, &vmesa->scissorRect))
900 continue;
901
902 via_emit_cliprect(vmesa, &b);
903
904 if (fire_buffer(vmesa) != 0) {
905 dump_dma( vmesa );
906 goto done;
907 }
908 }
909 } else {
910 if (0) fprintf(stderr, "%s: no cliprects\n", __FUNCTION__);
911 UNLOCK_HARDWARE(vmesa);
912 sched_yield();
913 LOCK_HARDWARE(vmesa);
914 }
915
916 done:
917 /* Reset vmesa vars:
918 */
919 vmesa->dmaLow = 0;
920 vmesa->dmaCliprectAddr = ~0;
921 vmesa->newEmitState = ~0;
922 }
923
924 void viaWrapPrimitive( struct via_context *vmesa )
925 {
926 GLenum renderPrimitive = vmesa->renderPrimitive;
927 GLenum hwPrimitive = vmesa->hwPrimitive;
928
929 if (VIA_DEBUG & DEBUG_PRIMS) fprintf(stderr, "%s\n", __FUNCTION__);
930
931 if (vmesa->dmaLastPrim)
932 viaFinishPrimitive( vmesa );
933
934 viaFlushDma(vmesa);
935
936 if (renderPrimitive != GL_POLYGON + 1)
937 viaRasterPrimitive( vmesa->glCtx,
938 renderPrimitive,
939 hwPrimitive );
940
941 }
942
943 void viaFlushDma(struct via_context *vmesa)
944 {
945 if (vmesa->dmaLow) {
946 assert(!vmesa->dmaLastPrim);
947
948 LOCK_HARDWARE(vmesa);
949 viaFlushDmaLocked(vmesa, 0);
950 UNLOCK_HARDWARE(vmesa);
951 }
952 }
953
954 static void viaFlush(GLcontext *ctx)
955 {
956 struct via_context *vmesa = VIA_CONTEXT(ctx);
957 VIA_FLUSH_DMA(vmesa);
958 }
959
960 static void viaFinish(GLcontext *ctx)
961 {
962 struct via_context *vmesa = VIA_CONTEXT(ctx);
963 VIA_FLUSH_DMA(vmesa);
964 viaWaitIdle(vmesa, GL_FALSE);
965 }
966
967 static void viaClearStencil(GLcontext *ctx, int s)
968 {
969 return;
970 }
971
972 void viaInitIoctlFuncs(GLcontext *ctx)
973 {
974 ctx->Driver.Flush = viaFlush;
975 ctx->Driver.Clear = viaClear;
976 ctx->Driver.Finish = viaFinish;
977 ctx->Driver.ClearStencil = viaClearStencil;
978 }
979
980
981