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