2 * 2D Surface implementation without OpenGL
4 * Copyright 1997-2000 Marcus Meissner
5 * Copyright 1998-2000 Lionel Ulmer
6 * Copyright 2000-2001 TransGaming Technologies Inc.
7 * Copyright 2002-2005 Jason Edmeades
8 * Copyright 2002-2003 Raphael Junqueira
9 * Copyright 2004 Christian Costa
10 * Copyright 2005 Oliver Stieber
11 * Copyright 2006 Stefan Dösinger
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #include "wine/port.h"
30 #include "wined3d_private.h"
35 /* Use the d3d_surface debug channel to have one channel for all surfaces */
36 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
38 /*****************************************************************************
41 * Helper function that blts the front buffer contents to the target window
44 * This: Surface to copy from
45 * rc: Rectangle to copy
47 *****************************************************************************/
49 x11_copy_to_screen(IWineD3DSurfaceImpl *This,
52 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
59 TRACE("(%p)->(%p): Copying to screen\n", This, rc);
61 hSurfaceDC = This->hDC;
63 hDisplayWnd = This->resource.wineD3DDevice->ddraw_window;
64 hDisplayDC = GetDCEx(hDisplayWnd, 0, DCX_CLIPSIBLINGS|DCX_CACHE);
67 TRACE(" copying rect (%ld,%ld)->(%ld,%ld), offset (%ld,%ld)\n",
68 rc->left, rc->top, rc->right, rc->bottom, offset.x, offset.y);
71 /* FIXME: this doesn't work... if users really want to run
72 * X in 8bpp, then we need to call directly into display.drv
73 * (or Wine's equivalent), and force a private colormap
74 * without default entries. */
76 SelectPalette(hDisplayDC, This->palette->hpal, FALSE);
77 RealizePalette(hDisplayDC); /* sends messages => deadlocks */
81 drawrect.right = This->currentDesc.Width;
83 drawrect.bottom = This->currentDesc.Height;
86 /* TODO: Support clippers */
90 HWND hwnd = This->clipper->hWnd;
91 if (hwnd && GetClientRect(hwnd,&xrc))
93 OffsetRect(&xrc,offset.x,offset.y);
94 IntersectRect(&drawrect,&drawrect,&xrc);
100 IntersectRect(&drawrect,&drawrect,rc);
104 /* Only use this if the caller did not pass a rectangle, since
105 * due to double locking this could be the wrong one ...
107 if (This->lockedRect.left != This->lockedRect.right)
109 IntersectRect(&drawrect,&drawrect,&This->lockedRect);
114 drawrect.left-offset.x, drawrect.top-offset.y,
115 drawrect.right-drawrect.left, drawrect.bottom-drawrect.top,
117 drawrect.left, drawrect.top,
119 ReleaseDC(hDisplayWnd, hDisplayDC);
123 /*****************************************************************************
124 * IWineD3DSurface::PreLoad, GDI version
126 * This call is unsupported on GDI surfaces, if it's called something went
127 * wrong in the parent library. Write an informative warning
129 *****************************************************************************/
131 IWineGDISurfaceImpl_PreLoad(IWineD3DSurface *iface)
133 ERR("(%p): PreLoad is not supported on X11 surfaces!\n", iface);
134 ERR("(%p): Most likely the parent library did something wrong.\n", iface);
135 ERR("(%p): Please report to wine-devel\n", iface);
138 /*****************************************************************************
139 * IWineD3DSurface::LockRect, GDI version
141 * Locks the surface and returns a pointer to the surface memory
144 * pLockedRect: Address to return the locking info at
145 * pRect: Rectangle to lock
149 * WINED3D_OK on success
150 * WINED3DERR_INVALIDCALL on errors
152 *****************************************************************************/
154 IWineGDISurfaceImpl_LockRect(IWineD3DSurface *iface,
155 WINED3DLOCKED_RECT* pLockedRect,
159 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
161 /* Already locked? */
162 if(This->Flags & SFLAG_LOCKED)
164 ERR("(%p) Surface already locked\n", This);
165 /* What should I return here? */
166 return D3DERR_INVALIDCALL;
169 if (!(This->Flags & SFLAG_LOCKABLE))
171 /* This is some GL specific thing, see the OpenGL version of
172 * this method, but check for the flag and write a trace
174 TRACE("Warning: trying to lock unlockable surf@%p\n", This);
177 TRACE("(%p) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n",
178 This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
180 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
184 pLockedRect->pBits = This->resource.allocatedMemory;
185 This->lockedRect.left = 0;
186 This->lockedRect.top = 0;
187 This->lockedRect.right = This->currentDesc.Width;
188 This->lockedRect.bottom = This->currentDesc.Height;
190 TRACE("Locked Rect (%p) = l %ld, t %ld, r %ld, b %ld\n",
191 &This->lockedRect, This->lockedRect.left, This->lockedRect.top,
192 This->lockedRect.right, This->lockedRect.bottom);
196 TRACE("Lock Rect (%p) = l %ld, t %ld, r %ld, b %ld\n",
197 pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
199 if (This->resource.format == WINED3DFMT_DXT1)
201 /* DXT1 is half byte per pixel */
202 pLockedRect->pBits = This->resource.allocatedMemory +
203 (pLockedRect->Pitch * pRect->top) +
204 ((pRect->left * This->bytesPerPixel / 2));
208 pLockedRect->pBits = This->resource.allocatedMemory +
209 (pLockedRect->Pitch * pRect->top) +
210 (pRect->left * This->bytesPerPixel);
212 This->lockedRect.left = pRect->left;
213 This->lockedRect.top = pRect->top;
214 This->lockedRect.right = pRect->right;
215 This->lockedRect.bottom = pRect->bottom;
218 /* No dirtifying is needed for this surface implementation */
219 TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch);
221 This->Flags |= SFLAG_LOCKED;
225 /*****************************************************************************
226 * IWineD3DSurface::UnlockRect, GDI version
228 * Unlocks a surface. This implementation doesn't do much, except updating
229 * the window if the front buffer is unlocked
232 * WINED3D_OK on success
233 * WINED3DERR_INVALIDCALL on failure
235 *****************************************************************************/
237 IWineGDISurfaceImpl_UnlockRect(IWineD3DSurface *iface)
239 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
240 IWineD3DDeviceImpl *dev = (IWineD3DDeviceImpl *) This->resource.wineD3DDevice;
241 TRACE("(%p)\n", This);
243 if (!(This->Flags & SFLAG_LOCKED))
245 WARN("trying to Unlock an unlocked surf@%p\n", This);
246 return WINED3DERR_INVALIDCALL;
249 /* Can be useful for debugging */
252 static unsigned int gen = 0;
255 if ((gen % 10) == 0) {
256 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
257 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
260 * debugging crash code
269 /* Update the screen */
270 if(This == (IWineD3DSurfaceImpl *) dev->ddraw_primary)
272 x11_copy_to_screen(This, &This->lockedRect);
275 This->Flags &= ~SFLAG_LOCKED;
276 memset(&This->lockedRect, 0, sizeof(RECT));
280 /*****************************************************************************
281 * IWineD3DSurface::Flip, GDI version
283 * Flips 2 flipping enabled surfaces. Determining the 2 targets is done by
284 * the parent library. This implementation changes the data pointers of the
285 * surfaces and copies the new front buffer content to the screen
288 * override: Flipping target(e.g. back buffer)
291 * WINED3D_OK on success
293 *****************************************************************************/
295 IWineGDISurfaceImpl_Flip(IWineD3DSurface *iface,
296 IWineD3DSurface *override,
299 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
300 IWineD3DSurfaceImpl *Target = (IWineD3DSurfaceImpl *) override;
301 TRACE("(%p)->(%p,%lx)\n", This, override, Flags);
303 TRACE("(%p) Flipping to surface %p\n", This, Target);
307 ERR("(%p): Can't flip without a target\n", This);
308 return WINED3DERR_INVALIDCALL;
315 This->hDC = Target->hDC;
319 /* Flip the DIBsection */
322 tmp = This->dib.DIBsection;
323 This->dib.DIBsection = Target->dib.DIBsection;
324 Target->dib.DIBsection = tmp;
327 /* Flip the surface data */
331 tmp = This->dib.bitmap_data;
332 This->dib.bitmap_data = Target->dib.bitmap_data;
333 Target->dib.bitmap_data = tmp;
335 tmp = This->resource.allocatedMemory;
336 This->resource.allocatedMemory = Target->resource.allocatedMemory;
337 Target->resource.allocatedMemory = tmp;
340 /* client_memory should not be different, but just in case */
343 tmp = This->dib.client_memory;
344 This->dib.client_memory = Target->dib.client_memory;
345 Target->dib.client_memory = tmp;
348 /* Useful for debugging */
351 static unsigned int gen = 0;
354 if ((gen % 10) == 0) {
355 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
356 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
359 * debugging crash code
368 /* Update the screen */
369 x11_copy_to_screen(This, NULL);
374 /*****************************************************************************
377 * Helper function that fills a memory area with a specific color
380 * buf: memory address to start filling at
381 * width, height: Dimensions of the area to fill
382 * bpp: Bit depth of the surface
383 * lPitch: pitch of the surface
384 * color: Color to fill with
386 *****************************************************************************/
388 _Blt_ColorFill(BYTE *buf,
389 int width, int height,
390 int bpp, LONG lPitch,
398 #define COLORFILL_ROW(type) \
400 type *d = (type *) buf; \
401 for (x = 0; x < width; x++) \
402 d[x] = (type) color; \
407 case 1: COLORFILL_ROW(BYTE)
408 case 2: COLORFILL_ROW(WORD)
411 BYTE *d = (BYTE *) buf;
412 for (x = 0; x < width; x++,d+=3)
414 d[0] = (color ) & 0xFF;
415 d[1] = (color>> 8) & 0xFF;
416 d[2] = (color>>16) & 0xFF;
420 case 4: COLORFILL_ROW(DWORD)
422 FIXME("Color fill not implemented for bpp %d!\n", bpp*8);
423 return DDERR_UNSUPPORTED;
428 /* Now copy first row */
430 for (y = 1; y < height; y++)
433 memcpy(buf, first, width * bpp);
438 /*****************************************************************************
439 * IWineD3DSurface::Blt, GDI version
441 * Performs blits to a surface, eighter from a source of source-less blts
442 * This is the main functionality of DirectDraw
445 * DestRect: Destination rectangle to write to
446 * SrcSurface: Source surface, can be NULL
447 * SrcRect: Source rectangle
448 *****************************************************************************/
450 IWineGDISurfaceImpl_Blt(IWineD3DSurface *iface,
452 IWineD3DSurface *SrcSurface,
457 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
458 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
461 WINED3DLOCKED_RECT dlock, slock;
462 WINED3DFORMAT dfmt = WINED3DFMT_UNKNOWN, sfmt = WINED3DFMT_UNKNOWN;
463 int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
466 TRACE("(%p)->(%p,%p,%p,%lx,%p)\n", This, DestRect, Src, SrcRect, Flags, DDBltFx);
468 if (TRACE_ON(d3d_surface))
470 if (DestRect) TRACE("\tdestrect :%ldx%ld-%ldx%ld\n",
471 DestRect->left, DestRect->top, DestRect->right, DestRect->bottom);
472 if (SrcRect) TRACE("\tsrcrect :%ldx%ld-%ldx%ld\n",
473 SrcRect->left, SrcRect->top, SrcRect->right, SrcRect->bottom);
476 DDRAW_dump_DDBLT(Flags);
477 if (Flags & DDBLT_DDFX)
480 DDRAW_dump_DDBLTFX(DDBltFx->dwDDFX);
485 if ( (This->Flags & SFLAG_LOCKED) || ((Src != NULL) && (Src->Flags & SFLAG_LOCKED)))
487 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
488 return DDERR_SURFACEBUSY;
493 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
494 dfmt = This->resource.format;
502 IWineD3DSurface_LockRect(SrcSurface, &slock, NULL, D3DLOCK_READONLY);
503 sfmt = Src->resource.format;
505 dfmt = This->resource.format;
506 IWineD3DSurface_LockRect(iface, &dlock,NULL,0);
509 if (!DDBltFx || !(DDBltFx->dwDDFX)) Flags &= ~DDBLT_DDFX;
511 if (isFourcc(sfmt) && isFourcc(dfmt))
515 FIXME("FOURCC->FOURCC copy only supported for the same type of surface\n");
516 ret = DDERR_INVALIDPIXELFORMAT;
519 TRACE("Fourcc->Fourcc copy)\n");
520 memcpy(dlock.pBits, slock.pBits, This->currentDesc.Height * dlock.Pitch);
524 if (isFourcc(sfmt) &&
527 FIXME("DXTC decompression not supported right now\n");
533 memcpy(&xdst,DestRect,sizeof(xdst));
538 xdst.bottom = This->currentDesc.Height;
540 xdst.right = This->currentDesc.Width;
545 memcpy(&xsrc,SrcRect,sizeof(xsrc));
552 xsrc.bottom = Src->currentDesc.Height;
554 xsrc.right = Src->currentDesc.Width;
558 memset(&xsrc,0,sizeof(xsrc));
562 /* First check for the validity of source / destination rectangles. This was
563 verified using a test application + by MSDN.
566 ((xsrc.bottom > Src->currentDesc.Height) || (xsrc.bottom < 0) ||
567 (xsrc.top > Src->currentDesc.Height) || (xsrc.top < 0) ||
568 (xsrc.left > Src->currentDesc.Width) || (xsrc.left < 0) ||
569 (xsrc.right > Src->currentDesc.Width) || (xsrc.right < 0) ||
570 (xsrc.right < xsrc.left) || (xsrc.bottom < xsrc.top)))
572 WARN("Application gave us bad source rectangle for Blt.\n");
573 ret = DDERR_INVALIDRECT;
576 /* For the Destination rect, it can be out of bounds on the condition that a clipper
577 is set for the given surface.
579 if ((/*This->clipper == NULL*/ TRUE) &&
580 ((xdst.bottom > This->currentDesc.Height) || (xdst.bottom < 0) ||
581 (xdst.top > This->currentDesc.Height) || (xdst.top < 0) ||
582 (xdst.left > This->currentDesc.Width) || (xdst.left < 0) ||
583 (xdst.right > This->currentDesc.Width) || (xdst.right < 0) ||
584 (xdst.right < xdst.left) || (xdst.bottom < xdst.top)))
586 WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
587 ret = DDERR_INVALIDRECT;
591 /* Now handle negative values in the rectangles. Warning: only supported for now
592 in the 'simple' cases (ie not in any stretching / rotation cases).
594 First, the case where nothing is to be done.
596 if (((xdst.bottom <= 0) || (xdst.right <= 0) ||
597 (xdst.top >= (int) This->currentDesc.Height) ||
598 (xdst.left >= (int) This->currentDesc.Width)) ||
600 ((xsrc.bottom <= 0) || (xsrc.right <= 0) ||
601 (xsrc.top >= (int) Src->currentDesc.Height) ||
602 (xsrc.left >= (int) Src->currentDesc.Width)) ))
604 TRACE("Nothing to be done !\n");
608 /* The easy case : the source-less blits.... */
612 RECT temp_rect; /* No idea if intersect rect can be the same as one of the source rect */
616 full_rect.right = This->currentDesc.Width;
617 full_rect.bottom = This->currentDesc.Height;
618 IntersectRect(&temp_rect, &full_rect, &xdst);
623 /* Only handle clipping on the destination rectangle */
624 int clip_horiz = (xdst.left < 0) || (xdst.right > (int) This->currentDesc.Width );
625 int clip_vert = (xdst.top < 0) || (xdst.bottom > (int) This->currentDesc.Height);
626 if (clip_vert || clip_horiz)
628 /* Now check if this is a special case or not... */
629 if ((((xdst.bottom - xdst.top ) != (xsrc.bottom - xsrc.top )) && clip_vert ) ||
630 (((xdst.right - xdst.left) != (xsrc.right - xsrc.left)) && clip_horiz) ||
631 (Flags & DDBLT_DDFX))
633 WARN("Out of screen rectangle in special case. Not handled right now.\n");
639 if (xdst.left < 0) { xsrc.left -= xdst.left; xdst.left = 0; }
640 if (xdst.right > This->currentDesc.Width)
642 xsrc.right -= (xdst.right - (int) This->currentDesc.Width);
643 xdst.right = (int) This->currentDesc.Width;
650 xsrc.top -= xdst.top;
653 if (xdst.bottom > This->currentDesc.Height)
655 xsrc.bottom -= (xdst.bottom - (int) This->currentDesc.Height);
656 xdst.bottom = (int) This->currentDesc.Height;
659 /* And check if after clipping something is still to be done... */
660 if ((xdst.bottom <= 0) || (xdst.right <= 0) ||
661 (xdst.top >= (int) This->currentDesc.Height) ||
662 (xdst.left >= (int) This->currentDesc.Width) ||
663 (xsrc.bottom <= 0) || (xsrc.right <= 0) ||
664 (xsrc.top >= (int) Src->currentDesc.Height) ||
665 (xsrc.left >= (int) Src->currentDesc.Width))
667 TRACE("Nothing to be done after clipping !\n");
673 bpp = This->bytesPerPixel;
674 srcheight = xsrc.bottom - xsrc.top;
675 srcwidth = xsrc.right - xsrc.left;
676 dstheight = xdst.bottom - xdst.top;
677 dstwidth = xdst.right - xdst.left;
678 width = (xdst.right - xdst.left) * bpp;
680 assert(width <= dlock.Pitch);
682 dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
684 if (Flags & DDBLT_WAIT)
686 static BOOL displayed = FALSE;
688 FIXME("Can't handle DDBLT_WAIT flag right now.\n");
690 Flags &= ~DDBLT_WAIT;
692 if (Flags & DDBLT_ASYNC)
694 static BOOL displayed = FALSE;
696 FIXME("Can't handle DDBLT_ASYNC flag right now.\n");
698 Flags &= ~DDBLT_ASYNC;
700 if (Flags & DDBLT_DONOTWAIT)
702 /* DDBLT_DONOTWAIT appeared in DX7 */
703 static BOOL displayed = FALSE;
705 FIXME("Can't handle DDBLT_DONOTWAIT flag right now.\n");
707 Flags &= ~DDBLT_DONOTWAIT;
710 /* First, all the 'source-less' blits */
711 if (Flags & DDBLT_COLORFILL)
713 ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
714 dlock.Pitch, DDBltFx->u5.dwFillColor);
715 Flags &= ~DDBLT_COLORFILL;
718 if (Flags & DDBLT_DEPTHFILL)
720 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
722 if (Flags & DDBLT_ROP)
724 /* Catch some degenerate cases here */
725 switch(DDBltFx->dwROP)
728 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
730 case 0xAA0029: /* No-op */
733 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
735 case SRCCOPY: /* well, we do that below ? */
738 FIXME("Unsupported raster op: %08lx Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern);
743 if (Flags & DDBLT_DDROPS)
745 FIXME("\tDdraw Raster Ops: %08lx Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern);
747 /* Now the 'with source' blits */
751 int sx, xinc, sy, yinc;
753 if (!dstwidth || !dstheight) /* hmm... stupid program ? */
755 sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
756 xinc = (srcwidth << 16) / dstwidth;
757 yinc = (srcheight << 16) / dstheight;
761 /* No effects, we can cheat here */
762 if (dstwidth == srcwidth)
764 if (dstheight == srcheight)
766 /* No stretching in either direction. This needs to be as
767 * fast as possible */
770 /* check for overlapping surfaces */
771 if (SrcSurface != iface || xdst.top < xsrc.top ||
772 xdst.right <= xsrc.left || xsrc.right <= xdst.left)
774 /* no overlap, or dst above src, so copy from top downwards */
775 for (y = 0; y < dstheight; y++)
777 memcpy(dbuf, sbuf, width);
782 else if (xdst.top > xsrc.top) /* copy from bottom upwards */
784 sbuf += (slock.Pitch*dstheight);
785 dbuf += (dlock.Pitch*dstheight);
786 for (y = 0; y < dstheight; y++)
790 memcpy(dbuf, sbuf, width);
793 else /* src and dst overlapping on the same line, use memmove */
795 for (y = 0; y < dstheight; y++)
797 memmove(dbuf, sbuf, width);
803 /* Stretching in Y direction only */
804 for (y = sy = 0; y < dstheight; y++, sy += yinc) {
805 sbuf = sbase + (sy >> 16) * slock.Pitch;
806 memcpy(dbuf, sbuf, width);
813 /* Stretching in X direction */
815 for (y = sy = 0; y < dstheight; y++, sy += yinc)
817 sbuf = sbase + (sy >> 16) * slock.Pitch;
819 if ((sy >> 16) == (last_sy >> 16))
821 /* this sourcerow is the same as last sourcerow -
822 * copy already stretched row
824 memcpy(dbuf, dbuf - dlock.Pitch, width);
828 #define STRETCH_ROW(type) { \
829 type *s = (type *) sbuf, *d = (type *) dbuf; \
830 for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
831 d[x] = s[sx >> 16]; \
836 case 1: STRETCH_ROW(BYTE)
837 case 2: STRETCH_ROW(WORD)
838 case 4: STRETCH_ROW(DWORD)
842 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
847 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
848 d[0] = (pixel )&0xff;
849 d[1] = (pixel>> 8)&0xff;
850 d[2] = (pixel>>16)&0xff;
856 FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
857 ret = DDERR_UNSUPPORTED;
869 LONG dstyinc = dlock.Pitch, dstxinc = bpp;
870 DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
871 if (Flags & (DDBLT_KEYSRC | DDBLT_KEYDEST | DDBLT_KEYSRCOVERRIDE | DDBLT_KEYDESTOVERRIDE))
874 if (Flags & DDBLT_KEYSRC)
876 keylow = Src->SrcBltCKey.dwColorSpaceLowValue;
877 keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
879 else if (Flags & DDBLT_KEYDEST)
881 keylow = This->DestBltCKey.dwColorSpaceLowValue;
882 keyhigh = This->DestBltCKey.dwColorSpaceHighValue;
884 else if (Flags & DDBLT_KEYSRCOVERRIDE)
886 keylow = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue;
887 keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue;
891 keylow = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue;
892 keyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue;
900 keymask = get_bitmask_red(Src->resource.format) |
901 get_bitmask_green(Src->resource.format) |
902 get_bitmask_blue(Src->resource.format);
904 Flags &= ~(DDBLT_KEYSRC | DDBLT_KEYDEST | DDBLT_KEYSRCOVERRIDE | DDBLT_KEYDESTOVERRIDE);
907 if (Flags & DDBLT_DDFX)
909 LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
912 dTopRight = dbuf+((dstwidth-1)*bpp);
913 dBottomLeft = dTopLeft+((dstheight-1)*dlock.Pitch);
914 dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
916 if (DDBltFx->dwDDFX & DDBLTFX_ARITHSTRETCHY)
918 /* I don't think we need to do anything about this flag */
919 WARN("Flags=DDBLT_DDFX nothing done for DDBLTFX_ARITHSTRETCHY\n");
921 if (DDBltFx->dwDDFX & DDBLTFX_MIRRORLEFTRIGHT)
924 dTopRight = dTopLeft;
927 dBottomRight = dBottomLeft;
929 dstxinc = dstxinc *-1;
931 if (DDBltFx->dwDDFX & DDBLTFX_MIRRORUPDOWN)
934 dTopLeft = dBottomLeft;
937 dTopRight = dBottomRight;
939 dstyinc = dstyinc *-1;
941 if (DDBltFx->dwDDFX & DDBLTFX_NOTEARING)
943 /* I don't think we need to do anything about this flag */
944 WARN("Flags=DDBLT_DDFX nothing done for DDBLTFX_NOTEARING\n");
946 if (DDBltFx->dwDDFX & DDBLTFX_ROTATE180)
949 dBottomRight = dTopLeft;
952 dBottomLeft = dTopRight;
954 dstxinc = dstxinc * -1;
955 dstyinc = dstyinc * -1;
957 if (DDBltFx->dwDDFX & DDBLTFX_ROTATE270)
960 dTopLeft = dBottomLeft;
961 dBottomLeft = dBottomRight;
962 dBottomRight = dTopRight;
967 dstxinc = dstxinc * -1;
969 if (DDBltFx->dwDDFX & DDBLTFX_ROTATE90)
972 dTopLeft = dTopRight;
973 dTopRight = dBottomRight;
974 dBottomRight = dBottomLeft;
979 dstyinc = dstyinc * -1;
981 if (DDBltFx->dwDDFX & DDBLTFX_ZBUFFERBASEDEST)
983 /* I don't think we need to do anything about this flag */
984 WARN("Flags=DDBLT_DDFX nothing done for DDBLTFX_ZBUFFERBASEDEST\n");
987 Flags &= ~(DDBLT_DDFX);
990 #define COPY_COLORKEY_FX(type) { \
991 type *s, *d = (type *) dbuf, *dx, tmp; \
992 for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
993 s = (type*)(sbase + (sy >> 16) * slock.Pitch); \
995 for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
997 if ((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) dx[0] = tmp; \
998 dx = (type*)(((LPBYTE)dx)+dstxinc); \
1000 d = (type*)(((LPBYTE)d)+dstyinc); \
1005 case 1: COPY_COLORKEY_FX(BYTE)
1006 case 2: COPY_COLORKEY_FX(WORD)
1007 case 4: COPY_COLORKEY_FX(DWORD)
1010 LPBYTE s,d = dbuf, dx;
1011 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1013 sbuf = sbase + (sy >> 16) * slock.Pitch;
1015 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1018 s = sbuf+3*(sx>>16);
1019 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1020 if ((pixel & keymask) < keylow || (pixel & keymask) > keyhigh)
1022 dx[0] = (pixel )&0xff;
1023 dx[1] = (pixel>> 8)&0xff;
1024 dx[2] = (pixel>>16)&0xff;
1033 FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1034 (Flags & DDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
1035 ret = DDERR_UNSUPPORTED;
1037 #undef COPY_COLORKEY_FX
1043 if (Flags && FIXME_ON(d3d_surface))
1045 FIXME("\tUnsupported flags: %08lx", Flags);
1049 IWineD3DSurface_UnlockRect(iface);
1050 if (SrcSurface && SrcSurface != iface) IWineD3DSurface_UnlockRect(SrcSurface);
1054 /*****************************************************************************
1055 * IWineD3DSurface::BltFast, GDI version
1057 * This is the software implementation of BltFast, as used by GDI surfaces
1058 * and as a fallback for OpenGL surfaces. This code is taken from the old
1059 * DirectDraw code, and was originally written by TransGaming.
1064 * Source: Source surface to copy from
1065 * rsrc: Source rectangle
1069 * WINED3D_OK on success
1071 *****************************************************************************/
1073 IWineGDISurfaceImpl_BltFast(IWineD3DSurface *iface,
1076 IWineD3DSurface *Source,
1080 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1081 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) Source;
1083 int bpp, w, h, x, y;
1084 WINED3DLOCKED_RECT dlock,slock;
1085 HRESULT ret = DD_OK;
1087 RECT lock_src, lock_dst, lock_union;
1090 if (TRACE_ON(d3d_surface))
1092 TRACE("(%p)->(%ld,%ld,%p,%p,%08lx)\n", This,dstx,dsty,Src,rsrc,trans);
1096 TRACE("\tsrcrect: %ldx%ld-%ldx%ld\n",rsrc->left,rsrc->top,
1097 rsrc->right,rsrc->bottom);
1101 TRACE(" srcrect: NULL\n");
1105 if ((This->Flags & SFLAG_LOCKED) ||
1106 ((Src != NULL) && (Src->Flags & SFLAG_LOCKED)))
1108 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1109 return DDERR_SURFACEBUSY;
1114 WARN("rsrc is NULL!\n");
1118 rsrc->right = Src->currentDesc.Width;
1119 rsrc->bottom = Src->currentDesc.Height;
1122 /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1123 if ((rsrc->bottom > Src->currentDesc.Height) || (rsrc->bottom < 0) ||
1124 (rsrc->top > Src->currentDesc.Height) || (rsrc->top < 0) ||
1125 (rsrc->left > Src->currentDesc.Width) || (rsrc->left < 0) ||
1126 (rsrc->right > Src->currentDesc.Width) || (rsrc->right < 0) ||
1127 (rsrc->right < rsrc->left) || (rsrc->bottom < rsrc->top))
1129 WARN("Application gave us bad source rectangle for BltFast.\n");
1130 return DDERR_INVALIDRECT;
1133 h = rsrc->bottom - rsrc->top;
1134 if (h > This->currentDesc.Height-dsty) h = This->currentDesc.Height-dsty;
1135 if (h > Src->currentDesc.Height-rsrc->top) h=Src->currentDesc.Height-rsrc->top;
1136 if (h <= 0) return DDERR_INVALIDRECT;
1138 w = rsrc->right - rsrc->left;
1139 if (w > This->currentDesc.Width-dstx) w = This->currentDesc.Width-dstx;
1140 if (w > Src->currentDesc.Width-rsrc->left) w = Src->currentDesc.Width-rsrc->left;
1141 if (w <= 0) return DDERR_INVALIDRECT;
1143 /* Now compute the locking rectangle... */
1144 lock_src.left = rsrc->left;
1145 lock_src.top = rsrc->top;
1146 lock_src.right = lock_src.left + w;
1147 lock_src.bottom = lock_src.top + h;
1149 lock_dst.left = dstx;
1150 lock_dst.top = dsty;
1151 lock_dst.right = dstx + w;
1152 lock_dst.bottom = dsty + h;
1154 bpp = This->bytesPerPixel;
1156 /* We need to lock the surfaces, or we won't get refreshes when done. */
1161 UnionRect(&lock_union, &lock_src, &lock_dst);
1163 /* Lock the union of the two rectangles */
1164 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_union, 0);
1165 if(ret != D3D_OK) goto error;
1167 pitch = dlock.Pitch;
1168 slock.Pitch = dlock.Pitch;
1170 /* Since slock was originally copied from this surface's description, we can just reuse it */
1171 assert(This->resource.allocatedMemory != NULL);
1172 sbuf = (BYTE *)This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
1173 dbuf = (BYTE *)This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
1177 ret = IWineD3DSurface_LockRect(Source, &slock, &lock_src, D3DLOCK_READONLY);
1178 if(ret != D3D_OK) goto error;
1179 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_dst, 0);
1180 if(ret != D3D_OK) goto error;
1184 TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf);
1187 /* Handle first the FOURCC surfaces... */
1188 if (isFourcc(Src->resource.format) && isFourcc(This->resource.format))
1190 TRACE("Fourcc -> Fourcc copy\n");
1192 FIXME("trans arg not supported when a FOURCC surface is involved\n");
1194 FIXME("offset for destination surface is not supported\n");
1195 if (Src->resource.format != This->resource.format)
1197 FIXME("FOURCC->FOURCC copy only supported for the same type of surface\n");
1198 ret = DDERR_INVALIDPIXELFORMAT;
1201 /* FIXME: Watch out that the size is correct for FOURCC surfaces */
1202 memcpy(dbuf, sbuf, This->resource.size);
1205 if ((isFourcc(Src->resource.format)) &&
1206 (!isFourcc(This->resource.format)))
1208 /* TODO: Use the libtxc_dxtn.so shared library to do
1209 * software decompression
1211 ERR("DXTC decompression not supported by now\n");
1215 if (trans & (DDBLTFAST_SRCCOLORKEY | DDBLTFAST_DESTCOLORKEY))
1217 DWORD keylow, keyhigh;
1218 TRACE("Color keyed copy\n");
1219 if (trans & DDBLTFAST_SRCCOLORKEY)
1221 keylow = Src->SrcBltCKey.dwColorSpaceLowValue;
1222 keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1226 /* I'm not sure if this is correct */
1227 FIXME("DDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
1228 keylow = This->DestBltCKey.dwColorSpaceLowValue;
1229 keyhigh = This->DestBltCKey.dwColorSpaceHighValue;
1232 #define COPYBOX_COLORKEY(type) { \
1234 s = (type *) sbuf; \
1235 d = (type *) dbuf; \
1236 for (y = 0; y < h; y++) { \
1237 for (x = 0; x < w; x++) { \
1239 if (tmp < keylow || tmp > keyhigh) d[x] = tmp; \
1241 s = (type *)((BYTE *)s + slock.Pitch); \
1242 d = (type *)((BYTE *)d + dlock.Pitch); \
1248 case 1: COPYBOX_COLORKEY(BYTE)
1249 case 2: COPYBOX_COLORKEY(WORD)
1250 case 4: COPYBOX_COLORKEY(DWORD)
1257 for (y = 0; y < h; y++)
1259 for (x = 0; x < w * 3; x += 3)
1261 tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
1262 if (tmp < keylow || tmp > keyhigh)
1264 d[x + 0] = s[x + 0];
1265 d[x + 1] = s[x + 1];
1266 d[x + 2] = s[x + 2];
1275 FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
1276 ret = DDERR_UNSUPPORTED;
1279 #undef COPYBOX_COLORKEY
1280 TRACE("Copy Done\n");
1284 int width = w * bpp;
1285 TRACE("NO color key copy\n");
1286 for (y = 0; y < h; y++)
1288 /* This is pretty easy, a line for line memcpy */
1289 memcpy(dbuf, sbuf, width);
1290 sbuf += slock.Pitch;
1291 dbuf += dlock.Pitch;
1293 TRACE("Copy done\n");
1299 IWineD3DSurface_UnlockRect(iface);
1303 IWineD3DSurface_UnlockRect(iface);
1304 IWineD3DSurface_UnlockRect(Source);
1310 /*****************************************************************************
1311 * IWineD3DSurface::LoadTexture, GDI version
1313 * This is mutually unsupported by GDI surfaces
1316 * D3DERR_INVALIDCALL
1318 *****************************************************************************/
1320 IWineGDISurfaceImpl_LoadTexture(IWineD3DSurface *iface)
1322 ERR("Unsupported on X11 surfaces\n");
1323 return D3DERR_INVALIDCALL;
1326 /*****************************************************************************
1327 * IWineD3DSurface::SaveSnapshot, GDI version
1329 * This method writes the surface's contents to the in tga format to the
1330 * file specified in filename.
1333 * filename: File to write to
1336 * WINED3DERR_INVALIDCALL if the file couldn't be opened
1337 * WINED3D_OK on success
1339 *****************************************************************************/
1340 static int get_shift(DWORD color_mask) {
1342 while (color_mask > 0xFF) {
1346 while ((color_mask & 0x80) == 0) {
1355 IWineGDISurfaceImpl_SaveSnapshot(IWineD3DSurface *iface,
1356 const char* filename)
1360 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1361 static char *output = NULL;
1362 static int size = 0;
1364 if (This->pow2Width > size) {
1365 output = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->pow2Width * 3);
1366 size = This->pow2Width;
1370 f = fopen(filename, "w+");
1372 ERR("opening of %s failed with\n", filename);
1373 return WINED3DERR_INVALIDCALL;
1375 fprintf(f, "P6\n%d %d\n255\n", This->pow2Width, This->pow2Height);
1377 if (This->resource.format == WINED3DFMT_P8) {
1378 unsigned char table[256][3];
1381 if (This->palette == NULL) {
1383 return WINED3DERR_INVALIDCALL;
1385 for (i = 0; i < 256; i++) {
1386 table[i][0] = This->palette->palents[i].peRed;
1387 table[i][1] = This->palette->palents[i].peGreen;
1388 table[i][2] = This->palette->palents[i].peBlue;
1390 for (y = 0; y < This->pow2Height; y++) {
1391 unsigned char *src = (unsigned char *) This->resource.allocatedMemory + (y * 1 * IWineD3DSurface_GetPitch(iface));
1392 for (x = 0; x < This->pow2Width; x++) {
1393 unsigned char color = *src;
1396 output[3 * x + 0] = table[color][0];
1397 output[3 * x + 1] = table[color][1];
1398 output[3 * x + 2] = table[color][2];
1400 fwrite(output, 3 * This->pow2Width, 1, f);
1403 int red_shift, green_shift, blue_shift, pix_width;
1405 pix_width = This->bytesPerPixel;
1407 red_shift = get_shift(get_bitmask_red(This->resource.format));
1408 green_shift = get_shift(get_bitmask_green(This->resource.format));
1409 blue_shift = get_shift(get_bitmask_blue(This->resource.format));
1411 for (y = 0; y < This->pow2Height; y++) {
1412 unsigned char *src = (unsigned char *) This->resource.allocatedMemory + (y * 1 * IWineD3DSurface_GetPitch(iface));
1413 for (x = 0; x < This->pow2Width; x++) {
1419 for (i = 0; i < pix_width; i++) {
1420 color |= src[i] << (8 * i);
1422 src += 1 * pix_width;
1424 comp = color & get_bitmask_red(This->resource.format);
1425 output[3 * x + 0] = red_shift > 0 ? comp >> red_shift : comp << -red_shift;
1426 comp = color & get_bitmask_green(This->resource.format);
1427 output[3 * x + 1] = green_shift > 0 ? comp >> green_shift : comp << -green_shift;
1428 comp = color & get_bitmask_blue(This->resource.format);
1429 output[3 * x + 2] = blue_shift > 0 ? comp >> blue_shift : comp << -blue_shift;
1431 fwrite(output, 3 * This->pow2Width, 1, f);
1438 /*****************************************************************************
1439 * IWineD3DSurface::PrivateSetup, GDI version
1441 * Initializes the GDI surface, aka creates the DIB section we render to
1442 * The DIB section creation is done by calling GetDC, which will create the
1443 * section and releasing the dc to allow the app to use it. The dib section
1444 * will stay until the surface is released
1446 * GDI surfaces do not need to be a power of 2 in size, so the pow2 sizes
1447 * are set to the real sizes to save memory. The NONPOW2 flag is unset to
1448 * avoid confusion in the shared surface code.
1452 * The return values of called methods on failure
1454 *****************************************************************************/
1456 IWineGDISurfaceImpl_PrivateSetup(IWineD3DSurface *iface)
1458 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1461 long oldsize = This->resource.size;
1463 /* Sysmem textures have memory already allocated -
1464 * release it, this avoids an unnecessary memcpy
1466 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1467 This->resource.allocatedMemory = NULL;
1469 /* We don't mind the nonpow2 stuff in GDI */
1470 This->resource.size = This->currentDesc.Width * D3DFmtGetBpp(This->resource.wineD3DDevice, This->resource.format) * This->currentDesc.Width;
1471 This->pow2Size = This->resource.size;
1472 This->pow2Width = This->currentDesc.Width;
1473 This->pow2Height = This->currentDesc.Height;
1474 This->Flags &= ~SFLAG_NONPOW2;
1476 /* Adjust the opengl mem counter */
1477 globalChangeGlRam(This->resource.size - oldsize);
1479 /* Call GetDC to create a DIB section. We will use that
1480 * DIB section for rendering
1482 * Release the DC afterwards to allow the app to use it
1484 hr = IWineD3DSurface_GetDC(iface, &hdc);
1487 ERR("(%p) IWineD3DSurface::GetDC failed with hr %08lx\n", This, hr);
1490 hr = IWineD3DSurface_ReleaseDC(iface, hdc);
1493 ERR("(%p) IWineD3DSurface::ReleaseDC failed with hr %08lx\n", This, hr);
1500 const IWineD3DSurfaceVtbl IWineGDISurface_Vtbl =
1503 IWineD3DSurfaceImpl_QueryInterface,
1504 IWineD3DSurfaceImpl_AddRef,
1505 IWineD3DSurfaceImpl_Release,
1506 /* IWineD3DResource */
1507 IWineD3DSurfaceImpl_GetParent,
1508 IWineD3DSurfaceImpl_GetDevice,
1509 IWineD3DSurfaceImpl_SetPrivateData,
1510 IWineD3DSurfaceImpl_GetPrivateData,
1511 IWineD3DSurfaceImpl_FreePrivateData,
1512 IWineD3DSurfaceImpl_SetPriority,
1513 IWineD3DSurfaceImpl_GetPriority,
1514 IWineGDISurfaceImpl_PreLoad,
1515 IWineD3DSurfaceImpl_GetType,
1516 /* IWineD3DSurface */
1517 IWineD3DSurfaceImpl_GetContainerParent,
1518 IWineD3DSurfaceImpl_GetContainer,
1519 IWineD3DSurfaceImpl_GetDesc,
1520 IWineGDISurfaceImpl_LockRect,
1521 IWineGDISurfaceImpl_UnlockRect,
1522 IWineD3DSurfaceImpl_GetDC,
1523 IWineD3DSurfaceImpl_ReleaseDC,
1524 IWineGDISurfaceImpl_Flip,
1525 IWineGDISurfaceImpl_Blt,
1526 IWineD3DSurfaceImpl_GetBltStatus,
1527 IWineD3DSurfaceImpl_GetFlipStatus,
1528 IWineD3DSurfaceImpl_IsLost,
1529 IWineD3DSurfaceImpl_Restore,
1530 IWineGDISurfaceImpl_BltFast,
1531 IWineD3DSurfaceImpl_SetPixelFormat,
1532 IWineD3DSurfaceImpl_GetPalette,
1533 IWineD3DSurfaceImpl_SetPalette,
1534 IWineD3DSurfaceImpl_RealizePalette,
1535 IWineD3DSurfaceImpl_SetColorKey,
1536 IWineD3DSurfaceImpl_GetPitch,
1538 IWineD3DSurfaceImpl_CleanDirtyRect,
1539 IWineD3DSurfaceImpl_AddDirtyRect,
1540 IWineGDISurfaceImpl_LoadTexture,
1541 IWineGDISurfaceImpl_SaveSnapshot,
1542 IWineD3DSurfaceImpl_SetContainer,
1543 IWineD3DSurfaceImpl_SetPBufferState,
1544 IWineD3DSurfaceImpl_SetGlTextureDesc,
1545 IWineD3DSurfaceImpl_GetGlDesc,
1546 IWineD3DSurfaceImpl_GetData,
1547 IWineD3DSurfaceImpl_SetFormat,
1548 IWineGDISurfaceImpl_PrivateSetup