/* * * 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 */ #include "main/mtypes.h" #include "main/mm.h" #include "ffb_dd.h" #include "ffb_span.h" #include "ffb_context.h" #include "ffb_vb.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, __DRIdrawable *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); __DRIdrawable *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); }