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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.