blob: 4eac1fb3498d49026920f337e0c4f5142a9f0e89 [file] [log] [blame]
/*
* Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
* Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sub license,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include "mtypes.h"
#include "macros.h"
#include "dd.h"
#include "context.h"
#include "swrast/swrast.h"
#include "colormac.h"
#include "mm.h"
#include "savagecontext.h"
#include "savageioctl.h"
#include "savage_bci.h"
#include "savagestate.h"
#include "savagespan.h"
#include "drm.h"
#include <sys/ioctl.h>
#include <sys/timeb.h>
#define DEPTH_SCALE_16 ((1<<16)-1)
#define DEPTH_SCALE_24 ((1<<24)-1)
void savageGetDMABuffer( savageContextPtr imesa )
{
int idx = 0;
int size = 0;
drmDMAReq dma;
int retcode;
drmBufPtr buf;
assert (imesa->savageScreen->bufs);
if (SAVAGE_DEBUG & DEBUG_DMA)
fprintf(stderr, "Getting dma buffer\n");
dma.context = imesa->hHWContext;
dma.send_count = 0;
dma.send_list = NULL;
dma.send_sizes = NULL;
dma.flags = 0;
dma.request_count = 1;
dma.request_size = imesa->bufferSize;
dma.request_list = &idx;
dma.request_sizes = &size;
dma.granted_count = 0;
if (SAVAGE_DEBUG & DEBUG_DMA)
fprintf(stderr, "drmDMA (get) ctx %d count %d size 0x%x\n",
dma.context, dma.request_count,
dma.request_size);
while (1) {
retcode = drmDMA(imesa->driFd, &dma);
if (SAVAGE_DEBUG & DEBUG_DMA)
fprintf(stderr, "retcode %d sz %d idx %d count %d\n",
retcode,
dma.request_sizes[0],
dma.request_list[0],
dma.granted_count);
if (retcode == 0 &&
dma.request_sizes[0] &&
dma.granted_count)
break;
if (SAVAGE_DEBUG & DEBUG_DMA)
fprintf(stderr, "\n\nflush");
}
buf = &(imesa->savageScreen->bufs->list[idx]);
if (SAVAGE_DEBUG & DEBUG_DMA)
fprintf(stderr,
"drmDMA (get) returns size[0] 0x%x idx[0] %d\n"
"dma_buffer now: buf idx: %d size: %d used: %d addr %p\n",
dma.request_sizes[0], dma.request_list[0],
buf->idx, buf->total,
buf->used, buf->address);
imesa->dmaVtxBuf.total = buf->total / 4;
imesa->dmaVtxBuf.used = 0;
imesa->dmaVtxBuf.flushed = 0;
imesa->dmaVtxBuf.idx = buf->idx;
imesa->dmaVtxBuf.buf = (u_int32_t *)buf->address;
if (SAVAGE_DEBUG & DEBUG_DMA)
fprintf(stderr, "finished getbuffer\n");
}
#if 0
/* Still keeping this around because it demonstrates page flipping and
* automatic z-clear. */
static void savage_BCI_clear(GLcontext *ctx, drm_savage_clear_t *pclear)
{
savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
int nbox = imesa->sarea->nbox;
drm_clip_rect_t *pbox = imesa->sarea->boxes;
int i;
if (nbox > SAVAGE_NR_SAREA_CLIPRECTS)
nbox = SAVAGE_NR_SAREA_CLIPRECTS;
for (i = 0 ; i < nbox ; i++, pbox++) {
unsigned int x = pbox->x1;
unsigned int y = pbox->y1;
unsigned int width = pbox->x2 - x;
unsigned int height = pbox->y2 - y;
u_int32_t *bciptr;
if (pbox->x1 > pbox->x2 ||
pbox->y1 > pbox->y2 ||
pbox->x2 > imesa->savageScreen->width ||
pbox->y2 > imesa->savageScreen->height)
continue;
if ( pclear->flags & SAVAGE_FRONT ) {
bciptr = savageDMAAlloc (imesa, 8);
WRITE_CMD((bciptr) , 0x4BCC8C00,u_int32_t);
WRITE_CMD((bciptr) , imesa->savageScreen->frontOffset,u_int32_t);
WRITE_CMD((bciptr) , imesa->savageScreen->frontBitmapDesc,u_int32_t);
WRITE_CMD((bciptr) , pclear->clear_color,u_int32_t);
WRITE_CMD((bciptr) , (y <<16) | x,u_int32_t);
WRITE_CMD((bciptr) , (height << 16) | width,u_int32_t);
savageDMACommit (imesa, bciptr);
}
if ( pclear->flags & SAVAGE_BACK ) {
bciptr = savageDMAAlloc (imesa, 8);
WRITE_CMD((bciptr) , 0x4BCC8C00,u_int32_t);
WRITE_CMD((bciptr) , imesa->savageScreen->backOffset,u_int32_t);
WRITE_CMD((bciptr) , imesa->savageScreen->backBitmapDesc,u_int32_t);
WRITE_CMD((bciptr) , pclear->clear_color,u_int32_t);
WRITE_CMD((bciptr) , (y <<16) | x,u_int32_t);
WRITE_CMD((bciptr) , (height << 16) | width,u_int32_t);
savageDMACommit (imesa, bciptr);
}
if ( pclear->flags & (SAVAGE_DEPTH |SAVAGE_STENCIL) ) {
u_int32_t writeMask = 0x0;
if(imesa->hw_stencil)
{
if(pclear->flags & SAVAGE_STENCIL)
{
writeMask |= 0xFF000000;
}
if(pclear->flags & SAVAGE_DEPTH)
{
writeMask |= 0x00FFFFFF;
}
}
if(imesa->IsFullScreen && imesa->NotFirstFrame &&
imesa->savageScreen->chipset >= S3_SAVAGE4)
{
imesa->regs.s4.zBufCtrl.ni.autoZEnable = GL_TRUE;
imesa->regs.s4.zBufCtrl.ni.frameID =
~imesa->regs.s4.zBufCtrl.ni.frameID;
imesa->dirty |= SAVAGE_UPLOAD_GLOBAL;
}
else
{
if(imesa->IsFullScreen)
imesa->NotFirstFrame = GL_TRUE;
if(imesa->hw_stencil)
{
bciptr = savageDMAAlloc (imesa, 10);
if(writeMask != 0xFFFFFFFF)
{
WRITE_CMD((bciptr) , 0x960100D7,u_int32_t);
WRITE_CMD((bciptr) , writeMask,u_int32_t);
}
}
else
{
bciptr = savageDMAAlloc (imesa, 6);
}
WRITE_CMD((bciptr) , 0x4BCC8C00,u_int32_t);
WRITE_CMD((bciptr) , imesa->savageScreen->depthOffset,u_int32_t);
WRITE_CMD((bciptr) , imesa->savageScreen->depthBitmapDesc,u_int32_t);
WRITE_CMD((bciptr) , pclear->clear_depth,u_int32_t);
WRITE_CMD((bciptr) , (y <<16) | x,u_int32_t);
WRITE_CMD((bciptr) , (height << 16) | width,u_int32_t);
if(imesa->hw_stencil)
{
if(writeMask != 0xFFFFFFFF)
{
WRITE_CMD((bciptr) , 0x960100D7,u_int32_t);
WRITE_CMD((bciptr) , 0xFFFFFFFF,u_int32_t);
}
}
savageDMACommit (imesa, bciptr);
}
}
}
/* FK: Make sure that the clear stuff is emitted. Otherwise a
software fallback may get overwritten by a delayed clear. */
savageDMAFlush (imesa);
}
static void savage_BCI_swap(savageContextPtr imesa)
{
int nbox = imesa->sarea->nbox;
drm_clip_rect_t *pbox = imesa->sarea->boxes;
int i;
volatile u_int32_t *bciptr;
if (nbox > SAVAGE_NR_SAREA_CLIPRECTS)
nbox = SAVAGE_NR_SAREA_CLIPRECTS;
savageDMAFlush (imesa);
if(imesa->IsFullScreen)
{ /* full screen*/
unsigned int tmp0;
tmp0 = imesa->savageScreen->frontOffset;
imesa->savageScreen->frontOffset = imesa->savageScreen->backOffset;
imesa->savageScreen->backOffset = tmp0;
if(imesa->toggle == TARGET_BACK)
imesa->toggle = TARGET_FRONT;
else
imesa->toggle = TARGET_BACK;
driFlipRenderbuffers(imesa->glCtx->DrawBuffer,
imesa->toggle != TARGET_FRONT);
imesa->regs.s4.destCtrl.ni.offset = imesa->savageScreen->backOffset>>11;
imesa->dirty |= SAVAGE_UPLOAD_GLOBAL;
bciptr = SAVAGE_GET_BCI_POINTER(imesa,3);
*(bciptr) = 0x960100B0;
*(bciptr) = (imesa->savageScreen->frontOffset);
*(bciptr) = 0xA0000000;
}
else
{ /* Use bitblt copy from back to front buffer*/
for (i = 0 ; i < nbox; i++, pbox++)
{
unsigned int w = pbox->x2 - pbox->x1;
unsigned int h = pbox->y2 - pbox->y1;
if (pbox->x1 > pbox->x2 ||
pbox->y1 > pbox->y2 ||
pbox->x2 > imesa->savageScreen->width ||
pbox->y2 > imesa->savageScreen->height)
continue;
bciptr = SAVAGE_GET_BCI_POINTER(imesa,6);
*(bciptr) = 0x4BCC00C0;
*(bciptr) = imesa->savageScreen->backOffset;
*(bciptr) = imesa->savageScreen->backBitmapDesc;
*(bciptr) = (pbox->y1 <<16) | pbox->x1; /*x0, y0*/
*(bciptr) = (pbox->y1 <<16) | pbox->x1;
*(bciptr) = (h << 16) | w;
}
}
}
#endif
static GLboolean intersect_rect( drm_clip_rect_t *out,
const drm_clip_rect_t *a,
const drm_clip_rect_t *b )
{
*out = *a;
if (b->x1 > out->x1) out->x1 = b->x1;
if (b->y1 > out->y1) out->y1 = b->y1;
if (b->x2 < out->x2) out->x2 = b->x2;
if (b->y2 < out->y2) out->y2 = b->y2;
return ((out->x1 < out->x2) && (out->y1 < out->y2));
}
static GLuint savageIntersectClipRects(drm_clip_rect_t *dest,
const drm_clip_rect_t *src,
GLuint nsrc,
const drm_clip_rect_t *clip)
{
GLuint i, ndest;
for (i = 0, ndest = 0; i < nsrc; ++i, ++src) {
if (intersect_rect(dest, src, clip)) {
dest++;
ndest++;
}
}
return ndest;
}
static void savageDDClear( GLcontext *ctx, GLbitfield mask )
{
savageContextPtr imesa = SAVAGE_CONTEXT( ctx );
GLuint colorMask, depthMask, clearColor, clearDepth, flags;
GLint cx = ctx->DrawBuffer->_Xmin;
GLint cy = ctx->DrawBuffer->_Ymin;
GLint cw = ctx->DrawBuffer->_Xmax - cx;
GLint ch = ctx->DrawBuffer->_Ymax - cy;
/* XXX FIX ME: the cx,cy,cw,ch vars are currently ignored! */
if (SAVAGE_DEBUG & DEBUG_VERBOSE_MSG)
fprintf (stderr, "%s\n", __FUNCTION__);
clearColor = imesa->ClearColor;
if (imesa->float_depth) {
if (imesa->savageScreen->zpp == 2)
clearDepth = savageEncodeFloat16(1.0 - ctx->Depth.Clear);
else
clearDepth = savageEncodeFloat24(1.0 - ctx->Depth.Clear);
} else {
if (imesa->savageScreen->zpp == 2)
clearDepth = (GLuint) ((1.0 - ctx->Depth.Clear) * DEPTH_SCALE_16);
else
clearDepth = (GLuint) ((1.0 - ctx->Depth.Clear) * DEPTH_SCALE_24);
}
colorMask = 0;
depthMask = 0;
switch (imesa->savageScreen->cpp) {
case 2:
colorMask = PACK_COLOR_565(ctx->Color.ColorMask[0],
ctx->Color.ColorMask[1],
ctx->Color.ColorMask[2]);
break;
case 4:
colorMask = PACK_COLOR_8888(ctx->Color.ColorMask[3],
ctx->Color.ColorMask[2],
ctx->Color.ColorMask[1],
ctx->Color.ColorMask[0]);
break;
}
flags = 0;
if (mask & BUFFER_BIT_FRONT_LEFT) {
flags |= SAVAGE_FRONT;
mask &= ~BUFFER_BIT_FRONT_LEFT;
}
if (mask & BUFFER_BIT_BACK_LEFT) {
flags |= SAVAGE_BACK;
mask &= ~BUFFER_BIT_BACK_LEFT;
}
if ((mask & BUFFER_BIT_DEPTH) && ctx->Depth.Mask) {
flags |= SAVAGE_DEPTH;
depthMask |=
(imesa->savageScreen->zpp == 2) ? 0xffffffff : 0x00ffffff;
mask &= ~BUFFER_BIT_DEPTH;
}
if((mask & BUFFER_BIT_STENCIL) && imesa->hw_stencil)
{
flags |= SAVAGE_DEPTH;
depthMask |= 0xff000000;
mask &= ~BUFFER_BIT_STENCIL;
}
savageFlushVertices(imesa);
if (flags) {
GLboolean depthCleared = GL_FALSE;
if (flags & (SAVAGE_FRONT|SAVAGE_BACK)) {
drm_savage_cmd_header_t *cmd;
cmd = savageAllocCmdBuf(imesa, sizeof(drm_savage_cmd_header_t));
cmd[0].clear0.cmd = SAVAGE_CMD_CLEAR;
if ((flags & SAVAGE_DEPTH) &&
clearDepth == clearColor && depthMask == colorMask) {
cmd[0].clear0.flags = flags;
depthCleared = GL_TRUE;
} else
cmd[0].clear0.flags = flags & (SAVAGE_FRONT|SAVAGE_BACK);
cmd[1].clear1.mask = colorMask;
cmd[1].clear1.value = clearColor;
}
if ((flags & SAVAGE_DEPTH) && !depthCleared) {
drm_savage_cmd_header_t *cmd;
cmd = savageAllocCmdBuf(imesa, sizeof(drm_savage_cmd_header_t));
cmd[0].clear0.cmd = SAVAGE_CMD_CLEAR;
cmd[0].clear0.flags = SAVAGE_DEPTH;
cmd[1].clear1.mask = depthMask;
cmd[1].clear1.value = clearDepth;
}
}
if (mask)
_swrast_Clear( ctx, mask );
}
/*
* Copy the back buffer to the front buffer.
*/
void savageSwapBuffers( __DRIdrawablePrivate *dPriv )
{
savageContextPtr imesa;
if (SAVAGE_DEBUG & DEBUG_VERBOSE_MSG)
fprintf (stderr, "%s\n================================\n", __FUNCTION__);
assert(dPriv);
assert(dPriv->driContextPriv);
assert(dPriv->driContextPriv->driverPrivate);
imesa = (savageContextPtr) dPriv->driContextPriv->driverPrivate;
if (imesa->IsDouble)
_mesa_notifySwapBuffers( imesa->glCtx );
FLUSH_BATCH(imesa);
if (imesa->sync_frames)
imesa->lastSwap = savageEmitEvent( imesa, 0 );
if (imesa->lastSwap != 0)
savageWaitEvent( imesa, imesa->lastSwap );
{
drm_savage_cmd_header_t *cmd = savageAllocCmdBuf(imesa, 0);
cmd->cmd.cmd = SAVAGE_CMD_SWAP;
imesa->inSwap = GL_TRUE; /* ignore scissors in savageFlushCmdBuf */
savageFlushCmdBuf(imesa, GL_FALSE);
imesa->inSwap = GL_FALSE;
}
if (!imesa->sync_frames)
/* don't sync, but limit the lag to one frame. */
imesa->lastSwap = savageEmitEvent( imesa, 0 );
}
unsigned int savageEmitEventLocked( savageContextPtr imesa, unsigned int flags )
{
drm_savage_event_emit_t event;
int ret;
event.count = 0;
event.flags = flags;
ret = drmCommandWriteRead( imesa->driFd, DRM_SAVAGE_BCI_EVENT_EMIT,
&event, sizeof(event) );
if (ret) {
fprintf (stderr, "emit event returned %d\n", ret);
exit (1);
}
return event.count;
}
unsigned int savageEmitEvent( savageContextPtr imesa, unsigned int flags )
{
unsigned int ret;
LOCK_HARDWARE( imesa );
ret = savageEmitEventLocked( imesa, flags );
UNLOCK_HARDWARE( imesa );
return ret;
}
void savageWaitEvent( savageContextPtr imesa, unsigned int count )
{
drm_savage_event_wait_t event;
int ret;
event.count = count;
event.flags = 0;
ret = drmCommandWriteRead( imesa->driFd, DRM_SAVAGE_BCI_EVENT_WAIT,
&event, sizeof(event) );
if (ret) {
fprintf (stderr, "wait event returned %d\n", ret);
exit (1);
}
}
void savageFlushVertices( savageContextPtr imesa )
{
struct savage_vtxbuf_t *buffer = imesa->vtxBuf;
if (SAVAGE_DEBUG & DEBUG_VERBOSE_MSG)
fprintf (stderr, "%s\n", __FUNCTION__);
if (!buffer->total)
return;
if (buffer->used > buffer->flushed) {
drm_savage_cmd_header_t *cmd;
/* State must be updated "per primitive" because hardware
* culling must be disabled for unfilled primitives, points
* and lines. */
savageEmitChangedState (imesa);
cmd = savageAllocCmdBuf(imesa, 0);
cmd->prim.cmd = buffer == &imesa->dmaVtxBuf ?
SAVAGE_CMD_DMA_PRIM : SAVAGE_CMD_VB_PRIM;
cmd->prim.prim = imesa->HwPrim;
cmd->prim.skip = imesa->skip;
cmd->prim.start = buffer->flushed / imesa->HwVertexSize;
cmd->prim.count = buffer->used / imesa->HwVertexSize - cmd->prim.start;
buffer->flushed = buffer->used;
}
}
void savageFlushCmdBufLocked( savageContextPtr imesa, GLboolean discard )
{
__DRIdrawablePrivate *dPriv = imesa->driDrawable;
if (!imesa->dmaVtxBuf.total)
discard = GL_FALSE;
/* complete indexed drawing commands */
savageFlushElts(imesa);
if (imesa->cmdBuf.write != imesa->cmdBuf.start || discard) {
drm_savage_cmdbuf_t cmdbuf;
drm_savage_cmd_header_t *start;
int ret;
/* If we lost the context we must restore the initial state (at
* the start of the command buffer). */
if (imesa->lostContext) {
start = imesa->cmdBuf.base;
imesa->lostContext = GL_FALSE;
} else
start = imesa->cmdBuf.start;
if ((SAVAGE_DEBUG & DEBUG_DMA) && discard)
fprintf (stderr, "Discarding DMA buffer, used=%u\n",
imesa->dmaVtxBuf.used);
cmdbuf.dma_idx = imesa->dmaVtxBuf.idx;
cmdbuf.discard = discard;
cmdbuf.vb_addr = imesa->clientVtxBuf.buf;
cmdbuf.vb_size = imesa->clientVtxBuf.total*4;
cmdbuf.vb_stride = imesa->HwVertexSize;
cmdbuf.cmd_addr = start;
cmdbuf.size = (imesa->cmdBuf.write - start);
if (!imesa->inSwap && imesa->scissor.enabled) {
drm_clip_rect_t *box = dPriv->pClipRects, *ibox;
drm_clip_rect_t scissor;
GLuint nbox = dPriv->numClipRects, nibox;
/* transform and clip scissor to viewport */
scissor.x1 = MAX2(imesa->scissor.x, 0) + dPriv->x;
scissor.y1 = MAX2(dPriv->h - imesa->scissor.y - imesa->scissor.h,
0) + dPriv->y;
scissor.x2 = MIN2(imesa->scissor.x + imesa->scissor.w,
dPriv->w) + dPriv->x;
scissor.y2 = MIN2(dPriv->h - imesa->scissor.y,
dPriv->h) + dPriv->y;
/* intersect cliprects with scissor */
ibox = malloc(dPriv->numClipRects*sizeof(drm_clip_rect_t));
if (!ibox) {
fprintf(stderr, "Out of memory.\n");
exit(1);
}
nibox = savageIntersectClipRects(ibox, box, nbox, &scissor);
cmdbuf.nbox = nibox;
cmdbuf.box_addr = ibox;
} else {
cmdbuf.nbox = dPriv->numClipRects;
cmdbuf.box_addr = dPriv->pClipRects;
}
ret = drmCommandWrite( imesa->driFd, DRM_SAVAGE_BCI_CMDBUF,
&cmdbuf, sizeof(cmdbuf) );
if (ret) {
fprintf (stderr, "cmdbuf ioctl returned %d\n", ret);
exit(1);
}
if (cmdbuf.box_addr != dPriv->pClipRects) {
free(cmdbuf.box_addr);
}
/* Save the current state at the start of the command buffer. That
* state will only be emitted, if the context was lost since the
* last command buffer. */
imesa->cmdBuf.write = imesa->cmdBuf.base;
savageEmitOldState(imesa);
imesa->cmdBuf.start = imesa->cmdBuf.write;
}
if (discard) {
assert (!savageHaveIndexedVerts(imesa));
imesa->dmaVtxBuf.total = 0;
imesa->dmaVtxBuf.used = 0;
imesa->dmaVtxBuf.flushed = 0;
}
if (!savageHaveIndexedVerts(imesa)) {
imesa->clientVtxBuf.used = 0;
imesa->clientVtxBuf.flushed = 0;
}
}
void savageFlushCmdBuf( savageContextPtr imesa, GLboolean discard )
{
if (SAVAGE_DEBUG & DEBUG_VERBOSE_MSG)
fprintf (stderr, "%s\n", __FUNCTION__);
LOCK_HARDWARE(imesa);
savageFlushCmdBufLocked (imesa, discard);
UNLOCK_HARDWARE(imesa);
}
static void savageDDFlush( GLcontext *ctx )
{
savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
if (SAVAGE_DEBUG & DEBUG_VERBOSE_MSG)
fprintf (stderr, "%s\n", __FUNCTION__);
savageFlushVertices (imesa);
savageFlushCmdBuf(imesa, GL_FALSE);
}
static void savageDDFinish( GLcontext *ctx )
{
savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
if (SAVAGE_DEBUG & DEBUG_VERBOSE_MSG)
fprintf (stderr, "%s\n", __FUNCTION__);
savageFlushVertices (imesa);
savageFlushCmdBuf(imesa, GL_FALSE);
WAIT_IDLE_EMPTY(imesa);
}
void savageDDInitIoctlFuncs( GLcontext *ctx )
{
ctx->Driver.Clear = savageDDClear;
ctx->Driver.Flush = savageDDFlush;
ctx->Driver.Finish = savageDDFinish;
}