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