369 lines
11 KiB
C
369 lines
11 KiB
C
/*
|
|
* Copyright © 1998 Keith Packard
|
|
*
|
|
* Permission to use, copy, modify, distribute, and sell this software and its
|
|
* documentation for any purpose is hereby granted without fee, provided that
|
|
* the above copyright notice appear in all copies and that both that
|
|
* copyright notice and this permission notice appear in supporting
|
|
* documentation, and that the name of Keith Packard not be used in
|
|
* advertising or publicity pertaining to distribution of the software without
|
|
* specific, written prior permission. Keith Packard makes no
|
|
* representations about the suitability of this software for any purpose. It
|
|
* is provided "as is" without express or implied warranty.
|
|
*
|
|
* KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
|
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
|
* EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
|
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
|
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
|
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
* PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
|
|
#ifdef HAVE_DIX_CONFIG_H
|
|
#include <dix-config.h>
|
|
#endif
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include "fb.h"
|
|
|
|
PixmapPtr
|
|
fbCreatePixmapBpp(ScreenPtr pScreen, int width, int height, int depth, int bpp,
|
|
unsigned usage_hint)
|
|
{
|
|
PixmapPtr pPixmap;
|
|
size_t datasize;
|
|
size_t paddedWidth;
|
|
int adjust;
|
|
int base;
|
|
|
|
paddedWidth = ((width * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits);
|
|
if (paddedWidth / 4 > 32767 || height > 32767)
|
|
return NullPixmap;
|
|
datasize = height * paddedWidth;
|
|
base = pScreen->totalPixmapSize;
|
|
adjust = 0;
|
|
if (base & 7)
|
|
adjust = 8 - (base & 7);
|
|
datasize += adjust;
|
|
#ifdef FB_DEBUG
|
|
datasize += 2 * paddedWidth;
|
|
#endif
|
|
pPixmap = AllocatePixmap(pScreen, datasize);
|
|
if (!pPixmap)
|
|
return NullPixmap;
|
|
pPixmap->drawable.type = DRAWABLE_PIXMAP;
|
|
pPixmap->drawable.class = 0;
|
|
pPixmap->drawable.pScreen = pScreen;
|
|
pPixmap->drawable.depth = depth;
|
|
pPixmap->drawable.bitsPerPixel = bpp;
|
|
pPixmap->drawable.id = 0;
|
|
pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
|
|
pPixmap->drawable.x = 0;
|
|
pPixmap->drawable.y = 0;
|
|
pPixmap->drawable.width = width;
|
|
pPixmap->drawable.height = height;
|
|
pPixmap->devKind = paddedWidth;
|
|
pPixmap->refcnt = 1;
|
|
pPixmap->devPrivate.ptr = (pointer) ((char *) pPixmap + base + adjust);
|
|
|
|
#ifdef FB_DEBUG
|
|
pPixmap->devPrivate.ptr =
|
|
(void *) ((char *) pPixmap->devPrivate.ptr + paddedWidth);
|
|
fbInitializeDrawable(&pPixmap->drawable);
|
|
#endif
|
|
|
|
#ifdef COMPOSITE
|
|
pPixmap->screen_x = 0;
|
|
pPixmap->screen_y = 0;
|
|
#endif
|
|
|
|
pPixmap->usage_hint = usage_hint;
|
|
|
|
return pPixmap;
|
|
}
|
|
|
|
PixmapPtr
|
|
fbCreatePixmap(ScreenPtr pScreen, int width, int height, int depth,
|
|
unsigned usage_hint)
|
|
{
|
|
int bpp;
|
|
|
|
bpp = BitsPerPixel(depth);
|
|
if (bpp == 32 && depth <= 24)
|
|
bpp = fbGetScreenPrivate(pScreen)->pix32bpp;
|
|
return fbCreatePixmapBpp(pScreen, width, height, depth, bpp, usage_hint);
|
|
}
|
|
|
|
Bool
|
|
fbDestroyPixmap(PixmapPtr pPixmap)
|
|
{
|
|
if (--pPixmap->refcnt)
|
|
return TRUE;
|
|
FreePixmap(pPixmap);
|
|
return TRUE;
|
|
}
|
|
|
|
#define ADDRECT(reg,r,fr,rx1,ry1,rx2,ry2) \
|
|
if (((rx1) < (rx2)) && ((ry1) < (ry2)) && \
|
|
(!((reg)->data->numRects && \
|
|
((r-1)->y1 == (ry1)) && \
|
|
((r-1)->y2 == (ry2)) && \
|
|
((r-1)->x1 <= (rx1)) && \
|
|
((r-1)->x2 >= (rx2))))) \
|
|
{ \
|
|
if ((reg)->data->numRects == (reg)->data->size) \
|
|
{ \
|
|
RegionRectAlloc(reg, 1); \
|
|
fr = RegionBoxptr(reg); \
|
|
r = fr + (reg)->data->numRects; \
|
|
} \
|
|
r->x1 = (rx1); \
|
|
r->y1 = (ry1); \
|
|
r->x2 = (rx2); \
|
|
r->y2 = (ry2); \
|
|
(reg)->data->numRects++; \
|
|
if(r->x1 < (reg)->extents.x1) \
|
|
(reg)->extents.x1 = r->x1; \
|
|
if(r->x2 > (reg)->extents.x2) \
|
|
(reg)->extents.x2 = r->x2; \
|
|
r++; \
|
|
}
|
|
|
|
/* Convert bitmap clip mask into clipping region.
|
|
* First, goes through each line and makes boxes by noting the transitions
|
|
* from 0 to 1 and 1 to 0.
|
|
* Then it coalesces the current line with the previous if they have boxes
|
|
* at the same X coordinates.
|
|
*/
|
|
RegionPtr
|
|
fbPixmapToRegion(PixmapPtr pPix)
|
|
{
|
|
register RegionPtr pReg;
|
|
FbBits *pw, w;
|
|
register int ib;
|
|
int width, h, base, rx1 = 0, crects;
|
|
FbBits *pwLineEnd;
|
|
int irectPrevStart, irectLineStart;
|
|
register BoxPtr prectO, prectN;
|
|
BoxPtr FirstRect, rects, prectLineStart;
|
|
Bool fInBox, fSame;
|
|
register FbBits mask0 = FB_ALLONES & ~FbScrRight(FB_ALLONES, 1);
|
|
FbBits *pwLine;
|
|
int nWidth;
|
|
|
|
pReg = RegionCreate(NULL, 1);
|
|
if (!pReg)
|
|
return NullRegion;
|
|
FirstRect = RegionBoxptr(pReg);
|
|
rects = FirstRect;
|
|
|
|
fbPrepareAccess(&pPix->drawable);
|
|
|
|
pwLine = (FbBits *) pPix->devPrivate.ptr;
|
|
nWidth = pPix->devKind >> (FB_SHIFT - 3);
|
|
|
|
width = pPix->drawable.width;
|
|
pReg->extents.x1 = width - 1;
|
|
pReg->extents.x2 = 0;
|
|
irectPrevStart = -1;
|
|
for (h = 0; h < pPix->drawable.height; h++) {
|
|
pw = pwLine;
|
|
pwLine += nWidth;
|
|
irectLineStart = rects - FirstRect;
|
|
/* If the Screen left most bit of the word is set, we're starting in
|
|
* a box */
|
|
if (READ(pw) & mask0) {
|
|
fInBox = TRUE;
|
|
rx1 = 0;
|
|
}
|
|
else
|
|
fInBox = FALSE;
|
|
/* Process all words which are fully in the pixmap */
|
|
pwLineEnd = pw + (width >> FB_SHIFT);
|
|
for (base = 0; pw < pwLineEnd; base += FB_UNIT) {
|
|
w = READ(pw++);
|
|
if (fInBox) {
|
|
if (!~w)
|
|
continue;
|
|
}
|
|
else {
|
|
if (!w)
|
|
continue;
|
|
}
|
|
for (ib = 0; ib < FB_UNIT; ib++) {
|
|
/* If the Screen left most bit of the word is set, we're
|
|
* starting a box */
|
|
if (w & mask0) {
|
|
if (!fInBox) {
|
|
rx1 = base + ib;
|
|
/* start new box */
|
|
fInBox = TRUE;
|
|
}
|
|
}
|
|
else {
|
|
if (fInBox) {
|
|
/* end box */
|
|
ADDRECT(pReg, rects, FirstRect,
|
|
rx1, h, base + ib, h + 1);
|
|
fInBox = FALSE;
|
|
}
|
|
}
|
|
/* Shift the word VISUALLY left one. */
|
|
w = FbScrLeft(w, 1);
|
|
}
|
|
}
|
|
if (width & FB_MASK) {
|
|
/* Process final partial word on line */
|
|
w = READ(pw++);
|
|
for (ib = 0; ib < (width & FB_MASK); ib++) {
|
|
/* If the Screen left most bit of the word is set, we're
|
|
* starting a box */
|
|
if (w & mask0) {
|
|
if (!fInBox) {
|
|
rx1 = base + ib;
|
|
/* start new box */
|
|
fInBox = TRUE;
|
|
}
|
|
}
|
|
else {
|
|
if (fInBox) {
|
|
/* end box */
|
|
ADDRECT(pReg, rects, FirstRect,
|
|
rx1, h, base + ib, h + 1);
|
|
fInBox = FALSE;
|
|
}
|
|
}
|
|
/* Shift the word VISUALLY left one. */
|
|
w = FbScrLeft(w, 1);
|
|
}
|
|
}
|
|
/* If scanline ended with last bit set, end the box */
|
|
if (fInBox) {
|
|
ADDRECT(pReg, rects, FirstRect,
|
|
rx1, h, base + (width & FB_MASK), h + 1);
|
|
}
|
|
/* if all rectangles on this line have the same x-coords as
|
|
* those on the previous line, then add 1 to all the previous y2s and
|
|
* throw away all the rectangles from this line
|
|
*/
|
|
fSame = FALSE;
|
|
if (irectPrevStart != -1) {
|
|
crects = irectLineStart - irectPrevStart;
|
|
if (crects == ((rects - FirstRect) - irectLineStart)) {
|
|
prectO = FirstRect + irectPrevStart;
|
|
prectN = prectLineStart = FirstRect + irectLineStart;
|
|
fSame = TRUE;
|
|
while (prectO < prectLineStart) {
|
|
if ((prectO->x1 != prectN->x1) ||
|
|
(prectO->x2 != prectN->x2)) {
|
|
fSame = FALSE;
|
|
break;
|
|
}
|
|
prectO++;
|
|
prectN++;
|
|
}
|
|
if (fSame) {
|
|
prectO = FirstRect + irectPrevStart;
|
|
while (prectO < prectLineStart) {
|
|
prectO->y2 += 1;
|
|
prectO++;
|
|
}
|
|
rects -= crects;
|
|
pReg->data->numRects -= crects;
|
|
}
|
|
}
|
|
}
|
|
if (!fSame)
|
|
irectPrevStart = irectLineStart;
|
|
}
|
|
if (!pReg->data->numRects)
|
|
pReg->extents.x1 = pReg->extents.x2 = 0;
|
|
else {
|
|
pReg->extents.y1 = RegionBoxptr(pReg)->y1;
|
|
pReg->extents.y2 = RegionEnd(pReg)->y2;
|
|
if (pReg->data->numRects == 1) {
|
|
free(pReg->data);
|
|
pReg->data = (RegDataPtr) NULL;
|
|
}
|
|
}
|
|
|
|
fbFinishAccess(&pPix->drawable);
|
|
#ifdef DEBUG
|
|
if (!RegionIsValid(pReg))
|
|
FatalError("Assertion failed file %s, line %d: expr\n", __FILE__,
|
|
__LINE__);
|
|
#endif
|
|
return pReg;
|
|
}
|
|
|
|
#ifdef FB_DEBUG
|
|
|
|
#ifndef WIN32
|
|
#include <stdio.h>
|
|
#else
|
|
#include <dbg.h>
|
|
#endif
|
|
|
|
static Bool
|
|
fbValidateBits(FbStip * bits, int stride, FbStip data)
|
|
{
|
|
while (stride--) {
|
|
if (*bits != data) {
|
|
#ifdef WIN32
|
|
NCD_DEBUG((DEBUG_FAILURE,
|
|
"fdValidateBits failed at 0x%x (is 0x%x want 0x%x)",
|
|
bits, *bits, data));
|
|
#else
|
|
fprintf(stderr, "fbValidateBits failed\n");
|
|
#endif
|
|
return FALSE;
|
|
}
|
|
bits++;
|
|
}
|
|
}
|
|
|
|
void
|
|
fbValidateDrawable(DrawablePtr pDrawable)
|
|
{
|
|
FbStip *bits, *first, *last;
|
|
int stride, bpp;
|
|
int xoff, yoff;
|
|
int height;
|
|
Bool failed;
|
|
|
|
if (pDrawable->type != DRAWABLE_PIXMAP)
|
|
pDrawable = (DrawablePtr) fbGetWindowPixmap(pDrawable);
|
|
fbGetStipDrawable(pDrawable, bits, stride, bpp, xoff, yoff);
|
|
first = bits - stride;
|
|
last = bits + stride * pDrawable->height;
|
|
if (!fbValidateBits(first, stride, FB_HEAD_BITS) ||
|
|
!fbValidateBits(last, stride, FB_TAIL_BITS))
|
|
fbInitializeDrawable(pDrawable);
|
|
fbFinishAccess(pDrawable);
|
|
}
|
|
|
|
void
|
|
fbSetBits(FbStip * bits, int stride, FbStip data)
|
|
{
|
|
while (stride--)
|
|
*bits++ = data;
|
|
}
|
|
|
|
void
|
|
fbInitializeDrawable(DrawablePtr pDrawable)
|
|
{
|
|
FbStip *bits, *first, *last;
|
|
int stride, bpp;
|
|
int xoff, yoff;
|
|
|
|
fbGetStipDrawable(pDrawable, bits, stride, bpp, xoff, yoff);
|
|
first = bits - stride;
|
|
last = bits + stride * pDrawable->height;
|
|
fbSetBits(first, stride, FB_HEAD_BITS);
|
|
fbSetBits(last, stride, FB_TAIL_BITS);
|
|
fbFinishAccess(pDrawable);
|
|
}
|
|
#endif /* FB_DEBUG */
|