2 * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
3 * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
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:
12 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial portions
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.
30 #include "main/mtypes.h"
31 #include "main/macros.h"
33 #include "main/context.h"
34 #include "main/colormac.h"
36 #include "swrast/swrast.h"
38 #include "savagecontext.h"
39 #include "savageioctl.h"
40 #include "savagestate.h"
41 #include "savagespan.h"
44 #include <sys/timeb.h>
46 #define DEPTH_SCALE_16 ((1<<16)-1)
47 #define DEPTH_SCALE_24 ((1<<24)-1)
50 void savageGetDMABuffer( savageContextPtr imesa )
58 assert (imesa->savageScreen->bufs);
60 if (SAVAGE_DEBUG & DEBUG_DMA)
61 fprintf(stderr, "Getting dma buffer\n");
63 dma.context = imesa->hHWContext;
66 dma.send_sizes = NULL;
68 dma.request_count = 1;
69 dma.request_size = imesa->bufferSize;
70 dma.request_list = &idx;
71 dma.request_sizes = &size;
72 dma.granted_count = 0;
75 if (SAVAGE_DEBUG & DEBUG_DMA)
76 fprintf(stderr, "drmDMA (get) ctx %d count %d size 0x%x\n",
77 dma.context, dma.request_count,
81 retcode = drmDMA(imesa->driFd, &dma);
83 if (SAVAGE_DEBUG & DEBUG_DMA)
84 fprintf(stderr, "retcode %d sz %d idx %d count %d\n",
91 dma.request_sizes[0] &&
95 if (SAVAGE_DEBUG & DEBUG_DMA)
96 fprintf(stderr, "\n\nflush");
99 buf = &(imesa->savageScreen->bufs->list[idx]);
101 if (SAVAGE_DEBUG & DEBUG_DMA)
103 "drmDMA (get) returns size[0] 0x%x idx[0] %d\n"
104 "dma_buffer now: buf idx: %d size: %d used: %d addr %p\n",
105 dma.request_sizes[0], dma.request_list[0],
106 buf->idx, buf->total,
107 buf->used, buf->address);
109 imesa->dmaVtxBuf.total = buf->total / 4;
110 imesa->dmaVtxBuf.used = 0;
111 imesa->dmaVtxBuf.flushed = 0;
112 imesa->dmaVtxBuf.idx = buf->idx;
113 imesa->dmaVtxBuf.buf = (uint32_t *)buf->address;
115 if (SAVAGE_DEBUG & DEBUG_DMA)
116 fprintf(stderr, "finished getbuffer\n");
120 /* Still keeping this around because it demonstrates page flipping and
121 * automatic z-clear. */
122 static void savage_BCI_clear(struct gl_context *ctx, drm_savage_clear_t *pclear)
124 savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
125 int nbox = imesa->sarea->nbox;
126 drm_clip_rect_t *pbox = imesa->sarea->boxes;
130 if (nbox > SAVAGE_NR_SAREA_CLIPRECTS)
131 nbox = SAVAGE_NR_SAREA_CLIPRECTS;
133 for (i = 0 ; i < nbox ; i++, pbox++) {
134 unsigned int x = pbox->x1;
135 unsigned int y = pbox->y1;
136 unsigned int width = pbox->x2 - x;
137 unsigned int height = pbox->y2 - y;
140 if (pbox->x1 > pbox->x2 ||
141 pbox->y1 > pbox->y2 ||
142 pbox->x2 > imesa->savageScreen->width ||
143 pbox->y2 > imesa->savageScreen->height)
146 if ( pclear->flags & SAVAGE_FRONT ) {
147 bciptr = savageDMAAlloc (imesa, 8);
148 WRITE_CMD((bciptr) , 0x4BCC8C00,uint32_t);
149 WRITE_CMD((bciptr) , imesa->savageScreen->frontOffset,uint32_t);
150 WRITE_CMD((bciptr) , imesa->savageScreen->frontBitmapDesc,uint32_t);
151 WRITE_CMD((bciptr) , pclear->clear_color,uint32_t);
152 WRITE_CMD((bciptr) , (y <<16) | x,uint32_t);
153 WRITE_CMD((bciptr) , (height << 16) | width,uint32_t);
154 savageDMACommit (imesa, bciptr);
156 if ( pclear->flags & SAVAGE_BACK ) {
157 bciptr = savageDMAAlloc (imesa, 8);
158 WRITE_CMD((bciptr) , 0x4BCC8C00,uint32_t);
159 WRITE_CMD((bciptr) , imesa->savageScreen->backOffset,uint32_t);
160 WRITE_CMD((bciptr) , imesa->savageScreen->backBitmapDesc,uint32_t);
161 WRITE_CMD((bciptr) , pclear->clear_color,uint32_t);
162 WRITE_CMD((bciptr) , (y <<16) | x,uint32_t);
163 WRITE_CMD((bciptr) , (height << 16) | width,uint32_t);
164 savageDMACommit (imesa, bciptr);
167 if ( pclear->flags & (SAVAGE_DEPTH |SAVAGE_STENCIL) ) {
168 uint32_t writeMask = 0x0;
169 if(imesa->hw_stencil)
171 if(pclear->flags & SAVAGE_STENCIL)
174 writeMask |= 0xFF000000;
176 if(pclear->flags & SAVAGE_DEPTH)
178 writeMask |= 0x00FFFFFF;
181 if(imesa->IsFullScreen && imesa->NotFirstFrame &&
182 imesa->savageScreen->chipset >= S3_SAVAGE4)
184 imesa->regs.s4.zBufCtrl.ni.autoZEnable = GL_TRUE;
185 imesa->regs.s4.zBufCtrl.ni.frameID =
186 ~imesa->regs.s4.zBufCtrl.ni.frameID;
188 imesa->dirty |= SAVAGE_UPLOAD_GLOBAL;
192 if(imesa->IsFullScreen)
193 imesa->NotFirstFrame = GL_TRUE;
195 if(imesa->hw_stencil)
197 bciptr = savageDMAAlloc (imesa, 10);
198 if(writeMask != 0xFFFFFFFF)
200 WRITE_CMD((bciptr) , 0x960100D7,uint32_t);
201 WRITE_CMD((bciptr) , writeMask,uint32_t);
206 bciptr = savageDMAAlloc (imesa, 6);
209 WRITE_CMD((bciptr) , 0x4BCC8C00,uint32_t);
210 WRITE_CMD((bciptr) , imesa->savageScreen->depthOffset,uint32_t);
211 WRITE_CMD((bciptr) , imesa->savageScreen->depthBitmapDesc,uint32_t);
212 WRITE_CMD((bciptr) , pclear->clear_depth,uint32_t);
213 WRITE_CMD((bciptr) , (y <<16) | x,uint32_t);
214 WRITE_CMD((bciptr) , (height << 16) | width,uint32_t);
215 if(imesa->hw_stencil)
217 if(writeMask != 0xFFFFFFFF)
219 WRITE_CMD((bciptr) , 0x960100D7,uint32_t);
220 WRITE_CMD((bciptr) , 0xFFFFFFFF,uint32_t);
223 savageDMACommit (imesa, bciptr);
227 /* FK: Make sure that the clear stuff is emitted. Otherwise a
228 software fallback may get overwritten by a delayed clear. */
229 savageDMAFlush (imesa);
232 static void savage_BCI_swap(savageContextPtr imesa)
234 int nbox = imesa->sarea->nbox;
235 drm_clip_rect_t *pbox = imesa->sarea->boxes;
237 volatile uint32_t *bciptr;
239 if (nbox > SAVAGE_NR_SAREA_CLIPRECTS)
240 nbox = SAVAGE_NR_SAREA_CLIPRECTS;
241 savageDMAFlush (imesa);
243 if(imesa->IsFullScreen)
246 tmp0 = imesa->savageScreen->frontOffset;
247 imesa->savageScreen->frontOffset = imesa->savageScreen->backOffset;
248 imesa->savageScreen->backOffset = tmp0;
250 if(imesa->toggle == TARGET_BACK)
251 imesa->toggle = TARGET_FRONT;
253 imesa->toggle = TARGET_BACK;
255 driFlipRenderbuffers(imesa->glCtx->DrawBuffer,
256 imesa->toggle != TARGET_FRONT);
258 imesa->regs.s4.destCtrl.ni.offset = imesa->savageScreen->backOffset>>11;
259 imesa->dirty |= SAVAGE_UPLOAD_GLOBAL;
260 bciptr = SAVAGE_GET_BCI_POINTER(imesa,3);
261 *(bciptr) = 0x960100B0;
262 *(bciptr) = (imesa->savageScreen->frontOffset);
263 *(bciptr) = 0xA0000000;
267 { /* Use bitblt copy from back to front buffer*/
269 for (i = 0 ; i < nbox; i++, pbox++)
271 unsigned int w = pbox->x2 - pbox->x1;
272 unsigned int h = pbox->y2 - pbox->y1;
274 if (pbox->x1 > pbox->x2 ||
275 pbox->y1 > pbox->y2 ||
276 pbox->x2 > imesa->savageScreen->width ||
277 pbox->y2 > imesa->savageScreen->height)
280 bciptr = SAVAGE_GET_BCI_POINTER(imesa,6);
282 *(bciptr) = 0x4BCC00C0;
284 *(bciptr) = imesa->savageScreen->backOffset;
285 *(bciptr) = imesa->savageScreen->backBitmapDesc;
286 *(bciptr) = (pbox->y1 <<16) | pbox->x1; /*x0, y0*/
287 *(bciptr) = (pbox->y1 <<16) | pbox->x1;
288 *(bciptr) = (h << 16) | w;
296 static GLboolean intersect_rect( drm_clip_rect_t *out,
297 const drm_clip_rect_t *a,
298 const drm_clip_rect_t *b )
301 if (b->x1 > out->x1) out->x1 = b->x1;
302 if (b->y1 > out->y1) out->y1 = b->y1;
303 if (b->x2 < out->x2) out->x2 = b->x2;
304 if (b->y2 < out->y2) out->y2 = b->y2;
306 return ((out->x1 < out->x2) && (out->y1 < out->y2));
310 static GLuint savageIntersectClipRects(drm_clip_rect_t *dest,
311 const drm_clip_rect_t *src,
313 const drm_clip_rect_t *clip)
317 for (i = 0, ndest = 0; i < nsrc; ++i, ++src) {
318 if (intersect_rect(dest, src, clip)) {
328 static void savageDDClear( struct gl_context *ctx, GLbitfield mask )
330 savageContextPtr imesa = SAVAGE_CONTEXT( ctx );
331 GLuint colorMask, depthMask, clearColor, clearDepth, flags;
332 GLint cx = ctx->DrawBuffer->_Xmin;
333 GLint cy = ctx->DrawBuffer->_Ymin;
334 GLint cw = ctx->DrawBuffer->_Xmax - cx;
335 GLint ch = ctx->DrawBuffer->_Ymax - cy;
337 /* XXX FIX ME: the cx,cy,cw,ch vars are currently ignored! */
341 if (SAVAGE_DEBUG & DEBUG_VERBOSE_MSG)
342 fprintf (stderr, "%s\n", __FUNCTION__);
344 clearColor = imesa->ClearColor;
345 if (imesa->float_depth) {
346 if (imesa->savageScreen->zpp == 2)
347 clearDepth = savageEncodeFloat16(1.0 - ctx->Depth.Clear);
349 clearDepth = savageEncodeFloat24(1.0 - ctx->Depth.Clear);
351 if (imesa->savageScreen->zpp == 2)
352 clearDepth = (GLuint) ((1.0 - ctx->Depth.Clear) * DEPTH_SCALE_16);
354 clearDepth = (GLuint) ((1.0 - ctx->Depth.Clear) * DEPTH_SCALE_24);
359 switch (imesa->savageScreen->cpp) {
361 colorMask = PACK_COLOR_565(ctx->Color.ColorMask[0][0],
362 ctx->Color.ColorMask[0][1],
363 ctx->Color.ColorMask[0][2]);
366 colorMask = PACK_COLOR_8888(ctx->Color.ColorMask[0][3],
367 ctx->Color.ColorMask[0][2],
368 ctx->Color.ColorMask[0][1],
369 ctx->Color.ColorMask[0][0]);
375 if (mask & BUFFER_BIT_FRONT_LEFT) {
376 flags |= SAVAGE_FRONT;
377 mask &= ~BUFFER_BIT_FRONT_LEFT;
380 if (mask & BUFFER_BIT_BACK_LEFT) {
381 flags |= SAVAGE_BACK;
382 mask &= ~BUFFER_BIT_BACK_LEFT;
385 if ((mask & BUFFER_BIT_DEPTH) && ctx->Depth.Mask) {
386 flags |= SAVAGE_DEPTH;
388 (imesa->savageScreen->zpp == 2) ? 0xffffffff : 0x00ffffff;
389 mask &= ~BUFFER_BIT_DEPTH;
392 if((mask & BUFFER_BIT_STENCIL) && imesa->hw_stencil)
394 flags |= SAVAGE_DEPTH;
395 depthMask |= 0xff000000;
396 mask &= ~BUFFER_BIT_STENCIL;
399 savageFlushVertices(imesa);
402 GLboolean depthCleared = GL_FALSE;
403 if (flags & (SAVAGE_FRONT|SAVAGE_BACK)) {
404 drm_savage_cmd_header_t *cmd;
405 cmd = savageAllocCmdBuf(imesa, sizeof(drm_savage_cmd_header_t));
406 cmd[0].clear0.cmd = SAVAGE_CMD_CLEAR;
407 if ((flags & SAVAGE_DEPTH) &&
408 clearDepth == clearColor && depthMask == colorMask) {
409 cmd[0].clear0.flags = flags;
410 depthCleared = GL_TRUE;
412 cmd[0].clear0.flags = flags & (SAVAGE_FRONT|SAVAGE_BACK);
413 cmd[1].clear1.mask = colorMask;
414 cmd[1].clear1.value = clearColor;
417 if ((flags & SAVAGE_DEPTH) && !depthCleared) {
418 drm_savage_cmd_header_t *cmd;
419 cmd = savageAllocCmdBuf(imesa, sizeof(drm_savage_cmd_header_t));
420 cmd[0].clear0.cmd = SAVAGE_CMD_CLEAR;
421 cmd[0].clear0.flags = SAVAGE_DEPTH;
422 cmd[1].clear1.mask = depthMask;
423 cmd[1].clear1.value = clearDepth;
428 _swrast_Clear( ctx, mask );
432 * Copy the back buffer to the front buffer.
434 void savageSwapBuffers( __DRIdrawable *dPriv )
436 savageContextPtr imesa;
438 if (SAVAGE_DEBUG & DEBUG_VERBOSE_MSG)
439 fprintf (stderr, "%s\n================================\n", __FUNCTION__);
442 assert(dPriv->driContextPriv);
443 assert(dPriv->driContextPriv->driverPrivate);
445 imesa = (savageContextPtr) dPriv->driContextPriv->driverPrivate;
447 _mesa_notifySwapBuffers( imesa->glCtx );
451 if (imesa->sync_frames)
452 imesa->lastSwap = savageEmitEvent( imesa, 0 );
454 if (imesa->lastSwap != 0)
455 savageWaitEvent( imesa, imesa->lastSwap );
458 drm_savage_cmd_header_t *cmd = savageAllocCmdBuf(imesa, 0);
459 cmd->cmd.cmd = SAVAGE_CMD_SWAP;
460 imesa->inSwap = GL_TRUE; /* ignore scissors in savageFlushCmdBuf */
461 savageFlushCmdBuf(imesa, GL_FALSE);
462 imesa->inSwap = GL_FALSE;
465 if (!imesa->sync_frames)
466 /* don't sync, but limit the lag to one frame. */
467 imesa->lastSwap = savageEmitEvent( imesa, 0 );
470 unsigned int savageEmitEventLocked( savageContextPtr imesa, unsigned int flags )
472 drm_savage_event_emit_t event;
476 ret = drmCommandWriteRead( imesa->driFd, DRM_SAVAGE_BCI_EVENT_EMIT,
477 &event, sizeof(event) );
479 fprintf (stderr, "emit event returned %d\n", ret);
484 unsigned int savageEmitEvent( savageContextPtr imesa, unsigned int flags )
487 LOCK_HARDWARE( imesa );
488 ret = savageEmitEventLocked( imesa, flags );
489 UNLOCK_HARDWARE( imesa );
494 void savageWaitEvent( savageContextPtr imesa, unsigned int count )
496 drm_savage_event_wait_t event;
500 ret = drmCommandWriteRead( imesa->driFd, DRM_SAVAGE_BCI_EVENT_WAIT,
501 &event, sizeof(event) );
503 fprintf (stderr, "wait event returned %d\n", ret);
509 void savageFlushVertices( savageContextPtr imesa )
511 struct savage_vtxbuf_t *buffer = imesa->vtxBuf;
513 if (SAVAGE_DEBUG & DEBUG_VERBOSE_MSG)
514 fprintf (stderr, "%s\n", __FUNCTION__);
519 if (buffer->used > buffer->flushed) {
520 drm_savage_cmd_header_t *cmd;
521 /* State must be updated "per primitive" because hardware
522 * culling must be disabled for unfilled primitives, points
524 savageEmitChangedState (imesa);
525 cmd = savageAllocCmdBuf(imesa, 0);
526 cmd->prim.cmd = buffer == &imesa->dmaVtxBuf ?
527 SAVAGE_CMD_DMA_PRIM : SAVAGE_CMD_VB_PRIM;
528 cmd->prim.prim = imesa->HwPrim;
529 cmd->prim.skip = imesa->skip;
530 cmd->prim.start = buffer->flushed / imesa->HwVertexSize;
531 cmd->prim.count = buffer->used / imesa->HwVertexSize - cmd->prim.start;
532 buffer->flushed = buffer->used;
536 void savageFlushCmdBufLocked( savageContextPtr imesa, GLboolean discard )
538 __DRIdrawable *dPriv = imesa->driDrawable;
540 if (!imesa->dmaVtxBuf.total)
543 /* complete indexed drawing commands */
544 savageFlushElts(imesa);
546 if (imesa->cmdBuf.write != imesa->cmdBuf.start || discard) {
547 drm_savage_cmdbuf_t cmdbuf;
548 drm_savage_cmd_header_t *start;
551 /* If we lost the context we must restore the initial state (at
552 * the start of the command buffer). */
553 if (imesa->lostContext) {
554 start = imesa->cmdBuf.base;
555 imesa->lostContext = GL_FALSE;
557 start = imesa->cmdBuf.start;
559 if ((SAVAGE_DEBUG & DEBUG_DMA) && discard)
560 fprintf (stderr, "Discarding DMA buffer, used=%u\n",
561 imesa->dmaVtxBuf.used);
563 cmdbuf.dma_idx = imesa->dmaVtxBuf.idx;
564 cmdbuf.discard = discard;
565 cmdbuf.vb_addr = imesa->clientVtxBuf.buf;
566 cmdbuf.vb_size = imesa->clientVtxBuf.total*4;
567 cmdbuf.vb_stride = imesa->HwVertexSize;
568 cmdbuf.cmd_addr = start;
569 cmdbuf.size = (imesa->cmdBuf.write - start);
570 if (!imesa->inSwap && imesa->scissor.enabled) {
571 drm_clip_rect_t *box = dPriv->pClipRects, *ibox;
572 drm_clip_rect_t scissor;
573 GLuint nbox = dPriv->numClipRects, nibox;
574 /* transform and clip scissor to viewport */
575 scissor.x1 = MAX2(imesa->scissor.x, 0) + dPriv->x;
576 scissor.y1 = MAX2(dPriv->h - imesa->scissor.y - imesa->scissor.h,
578 scissor.x2 = MIN2(imesa->scissor.x + imesa->scissor.w,
579 dPriv->w) + dPriv->x;
580 scissor.y2 = MIN2(dPriv->h - imesa->scissor.y,
581 dPriv->h) + dPriv->y;
582 /* intersect cliprects with scissor */
583 ibox = malloc(dPriv->numClipRects*sizeof(drm_clip_rect_t));
585 fprintf(stderr, "Out of memory.\n");
588 nibox = savageIntersectClipRects(ibox, box, nbox, &scissor);
590 cmdbuf.box_addr = ibox;
592 cmdbuf.nbox = dPriv->numClipRects;
593 cmdbuf.box_addr = dPriv->pClipRects;
596 ret = drmCommandWrite( imesa->driFd, DRM_SAVAGE_BCI_CMDBUF,
597 &cmdbuf, sizeof(cmdbuf) );
599 fprintf (stderr, "cmdbuf ioctl returned %d\n", ret);
603 if (cmdbuf.box_addr != dPriv->pClipRects) {
604 free(cmdbuf.box_addr);
607 /* Save the current state at the start of the command buffer. That
608 * state will only be emitted, if the context was lost since the
609 * last command buffer. */
610 imesa->cmdBuf.write = imesa->cmdBuf.base;
611 savageEmitOldState(imesa);
612 imesa->cmdBuf.start = imesa->cmdBuf.write;
616 assert (!savageHaveIndexedVerts(imesa));
617 imesa->dmaVtxBuf.total = 0;
618 imesa->dmaVtxBuf.used = 0;
619 imesa->dmaVtxBuf.flushed = 0;
621 if (!savageHaveIndexedVerts(imesa)) {
622 imesa->clientVtxBuf.used = 0;
623 imesa->clientVtxBuf.flushed = 0;
628 void savageFlushCmdBuf( savageContextPtr imesa, GLboolean discard )
630 if (SAVAGE_DEBUG & DEBUG_VERBOSE_MSG)
631 fprintf (stderr, "%s\n", __FUNCTION__);
632 LOCK_HARDWARE(imesa);
633 savageFlushCmdBufLocked (imesa, discard);
634 UNLOCK_HARDWARE(imesa);
638 static void savageDDFlush( struct gl_context *ctx )
640 savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
641 if (SAVAGE_DEBUG & DEBUG_VERBOSE_MSG)
642 fprintf (stderr, "%s\n", __FUNCTION__);
643 savageFlushVertices (imesa);
644 savageFlushCmdBuf(imesa, GL_FALSE);
647 static void savageDDFinish( struct gl_context *ctx )
649 savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
650 if (SAVAGE_DEBUG & DEBUG_VERBOSE_MSG)
651 fprintf (stderr, "%s\n", __FUNCTION__);
652 savageFlushVertices (imesa);
653 savageFlushCmdBuf(imesa, GL_FALSE);
654 WAIT_IDLE_EMPTY(imesa);
657 void savageDDInitIoctlFuncs( struct gl_context *ctx )
659 ctx->Driver.Clear = savageDDClear;
660 ctx->Driver.Flush = savageDDFlush;
661 ctx->Driver.Finish = savageDDFinish;