oleaut32/tests: Make sure return values are used (LLVM/Clang).
[wine] / dlls / wined3d / surface_gdi.c
1 /*
2  * 2D Surface implementation without OpenGL
3  *
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
12  *
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.
17  *
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.
22  *
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
26  */
27
28 #include "config.h"
29 #include "wine/port.h"
30 #include "wined3d_private.h"
31
32 #include <stdio.h>
33
34 /* Use the d3d_surface debug channel to have one channel for all surfaces */
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
36
37 void surface_gdi_cleanup(IWineD3DSurfaceImpl *This)
38 {
39     TRACE("(%p) : Cleaning up.\n", This);
40
41     if (This->flags & SFLAG_DIBSECTION)
42     {
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;
50     }
51
52     if (This->flags & SFLAG_USERPTR) IWineD3DSurface_SetMem((IWineD3DSurface *)This, NULL);
53     if (This->overlay_dest) list_remove(&This->overlay_entry);
54
55     HeapFree(GetProcessHeap(), 0, This->palette9);
56
57     resource_cleanup((IWineD3DResourceImpl *)This);
58 }
59
60 static void gdi_surface_realize_palette(IWineD3DSurfaceImpl *surface)
61 {
62     struct wined3d_palette *palette = surface->palette;
63
64     TRACE("surface %p.\n", surface);
65
66     if (!palette) return;
67
68     if (surface->flags & SFLAG_DIBSECTION)
69     {
70         RGBQUAD col[256];
71         unsigned int i;
72
73         TRACE("Updating the DC's palette.\n");
74
75         for (i = 0; i < 256; ++i)
76         {
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;
81         }
82         SetDIBColorTable(surface->hDC, 0, 256, col);
83     }
84
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)
89     {
90         IWineD3DSwapChainImpl *swapchain = surface->container.u.swapchain;
91         if (surface == swapchain->front_buffer)
92         {
93             x11_copy_to_screen(swapchain, NULL);
94         }
95     }
96 }
97
98 static HRESULT gdi_surface_draw_overlay(IWineD3DSurfaceImpl *surface)
99 {
100     FIXME("GDI surfaces can't draw overlays yet.\n");
101     return E_FAIL;
102 }
103
104 static const struct wined3d_surface_ops gdi_surface_ops =
105 {
106     gdi_surface_realize_palette,
107     gdi_surface_draw_overlay,
108 };
109
110 /*****************************************************************************
111  * IWineD3DSurface::Release, GDI version
112  *
113  * In general a normal COM Release method, but the GDI version doesn't have
114  * to destroy all the GL things.
115  *
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);
121
122     if (!ref)
123     {
124         surface_gdi_cleanup(This);
125
126         TRACE("(%p) Released.\n", This);
127         HeapFree(GetProcessHeap(), 0, This);
128     }
129
130     return ref;
131 }
132
133 /*****************************************************************************
134  * IWineD3DSurface::PreLoad, GDI version
135  *
136  * This call is unsupported on GDI surfaces, if it's called something went
137  * wrong in the parent library. Write an informative warning
138  *
139  *****************************************************************************/
140 static void WINAPI
141 IWineGDISurfaceImpl_PreLoad(IWineD3DSurface *iface)
142 {
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);
146 }
147
148 /*****************************************************************************
149  * IWineD3DSurface::UnLoad, GDI version
150  *
151  * This call is unsupported on GDI surfaces, if it's called something went
152  * wrong in the parent library. Write an informative warning.
153  *
154  *****************************************************************************/
155 static void WINAPI IWineGDISurfaceImpl_UnLoad(IWineD3DSurface *iface)
156 {
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);
160 }
161
162 static HRESULT WINAPI IWineGDISurfaceImpl_Map(IWineD3DSurface *iface,
163         WINED3DLOCKED_RECT *pLockedRect, const RECT *pRect, DWORD flags)
164 {
165     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
166
167     /* Already locked? */
168     if (This->flags & SFLAG_LOCKED)
169     {
170         WARN("(%p) Surface already locked\n", This);
171         /* What should I return here? */
172         return WINED3DERR_INVALIDCALL;
173     }
174     This->flags |= SFLAG_LOCKED;
175
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
179          */
180         IWineD3DBaseSurfaceImpl_CreateDIBSection(iface);
181         This->resource.allocatedMemory = This->dib.bitmap_data;
182     }
183
184     return IWineD3DBaseSurfaceImpl_Map(iface, pLockedRect, pRect, flags);
185 }
186
187 static HRESULT WINAPI IWineGDISurfaceImpl_Unmap(IWineD3DSurface *iface)
188 {
189     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
190     TRACE("(%p)\n", This);
191
192     if (!(This->flags & SFLAG_LOCKED))
193     {
194         WARN("Trying to unmap unmapped surfaces %p.\n", iface);
195         return WINEDDERR_NOTLOCKED;
196     }
197
198     /* Tell the swapchain to update the screen */
199     if (This->container.type == WINED3D_CONTAINER_SWAPCHAIN)
200     {
201         IWineD3DSwapChainImpl *swapchain = This->container.u.swapchain;
202         if (This == swapchain->front_buffer)
203         {
204             x11_copy_to_screen(swapchain, &This->lockedRect);
205         }
206     }
207
208     This->flags &= ~SFLAG_LOCKED;
209     memset(&This->lockedRect, 0, sizeof(RECT));
210     return WINED3D_OK;
211 }
212
213 /*****************************************************************************
214  * IWineD3DSurface::Flip, GDI version
215  *
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
219  *
220  * Params:
221  *  override: Flipping target(e.g. back buffer)
222  *
223  * Returns:
224  *  WINED3D_OK on success
225  *
226  *****************************************************************************/
227 static HRESULT WINAPI IWineGDISurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DSurface *override, DWORD flags)
228 {
229     IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
230     IWineD3DSwapChainImpl *swapchain;
231     HRESULT hr;
232
233     if (surface->container.type != WINED3D_CONTAINER_SWAPCHAIN)
234     {
235         ERR("Flipped surface is not on a swapchain\n");
236         return WINEDDERR_NOTFLIPPABLE;
237     }
238
239     swapchain = surface->container.u.swapchain;
240     hr = IWineD3DSwapChain_Present((IWineD3DSwapChain *)swapchain,
241             NULL, NULL, swapchain->win_handle, NULL, 0);
242
243     return hr;
244 }
245
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];
251
252     TRACE("(%p)->(%p)\n",This,pHDC);
253
254     if (!(This->flags & SFLAG_DIBSECTION))
255     {
256         WARN("DC not supported on this surface\n");
257         return WINED3DERR_INVALIDCALL;
258     }
259
260     if (This->flags & SFLAG_USERPTR)
261     {
262         ERR("Not supported on surfaces with an application-provided surfaces\n");
263         return WINEDDERR_NODC;
264     }
265
266     /* Give more detailed info for ddraw */
267     if (This->flags & SFLAG_DCINUSE)
268         return WINEDDERR_DCALREADYCREATED;
269
270     /* Can't GetDC if the surface is locked */
271     if (This->flags & SFLAG_LOCKED)
272         return WINED3DERR_INVALIDCALL;
273
274     memset(&lock, 0, sizeof(lock)); /* To be sure */
275
276     /* Should have a DIB section already */
277
278     /* Map the surface. */
279     hr = IWineD3DSurface_Map(iface, &lock, NULL, 0);
280     if (FAILED(hr))
281     {
282         ERR("IWineD3DSurface_Map failed, hr %#x.\n", hr);
283         /* keep the dib section */
284         return hr;
285     }
286
287     if (This->resource.format->id == WINED3DFMT_P8_UINT
288             || This->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM)
289     {
290         unsigned int n;
291         const PALETTEENTRY *pal = NULL;
292
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;
302         }
303
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;
310             }
311             SetDIBColorTable(This->hDC, 0, 256, col);
312         }
313     }
314
315     *pHDC = This->hDC;
316     TRACE("returning %p\n",*pHDC);
317     This->flags |= SFLAG_DCINUSE;
318
319     return WINED3D_OK;
320 }
321
322 static HRESULT WINAPI IWineGDISurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) {
323     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
324
325     TRACE("(%p)->(%p)\n",This,hDC);
326
327     if (!(This->flags & SFLAG_DCINUSE))
328         return WINEDDERR_NODC;
329
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;
333     }
334
335     /* we locked first, so unlock now */
336     IWineD3DSurface_Unmap(iface);
337
338     This->flags &= ~SFLAG_DCINUSE;
339
340     return WINED3D_OK;
341 }
342
343 /*****************************************************************************
344  * IWineD3DSurface::PrivateSetup, GDI version
345  *
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
350  *
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.
354  *
355  * Returns:
356  *  WINED3D_OK on success
357  *  The return values of called methods on failure
358  *
359  *****************************************************************************/
360 static HRESULT WINAPI
361 IWineGDISurfaceImpl_PrivateSetup(IWineD3DSurface *iface)
362 {
363     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
364     HRESULT hr;
365
366     This->surface_ops = &gdi_surface_ops;
367
368     if(This->resource.usage & WINED3DUSAGE_OVERLAY)
369     {
370         ERR("(%p) Overlays not yet supported by GDI surfaces\n", This);
371         return WINED3DERR_INVALIDCALL;
372     }
373
374     /* Sysmem textures have memory already allocated -
375      * release it, this avoids an unnecessary memcpy
376      */
377     hr = IWineD3DBaseSurfaceImpl_CreateDIBSection(iface);
378     if(SUCCEEDED(hr))
379     {
380         HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
381         This->resource.heapMemory = NULL;
382         This->resource.allocatedMemory = This->dib.bitmap_data;
383     }
384
385     /* We don't mind the nonpow2 stuff in GDI */
386     This->pow2Width = This->currentDesc.Width;
387     This->pow2Height = This->currentDesc.Height;
388
389     return WINED3D_OK;
390 }
391
392 static HRESULT WINAPI IWineGDISurfaceImpl_SetMem(IWineD3DSurface *iface, void *Mem) {
393     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
394
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;
399     }
400
401     if (This->flags & (SFLAG_LOCKED | SFLAG_DCINUSE))
402     {
403         WARN("Surface is locked or the HDC is in use\n");
404         return WINED3DERR_INVALIDCALL;
405     }
406
407     if(Mem && Mem != This->resource.allocatedMemory) {
408         void *release = NULL;
409
410         /* Do I have to copy the old surface content? */
411         if (This->flags & SFLAG_DIBSECTION)
412         {
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.
416                 */
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;
425         }
426         else if(!(This->flags & SFLAG_USERPTR))
427         {
428             release = This->resource.allocatedMemory;
429         }
430         This->resource.allocatedMemory = Mem;
431         This->flags |= SFLAG_USERPTR | SFLAG_INSYSMEM;
432
433         /* Now free the old memory if any */
434         HeapFree(GetProcessHeap(), 0, release);
435     }
436     else if (This->flags & SFLAG_USERPTR)
437     {
438         /* Map() and GetDC() will re-create the dib section and allocated memory. */
439         This->resource.allocatedMemory = NULL;
440         This->flags &= ~SFLAG_USERPTR;
441     }
442     return WINED3D_OK;
443 }
444
445 static WINED3DSURFTYPE WINAPI IWineGDISurfaceImpl_GetImplType(IWineD3DSurface *iface) {
446     return SURFACE_GDI;
447 }
448
449 /* FIXME: This vtable should not use any IWineD3DSurface* implementation functions,
450  * only IWineD3DBaseSurface and IWineGDISurface ones.
451  */
452 const IWineD3DSurfaceVtbl IWineGDISurface_Vtbl =
453 {
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,
496 };