blob: 2aa5836036130aea178438d5df0e565212c51524 [file] [log] [blame]
/* $XFree86: xc/lib/GL/mesa/src/drv/ffb/ffb_clear.c,v 1.2 2002/02/22 21:32:58 dawes Exp $
*
* GLX Hardware Device Driver for Sun Creator/Creator3D
* Copyright (C) 2000 David S. Miller
*
* 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, sublicense,
* 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
* DAVID MILLER, OR ANY OTHER CONTRIBUTORS 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.
*
*
* David S. Miller <davem@redhat.com>
*/
#include "mtypes.h"
#include "extensions.h"
#include "mm.h"
#include "ffb_dd.h"
#include "ffb_span.h"
#include "ffb_depth.h"
#include "ffb_context.h"
#include "ffb_vb.h"
#include "ffb_tris.h"
#include "ffb_clear.h"
#include "ffb_lock.h"
#undef CLEAR_TRACE
#define BOX_AREA(__w, __h) ((int)(__w) * (int)(__h))
/* Compute the page aligned box for a page mode fast fill.
* In 'ework' this returns greater than zero if there are some odd
* edges to take care of which are outside of the page aligned area.
* It will place less than zero there if the box is too small,
* indicating that a different method must be used to fill it.
*/
#define CreatorPageFillParms(ffp, x, y, w, h, px, py, pw, ph, ework) \
do { int xdiff, ydiff; \
int pf_bh = ffp->pagefill_height; \
int pf_bw = ffp->pagefill_width; \
py = ((y + (pf_bh - 1)) & ~(pf_bh - 1)); \
ydiff = py - y; \
px = ffp->Pf_AlignTab[x + (pf_bw - 1)]; \
xdiff = px - x; \
ph = ((h - ydiff) & ~(pf_bh - 1)); \
if(ph <= 0) \
ework = -1; \
else { \
pw = ffp->Pf_AlignTab[w - xdiff]; \
if(pw <= 0) { \
ework = -1; \
} else { \
ework = (((xdiff > 0) || \
(ydiff > 0) || \
((w - pw) > 0) || \
((h - ph) > 0))) ? 1 : 0; \
} \
} \
} while(0);
struct ff_fixups {
int x, y, width, height;
};
/* Compute fixups of non-page aligned areas after a page fill.
* Return the number of fixups needed.
*/
static INLINE int
CreatorComputePageFillFixups(struct ff_fixups *fixups,
int x, int y, int w, int h,
int paligned_x, int paligned_y,
int paligned_w, int paligned_h)
{
int nfixups = 0;
/* FastFill Left */
if(paligned_x != x) {
fixups[nfixups].x = x;
fixups[nfixups].y = paligned_y;
fixups[nfixups].width = paligned_x - x;
fixups[nfixups].height = paligned_h;
nfixups++;
}
/* FastFill Top */
if(paligned_y != y) {
fixups[nfixups].x = x;
fixups[nfixups].y = y;
fixups[nfixups].width = w;
fixups[nfixups].height = paligned_y - y;
nfixups++;
}
/* FastFill Right */
if((x+w) != (paligned_x+paligned_w)) {
fixups[nfixups].x = (paligned_x+paligned_w);
fixups[nfixups].y = paligned_y;
fixups[nfixups].width = (x+w) - fixups[nfixups].x;
fixups[nfixups].height = paligned_h;
nfixups++;
}
/* FastFill Bottom */
if((y+h) != (paligned_y+paligned_h)) {
fixups[nfixups].x = x;
fixups[nfixups].y = (paligned_y+paligned_h);
fixups[nfixups].width = w;
fixups[nfixups].height = (y+h) - fixups[nfixups].y;
nfixups++;
}
return nfixups;
}
static void
ffb_do_clear(GLcontext *ctx, __DRIdrawablePrivate *dPriv)
{
ffbContextPtr fmesa = FFB_CONTEXT(ctx);
FFBDRIPtr gDRIPriv = (FFBDRIPtr) fmesa->driScreen->pDevPriv;
ffb_fbcPtr ffb = fmesa->regs;
drm_clip_rect_t *box = dPriv->pClipRects;
int nc = dPriv->numClipRects;
GLint cx, cy, cw, ch;
/* compute region after locking: */
cx = ctx->DrawBuffer->_Xmin;
cy = ctx->DrawBuffer->_Ymin;
cw = ctx->DrawBuffer->_Xmax - cx;
ch = ctx->DrawBuffer->_Ymax - cy;
cy = dPriv->h - cy - ch;
cx += dPriv->x;
cy += dPriv->y;
while (nc--) {
GLint x = box[nc].x1;
GLint y = box[nc].y1;
GLint width = box[nc].x2 - x;
GLint height = box[nc].y2 - y;
int paligned_y, paligned_x;
int paligned_h, paligned_w = 0;
int extra_work;
if (BOX_AREA(width, height) < gDRIPriv->fastfill_small_area) {
FFBFifo(fmesa, 5);
ffb->drawop = FFB_DRAWOP_RECTANGLE;
ffb->by = y;
ffb->bx = x;
ffb->bh = height;
ffb->bw = width;
continue;
}
FFBFifo(fmesa, 1);
ffb->drawop = FFB_DRAWOP_FASTFILL;
if (gDRIPriv->disable_pagefill ||
(width < (gDRIPriv->pagefill_width<<1)) ||
(height < (gDRIPriv->pagefill_height<<1)))
goto do_fastfill;
CreatorPageFillParms(gDRIPriv,
x, y, width, height,
paligned_x, paligned_y,
paligned_w, paligned_h, extra_work);
if (extra_work < 0 ||
BOX_AREA(paligned_w, paligned_h) < gDRIPriv->pagefill_small_area) {
do_fastfill:
FFBFifo(fmesa, 10);
ffb->by = FFB_FASTFILL_COLOR_BLK;
ffb->dy = 0;
ffb->dx = 0;
ffb->bh = gDRIPriv->fastfill_height;
ffb->bw = (gDRIPriv->fastfill_width * 4);
ffb->by = FFB_FASTFILL_BLOCK;
ffb->dy = y;
ffb->dx = x;
ffb->bh = (height + (y & (gDRIPriv->fastfill_height - 1)));
ffb->bx = (width + (x & (gDRIPriv->fastfill_width - 1)));
continue;
}
/* Ok, page fill is possible and worth it. */
FFBFifo(fmesa, 15);
ffb->by = FFB_FASTFILL_COLOR_BLK;
ffb->dy = 0;
ffb->dx = 0;
ffb->bh = gDRIPriv->fastfill_height;
ffb->bw = gDRIPriv->fastfill_width * 4;
ffb->by = FFB_FASTFILL_BLOCK_X;
ffb->dy = 0;
ffb->dx = 0;
ffb->bh = gDRIPriv->pagefill_height;
ffb->bw = gDRIPriv->pagefill_width * 4;
ffb->by = FFB_FASTFILL_PAGE;
ffb->dy = paligned_y;
ffb->dx = paligned_x;
ffb->bh = paligned_h;
ffb->bx = paligned_w;
if (extra_work) {
struct ff_fixups local_fixups[4];
int nfixups;
nfixups = CreatorComputePageFillFixups(local_fixups,
x, y, width, height,
paligned_x, paligned_y,
paligned_w, paligned_h);
FFBFifo(fmesa, 5 + (nfixups * 5));
ffb->by = FFB_FASTFILL_COLOR_BLK;
ffb->dy = 0;
ffb->dx = 0;
ffb->bh = gDRIPriv->fastfill_height;
ffb->bw = gDRIPriv->fastfill_width * 4;
while (--nfixups >= 0) {
int xx, yy, ww, hh;
xx = local_fixups[nfixups].x;
yy = local_fixups[nfixups].y;
ffb->dy = yy;
ffb->dx = xx;
ww = (local_fixups[nfixups].width +
(xx & (gDRIPriv->fastfill_width - 1)));
hh = (local_fixups[nfixups].height +
(yy & (gDRIPriv->fastfill_height - 1)));
if (nfixups != 0) {
ffb->by = FFB_FASTFILL_BLOCK;
ffb->bh = hh;
ffb->bw = ww;
} else {
ffb->bh = hh;
ffb->by = FFB_FASTFILL_BLOCK;
ffb->bx = ww;
}
}
}
}
}
void ffbDDClear(GLcontext *ctx, GLbitfield mask)
{
ffbContextPtr fmesa = FFB_CONTEXT(ctx);
__DRIdrawablePrivate *dPriv = fmesa->driDrawable;
unsigned int stcmask = BUFFER_BIT_STENCIL;
#ifdef CLEAR_TRACE
fprintf(stderr, "ffbDDClear: mask(%08x) \n", mask);
#endif
if (!(fmesa->ffb_sarea->flags & FFB_DRI_FFB2PLUS))
stcmask = 0;
if (mask & (BUFFER_BIT_FRONT_LEFT | BUFFER_BIT_BACK_LEFT | BUFFER_BIT_DEPTH | stcmask)) {
ffb_fbcPtr ffb = fmesa->regs;
unsigned int fbc, ppc;
fbc = (FFB_FBC_XE_ON);
ppc = (FFB_PPC_ACE_DISABLE | FFB_PPC_DCE_DISABLE |
FFB_PPC_ABE_DISABLE | FFB_PPC_VCE_DISABLE |
FFB_PPC_APE_DISABLE | FFB_PPC_XS_WID |
FFB_PPC_ZS_CONST | FFB_PPC_CS_CONST);
/* Y/X enables must be both on or both off. */
if (mask & (BUFFER_BIT_DEPTH | stcmask)) {
fbc |= (FFB_FBC_ZE_ON | FFB_FBC_YE_ON | FFB_FBC_WB_C);
} else
fbc |= FFB_FBC_ZE_OFF | FFB_FBC_YE_OFF;
/* All RGB enables must be both on or both off. */
if (mask & (BUFFER_BIT_FRONT_LEFT | BUFFER_BIT_BACK_LEFT)) {
if (mask & BUFFER_BIT_FRONT_LEFT) {
if (fmesa->back_buffer == 0)
fbc |= FFB_FBC_WB_B;
else
fbc |= FFB_FBC_WB_A;
}
if (mask & BUFFER_BIT_BACK_LEFT) {
if (fmesa->back_buffer == 0)
fbc |= FFB_FBC_WB_A;
else
fbc |= FFB_FBC_WB_B;
}
fbc |= FFB_FBC_RGBE_ON;
} else
fbc |= FFB_FBC_RGBE_OFF;
LOCK_HARDWARE(fmesa);
if (dPriv->numClipRects) {
FFBFifo(fmesa, 8);
ffb->fbc = fbc;
ffb->ppc = ppc;
ffb->xclip = FFB_XCLIP_TEST_ALWAYS;
ffb->cmp = 0x80808080;
ffb->rop = FFB_ROP_NEW;
if (mask & (BUFFER_BIT_FRONT_LEFT | BUFFER_BIT_BACK_LEFT))
ffb->fg = fmesa->clear_pixel;
if (mask & BUFFER_BIT_DEPTH)
ffb->constz = fmesa->clear_depth;
if (mask & stcmask)
ffb->consty = fmesa->clear_stencil;
ffb_do_clear(ctx, dPriv);
FFBFifo(fmesa, 6);
ffb->ppc = fmesa->ppc;
ffb->fbc = fmesa->fbc;
ffb->xclip = fmesa->xclip;
ffb->cmp = fmesa->cmp;
ffb->rop = fmesa->rop;
ffb->drawop = fmesa->drawop;
if (mask & stcmask)
ffb->consty = fmesa->consty;
fmesa->ffbScreen->rp_active = 1;
}
UNLOCK_HARDWARE(fmesa);
mask &= ~(BUFFER_BIT_FRONT_LEFT | BUFFER_BIT_BACK_LEFT |
BUFFER_BIT_DEPTH | stcmask);
}
if (mask)
_swrast_Clear(ctx, mask);
}