New Blitter Code
Jarmo <[email protected]>
| Newsgroups | gmane.comp.emulators.winex.devel |
|---|---|
| Message-ID | <[email protected]> |
Here is new blitter code for testing purposes. The code should support DirectDrawClipper when we have workking Clipper interface. New code also supports clipping when scaling surfaces. This will prevent a crash when moving a window outside the screen on some applications. Regards, Jarmo Nikkanen
NewBlitter.c
(text/x-csrc, 14.9 KB)
/* Not an API */
RECT __union(RECT a,RECT b)
{
RECT r;
r.top = max(a.top, b.top);
r.left = max(a.left, b.left);
r.right = min(a.right, b.right);
r.bottom = min(a.bottom, b.bottom);
return r;
}
RECT __translate_rect(RECT a,int x,int y)
{
RECT r;
r.top=a.top+y;
r.left=a.left+x;
r.right=a.right+x;
r.bottom=a.bottom+y;
return r;
}
RECT __scale_rect(RECT a,DWORD xm,DWORD xd,DWORD ym,DWORD yd)
{
RECT r;
int w=(a.right-a.left)*xm/xd;
int h=(a.bottom-a.top)*ym/yd;
r.top=a.top;
r.left=a.left;
r.right=a.left+w;
r.bottom=a.top+h;
return r;
}
#define COPYBOX_COLORKEY(type) { \
type *d = (type *)dbuf, *s = (type *)sbuf, tmp; \
for (y = 0; y < h; y++) { \
for (x = 0; x < w; x++) { \
tmp = s[x]; \
if (tmp < keylow || tmp > keyhigh) d[x] = tmp; \
} \
(LPBYTE)s += sdesc.u1.lPitch; \
(LPBYTE)d += ddesc.u1.lPitch; \
} break; \
}
#define STRETCH_ROW(type) { \
type *s = (type *) sbuf, *d = (type *) dbuf; \
for (x = sx = 0; x < w; x++, sx += xinc) \
d[x] = s[sx >> 16]; \
break; }
#define COPYROW_COLORKEY(type) { \
type *s = (type *) sbuf, *d = (type *) dbuf, tmp; \
for (x = sx = 0; x < w; x++, sx += xinc) { \
tmp = s[sx >> 16]; \
if (tmp < keylow || tmp > keyhigh) d[x] = tmp; \
} \
break; }
/* ChangLog 19.06.2003 Jarmo Nikkanen
* -Support for DirectDrawClipper (multible clipping rectangles)
* -Support for clipping when scaling */
HRESULT WINAPI
DIB_DirectDrawSurface_Blt(LPDIRECTDRAWSURFACE7 iface, LPRECT rdst,
LPDIRECTDRAWSURFACE7 src, LPRECT rsrc,
DWORD dwFlags, LPDDBLTFX lpbltfx)
{
ICOM_THIS(IDirectDrawSurfaceImpl,iface);
DDSURFACEDESC2 ddesc,sdesc;
HRESULT ret = DD_OK;
int bpp, srcheight, srcwidth, dstheight, dstwidth;
int x, y;
LPBYTE dbuf, sbuf;
DWORD keylow=0, keyhigh=0, xinc=0, yinc=0, fillcolor=0;
/* Clipper Data */
LPDIRECTDRAWCLIPPER dClipper;
LPRGNDATA lpDstClipList=NULL;
LPRECT lpDstRects=NULL;
DWORD drcount=0;
RECT DefaultDstClipRect;
RECT DefaultSrcClipRect;
RECT srect, drect;
TRACE("(%p)->(%p,%p,%p,%08lx,%p)\n", This,rdst,src,rsrc,dwFlags,lpbltfx);
DD_STRUCT_INIT(&ddesc);
DD_STRUCT_INIT(&sdesc);
/* Make Some Checks */
if (dwFlags & (DDBLT_WAIT|DDBLT_ASYNC)){
static BOOL displayed = FALSE;
if (!displayed) {
FIXME("dwFlags DDBLT_WAIT and/or DDBLT_ASYNC: can't handle right now.\n");
displayed = TRUE;
}
dwFlags &= ~(DDBLT_WAIT|DDBLT_ASYNC);
}
sdesc.dwSize = sizeof(sdesc);
if (src) IDirectDrawSurface7_Lock(src, NULL, &sdesc, DDLOCK_READONLY, 0);
ddesc.dwSize = sizeof(ddesc);
IDirectDrawSurface7_Lock(iface,NULL,&ddesc,DDLOCK_WRITEONLY,0);
/* Default Clipping Rectangles */
DefaultDstClipRect.top=DefaultDstClipRect.left=0;
DefaultDstClipRect.right=ddesc.dwWidth;
DefaultDstClipRect.bottom=ddesc.dwHeight;
if (src) {
DefaultSrcClipRect.right=sdesc.dwWidth;
DefaultSrcClipRect.bottom=sdesc.dwHeight;
}
else DefaultSrcClipRect.right=DefaultSrcClipRect.bottom=0;
DefaultSrcClipRect.top=DefaultSrcClipRect.left=0;
/* Process Compressed Formats, Does not support clipping */
if (sdesc.u4.ddpfPixelFormat.dwFlags & DDPF_FOURCC)
{
if (ddesc.u4.ddpfPixelFormat.dwFlags & DDPF_FOURCC) {
if (sdesc.u4.ddpfPixelFormat.dwFourCC == ddesc.u4.ddpfPixelFormat.dwFourCC &&
sdesc.u1.dwLinearSize == ddesc.u1.dwLinearSize) {
memcpy(ddesc.lpSurface, sdesc.lpSurface, ddesc.u1.dwLinearSize);
} else {
FIXME("trying to decompress %4.4s surface to %4.4s surface\n", (char*)&sdesc.u4.ddpfPixelFormat.dwFourCC,
(char*)&ddesc.u4.ddpfPixelFormat.dwFourCC);
}
} else {
FIXME("software-decompression of %4.4s surface not supported\n", (char*)&sdesc.u4.ddpfPixelFormat.dwFourCC);
/* most compression algorithms are patented, which limits source distribution...
* patented software decompressors will only be available in the WineX binaries */
/* here, we'll just clear the destination surface */
memset(ddesc.lpSurface, 0, ddesc.u1.lPitch * ddesc.dwHeight);
}
goto release;
}
/* Reset mode flags */
BYTE has_dclipper=0;
BYTE has_scaling=0;
BYTE has_colorkey=0;
BYTE has_srccopy=0;
/* Access Clippers and find clipping rectangles, use defaults if fails */
/* Currently only destination clipping is supported. */
#ifdef jakshdksahkfsd /* Disable code, IDirectDrawClipper is not ready yet.*/
if (IDirectDrawSurface7_GetClipper(iface, &dClipper)==DD_OK) {
/* Clipper Found */
DWORD dwSize;
if (IDirectDrawClipper_GetClipList(dClipper, rdst, NULL, &dwSize)==DD_OK) {
/* Allocate space for ClipList */
lpDstClipList = (LPRGNDATA)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize);
if (IDirectDrawClipper_GetClipList(dClipper, rdst, lpDstClipList, &dwSize)==DD_OK) {
/* Read data from cliplist */
has_dclipper = 1;
lpDstRects = (LPRECT)lpDstClipList->Buffer;
drcount = lpDstClipList->rdh.nCount;
}
}
}
if (has_dclipper) {
/* FIXME: Check that rectangles in clip list wont overlap each other*/
/* ret=DDERR_INVALIDCLIPLIST; */
/* goto release; */
}
#endif
/* Set Default Clipper for destination if no cliplist defined*/
if (has_dclipper==0) {
drcount=1;
lpDstRects=&DefaultDstClipRect;
}
/* Check that input rectangles are valid */
if (rdst) {
if (rdst->left > rdst->right) { ERR("Invalid Rect\n"); ret=DDERR_INVALIDRECT; goto error; }
if (rdst->top > rdst->bottom) { ERR("Invalid Rect\n"); ret=DDERR_INVALIDRECT; goto error; }
}
else rdst=&DefaultDstClipRect;
if (rsrc) {
if (rsrc->left>rsrc->right) { ERR("Invalid Rect\n"); ret=DDERR_INVALIDRECT; goto error; }
if (rsrc->top>rsrc->bottom) { ERR("Invalid Rect\n"); ret=DDERR_INVALIDRECT; goto error; }
}
else rsrc=&DefaultSrcClipRect;
/* Width & Height values for original src,dst-rectangles */
bpp = GET_BPP(ddesc);
srcheight = rsrc->bottom - rsrc->top;
srcwidth = rsrc->right - rsrc->left;
dstheight = rdst->bottom - rdst->top;
dstwidth = rdst->right - rdst->left;
/* Scaling values */
if (src && (srcwidth!=dstwidth || srcheight!=dstheight)) {
xinc = (srcwidth << 16) / dstwidth;
yinc = (srcheight << 16) / dstheight;
has_scaling=1;
}
else xinc=1<<16, yinc=1<<16;
/* Special operations */
if (dwFlags & DDBLT_COLORFILL) fillcolor=lpbltfx->u5.dwFillColor;
if (dwFlags & DDBLT_ROP) {
switch(lpbltfx->dwROP) {
case BLACKNESS: fillcolor=0; dwFlags|=DDBLT_COLORFILL; break;
case WHITENESS: fillcolor=~0; dwFlags|=DDBLT_COLORFILL; break;
case SRCCOPY: has_srccopy=1; break;
case 0xAA0029: /* No-op */ break; /* ???? */
default:
FIXME("Unsupported raster op: %08lx Pattern: %p\n", lpbltfx->dwROP, lpbltfx->u5.lpDDSPattern);
goto error;
}
dwFlags &= ~DDBLT_ROP;
}
/* ColorKey Configuration */
if (dwFlags & (DDBLT_KEYSRC | DDBLT_KEYSRCOVERRIDE | DDBLT_KEYDEST)) {
if (dwFlags & DDBLT_KEYSRCOVERRIDE) {
keylow = lpbltfx->ddckSrcColorkey.dwColorSpaceLowValue;
keyhigh = lpbltfx->ddckSrcColorkey.dwColorSpaceHighValue;
dwFlags &= ~DDBLT_KEYSRCOVERRIDE;
}
else if (dwFlags & DDBLT_KEYSRC) {
keylow = sdesc.ddckCKSrcBlt.dwColorSpaceLowValue;
keyhigh = sdesc.ddckCKSrcBlt.dwColorSpaceHighValue;
dwFlags &= ~DDBLT_KEYSRC;
} else {
/* I'm not sure if this is correct */
FIXME("DDBLT_KEYDEST not supported yet.\n");
keylow = ddesc.ddckCKDestBlt.dwColorSpaceLowValue;
keyhigh = ddesc.ddckCKDestBlt.dwColorSpaceHighValue;
dwFlags &= ~DDBLT_KEYDEST;
}
has_colorkey=1;
}
if (src) has_srccopy=1;
/* Primary loop for clipping operations */
/* Rectangles in clip list must not overlap */
begin:
while (drcount) {
drcount--;
RECT rect=lpDstRects[drcount];
/* Compute operative rectangles srect and drect */
if (!src) drect=__union(rect,*rdst); /* Sourceless Blits */
else {
srect=__union(DefaultSrcClipRect,*rsrc); /* Source clipping */
drect=__union(rect,*rdst); /* Destination clipping */
int disx=rsrc->left - rdst->left;
int disy=rsrc->top - rdst->top;
drect=__translate_rect(drect,disx,disy); /* Overlap and unscale for final combination */
if (has_scaling) drect=__scale_rect(drect,srcwidth,dstwidth,srcheight,dstheight);
srect=drect=__union(srect,drect); /* Combine source and distination */
if (has_scaling) drect=__scale_rect(drect,dstwidth,srcwidth,dstheight,srcheight); /* UnScale */
drect=__translate_rect(drect,-disx,-disy); /* UnTranslate */
}
int h = drect.bottom - drect.top;
int w = drect.right - drect.left;
if (w<=0 || h<=0) goto release;
if (!src) { /* Sourceless operations */
dbuf = (BYTE*)ddesc.lpSurface+(drect.top*ddesc.u1.lPitch)+(drect.left*bpp);
if (dwFlags & DDBLT_COLORFILL) {
ret = _Blt_ColorFill(dbuf, w, h, bpp, ddesc.u1.lPitch, fillcolor);
dwFlags &= ~DDBLT_COLORFILL;
if (ret!=DD_OK) goto begin;
else goto error;
}
/* This relies on the underlying hal driver to copy the z dib bits into the GL z-buffer */
if (dwFlags & DDBLT_DEPTHFILL) {
ret = _Blt_ColorFill(dbuf, w, h, bpp, ddesc.u1.lPitch, lpbltfx->u5.dwFillDepth);
dwFlags &= ~DDBLT_DEPTHFILL;
if (ret!=DD_OK) goto begin;
else goto error;
}
if (dwFlags & DDBLT_DDROPS) {
FIXME("\tDdraw Raster Ops: %08lx Pattern: %p\n", lpbltfx->dwDDROP, lpbltfx->u5.lpDDSPattern);
ret=DDERR_UNSUPPORTED;
dwFlags &= ~DDBLT_DDROPS;
goto error;
}
}
/* Operations With Source */
if (src && has_srccopy) {
LONG spitch = sdesc.u1.lPitch;
LONG dpitch = ddesc.u1.lPitch;
dbuf = (BYTE*)ddesc.lpSurface+(drect.top*ddesc.u1.lPitch)+(drect.left*bpp);
sbuf = (BYTE*)sdesc.lpSurface+(srect.top*sdesc.u1.lPitch)+(srect.left*bpp);
/* Copy Witout Scaling */
if (!has_scaling) {
if (!has_colorkey) { /* Copy without colorkey */
/* Detect self-copies and ensure that we copy rows in the
* right order to avoid overwriting a that is still needed.
* (memmove is used to ensure that the pixels in a row are
* copied in the right order.) */
if (src == iface && srect.top < drect.top) {
LPBYTE surf = (BYTE*)sdesc.lpSurface;
sbuf = surf + (srect.bottom-1)*spitch + srect.left*bpp;
dbuf = surf + (drect.top+h-1)*dpitch + drect.left*bpp;
spitch = -sdesc.u1.lPitch;
dpitch = -ddesc.u1.lPitch;
}
DWORD width=w*bpp;
for (y = 0; y < h; y++) {
memmove(dbuf, sbuf, width);
sbuf += spitch;
dbuf += dpitch;
}
goto begin;
}
else { /* Copy with colorkey */
switch (bpp) {
case 1: COPYBOX_COLORKEY(BYTE)
case 2: COPYBOX_COLORKEY(WORD)
case 4: COPYBOX_COLORKEY(DWORD)
default:
FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
ret = DDERR_UNSUPPORTED;
goto error;
}
goto begin;
}
}
/* Copy with scaling */
if (has_scaling) {
LPBYTE sbase;
int sx, sy;
sbase = (BYTE*)sdesc.lpSurface+(srect.top*sdesc.u1.lPitch)+srect.left*bpp;
if (!has_colorkey) {
if (dstwidth == srcwidth) {
/* Stretching in Y direction only */
DWORD width = w * bpp;
for (y = sy = 0; y < h; y++, sy += yinc) {
sbuf = sbase + (sy >> 16) * sdesc.u1.lPitch;
memmove(dbuf, sbuf, width);
dbuf += ddesc.u1.lPitch;
}
goto begin;
}
if (dstwidth != srcwidth) {
/* Stretching in X,Y direction */
int last_sy = -1;
DWORD width = w * bpp;
for (y = sy = 0; y < h; y++, sy += yinc) {
sbuf = sbase + (sy >> 16) * sdesc.u1.lPitch;
if ((sy >> 16) == (last_sy >> 16)) {
/* this sourcerow is the same as last sourcerow -
* copy already stretched row
*/
memmove(dbuf, dbuf - ddesc.u1.lPitch, width);
}
else {
switch(bpp) {
case 1: STRETCH_ROW(BYTE)
case 2: STRETCH_ROW(WORD)
case 4: STRETCH_ROW(DWORD)
case 3: {
LPBYTE s,d = dbuf;
for (x = sx = 0; x < w; x++, sx+= xinc) {
DWORD pixel;
s = sbuf+3*(sx>>16);
pixel = (s[0]<<16)|(s[1]<<8)|s[2];
d[0] = (pixel>>16)&0xff;
d[1] = (pixel>> 8)&0xff;
d[2] = (pixel )&0xff;
d+=3;
} break;
}
default:
FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
ret = DDERR_UNSUPPORTED;
goto error;
}
} /* else */
dbuf += ddesc.u1.lPitch;
last_sy = sy;
}
goto begin;
}
} /* has_colorkey==0 */
if (has_colorkey) {
for (y = sy = 0; y < h; y++, sy += yinc) {
sbuf = sbase + (sy >> 16) * sdesc.u1.lPitch;
switch (bpp) {
case 1: COPYROW_COLORKEY(BYTE)
case 2: COPYROW_COLORKEY(WORD)
case 4: COPYROW_COLORKEY(DWORD)
default:
FIXME("%s color-keyed blit not implemented for bpp %d!\n",
(dwFlags & DDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
ret = DDERR_UNSUPPORTED;
goto error;
}
dbuf += ddesc.u1.lPitch;
}
goto begin;
} /* has_colorkey */
} /* has_scaling */
} /* has_srccopy */
} /* main loop ends */
error:
release:
if (dwFlags && FIXME_ON(ddraw)) {
FIXME("\tUnsupported flags: ");
DDRAW_dump_DDBLT(dwFlags);
}
if (lpDstClipList) HeapFree(GetProcessHeap(), 0, lpDstClipList);
IDirectDrawSurface7_Unlock(iface,NULL);
if (src) IDirectDrawSurface7_Unlock(src,NULL);
return ret;
}
#undef COPYBOX_COLORKEY
#undef STRETCH_ROW
#undef COPYROW_COLORKEY