wined3d: Move "parse_state" to wined3d_shader_context.
[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((IWineD3DResource *)This);
58 }
59
60 /*****************************************************************************
61  * IWineD3DSurface::Release, GDI version
62  *
63  * In general a normal COM Release method, but the GDI version doesn't have
64  * to destroy all the GL things.
65  *
66  *****************************************************************************/
67 static ULONG WINAPI IWineGDISurfaceImpl_Release(IWineD3DSurface *iface) {
68     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
69     ULONG ref = InterlockedDecrement(&This->resource.ref);
70     TRACE("(%p) : Releasing from %d\n", This, ref + 1);
71
72     if (!ref)
73     {
74         surface_gdi_cleanup(This);
75
76         TRACE("(%p) Released.\n", This);
77         HeapFree(GetProcessHeap(), 0, This);
78     }
79
80     return ref;
81 }
82
83 /*****************************************************************************
84  * IWineD3DSurface::PreLoad, GDI version
85  *
86  * This call is unsupported on GDI surfaces, if it's called something went
87  * wrong in the parent library. Write an informative warning
88  *
89  *****************************************************************************/
90 static void WINAPI
91 IWineGDISurfaceImpl_PreLoad(IWineD3DSurface *iface)
92 {
93     ERR("(%p): PreLoad is not supported on X11 surfaces!\n", iface);
94     ERR("(%p): Most likely the parent library did something wrong.\n", iface);
95     ERR("(%p): Please report to wine-devel\n", iface);
96 }
97
98 /*****************************************************************************
99  * IWineD3DSurface::UnLoad, GDI version
100  *
101  * This call is unsupported on GDI surfaces, if it's called something went
102  * wrong in the parent library. Write an informative warning.
103  *
104  *****************************************************************************/
105 static void WINAPI IWineGDISurfaceImpl_UnLoad(IWineD3DSurface *iface)
106 {
107     ERR("(%p): UnLoad is not supported on X11 surfaces!\n", iface);
108     ERR("(%p): Most likely the parent library did something wrong.\n", iface);
109     ERR("(%p): Please report to wine-devel\n", iface);
110 }
111
112 static HRESULT WINAPI IWineGDISurfaceImpl_Map(IWineD3DSurface *iface,
113         WINED3DLOCKED_RECT *pLockedRect, const RECT *pRect, DWORD Flags)
114 {
115     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
116
117     /* Already locked? */
118     if(This->Flags & SFLAG_LOCKED)
119     {
120         WARN("(%p) Surface already locked\n", This);
121         /* What should I return here? */
122         return WINED3DERR_INVALIDCALL;
123     }
124     This->Flags |= SFLAG_LOCKED;
125
126     if(!This->resource.allocatedMemory) {
127         /* This happens on gdi surfaces if the application set a user pointer and resets it.
128          * Recreate the DIB section
129          */
130         IWineD3DBaseSurfaceImpl_CreateDIBSection(iface);
131         This->resource.allocatedMemory = This->dib.bitmap_data;
132     }
133
134     return IWineD3DBaseSurfaceImpl_Map(iface, pLockedRect, pRect, Flags);
135 }
136
137 static HRESULT WINAPI IWineGDISurfaceImpl_Unmap(IWineD3DSurface *iface)
138 {
139     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
140     TRACE("(%p)\n", This);
141
142     if (!(This->Flags & SFLAG_LOCKED))
143     {
144         WARN("Trying to unmap unmapped surfaces %p.\n", iface);
145         return WINEDDERR_NOTLOCKED;
146     }
147
148     /* Tell the swapchain to update the screen */
149     if (This->container.type == WINED3D_CONTAINER_SWAPCHAIN)
150     {
151         IWineD3DSwapChainImpl *swapchain = This->container.u.swapchain;
152         if (This == swapchain->front_buffer)
153         {
154             x11_copy_to_screen(swapchain, &This->lockedRect);
155         }
156     }
157
158     This->Flags &= ~SFLAG_LOCKED;
159     memset(&This->lockedRect, 0, sizeof(RECT));
160     return WINED3D_OK;
161 }
162
163 /*****************************************************************************
164  * IWineD3DSurface::Flip, GDI version
165  *
166  * Flips 2 flipping enabled surfaces. Determining the 2 targets is done by
167  * the parent library. This implementation changes the data pointers of the
168  * surfaces and copies the new front buffer content to the screen
169  *
170  * Params:
171  *  override: Flipping target(e.g. back buffer)
172  *
173  * Returns:
174  *  WINED3D_OK on success
175  *
176  *****************************************************************************/
177 static HRESULT WINAPI
178 IWineGDISurfaceImpl_Flip(IWineD3DSurface *iface,
179                          IWineD3DSurface *override,
180                          DWORD Flags)
181 {
182     IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
183     IWineD3DSwapChainImpl *swapchain;
184     HRESULT hr;
185
186     if (surface->container.type != WINED3D_CONTAINER_SWAPCHAIN)
187     {
188         ERR("Flipped surface is not on a swapchain\n");
189         return WINEDDERR_NOTFLIPPABLE;
190     }
191
192     swapchain = surface->container.u.swapchain;
193     hr = IWineD3DSwapChain_Present((IWineD3DSwapChain *)swapchain,
194             NULL, NULL, swapchain->win_handle, NULL, 0);
195
196     return hr;
197 }
198
199 /*****************************************************************************
200  * IWineD3DSurface::LoadTexture, GDI version
201  *
202  * This is mutually unsupported by GDI surfaces
203  *
204  * Returns:
205  *  D3DERR_INVALIDCALL
206  *
207  *****************************************************************************/
208 static HRESULT WINAPI
209 IWineGDISurfaceImpl_LoadTexture(IWineD3DSurface *iface, BOOL srgb_mode)
210 {
211     ERR("Unsupported on X11 surfaces\n");
212     return WINED3DERR_INVALIDCALL;
213 }
214
215 static void WINAPI IWineGDISurfaceImpl_BindTexture(IWineD3DSurface *iface, BOOL srgb)
216 {
217     ERR("Not supported.\n");
218 }
219
220 static HRESULT WINAPI IWineGDISurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) {
221     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
222     WINED3DLOCKED_RECT lock;
223     HRESULT hr;
224     RGBQUAD col[256];
225
226     TRACE("(%p)->(%p)\n",This,pHDC);
227
228     if(!(This->Flags & SFLAG_DIBSECTION))
229     {
230         WARN("DC not supported on this surface\n");
231         return WINED3DERR_INVALIDCALL;
232     }
233
234     if(This->Flags & SFLAG_USERPTR) {
235         ERR("Not supported on surfaces with an application-provided surfaces\n");
236         return WINEDDERR_NODC;
237     }
238
239     /* Give more detailed info for ddraw */
240     if (This->Flags & SFLAG_DCINUSE)
241         return WINEDDERR_DCALREADYCREATED;
242
243     /* Can't GetDC if the surface is locked */
244     if (This->Flags & SFLAG_LOCKED)
245         return WINED3DERR_INVALIDCALL;
246
247     memset(&lock, 0, sizeof(lock)); /* To be sure */
248
249     /* Should have a DIB section already */
250
251     /* Map the surface. */
252     hr = IWineD3DSurface_Map(iface, &lock, NULL, 0);
253     if (FAILED(hr))
254     {
255         ERR("IWineD3DSurface_Map failed, hr %#x.\n", hr);
256         /* keep the dib section */
257         return hr;
258     }
259
260     if (This->resource.format->id == WINED3DFMT_P8_UINT
261             || This->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM)
262     {
263         unsigned int n;
264         const PALETTEENTRY *pal = NULL;
265
266         if(This->palette) {
267             pal = This->palette->palents;
268         } else {
269             IWineD3DSurfaceImpl *dds_primary;
270             IWineD3DSwapChainImpl *swapchain;
271             swapchain = (IWineD3DSwapChainImpl *)This->resource.device->swapchains[0];
272             dds_primary = swapchain->front_buffer;
273             if (dds_primary && dds_primary->palette)
274                 pal = dds_primary->palette->palents;
275         }
276
277         if (pal) {
278             for (n=0; n<256; n++) {
279                 col[n].rgbRed   = pal[n].peRed;
280                 col[n].rgbGreen = pal[n].peGreen;
281                 col[n].rgbBlue  = pal[n].peBlue;
282                 col[n].rgbReserved = 0;
283             }
284             SetDIBColorTable(This->hDC, 0, 256, col);
285         }
286     }
287
288     *pHDC = This->hDC;
289     TRACE("returning %p\n",*pHDC);
290     This->Flags |= SFLAG_DCINUSE;
291
292     return WINED3D_OK;
293 }
294
295 static HRESULT WINAPI IWineGDISurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) {
296     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
297
298     TRACE("(%p)->(%p)\n",This,hDC);
299
300     if (!(This->Flags & SFLAG_DCINUSE))
301         return WINEDDERR_NODC;
302
303     if (This->hDC !=hDC) {
304         WARN("Application tries to release an invalid DC(%p), surface dc is %p\n", hDC, This->hDC);
305         return WINEDDERR_NODC;
306     }
307
308     /* we locked first, so unlock now */
309     IWineD3DSurface_Unmap(iface);
310
311     This->Flags &= ~SFLAG_DCINUSE;
312
313     return WINED3D_OK;
314 }
315
316 static HRESULT WINAPI IWineGDISurfaceImpl_RealizePalette(IWineD3DSurface *iface) {
317     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
318     RGBQUAD col[256];
319     IWineD3DPaletteImpl *pal = This->palette;
320     unsigned int n;
321     TRACE("(%p)\n", This);
322
323     if (!pal) return WINED3D_OK;
324
325     if(This->Flags & SFLAG_DIBSECTION) {
326         TRACE("(%p): Updating the hdc's palette\n", This);
327         for (n=0; n<256; n++) {
328             col[n].rgbRed   = pal->palents[n].peRed;
329             col[n].rgbGreen = pal->palents[n].peGreen;
330             col[n].rgbBlue  = pal->palents[n].peBlue;
331             col[n].rgbReserved = 0;
332         }
333         SetDIBColorTable(This->hDC, 0, 256, col);
334     }
335
336     /* Update the image because of the palette change. Some games like e.g Red Alert
337        call SetEntries a lot to implement fading. */
338     /* Tell the swapchain to update the screen */
339     if (This->container.type == WINED3D_CONTAINER_SWAPCHAIN)
340     {
341         IWineD3DSwapChainImpl *swapchain = This->container.u.swapchain;
342         if (This == swapchain->front_buffer)
343         {
344             x11_copy_to_screen(swapchain, NULL);
345         }
346     }
347
348     return WINED3D_OK;
349 }
350
351 /*****************************************************************************
352  * IWineD3DSurface::PrivateSetup, GDI version
353  *
354  * Initializes the GDI surface, aka creates the DIB section we render to
355  * The DIB section creation is done by calling GetDC, which will create the
356  * section and releasing the dc to allow the app to use it. The dib section
357  * will stay until the surface is released
358  *
359  * GDI surfaces do not need to be a power of 2 in size, so the pow2 sizes
360  * are set to the real sizes to save memory. The NONPOW2 flag is unset to
361  * avoid confusion in the shared surface code.
362  *
363  * Returns:
364  *  WINED3D_OK on success
365  *  The return values of called methods on failure
366  *
367  *****************************************************************************/
368 static HRESULT WINAPI
369 IWineGDISurfaceImpl_PrivateSetup(IWineD3DSurface *iface)
370 {
371     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
372     HRESULT hr;
373
374     if(This->resource.usage & WINED3DUSAGE_OVERLAY)
375     {
376         ERR("(%p) Overlays not yet supported by GDI surfaces\n", This);
377         return WINED3DERR_INVALIDCALL;
378     }
379
380     /* Sysmem textures have memory already allocated -
381      * release it, this avoids an unnecessary memcpy
382      */
383     hr = IWineD3DBaseSurfaceImpl_CreateDIBSection(iface);
384     if(SUCCEEDED(hr))
385     {
386         HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
387         This->resource.heapMemory = NULL;
388         This->resource.allocatedMemory = This->dib.bitmap_data;
389     }
390
391     /* We don't mind the nonpow2 stuff in GDI */
392     This->pow2Width = This->currentDesc.Width;
393     This->pow2Height = This->currentDesc.Height;
394
395     return WINED3D_OK;
396 }
397
398 static HRESULT WINAPI IWineGDISurfaceImpl_SetMem(IWineD3DSurface *iface, void *Mem) {
399     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
400
401     /* Render targets depend on their hdc, and we can't create an hdc on a user pointer */
402     if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
403         ERR("Not supported on render targets\n");
404         return WINED3DERR_INVALIDCALL;
405     }
406
407     if(This->Flags & (SFLAG_LOCKED | SFLAG_DCINUSE)) {
408         WARN("Surface is locked or the HDC is in use\n");
409         return WINED3DERR_INVALIDCALL;
410     }
411
412     if(Mem && Mem != This->resource.allocatedMemory) {
413         void *release = NULL;
414
415         /* Do I have to copy the old surface content? */
416         if(This->Flags & SFLAG_DIBSECTION) {
417                 /* Release the DC. No need to hold the critical section for the update
418             * Thread because this thread runs only on front buffers, but this method
419             * fails for render targets in the check above.
420                 */
421             SelectObject(This->hDC, This->dib.holdbitmap);
422             DeleteDC(This->hDC);
423             /* Release the DIB section */
424             DeleteObject(This->dib.DIBsection);
425             This->dib.bitmap_data = NULL;
426             This->resource.allocatedMemory = NULL;
427             This->hDC = NULL;
428             This->Flags &= ~SFLAG_DIBSECTION;
429         } else if(!(This->Flags & SFLAG_USERPTR)) {
430             release = This->resource.allocatedMemory;
431         }
432         This->resource.allocatedMemory = Mem;
433         This->Flags |= SFLAG_USERPTR | SFLAG_INSYSMEM;
434
435         /* Now free the old memory if any */
436         HeapFree(GetProcessHeap(), 0, release);
437     }
438     else if(This->Flags & SFLAG_USERPTR)
439     {
440         /* Map() and GetDC() will re-create the dib section and allocated memory. */
441         This->resource.allocatedMemory = NULL;
442         This->Flags &= ~SFLAG_USERPTR;
443     }
444     return WINED3D_OK;
445 }
446
447 static WINED3DSURFTYPE WINAPI IWineGDISurfaceImpl_GetImplType(IWineD3DSurface *iface) {
448     return SURFACE_GDI;
449 }
450
451 static HRESULT WINAPI IWineGDISurfaceImpl_DrawOverlay(IWineD3DSurface *iface) {
452     FIXME("GDI surfaces can't draw overlays yet\n");
453     return E_FAIL;
454 }
455
456 /* FIXME: This vtable should not use any IWineD3DSurface* implementation functions,
457  * only IWineD3DBaseSurface and IWineGDISurface ones.
458  */
459 const IWineD3DSurfaceVtbl IWineGDISurface_Vtbl =
460 {
461     /* IUnknown */
462     IWineD3DBaseSurfaceImpl_QueryInterface,
463     IWineD3DBaseSurfaceImpl_AddRef,
464     IWineGDISurfaceImpl_Release,
465     /* IWineD3DResource */
466     IWineD3DBaseSurfaceImpl_GetParent,
467     IWineD3DBaseSurfaceImpl_SetPrivateData,
468     IWineD3DBaseSurfaceImpl_GetPrivateData,
469     IWineD3DBaseSurfaceImpl_FreePrivateData,
470     IWineD3DBaseSurfaceImpl_SetPriority,
471     IWineD3DBaseSurfaceImpl_GetPriority,
472     IWineGDISurfaceImpl_PreLoad,
473     IWineGDISurfaceImpl_UnLoad,
474     IWineD3DBaseSurfaceImpl_GetType,
475     /* IWineD3DSurface */
476     IWineD3DBaseSurfaceImpl_GetDesc,
477     IWineGDISurfaceImpl_Map,
478     IWineGDISurfaceImpl_Unmap,
479     IWineGDISurfaceImpl_GetDC,
480     IWineGDISurfaceImpl_ReleaseDC,
481     IWineGDISurfaceImpl_Flip,
482     IWineD3DBaseSurfaceImpl_Blt,
483     IWineD3DBaseSurfaceImpl_GetBltStatus,
484     IWineD3DBaseSurfaceImpl_GetFlipStatus,
485     IWineD3DBaseSurfaceImpl_IsLost,
486     IWineD3DBaseSurfaceImpl_Restore,
487     IWineD3DBaseSurfaceImpl_BltFast,
488     IWineD3DBaseSurfaceImpl_GetPalette,
489     IWineD3DBaseSurfaceImpl_SetPalette,
490     IWineGDISurfaceImpl_RealizePalette,
491     IWineD3DBaseSurfaceImpl_SetColorKey,
492     IWineD3DBaseSurfaceImpl_GetPitch,
493     IWineGDISurfaceImpl_SetMem,
494     IWineD3DBaseSurfaceImpl_SetOverlayPosition,
495     IWineD3DBaseSurfaceImpl_GetOverlayPosition,
496     IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder,
497     IWineD3DBaseSurfaceImpl_UpdateOverlay,
498     IWineD3DBaseSurfaceImpl_SetClipper,
499     IWineD3DBaseSurfaceImpl_GetClipper,
500     /* Internal use: */
501     IWineGDISurfaceImpl_LoadTexture,
502     IWineGDISurfaceImpl_BindTexture,
503     IWineD3DBaseSurfaceImpl_GetData,
504     IWineD3DBaseSurfaceImpl_SetFormat,
505     IWineGDISurfaceImpl_PrivateSetup,
506     IWineGDISurfaceImpl_GetImplType,
507     IWineGDISurfaceImpl_DrawOverlay
508 };