|
|
#include "nfbGCStr.h"xxx is the routine's prefix. Valid values are gen to use the default routine or your driver's prefix if you are rewriting this routine to use the specific capabilities of your hardware.void xxx[Op]StippledFillRects ( GCPtr pGC, DrawablePtr pDraw, BoxPtr pbox, unsigned int nbox) ;
pbox
and nbox
based on
members of pGC
required by the fill style.
They can be used to implement solid, stippled,
or stippled and tiled fill styles.
Overall, stipples are similar to tiles
except the initial image to be used as a pattern is a bitmap.
StippledFillRects( )
implements a transparent stipple fill;
OpStippledFillRects( )
implements an opaque stipple fill.
The syntax of the two routines is identical.
The parameters are:
pGC
alu
, planemask
, and fg
colors
are extracted from this structure.
Also, all information associated with the stipple,
including a pointer to its image,
is extracted from this structure.
See the sample code below for how this is done.
pDraw
pbox
pbox[0]
is the first rectangle,
pbox[1]
is the second,
and pbox[nbox - 1]}
is last.
nbox
fg
and bg
colors
extracted from the pGC
pointer.
If you have no off-screen memory available to help rendering stippled rectangles, then it is unlikely that you will be able to improve on the performance of the gen code. Also, if your hardware is unable to transparently expand bitmaps from off-screen memory (which is a limitation of the Weitek P9000), then you will probably only be able to implement the opaque stippled rectangle fill routine, OpStippledFillRects.
#define NTE_WORK_AREA_STIP(src, dest_x, dest_y, width, height) \ { \ NTE_CLEAR_QUEUE(7); \ NTE_CURX((src)->x); \ NTE_CURY((src)->y); \ NTE_DESTX_DIASTP(dest_x); \ NTE_DESTY_AXSTP(dest_y); \ NTE_MAJ_AXIS_PCNT((width) - 1); \ NTE_MIN_AXIS_PCNT((height) - 1); \ NTE_CMD(S3C_BLIT_XP_YP_Y); \ }The next three lines extract some stipple information from the pGC structure.void NTE(StippledFillRects)( GCPtr pGC, DrawablePtr pDraw, BoxPtr pbox, unsigned int nbox) { int w, h, min_width, min_height, max_width, max_height; int stride, width, height; DDXPointPtr patOrg; PixmapPtr pStip; unsigned char *image; nfbGCPrivPtr pGCPriv = NFB_GC_PRIV(pGC); unsigned long fg = pGCPriv->rRop.fg; unsigned char alu = pGCPriv->rRop.alu; unsigned long planemask = pGCPriv->rRop.planemask; BoxRec *p, box; ntePrivateData_t *ntePriv = NTE_PRIVATE_DATA(pDraw->pScreen); DDXPointRec src;
w
will contain the width of the stipple in bits,
and h will contain the height.
pStip = pGC->stipple; w = pStip->drawable.width; h = pStip->drawable.height;Stipples are subject tomin_width = w * 2; min_height = h * 2;
if (min_width > ntePriv->wawidth || min_height > ntePriv->waheight) {
patOrg
offset rules
exactly the same as tiles.
This algorithm uses a similar approach to that of
the tile filling algorithm so if we can't fit
the stipple in off-screen memory,
then bail out to the gen code.
genStippledFillRects(pGC, pDraw, pbox, nbox); return; }The next three lines extract more information about the stipple from various parts of the pGC structure.
image
points to the bitmap pattern
that is to be used as the stipple.
stride
is the value in bytes
that should be added to image
to move from one line of the stipple image to the next.
patOrg
is the
DDXPointRec(D4nfb)
that defines the offset values that
must be used when filling each rectangle with the stipple.
image = pStip->devPrivate.ptr; stride = pStip->devKind; patOrg = &(pGCPriv->screenPatOrg);The above section of code samples the sizes of three rectangles in an attempt to determine the optimal size of the off-screen stipple. This is similar to the tile rectangle filling code.max_width = w; max_height = h; p = pbox; width = p->x2 - p->x1; height = p->y2 - p->y1; if (width > max_width) max_width = width; if (height > max_height) max_height = height; p = &pbox[nbox / 2]; width = p->x2 - p->x1; height = p->y2 - p->y1; if (width > max_width) max_width = width; if (height > max_height) max_height = height; p = &pbox[nbox - 1]; width = p->x2 - p->x1; height = p->y2 - p->y1; if (width > max_width) max_width = width; if (height > max_height) max_height = height;
if (max_width > ntePriv->wawidth) max_width = ntePriv->wawidth; if (max_height > ntePriv->waheight) max_height = ntePriv->waheight;
max_width = (max_width / w) * w; max_height = (max_height / h) * h;
if (max_width < min_width) max_width = min_width; if (max_height < min_height) max_height = min_height;
box.x1 = ntePriv->wax; box.y1 = ntePriv->way; box.x2 = box.x1 + w; box.y2 = box.y1 + h;The next line draws the stipple to off-screen memory on the graphics adapter. Note that we must use DrawOpaqueMonoImage(D3nfb) when drawing to off-screen memory. Using DrawMonoImage would result in garbage appearing in the stipple pattern. Also note that we only need to draw to a single plane.
NTE(DrawOpaqueMonoImage)(&box, image, 0, stride, ~0, 0, GXcopy, 1, pDraw); box.x2 = box.x1 + max_width; box.y2 = box.y1 + max_height;The following line replicates the off-screen stipple out to the optimal size determined above. Note that once again a planemask with only 1 bit is used.
nfbReplicateArea(&box, w, h, 1, pDraw);Similar to TileRects(D3nfb), we now ``blit'' the stipple in off-screen memory to on-screen memory. The only significant differences are;max_width -= w; max_height -= h;
NTE_BEGIN(ntePriv->regs); NTE_CLEAR_QUEUE(6); NTE_FRGD_COLOR(fg); NTE_PIX_CNTL(NTE_VIDEO_MEMORY_DATA_MIX); NTE_WRT_MASK(planemask); NTE_RD_MASK(1); NTE_FRGD_MIX(NTE_FRGD_SOURCE, NTE(RasterOps)[alu]); NTE_BKGD_MIX(NTE_BKGD_SOURCE, NTE(RasterOps)[GXnoop]);
while (nbox--) {
width = pbox->x2 - pbox->x1; height = pbox->y2 - pbox->y1;src.x = (pbox->x1 - patOrg->x) % (int)w; if (src.x < 0) src.x += w; src.x += ntePriv->wax; src.y = (pbox->y1 - patOrg->y) % (int)h; if (src.y < 0) src.y += h; src.y += ntePriv->way;
if (width < max_width && height < max_height) { NTE_WORK_AREA_STIP(&src, pbox->x1, pbox->y1, width, height); } else nteStippleAreaSlow(pbox, &src, max_height, max_width, ntePriv); ++pbox; }
NTE_CLEAR_QUEUE(2); NTE_RD_MASK(NTE_ALLPLANES); NTE_PIX_CNTL(0); NTE_END(); }
static void nteStippleAreaSlowXExpand( BoxRec *pbox, DDXPointRec *src, int max_width, ntePrivateData_t *ntePriv) { int width, height, x, y; int chunks, extra_width;
width = pbox->x2 - pbox->x1; height = pbox->y2 - pbox->y1; x = pbox->x1; y = pbox->y1; chunks = width / max_width; extra_width = width % max_width;
NTE_BEGIN(ntePriv->regs); while (chunks--) { NTE_WORK_AREA_STIP(src, x, y, max_width, height); x += max_width; } if (extra_width) NTE_WORK_AREA_STIP(src, x, y, extra_width, height); NTE_END(); }
static void nteStippleAreaSlow( BoxRec *pbox, DDXPointRec *src, int max_height, int max_width, ntePrivateData_t *ntePriv) { int height; int chunks, extra_height; BoxRec screen_box;height = pbox->y2 - pbox->y1; chunks = height / max_height; extra_height = height % max_height; screen_box.x1 = pbox->x1; screen_box.x2 = pbox->x2; screen_box.y1 = pbox->y1; while (chunks--) { screen_box.y2 = screen_box.y1 + max_height; nteStippleAreaSlowXExpand(&screen_box, src, max_width, ntePriv); screen_box.y1 += max_height; } if (extra_height) { screen_box.y2 = screen_box.y1 + extra_height; nteStippleAreaSlowXExpand(&screen_box, src, max_width, ntePriv); } }