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