Bring in last minute 6_4 branch changes to the unichrome driver
[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 "glheader.h"
28 #include "mtypes.h"
29 #include "macros.h"
30 #include "dd.h"
31 #include "swrast/swrast.h"
32
33 #include "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 - vmesa->drawX;
186 int y = pbox[i].y1 - vmesa->drawY;
187 int w = pbox[i].x2 - pbox[i].x1;
188 int h = pbox[i].y2 - pbox[i].y1;
189
190 int offset = (buffer->orig +
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, GLboolean all,
206 GLint cx, GLint cy, GLint cw, GLint ch)
207 {
208 struct via_context *vmesa = VIA_CONTEXT(ctx);
209 __DRIdrawablePrivate *dPriv = vmesa->driDrawable;
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) {
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
265 LOCK_HARDWARE(vmesa);
266
267 /* flip top to bottom */
268 cy = dPriv->h - cy - ch;
269 cx += vmesa->drawX + vmesa->drawXoff;
270 cy += vmesa->drawY;
271
272 if (!all) {
273 drm_clip_rect_t *b = vmesa->pClipRects;
274
275 boxes = tmp_boxes =
276 (drm_clip_rect_t *)malloc(vmesa->numClipRects *
277 sizeof(drm_clip_rect_t));
278 if (!boxes) {
279 UNLOCK_HARDWARE(vmesa);
280 return;
281 }
282
283 for (; i < vmesa->numClipRects; i++) {
284 GLint x = b[i].x1;
285 GLint y = b[i].y1;
286 GLint w = b[i].x2 - x;
287 GLint h = b[i].y2 - y;
288
289 if (x < cx) w -= cx - x, x = cx;
290 if (y < cy) h -= cy - y, y = cy;
291 if (x + w > cx + cw) w = cx + cw - x;
292 if (y + h > cy + ch) h = cy + ch - y;
293 if (w <= 0) continue;
294 if (h <= 0) continue;
295
296 boxes[nr].x1 = x;
297 boxes[nr].y1 = y;
298 boxes[nr].x2 = x + w;
299 boxes[nr].y2 = y + h;
300 nr++;
301 }
302 }
303 else {
304 boxes = vmesa->pClipRects;
305 nr = vmesa->numClipRects;
306 }
307
308 if (flag & VIA_FRONT) {
309 viaFillBuffer(vmesa, &vmesa->front, boxes, nr, vmesa->ClearColor,
310 vmesa->ClearMask);
311 }
312
313 if (flag & VIA_BACK) {
314 viaFillBuffer(vmesa, &vmesa->back, boxes, nr, vmesa->ClearColor,
315 vmesa->ClearMask);
316 }
317
318 if (flag & VIA_DEPTH) {
319 viaFillBuffer(vmesa, &vmesa->depth, boxes, nr, clear_depth,
320 clear_depth_mask);
321 }
322
323 viaFlushDmaLocked(vmesa, VIA_NO_CLIPRECTS);
324 UNLOCK_HARDWARE(vmesa);
325
326 if (tmp_boxes)
327 free(tmp_boxes);
328 }
329
330 if (mask)
331 _swrast_Clear(ctx, mask, all, cx, cy, cw, ch);
332 }
333
334
335
336
337 static void viaDoSwapBuffers(struct via_context *vmesa,
338 drm_clip_rect_t *b,
339 GLuint nbox)
340 {
341 GLuint bytePerPixel = vmesa->viaScreen->bitsPerPixel >> 3;
342 struct via_renderbuffer *front = &vmesa->front;
343 struct via_renderbuffer *back = &vmesa->back;
344 GLuint i;
345
346 for (i = 0; i < nbox; i++, b++) {
347 GLint x = b->x1 - vmesa->drawX;
348 GLint y = b->y1 - vmesa->drawY;
349 GLint w = b->x2 - b->x1;
350 GLint h = b->y2 - b->y1;
351
352 GLuint src = back->orig + y * back->pitch + x * bytePerPixel;
353 GLuint dest = front->orig + y * front->pitch + x * bytePerPixel;
354
355 viaBlit(vmesa,
356 bytePerPixel << 3,
357 src, back->pitch,
358 dest, front->pitch,
359 w, h,
360 VIA_BLIT_COPY, 0, 0);
361 }
362
363 viaFlushDmaLocked(vmesa, VIA_NO_CLIPRECTS); /* redundant */
364 }
365
366
367 static void viaEmitBreadcrumbLocked( struct via_context *vmesa )
368 {
369 struct via_renderbuffer *buffer = &vmesa->breadcrumb;
370 GLuint value = vmesa->lastBreadcrumbWrite + 1;
371
372 if (VIA_DEBUG & DEBUG_IOCTL)
373 fprintf(stderr, "%s %d\n", __FUNCTION__, value);
374
375 assert(!vmesa->dmaLow);
376
377 viaBlit(vmesa,
378 buffer->bpp,
379 buffer->offset, buffer->pitch,
380 buffer->offset, buffer->pitch,
381 1, 1,
382 VIA_BLIT_FILL, value, 0);
383
384 viaFlushDmaLocked(vmesa, VIA_NO_CLIPRECTS); /* often redundant */
385 vmesa->lastBreadcrumbWrite = value;
386 }
387
388 void viaEmitBreadcrumb( struct via_context *vmesa )
389 {
390 LOCK_HARDWARE(vmesa);
391 if (vmesa->dmaLow)
392 viaFlushDmaLocked(vmesa, 0);
393
394 viaEmitBreadcrumbLocked( vmesa );
395 UNLOCK_HARDWARE(vmesa);
396 }
397
398 static GLboolean viaCheckIdle( struct via_context *vmesa )
399 {
400 if ((vmesa->regEngineStatus[0] & 0xFFFEFFFF) == 0x00020000) {
401 return GL_TRUE;
402 }
403 return GL_FALSE;
404 }
405
406
407 GLboolean viaCheckBreadcrumb( struct via_context *vmesa, GLuint value )
408 {
409 GLuint *buf = (GLuint *)vmesa->breadcrumb.map;
410 vmesa->lastBreadcrumbRead = *buf;
411
412 if (VIA_DEBUG & DEBUG_IOCTL)
413 fprintf(stderr, "%s %d < %d: %d\n", __FUNCTION__, value,
414 vmesa->lastBreadcrumbRead,
415 !VIA_GEQ_WRAP(value, vmesa->lastBreadcrumbRead));
416
417 return !VIA_GEQ_WRAP(value, vmesa->lastBreadcrumbRead);
418 }
419
420 static void viaWaitBreadcrumb( struct via_context *vmesa, GLuint value )
421 {
422 if (VIA_DEBUG & DEBUG_IOCTL)
423 fprintf(stderr, "%s %d\n", __FUNCTION__, value);
424
425 assert(!VIA_GEQ_WRAP(value, vmesa->lastBreadcrumbWrite));
426
427 while (!viaCheckBreadcrumb( vmesa, value )) {
428 viaSwapOutWork( vmesa );
429 via_release_pending_textures( vmesa );
430 }
431 }
432
433
434 void viaWaitIdle( struct via_context *vmesa, GLboolean light )
435 {
436 VIA_FLUSH_DMA(vmesa);
437
438 if (VIA_DEBUG & DEBUG_IOCTL)
439 fprintf(stderr, "%s lastDma %d lastBreadcrumbWrite %d\n",
440 __FUNCTION__, vmesa->lastDma, vmesa->lastBreadcrumbWrite);
441
442 /* Need to emit a new breadcrumb?
443 */
444 if (vmesa->lastDma == vmesa->lastBreadcrumbWrite) {
445 LOCK_HARDWARE(vmesa);
446 viaEmitBreadcrumbLocked( vmesa );
447 UNLOCK_HARDWARE(vmesa);
448 }
449
450 /* Need to wait?
451 */
452 if (VIA_GEQ_WRAP(vmesa->lastDma, vmesa->lastBreadcrumbRead))
453 viaWaitBreadcrumb( vmesa, vmesa->lastDma );
454
455 if (light) return;
456
457 LOCK_HARDWARE(vmesa);
458 while(!viaCheckIdle(vmesa))
459 ;
460 UNLOCK_HARDWARE(vmesa);
461 via_release_pending_textures(vmesa);
462 }
463
464
465 void viaWaitIdleLocked( struct via_context *vmesa, GLboolean light )
466 {
467 if (vmesa->dmaLow)
468 viaFlushDmaLocked(vmesa, 0);
469
470 if (VIA_DEBUG & DEBUG_IOCTL)
471 fprintf(stderr, "%s lastDma %d lastBreadcrumbWrite %d\n",
472 __FUNCTION__, vmesa->lastDma, vmesa->lastBreadcrumbWrite);
473
474 /* Need to emit a new breadcrumb?
475 */
476 if (vmesa->lastDma == vmesa->lastBreadcrumbWrite) {
477 viaEmitBreadcrumbLocked( vmesa );
478 }
479
480 /* Need to wait?
481 */
482 if (vmesa->lastDma >= vmesa->lastBreadcrumbRead)
483 viaWaitBreadcrumb( vmesa, vmesa->lastDma );
484
485 if (light) return;
486
487 while(!viaCheckIdle(vmesa))
488 ;
489
490 via_release_pending_textures(vmesa);
491 }
492
493
494
495 /* Wait for command stream to be processed *and* the next vblank to
496 * occur. Equivalent to calling WAIT_IDLE() and then WaitVBlank,
497 * except that WAIT_IDLE() will spin the CPU polling, while this is
498 * IRQ driven.
499 */
500 static void viaWaitIdleVBlank( const __DRIdrawablePrivate *dPriv,
501 struct via_context *vmesa,
502 GLuint value )
503 {
504 GLboolean missed_target;
505
506 VIA_FLUSH_DMA(vmesa);
507
508 if (!value)
509 return;
510
511 do {
512 if (value < vmesa->lastBreadcrumbRead ||
513 vmesa->thrashing)
514 viaSwapOutWork(vmesa);
515
516 driWaitForVBlank( dPriv, & vmesa->vbl_seq,
517 vmesa->vblank_flags, & missed_target );
518 if ( missed_target ) {
519 vmesa->swap_missed_count++;
520 (*dri_interface->getUST)( &vmesa->swap_missed_ust );
521 }
522 }
523 while (!viaCheckBreadcrumb(vmesa, value));
524
525 vmesa->thrashing = 0; /* reset flag on swap */
526 vmesa->swap_count++;
527 via_release_pending_textures( vmesa );
528 }
529
530
531
532 static void viaDoPageFlipLocked(struct via_context *vmesa, GLuint offset)
533 {
534 RING_VARS;
535
536 if (VIA_DEBUG & DEBUG_2D)
537 fprintf(stderr, "%s %x\n", __FUNCTION__, offset);
538
539 if (!vmesa->nDoneFirstFlip) {
540 vmesa->nDoneFirstFlip = GL_TRUE;
541 BEGIN_RING(4);
542 OUT_RING(HALCYON_HEADER2);
543 OUT_RING(0x00fe0000);
544 OUT_RING(0x0000000e);
545 OUT_RING(0x0000000e);
546 ADVANCE_RING();
547 }
548
549 BEGIN_RING(4);
550 OUT_RING( HALCYON_HEADER2 );
551 OUT_RING( 0x00fe0000 );
552 OUT_RING((HC_SubA_HFBBasL << 24) | (offset & 0xFFFFF8) | 0x2);
553 OUT_RING((HC_SubA_HFBDrawFirst << 24) |
554 ((offset & 0xFF000000) >> 24) | 0x0100);
555 ADVANCE_RING();
556
557 vmesa->pfCurrentOffset = vmesa->sarea->pfCurrentOffset = offset;
558
559 viaFlushDmaLocked(vmesa, VIA_NO_CLIPRECTS); /* often redundant */
560 }
561
562 void viaResetPageFlippingLocked(struct via_context *vmesa)
563 {
564 if (VIA_DEBUG & DEBUG_2D)
565 fprintf(stderr, "%s\n", __FUNCTION__);
566
567 viaDoPageFlipLocked( vmesa, 0 );
568
569 if (vmesa->front.offset != 0) {
570 struct via_renderbuffer buffer_tmp;
571 memcpy(&buffer_tmp, &vmesa->back, sizeof(struct via_renderbuffer));
572 memcpy(&vmesa->back, &vmesa->front, sizeof(struct via_renderbuffer));
573 memcpy(&vmesa->front, &buffer_tmp, sizeof(struct via_renderbuffer));
574 }
575
576 assert(vmesa->front.offset == 0);
577 vmesa->doPageFlip = vmesa->allowPageFlip = 0;
578 }
579
580
581 /*
582 * Copy the back buffer to the front buffer.
583 */
584 void viaCopyBuffer(const __DRIdrawablePrivate *dPriv)
585 {
586 struct via_context *vmesa =
587 (struct via_context *)dPriv->driContextPriv->driverPrivate;
588
589 if (VIA_DEBUG & DEBUG_IOCTL)
590 fprintf(stderr,
591 "%s: lastSwap[1] %d lastSwap[0] %d lastWrite %d lastRead %d\n",
592 __FUNCTION__,
593 vmesa->lastSwap[1],
594 vmesa->lastSwap[0],
595 vmesa->lastBreadcrumbWrite,
596 vmesa->lastBreadcrumbRead);
597
598 VIA_FLUSH_DMA(vmesa);
599
600 if (vmesa->vblank_flags == VBLANK_FLAG_SYNC &&
601 vmesa->lastBreadcrumbWrite > 1)
602 viaWaitIdleVBlank(dPriv, vmesa, vmesa->lastBreadcrumbWrite-1);
603 else
604 viaWaitIdleVBlank(dPriv, vmesa, vmesa->lastSwap[1]);
605
606 LOCK_HARDWARE(vmesa);
607
608 /* Catch and cleanup situation where we were pageflipping but have
609 * stopped.
610 */
611 if (dPriv->numClipRects && vmesa->sarea->pfCurrentOffset != 0) {
612 viaResetPageFlippingLocked(vmesa);
613 UNLOCK_HARDWARE(vmesa);
614 return;
615 }
616
617 viaDoSwapBuffers(vmesa, dPriv->pClipRects, dPriv->numClipRects);
618 vmesa->lastSwap[1] = vmesa->lastSwap[0];
619 vmesa->lastSwap[0] = vmesa->lastBreadcrumbWrite;
620 viaEmitBreadcrumbLocked(vmesa);
621 UNLOCK_HARDWARE(vmesa);
622
623 (*dri_interface->getUST)( &vmesa->swap_ust );
624 }
625
626
627 void viaPageFlip(const __DRIdrawablePrivate *dPriv)
628 {
629 struct via_context *vmesa =
630 (struct via_context *)dPriv->driContextPriv->driverPrivate;
631 struct via_renderbuffer buffer_tmp;
632
633 VIA_FLUSH_DMA(vmesa);
634 if (vmesa->vblank_flags == VBLANK_FLAG_SYNC &&
635 vmesa->lastBreadcrumbWrite > 1)
636 viaWaitIdleVBlank(dPriv, vmesa, vmesa->lastBreadcrumbWrite - 1);
637 else
638 viaWaitIdleVBlank(dPriv, vmesa, vmesa->lastSwap[0]);
639
640 LOCK_HARDWARE(vmesa);
641 viaDoPageFlipLocked(vmesa, vmesa->back.offset);
642 vmesa->lastSwap[1] = vmesa->lastSwap[0];
643 vmesa->lastSwap[0] = vmesa->lastBreadcrumbWrite;
644 viaEmitBreadcrumbLocked(vmesa);
645 UNLOCK_HARDWARE(vmesa);
646
647 (*dri_interface->getUST)( &vmesa->swap_ust );
648
649
650 /* KW: FIXME: When buffers are freed, could free frontbuffer by
651 * accident:
652 */
653 memcpy(&buffer_tmp, &vmesa->back, sizeof(struct via_renderbuffer));
654 memcpy(&vmesa->back, &vmesa->front, sizeof(struct via_renderbuffer));
655 memcpy(&vmesa->front, &buffer_tmp, sizeof(struct via_renderbuffer));
656 }
657
658
659
660
661 #define VIA_CMDBUF_MAX_LAG 50000
662
663 static int fire_buffer(struct via_context *vmesa)
664 {
665 drm_via_cmdbuffer_t bufI;
666 int ret;
667
668 bufI.buf = (char *)vmesa->dma;
669 bufI.size = vmesa->dmaLow;
670
671 if (vmesa->useAgp) {
672 drm_via_cmdbuf_size_t bSiz;
673
674 /* Do the CMDBUF_SIZE ioctl:
675 */
676 bSiz.func = VIA_CMDBUF_LAG;
677 bSiz.wait = 1;
678 bSiz.size = VIA_CMDBUF_MAX_LAG;
679 do {
680 ret = drmCommandWriteRead(vmesa->driFd, DRM_VIA_CMDBUF_SIZE,
681 &bSiz, sizeof(bSiz));
682 } while (ret == -EAGAIN);
683 if (ret) {
684 UNLOCK_HARDWARE(vmesa);
685 fprintf(stderr, "%s: DRM_VIA_CMDBUF_SIZE returned %d\n",
686 __FUNCTION__, ret);
687 abort();
688 return ret;
689 }
690
691 /* Actually fire the buffer:
692 */
693 do {
694 ret = drmCommandWrite(vmesa->driFd, DRM_VIA_CMDBUFFER,
695 &bufI, sizeof(bufI));
696 } while (ret == -EAGAIN);
697 if (ret) {
698 UNLOCK_HARDWARE(vmesa);
699 fprintf(stderr, "%s: DRM_VIA_CMDBUFFER returned %d\n",
700 __FUNCTION__, ret);
701 abort();
702 /* If this fails, the original code fell back to the PCI path.
703 */
704 }
705 else
706 return 0;
707
708 /* Fall through to PCI handling?!?
709 */
710 viaWaitIdleLocked(vmesa, GL_FALSE);
711 }
712
713 ret = drmCommandWrite(vmesa->driFd, DRM_VIA_PCICMD, &bufI, sizeof(bufI));
714 if (ret) {
715 UNLOCK_HARDWARE(vmesa);
716 dump_dma(vmesa);
717 fprintf(stderr, "%s: DRM_VIA_PCICMD returned %d\n", __FUNCTION__, ret);
718 abort();
719 }
720
721 return ret;
722 }
723
724
725 /* Inserts the surface addresss and active cliprects one at a time
726 * into the head of the DMA buffer being flushed. Fires the buffer
727 * for each cliprect.
728 */
729 static void via_emit_cliprect(struct via_context *vmesa,
730 drm_clip_rect_t *b)
731 {
732 struct via_renderbuffer *buffer = vmesa->drawBuffer;
733 GLuint *vb = (GLuint *)(vmesa->dma + vmesa->dmaCliprectAddr);
734
735 GLuint format = (vmesa->viaScreen->bitsPerPixel == 0x20
736 ? HC_HDBFM_ARGB8888
737 : HC_HDBFM_RGB565);
738
739 GLuint pitch = buffer->pitch;
740 GLuint offset = buffer->orig;
741
742 if (0)
743 fprintf(stderr, "emit cliprect for box %d,%d %d,%d\n",
744 b->x1, b->y1, b->x2, b->y2);
745
746 vb[0] = HC_HEADER2;
747 vb[1] = (HC_ParaType_NotTex << 16);
748
749 if (vmesa->driDrawable->w == 0 || vmesa->driDrawable->h == 0) {
750 vb[2] = (HC_SubA_HClipTB << 24) | 0x0;
751 vb[3] = (HC_SubA_HClipLR << 24) | 0x0;
752 }
753 else {
754 vb[2] = (HC_SubA_HClipTB << 24) | (b->y1 << 12) | b->y2;
755 vb[3] = (HC_SubA_HClipLR << 24) | (b->x1 << 12) | b->x2;
756 }
757
758 vb[4] = (HC_SubA_HDBBasL << 24) | (offset & 0xFFFFFF);
759 vb[5] = (HC_SubA_HDBBasH << 24) | ((offset & 0xFF000000) >> 24);
760
761 vb[6] = (HC_SubA_HSPXYOS << 24) | ((31-vmesa->drawXoff) << HC_HSPXOS_SHIFT);
762 vb[7] = (HC_SubA_HDBFM << 24) | HC_HDBLoc_Local | format | pitch;
763 }
764
765
766
767 static int intersect_rect(drm_clip_rect_t *out,
768 drm_clip_rect_t *a,
769 drm_clip_rect_t *b)
770 {
771 *out = *a;
772
773 if (0)
774 fprintf(stderr, "intersect %d,%d %d,%d and %d,%d %d,%d\n",
775 a->x1, a->y1, a->x2, a->y2,
776 b->x1, b->y1, b->x2, b->y2);
777
778 if (b->x1 > out->x1) out->x1 = b->x1;
779 if (b->x2 < out->x2) out->x2 = b->x2;
780 if (out->x1 >= out->x2) return 0;
781
782 if (b->y1 > out->y1) out->y1 = b->y1;
783 if (b->y2 < out->y2) out->y2 = b->y2;
784 if (out->y1 >= out->y2) return 0;
785
786 return 1;
787 }
788
789 void viaFlushDmaLocked(struct via_context *vmesa, GLuint flags)
790 {
791 int i;
792 RING_VARS;
793
794 if (VIA_DEBUG & (DEBUG_IOCTL|DEBUG_DMA))
795 fprintf(stderr, "%s\n", __FUNCTION__);
796
797 if (*(GLuint *)vmesa->driHwLock != (DRM_LOCK_HELD|vmesa->hHWContext) &&
798 *(GLuint *)vmesa->driHwLock !=
799 (DRM_LOCK_HELD|DRM_LOCK_CONT|vmesa->hHWContext)) {
800 fprintf(stderr, "%s called without lock held\n", __FUNCTION__);
801 abort();
802 }
803
804 if (vmesa->dmaLow == 0) {
805 return;
806 }
807
808 assert(vmesa->dmaLastPrim == 0);
809
810 /* viaFinishPrimitive can add up to 8 bytes beyond VIA_DMA_HIGHWATER:
811 */
812 if (vmesa->dmaLow > VIA_DMA_HIGHWATER + 8) {
813 fprintf(stderr, "buffer overflow in Flush Prims = %d\n",vmesa->dmaLow);
814 abort();
815 }
816
817 switch (vmesa->dmaLow & 0x1F) {
818 case 8:
819 BEGIN_RING_NOCHECK( 6 );
820 OUT_RING( HC_HEADER2 );
821 OUT_RING( (HC_ParaType_NotTex << 16) );
822 OUT_RING( HC_DUMMY );
823 OUT_RING( HC_DUMMY );
824 OUT_RING( HC_DUMMY );
825 OUT_RING( HC_DUMMY );
826 ADVANCE_RING();
827 break;
828 case 16:
829 BEGIN_RING_NOCHECK( 4 );
830 OUT_RING( HC_HEADER2 );
831 OUT_RING( (HC_ParaType_NotTex << 16) );
832 OUT_RING( HC_DUMMY );
833 OUT_RING( HC_DUMMY );
834 ADVANCE_RING();
835 break;
836 case 24:
837 BEGIN_RING_NOCHECK( 10 );
838 OUT_RING( HC_HEADER2 );
839 OUT_RING( (HC_ParaType_NotTex << 16) );
840 OUT_RING( HC_DUMMY );
841 OUT_RING( HC_DUMMY );
842 OUT_RING( HC_DUMMY );
843 OUT_RING( HC_DUMMY );
844 OUT_RING( HC_DUMMY );
845 OUT_RING( HC_DUMMY );
846 OUT_RING( HC_DUMMY );
847 OUT_RING( HC_DUMMY );
848 ADVANCE_RING();
849 break;
850 case 0:
851 break;
852 default:
853 if (VIA_DEBUG & DEBUG_IOCTL)
854 fprintf(stderr, "%s: unaligned value for vmesa->dmaLow: %x\n",
855 __FUNCTION__, vmesa->dmaLow);
856 }
857
858 vmesa->lastDma = vmesa->lastBreadcrumbWrite;
859
860 if (VIA_DEBUG & DEBUG_DMA)
861 dump_dma( vmesa );
862
863 if (flags & VIA_NO_CLIPRECTS) {
864 if (0) fprintf(stderr, "%s VIA_NO_CLIPRECTS\n", __FUNCTION__);
865 assert(vmesa->dmaCliprectAddr == ~0);
866 fire_buffer( vmesa );
867 }
868 else if (vmesa->dmaCliprectAddr == ~0) {
869 /* Contains only state. Could just dump the packet?
870 */
871 if (0) fprintf(stderr, "%s: no dmaCliprectAddr\n", __FUNCTION__);
872 if (0) fire_buffer( vmesa );
873 }
874 else if (vmesa->numClipRects) {
875 drm_clip_rect_t *pbox = vmesa->pClipRects;
876
877 for (i = 0; i < vmesa->numClipRects; i++) {
878 drm_clip_rect_t b;
879
880 b.x1 = pbox[i].x1 - (vmesa->drawX + vmesa->drawXoff);
881 b.x2 = pbox[i].x2 - (vmesa->drawX + vmesa->drawXoff);
882 b.y1 = pbox[i].y1 - vmesa->drawY;
883 b.y2 = pbox[i].y2 - vmesa->drawY;
884
885 if (vmesa->scissor &&
886 !intersect_rect(&b, &b, &vmesa->scissorRect))
887 continue;
888
889 b.x1 += vmesa->drawXoff;
890 b.x2 += vmesa->drawXoff;
891
892 via_emit_cliprect(vmesa, &b);
893
894 if (fire_buffer(vmesa) != 0) {
895 dump_dma( vmesa );
896 goto done;
897 }
898 }
899 } else {
900 if (0) fprintf(stderr, "%s: no cliprects\n", __FUNCTION__);
901 UNLOCK_HARDWARE(vmesa);
902 sched_yield();
903 LOCK_HARDWARE(vmesa);
904 }
905
906 done:
907 /* Reset vmesa vars:
908 */
909 vmesa->dmaLow = 0;
910 vmesa->dmaCliprectAddr = ~0;
911 vmesa->newEmitState = ~0;
912 }
913
914 void viaWrapPrimitive( struct via_context *vmesa )
915 {
916 GLenum renderPrimitive = vmesa->renderPrimitive;
917 GLenum hwPrimitive = vmesa->hwPrimitive;
918
919 if (VIA_DEBUG & DEBUG_PRIMS) fprintf(stderr, "%s\n", __FUNCTION__);
920
921 if (vmesa->dmaLastPrim)
922 viaFinishPrimitive( vmesa );
923
924 viaFlushDma(vmesa);
925
926 if (renderPrimitive != GL_POLYGON + 1)
927 viaRasterPrimitive( vmesa->glCtx,
928 renderPrimitive,
929 hwPrimitive );
930
931 }
932
933 void viaFlushDma(struct via_context *vmesa)
934 {
935 if (vmesa->dmaLow) {
936 assert(!vmesa->dmaLastPrim);
937
938 LOCK_HARDWARE(vmesa);
939 viaFlushDmaLocked(vmesa, 0);
940 UNLOCK_HARDWARE(vmesa);
941 }
942 }
943
944 static void viaFlush(GLcontext *ctx)
945 {
946 struct via_context *vmesa = VIA_CONTEXT(ctx);
947 VIA_FLUSH_DMA(vmesa);
948 }
949
950 static void viaFinish(GLcontext *ctx)
951 {
952 struct via_context *vmesa = VIA_CONTEXT(ctx);
953 VIA_FLUSH_DMA(vmesa);
954 viaWaitIdle(vmesa, GL_FALSE);
955 }
956
957 static void viaClearStencil(GLcontext *ctx, int s)
958 {
959 return;
960 }
961
962 void viaInitIoctlFuncs(GLcontext *ctx)
963 {
964 ctx->Driver.Flush = viaFlush;
965 ctx->Driver.Clear = viaClear;
966 ctx->Driver.Finish = viaFinish;
967 ctx->Driver.ClearStencil = viaClearStencil;
968 }
969
970
971