wined3d: Remove IWineD3DSurface::DrawOverlay() from the public interface.
[wine.git] / dlls / wined3d / surface_gdi.c
blob9a729fb0c3ab0f95fc4f6bc0f2e6c295f0d072e5
1 /*
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
28 #include "config.h"
29 #include "wine/port.h"
30 #include "wined3d_private.h"
32 #include <stdio.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)
43 /* Release the DC. */
44 SelectObject(This->hDC, This->dib.holdbitmap);
45 DeleteDC(This->hDC);
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 IWineD3DPaletteImpl *palette = surface->palette;
64 TRACE("surface %p.\n", surface);
66 if (!palette) return;
68 if (surface->flags & SFLAG_DIBSECTION)
70 RGBQUAD col[256];
71 unsigned int i;
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");
101 return E_FAIL;
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);
122 if (!ref)
124 surface_gdi_cleanup(This);
126 TRACE("(%p) Released.\n", This);
127 HeapFree(GetProcessHeap(), 0, This);
130 return ref;
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 *****************************************************************************/
140 static void WINAPI
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 /*****************************************************************************
149 * IWineD3DSurface::UnLoad, GDI version
151 * This call is unsupported on GDI surfaces, if it's called something went
152 * wrong in the parent library. Write an informative warning.
154 *****************************************************************************/
155 static void WINAPI IWineGDISurfaceImpl_UnLoad(IWineD3DSurface *iface)
157 ERR("(%p): UnLoad is not supported on X11 surfaces!\n", iface);
158 ERR("(%p): Most likely the parent library did something wrong.\n", iface);
159 ERR("(%p): Please report to wine-devel\n", iface);
162 static HRESULT WINAPI IWineGDISurfaceImpl_Map(IWineD3DSurface *iface,
163 WINED3DLOCKED_RECT *pLockedRect, const RECT *pRect, DWORD flags)
165 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
167 /* Already locked? */
168 if (This->flags & SFLAG_LOCKED)
170 WARN("(%p) Surface already locked\n", This);
171 /* What should I return here? */
172 return WINED3DERR_INVALIDCALL;
174 This->flags |= SFLAG_LOCKED;
176 if(!This->resource.allocatedMemory) {
177 /* This happens on gdi surfaces if the application set a user pointer and resets it.
178 * Recreate the DIB section
180 IWineD3DBaseSurfaceImpl_CreateDIBSection(iface);
181 This->resource.allocatedMemory = This->dib.bitmap_data;
184 return IWineD3DBaseSurfaceImpl_Map(iface, pLockedRect, pRect, flags);
187 static HRESULT WINAPI IWineGDISurfaceImpl_Unmap(IWineD3DSurface *iface)
189 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
190 TRACE("(%p)\n", This);
192 if (!(This->flags & SFLAG_LOCKED))
194 WARN("Trying to unmap unmapped surfaces %p.\n", iface);
195 return WINEDDERR_NOTLOCKED;
198 /* Tell the swapchain to update the screen */
199 if (This->container.type == WINED3D_CONTAINER_SWAPCHAIN)
201 IWineD3DSwapChainImpl *swapchain = This->container.u.swapchain;
202 if (This == swapchain->front_buffer)
204 x11_copy_to_screen(swapchain, &This->lockedRect);
208 This->flags &= ~SFLAG_LOCKED;
209 memset(&This->lockedRect, 0, sizeof(RECT));
210 return WINED3D_OK;
213 /*****************************************************************************
214 * IWineD3DSurface::Flip, GDI version
216 * Flips 2 flipping enabled surfaces. Determining the 2 targets is done by
217 * the parent library. This implementation changes the data pointers of the
218 * surfaces and copies the new front buffer content to the screen
220 * Params:
221 * override: Flipping target(e.g. back buffer)
223 * Returns:
224 * WINED3D_OK on success
226 *****************************************************************************/
227 static HRESULT WINAPI IWineGDISurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DSurface *override, DWORD flags)
229 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
230 IWineD3DSwapChainImpl *swapchain;
231 HRESULT hr;
233 if (surface->container.type != WINED3D_CONTAINER_SWAPCHAIN)
235 ERR("Flipped surface is not on a swapchain\n");
236 return WINEDDERR_NOTFLIPPABLE;
239 swapchain = surface->container.u.swapchain;
240 hr = IWineD3DSwapChain_Present((IWineD3DSwapChain *)swapchain,
241 NULL, NULL, swapchain->win_handle, NULL, 0);
243 return hr;
246 static HRESULT WINAPI IWineGDISurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) {
247 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
248 WINED3DLOCKED_RECT lock;
249 HRESULT hr;
250 RGBQUAD col[256];
252 TRACE("(%p)->(%p)\n",This,pHDC);
254 if (!(This->flags & SFLAG_DIBSECTION))
256 WARN("DC not supported on this surface\n");
257 return WINED3DERR_INVALIDCALL;
260 if (This->flags & SFLAG_USERPTR)
262 ERR("Not supported on surfaces with an application-provided surfaces\n");
263 return WINEDDERR_NODC;
266 /* Give more detailed info for ddraw */
267 if (This->flags & SFLAG_DCINUSE)
268 return WINEDDERR_DCALREADYCREATED;
270 /* Can't GetDC if the surface is locked */
271 if (This->flags & SFLAG_LOCKED)
272 return WINED3DERR_INVALIDCALL;
274 memset(&lock, 0, sizeof(lock)); /* To be sure */
276 /* Should have a DIB section already */
278 /* Map the surface. */
279 hr = IWineD3DSurface_Map(iface, &lock, NULL, 0);
280 if (FAILED(hr))
282 ERR("IWineD3DSurface_Map failed, hr %#x.\n", hr);
283 /* keep the dib section */
284 return hr;
287 if (This->resource.format->id == WINED3DFMT_P8_UINT
288 || This->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM)
290 unsigned int n;
291 const PALETTEENTRY *pal = NULL;
293 if(This->palette) {
294 pal = This->palette->palents;
295 } else {
296 IWineD3DSurfaceImpl *dds_primary;
297 IWineD3DSwapChainImpl *swapchain;
298 swapchain = This->resource.device->swapchains[0];
299 dds_primary = swapchain->front_buffer;
300 if (dds_primary && dds_primary->palette)
301 pal = dds_primary->palette->palents;
304 if (pal) {
305 for (n=0; n<256; n++) {
306 col[n].rgbRed = pal[n].peRed;
307 col[n].rgbGreen = pal[n].peGreen;
308 col[n].rgbBlue = pal[n].peBlue;
309 col[n].rgbReserved = 0;
311 SetDIBColorTable(This->hDC, 0, 256, col);
315 *pHDC = This->hDC;
316 TRACE("returning %p\n",*pHDC);
317 This->flags |= SFLAG_DCINUSE;
319 return WINED3D_OK;
322 static HRESULT WINAPI IWineGDISurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) {
323 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
325 TRACE("(%p)->(%p)\n",This,hDC);
327 if (!(This->flags & SFLAG_DCINUSE))
328 return WINEDDERR_NODC;
330 if (This->hDC !=hDC) {
331 WARN("Application tries to release an invalid DC(%p), surface dc is %p\n", hDC, This->hDC);
332 return WINEDDERR_NODC;
335 /* we locked first, so unlock now */
336 IWineD3DSurface_Unmap(iface);
338 This->flags &= ~SFLAG_DCINUSE;
340 return WINED3D_OK;
343 /*****************************************************************************
344 * IWineD3DSurface::PrivateSetup, GDI version
346 * Initializes the GDI surface, aka creates the DIB section we render to
347 * The DIB section creation is done by calling GetDC, which will create the
348 * section and releasing the dc to allow the app to use it. The dib section
349 * will stay until the surface is released
351 * GDI surfaces do not need to be a power of 2 in size, so the pow2 sizes
352 * are set to the real sizes to save memory. The NONPOW2 flag is unset to
353 * avoid confusion in the shared surface code.
355 * Returns:
356 * WINED3D_OK on success
357 * The return values of called methods on failure
359 *****************************************************************************/
360 static HRESULT WINAPI
361 IWineGDISurfaceImpl_PrivateSetup(IWineD3DSurface *iface)
363 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
364 HRESULT hr;
366 This->surface_ops = &gdi_surface_ops;
368 if(This->resource.usage & WINED3DUSAGE_OVERLAY)
370 ERR("(%p) Overlays not yet supported by GDI surfaces\n", This);
371 return WINED3DERR_INVALIDCALL;
374 /* Sysmem textures have memory already allocated -
375 * release it, this avoids an unnecessary memcpy
377 hr = IWineD3DBaseSurfaceImpl_CreateDIBSection(iface);
378 if(SUCCEEDED(hr))
380 HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
381 This->resource.heapMemory = NULL;
382 This->resource.allocatedMemory = This->dib.bitmap_data;
385 /* We don't mind the nonpow2 stuff in GDI */
386 This->pow2Width = This->currentDesc.Width;
387 This->pow2Height = This->currentDesc.Height;
389 return WINED3D_OK;
392 static HRESULT WINAPI IWineGDISurfaceImpl_SetMem(IWineD3DSurface *iface, void *Mem) {
393 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
395 /* Render targets depend on their hdc, and we can't create an hdc on a user pointer */
396 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
397 ERR("Not supported on render targets\n");
398 return WINED3DERR_INVALIDCALL;
401 if (This->flags & (SFLAG_LOCKED | SFLAG_DCINUSE))
403 WARN("Surface is locked or the HDC is in use\n");
404 return WINED3DERR_INVALIDCALL;
407 if(Mem && Mem != This->resource.allocatedMemory) {
408 void *release = NULL;
410 /* Do I have to copy the old surface content? */
411 if (This->flags & SFLAG_DIBSECTION)
413 /* Release the DC. No need to hold the critical section for the update
414 * Thread because this thread runs only on front buffers, but this method
415 * fails for render targets in the check above.
417 SelectObject(This->hDC, This->dib.holdbitmap);
418 DeleteDC(This->hDC);
419 /* Release the DIB section */
420 DeleteObject(This->dib.DIBsection);
421 This->dib.bitmap_data = NULL;
422 This->resource.allocatedMemory = NULL;
423 This->hDC = NULL;
424 This->flags &= ~SFLAG_DIBSECTION;
426 else if(!(This->flags & SFLAG_USERPTR))
428 release = This->resource.allocatedMemory;
430 This->resource.allocatedMemory = Mem;
431 This->flags |= SFLAG_USERPTR | SFLAG_INSYSMEM;
433 /* Now free the old memory if any */
434 HeapFree(GetProcessHeap(), 0, release);
436 else if (This->flags & SFLAG_USERPTR)
438 /* Map() and GetDC() will re-create the dib section and allocated memory. */
439 This->resource.allocatedMemory = NULL;
440 This->flags &= ~SFLAG_USERPTR;
442 return WINED3D_OK;
445 static WINED3DSURFTYPE WINAPI IWineGDISurfaceImpl_GetImplType(IWineD3DSurface *iface) {
446 return SURFACE_GDI;
449 /* FIXME: This vtable should not use any IWineD3DSurface* implementation functions,
450 * only IWineD3DBaseSurface and IWineGDISurface ones.
452 const IWineD3DSurfaceVtbl IWineGDISurface_Vtbl =
454 /* IUnknown */
455 IWineD3DBaseSurfaceImpl_QueryInterface,
456 IWineD3DBaseSurfaceImpl_AddRef,
457 IWineGDISurfaceImpl_Release,
458 /* IWineD3DResource */
459 IWineD3DBaseSurfaceImpl_GetParent,
460 IWineD3DBaseSurfaceImpl_SetPrivateData,
461 IWineD3DBaseSurfaceImpl_GetPrivateData,
462 IWineD3DBaseSurfaceImpl_FreePrivateData,
463 IWineD3DBaseSurfaceImpl_SetPriority,
464 IWineD3DBaseSurfaceImpl_GetPriority,
465 IWineGDISurfaceImpl_PreLoad,
466 IWineGDISurfaceImpl_UnLoad,
467 IWineD3DBaseSurfaceImpl_GetType,
468 /* IWineD3DSurface */
469 IWineD3DBaseSurfaceImpl_GetDesc,
470 IWineGDISurfaceImpl_Map,
471 IWineGDISurfaceImpl_Unmap,
472 IWineGDISurfaceImpl_GetDC,
473 IWineGDISurfaceImpl_ReleaseDC,
474 IWineGDISurfaceImpl_Flip,
475 IWineD3DBaseSurfaceImpl_Blt,
476 IWineD3DBaseSurfaceImpl_GetBltStatus,
477 IWineD3DBaseSurfaceImpl_GetFlipStatus,
478 IWineD3DBaseSurfaceImpl_IsLost,
479 IWineD3DBaseSurfaceImpl_Restore,
480 IWineD3DBaseSurfaceImpl_BltFast,
481 IWineD3DBaseSurfaceImpl_GetPalette,
482 IWineD3DBaseSurfaceImpl_SetPalette,
483 IWineD3DBaseSurfaceImpl_SetColorKey,
484 IWineD3DBaseSurfaceImpl_GetPitch,
485 IWineGDISurfaceImpl_SetMem,
486 IWineD3DBaseSurfaceImpl_SetOverlayPosition,
487 IWineD3DBaseSurfaceImpl_GetOverlayPosition,
488 IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder,
489 IWineD3DBaseSurfaceImpl_UpdateOverlay,
490 IWineD3DBaseSurfaceImpl_SetClipper,
491 IWineD3DBaseSurfaceImpl_GetClipper,
492 /* Internal use: */
493 IWineD3DBaseSurfaceImpl_SetFormat,
494 IWineGDISurfaceImpl_PrivateSetup,
495 IWineGDISurfaceImpl_GetImplType,