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-2008 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"
34 /* Use the d3d_surface debug channel to have one channel for all surfaces */
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
37 void surface_gdi_cleanup(IWineD3DSurfaceImpl *This)
39 TRACE("(%p) : Cleaning up.\n", This);
41 if (This->flags & SFLAG_DIBSECTION)
44 SelectObject(This->hDC, This->dib.holdbitmap);
46 /* Release the DIB section. */
47 DeleteObject(This->dib.DIBsection);
48 This->dib.bitmap_data = NULL;
49 This->resource.allocatedMemory = NULL;
52 if (This->flags & SFLAG_USERPTR) IWineD3DSurface_SetMem((IWineD3DSurface *)This, NULL);
53 if (This->overlay_dest) list_remove(&This->overlay_entry);
55 HeapFree(GetProcessHeap(), 0, This->palette9);
57 resource_cleanup((IWineD3DResourceImpl *)This);
60 static void gdi_surface_realize_palette(IWineD3DSurfaceImpl *surface)
62 struct wined3d_palette *palette = surface->palette;
64 TRACE("surface %p.\n", surface);
68 if (surface->flags & SFLAG_DIBSECTION)
73 TRACE("Updating the DC's palette.\n");
75 for (i = 0; i < 256; ++i)
77 col[i].rgbRed = palette->palents[i].peRed;
78 col[i].rgbGreen = palette->palents[i].peGreen;
79 col[i].rgbBlue = palette->palents[i].peBlue;
80 col[i].rgbReserved = 0;
82 SetDIBColorTable(surface->hDC, 0, 256, col);
85 /* Update the image because of the palette change. Some games like e.g.
86 * Red Alert call SetEntries a lot to implement fading. */
87 /* Tell the swapchain to update the screen. */
88 if (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
90 IWineD3DSwapChainImpl *swapchain = surface->container.u.swapchain;
91 if (surface == swapchain->front_buffer)
93 x11_copy_to_screen(swapchain, NULL);
98 static HRESULT gdi_surface_draw_overlay(IWineD3DSurfaceImpl *surface)
100 FIXME("GDI surfaces can't draw overlays yet.\n");
104 static const struct wined3d_surface_ops gdi_surface_ops =
106 gdi_surface_realize_palette,
107 gdi_surface_draw_overlay,
110 /*****************************************************************************
111 * IWineD3DSurface::Release, GDI version
113 * In general a normal COM Release method, but the GDI version doesn't have
114 * to destroy all the GL things.
116 *****************************************************************************/
117 static ULONG WINAPI IWineGDISurfaceImpl_Release(IWineD3DSurface *iface) {
118 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
119 ULONG ref = InterlockedDecrement(&This->resource.ref);
120 TRACE("(%p) : Releasing from %d\n", This, ref + 1);
124 surface_gdi_cleanup(This);
126 TRACE("(%p) Released.\n", This);
127 HeapFree(GetProcessHeap(), 0, This);
133 /*****************************************************************************
134 * IWineD3DSurface::PreLoad, GDI version
136 * This call is unsupported on GDI surfaces, if it's called something went
137 * wrong in the parent library. Write an informative warning
139 *****************************************************************************/
141 IWineGDISurfaceImpl_PreLoad(IWineD3DSurface *iface)
143 ERR("(%p): PreLoad is not supported on X11 surfaces!\n", iface);
144 ERR("(%p): Most likely the parent library did something wrong.\n", iface);
145 ERR("(%p): Please report to wine-devel\n", iface);
148 static HRESULT WINAPI IWineGDISurfaceImpl_Map(IWineD3DSurface *iface,
149 WINED3DLOCKED_RECT *pLockedRect, const RECT *pRect, DWORD flags)
151 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
153 /* Already locked? */
154 if (This->flags & SFLAG_LOCKED)
156 WARN("(%p) Surface already locked\n", This);
157 /* What should I return here? */
158 return WINED3DERR_INVALIDCALL;
160 This->flags |= SFLAG_LOCKED;
162 if(!This->resource.allocatedMemory) {
163 /* This happens on gdi surfaces if the application set a user pointer and resets it.
164 * Recreate the DIB section
166 IWineD3DBaseSurfaceImpl_CreateDIBSection(iface);
167 This->resource.allocatedMemory = This->dib.bitmap_data;
170 return IWineD3DBaseSurfaceImpl_Map(iface, pLockedRect, pRect, flags);
173 static HRESULT WINAPI IWineGDISurfaceImpl_Unmap(IWineD3DSurface *iface)
175 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
176 TRACE("(%p)\n", This);
178 if (!(This->flags & SFLAG_LOCKED))
180 WARN("Trying to unmap unmapped surfaces %p.\n", iface);
181 return WINEDDERR_NOTLOCKED;
184 /* Tell the swapchain to update the screen */
185 if (This->container.type == WINED3D_CONTAINER_SWAPCHAIN)
187 IWineD3DSwapChainImpl *swapchain = This->container.u.swapchain;
188 if (This == swapchain->front_buffer)
190 x11_copy_to_screen(swapchain, &This->lockedRect);
194 This->flags &= ~SFLAG_LOCKED;
195 memset(&This->lockedRect, 0, sizeof(RECT));
199 /*****************************************************************************
200 * IWineD3DSurface::Flip, GDI version
202 * Flips 2 flipping enabled surfaces. Determining the 2 targets is done by
203 * the parent library. This implementation changes the data pointers of the
204 * surfaces and copies the new front buffer content to the screen
207 * override: Flipping target(e.g. back buffer)
210 * WINED3D_OK on success
212 *****************************************************************************/
213 static HRESULT WINAPI IWineGDISurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DSurface *override, DWORD flags)
215 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
216 IWineD3DSwapChainImpl *swapchain;
219 if (surface->container.type != WINED3D_CONTAINER_SWAPCHAIN)
221 ERR("Flipped surface is not on a swapchain\n");
222 return WINEDDERR_NOTFLIPPABLE;
225 swapchain = surface->container.u.swapchain;
226 hr = IWineD3DSwapChain_Present((IWineD3DSwapChain *)swapchain,
227 NULL, NULL, swapchain->win_handle, NULL, 0);
232 static HRESULT WINAPI IWineGDISurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) {
233 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
234 WINED3DLOCKED_RECT lock;
238 TRACE("(%p)->(%p)\n",This,pHDC);
240 if (!(This->flags & SFLAG_DIBSECTION))
242 WARN("DC not supported on this surface\n");
243 return WINED3DERR_INVALIDCALL;
246 if (This->flags & SFLAG_USERPTR)
248 ERR("Not supported on surfaces with an application-provided surfaces\n");
249 return WINEDDERR_NODC;
252 /* Give more detailed info for ddraw */
253 if (This->flags & SFLAG_DCINUSE)
254 return WINEDDERR_DCALREADYCREATED;
256 /* Can't GetDC if the surface is locked */
257 if (This->flags & SFLAG_LOCKED)
258 return WINED3DERR_INVALIDCALL;
260 memset(&lock, 0, sizeof(lock)); /* To be sure */
262 /* Should have a DIB section already */
264 /* Map the surface. */
265 hr = IWineD3DSurface_Map(iface, &lock, NULL, 0);
268 ERR("IWineD3DSurface_Map failed, hr %#x.\n", hr);
269 /* keep the dib section */
273 if (This->resource.format->id == WINED3DFMT_P8_UINT
274 || This->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM)
277 const PALETTEENTRY *pal = NULL;
280 pal = This->palette->palents;
282 IWineD3DSurfaceImpl *dds_primary;
283 IWineD3DSwapChainImpl *swapchain;
284 swapchain = This->resource.device->swapchains[0];
285 dds_primary = swapchain->front_buffer;
286 if (dds_primary && dds_primary->palette)
287 pal = dds_primary->palette->palents;
291 for (n=0; n<256; n++) {
292 col[n].rgbRed = pal[n].peRed;
293 col[n].rgbGreen = pal[n].peGreen;
294 col[n].rgbBlue = pal[n].peBlue;
295 col[n].rgbReserved = 0;
297 SetDIBColorTable(This->hDC, 0, 256, col);
302 TRACE("returning %p\n",*pHDC);
303 This->flags |= SFLAG_DCINUSE;
308 static HRESULT WINAPI IWineGDISurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) {
309 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
311 TRACE("(%p)->(%p)\n",This,hDC);
313 if (!(This->flags & SFLAG_DCINUSE))
314 return WINEDDERR_NODC;
316 if (This->hDC !=hDC) {
317 WARN("Application tries to release an invalid DC(%p), surface dc is %p\n", hDC, This->hDC);
318 return WINEDDERR_NODC;
321 /* we locked first, so unlock now */
322 IWineD3DSurface_Unmap(iface);
324 This->flags &= ~SFLAG_DCINUSE;
329 /*****************************************************************************
330 * IWineD3DSurface::PrivateSetup, GDI version
332 * Initializes the GDI surface, aka creates the DIB section we render to
333 * The DIB section creation is done by calling GetDC, which will create the
334 * section and releasing the dc to allow the app to use it. The dib section
335 * will stay until the surface is released
337 * GDI surfaces do not need to be a power of 2 in size, so the pow2 sizes
338 * are set to the real sizes to save memory. The NONPOW2 flag is unset to
339 * avoid confusion in the shared surface code.
342 * WINED3D_OK on success
343 * The return values of called methods on failure
345 *****************************************************************************/
346 static HRESULT WINAPI
347 IWineGDISurfaceImpl_PrivateSetup(IWineD3DSurface *iface)
349 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
352 This->surface_ops = &gdi_surface_ops;
354 if(This->resource.usage & WINED3DUSAGE_OVERLAY)
356 ERR("(%p) Overlays not yet supported by GDI surfaces\n", This);
357 return WINED3DERR_INVALIDCALL;
360 /* Sysmem textures have memory already allocated -
361 * release it, this avoids an unnecessary memcpy
363 hr = IWineD3DBaseSurfaceImpl_CreateDIBSection(iface);
366 HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
367 This->resource.heapMemory = NULL;
368 This->resource.allocatedMemory = This->dib.bitmap_data;
371 /* We don't mind the nonpow2 stuff in GDI */
372 This->pow2Width = This->currentDesc.Width;
373 This->pow2Height = This->currentDesc.Height;
378 static HRESULT WINAPI IWineGDISurfaceImpl_SetMem(IWineD3DSurface *iface, void *Mem) {
379 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
381 /* Render targets depend on their hdc, and we can't create an hdc on a user pointer */
382 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
383 ERR("Not supported on render targets\n");
384 return WINED3DERR_INVALIDCALL;
387 if (This->flags & (SFLAG_LOCKED | SFLAG_DCINUSE))
389 WARN("Surface is locked or the HDC is in use\n");
390 return WINED3DERR_INVALIDCALL;
393 if(Mem && Mem != This->resource.allocatedMemory) {
394 void *release = NULL;
396 /* Do I have to copy the old surface content? */
397 if (This->flags & SFLAG_DIBSECTION)
399 /* Release the DC. No need to hold the critical section for the update
400 * Thread because this thread runs only on front buffers, but this method
401 * fails for render targets in the check above.
403 SelectObject(This->hDC, This->dib.holdbitmap);
405 /* Release the DIB section */
406 DeleteObject(This->dib.DIBsection);
407 This->dib.bitmap_data = NULL;
408 This->resource.allocatedMemory = NULL;
410 This->flags &= ~SFLAG_DIBSECTION;
412 else if(!(This->flags & SFLAG_USERPTR))
414 release = This->resource.allocatedMemory;
416 This->resource.allocatedMemory = Mem;
417 This->flags |= SFLAG_USERPTR | SFLAG_INSYSMEM;
419 /* Now free the old memory if any */
420 HeapFree(GetProcessHeap(), 0, release);
422 else if (This->flags & SFLAG_USERPTR)
424 /* Map() and GetDC() will re-create the dib section and allocated memory. */
425 This->resource.allocatedMemory = NULL;
426 This->flags &= ~SFLAG_USERPTR;
431 static WINED3DSURFTYPE WINAPI IWineGDISurfaceImpl_GetImplType(IWineD3DSurface *iface) {
435 /* FIXME: This vtable should not use any IWineD3DSurface* implementation functions,
436 * only IWineD3DBaseSurface and IWineGDISurface ones.
438 const IWineD3DSurfaceVtbl IWineGDISurface_Vtbl =
441 IWineD3DBaseSurfaceImpl_QueryInterface,
442 IWineD3DBaseSurfaceImpl_AddRef,
443 IWineGDISurfaceImpl_Release,
444 /* IWineD3DResource */
445 IWineD3DBaseSurfaceImpl_GetParent,
446 IWineD3DBaseSurfaceImpl_SetPrivateData,
447 IWineD3DBaseSurfaceImpl_GetPrivateData,
448 IWineD3DBaseSurfaceImpl_FreePrivateData,
449 IWineD3DBaseSurfaceImpl_SetPriority,
450 IWineD3DBaseSurfaceImpl_GetPriority,
451 IWineGDISurfaceImpl_PreLoad,
452 IWineD3DBaseSurfaceImpl_GetType,
453 /* IWineD3DSurface */
454 IWineD3DBaseSurfaceImpl_GetDesc,
455 IWineGDISurfaceImpl_Map,
456 IWineGDISurfaceImpl_Unmap,
457 IWineGDISurfaceImpl_GetDC,
458 IWineGDISurfaceImpl_ReleaseDC,
459 IWineGDISurfaceImpl_Flip,
460 IWineD3DBaseSurfaceImpl_Blt,
461 IWineD3DBaseSurfaceImpl_GetBltStatus,
462 IWineD3DBaseSurfaceImpl_GetFlipStatus,
463 IWineD3DBaseSurfaceImpl_IsLost,
464 IWineD3DBaseSurfaceImpl_Restore,
465 IWineD3DBaseSurfaceImpl_BltFast,
466 IWineD3DBaseSurfaceImpl_GetPalette,
467 IWineD3DBaseSurfaceImpl_SetPalette,
468 IWineD3DBaseSurfaceImpl_SetColorKey,
469 IWineD3DBaseSurfaceImpl_GetPitch,
470 IWineGDISurfaceImpl_SetMem,
471 IWineD3DBaseSurfaceImpl_SetOverlayPosition,
472 IWineD3DBaseSurfaceImpl_GetOverlayPosition,
473 IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder,
474 IWineD3DBaseSurfaceImpl_UpdateOverlay,
475 IWineD3DBaseSurfaceImpl_SetClipper,
476 IWineD3DBaseSurfaceImpl_GetClipper,
478 IWineD3DBaseSurfaceImpl_SetFormat,
479 IWineGDISurfaceImpl_PrivateSetup,
480 IWineGDISurfaceImpl_GetImplType,