Add support for more than 2 audio channels.
[wine] / dlls / ddraw / dsurface / main.c
1 /*              DirectDrawSurface base implementation
2  *
3  * Copyright 1997-2000 Marcus Meissner
4  * Copyright 1998-2000 Lionel Ulmer (most of Direct3D stuff)
5  * Copyright 2000-2001 TransGaming Technologies Inc.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21 #include "config.h"
22
23 #include <assert.h>
24 #include <string.h>
25
26 #define COBJMACROS
27 #define CONST_VTABLE
28
29 #define NONAMELESSUNION
30 #define NONAMELESSSTRUCT
31
32 #include "winerror.h"
33 #include "mesa_private.h"
34 #include "wine/debug.h"
35 #include "ddraw_private.h"
36 #include "dsurface/main.h"
37 #include "ddraw/main.h"
38 #include "dsurface/thunks.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
41 WINE_DECLARE_DEBUG_CHANNEL(ddraw_flip);
42 WINE_DECLARE_DEBUG_CHANNEL(ddraw_fps);
43
44 /** Creation/Destruction functions */
45
46 HRESULT
47 Main_DirectDrawSurface_Construct(IDirectDrawSurfaceImpl *This,
48                                  IDirectDrawImpl *pDD,
49                                  const DDSURFACEDESC2 *pDDSD)
50 {
51     TRACE("(%p)->(%p,%p)\n", This, pDD, pDDSD);
52
53     if (pDDSD != &This->surface_desc) {
54         This->surface_desc.dwSize = sizeof(This->surface_desc);
55         DD_STRUCT_COPY_BYSIZE(&(This->surface_desc),pDDSD);
56     }
57     This->uniqueness_value = 1; /* unchecked */
58     This->ref = 1;
59
60     This->local.lpSurfMore = &This->more;
61     This->local.lpGbl = &This->global;
62     This->local.dwProcessId = GetCurrentProcessId();
63     This->local.dwFlags = 0; /* FIXME */
64     This->local.ddsCaps.dwCaps = This->surface_desc.ddsCaps.dwCaps;
65     /* FIXME: more local stuff */
66     This->more.lpDD_lcl = &pDD->local;
67     This->more.ddsCapsEx.dwCaps2 = This->surface_desc.ddsCaps.dwCaps2;
68     This->more.ddsCapsEx.dwCaps3 = This->surface_desc.ddsCaps.dwCaps3;
69     This->more.ddsCapsEx.dwCaps4 = This->surface_desc.ddsCaps.dwCaps4;
70     /* FIXME: more more stuff */
71     This->gmore = &This->global_more;
72     This->global.u3.lpDD = pDD->local.lpGbl;
73     /* FIXME: more global stuff */
74
75     This->final_release = Main_DirectDrawSurface_final_release;
76     This->late_allocate = Main_DirectDrawSurface_late_allocate;
77     This->attach = Main_DirectDrawSurface_attach;
78     This->detach = Main_DirectDrawSurface_detach;
79     This->lock_update = Main_DirectDrawSurface_lock_update;
80     This->unlock_update = Main_DirectDrawSurface_unlock_update;
81     This->lose_surface = Main_DirectDrawSurface_lose_surface;
82     This->set_palette    = Main_DirectDrawSurface_set_palette;
83     This->update_palette = Main_DirectDrawSurface_update_palette;
84     This->get_display_window = Main_DirectDrawSurface_get_display_window;
85     This->get_gamma_ramp = Main_DirectDrawSurface_get_gamma_ramp;
86     This->set_gamma_ramp = Main_DirectDrawSurface_set_gamma_ramp;
87
88     ICOM_INIT_INTERFACE(This, IDirectDrawSurface3,
89                         DDRAW_IDDS3_Thunk_VTable);
90     ICOM_INIT_INTERFACE(This, IDirectDrawGammaControl,
91                         DDRAW_IDDGC_VTable);
92
93     /* There is no generic implementation of IDDS7 or texture */
94
95     Main_DirectDraw_AddSurface(pDD, This);
96     return DD_OK;
97 }
98
99 void Main_DirectDrawSurface_final_release(IDirectDrawSurfaceImpl* This)
100 {
101     Main_DirectDraw_RemoveSurface(This->ddraw_owner, This);
102 }
103
104 HRESULT Main_DirectDrawSurface_late_allocate(IDirectDrawSurfaceImpl* This)
105 {
106     return DD_OK;
107 }
108
109 static void Main_DirectDrawSurface_Destroy(IDirectDrawSurfaceImpl* This)
110 {
111     if (This->palette) {
112         IDirectDrawPalette_Release(ICOM_INTERFACE(This->palette, IDirectDrawPalette));
113         This->palette = NULL;
114     }
115     This->final_release(This);
116     if (This->private != This+1) HeapFree(GetProcessHeap(), 0, This->private);
117     if (This->tex_private) HeapFree(GetProcessHeap(), 0, This->tex_private);
118     HeapFree(GetProcessHeap(), 0, This);
119 }
120
121 void Main_DirectDrawSurface_ForceDestroy(IDirectDrawSurfaceImpl* This)
122 {
123     WARN("destroying surface %p with refcnt %lu\n", This, This->ref);
124     Main_DirectDrawSurface_Destroy(This);
125 }
126
127 ULONG WINAPI Main_DirectDrawSurface_Release(LPDIRECTDRAWSURFACE7 iface)
128 {
129     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
130     ULONG ref = InterlockedDecrement(&This->ref);
131
132     TRACE("(%p)->(): decreasing from %ld\n", This, ref + 1);
133     
134     if (ref == 0)
135     {
136         if (This->aux_release)
137             This->aux_release(This->aux_ctx, This->aux_data);
138         Main_DirectDrawSurface_Destroy(This);
139
140         TRACE("released surface %p\n", This);
141         
142         return 0;
143     }
144
145     return ref;
146 }
147
148 ULONG WINAPI Main_DirectDrawSurface_AddRef(LPDIRECTDRAWSURFACE7 iface)
149 {
150     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
151     ULONG ref = InterlockedIncrement(&This->ref);
152
153     TRACE("(%p)->(): increasing from %ld\n", This, ref - 1);
154     
155     return ref;
156 }
157
158 HRESULT WINAPI
159 Main_DirectDrawSurface_QueryInterface(LPDIRECTDRAWSURFACE7 iface, REFIID riid,
160                                       LPVOID* ppObj)
161 {
162     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
163     TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppObj);
164
165     *ppObj = NULL;
166
167     if (IsEqualGUID(&IID_IUnknown, riid)
168         || IsEqualGUID(&IID_IDirectDrawSurface7, riid)
169         || IsEqualGUID(&IID_IDirectDrawSurface4, riid))
170     {
171         InterlockedIncrement(&This->ref);
172         *ppObj = ICOM_INTERFACE(This, IDirectDrawSurface7);
173         return S_OK;
174     }
175     else if (IsEqualGUID(&IID_IDirectDrawSurface, riid)
176              || IsEqualGUID(&IID_IDirectDrawSurface2, riid)
177              || IsEqualGUID(&IID_IDirectDrawSurface3, riid))
178     {
179         InterlockedIncrement(&This->ref);
180         *ppObj = ICOM_INTERFACE(This, IDirectDrawSurface3);
181         return S_OK;
182     }
183     else if (IsEqualGUID(&IID_IDirectDrawGammaControl, riid))
184     {
185         InterlockedIncrement(&This->ref);
186         *ppObj = ICOM_INTERFACE(This, IDirectDrawGammaControl);
187         return S_OK;
188     }
189 #ifdef HAVE_OPENGL
190     /* interfaces following here require OpenGL */
191     if( !opengl_initialized )
192         return E_NOINTERFACE;
193
194     if ( IsEqualGUID( &IID_D3DDEVICE_OpenGL, riid ) ||
195           IsEqualGUID( &IID_IDirect3DHALDevice, riid) )
196     {
197         IDirect3DDeviceImpl *d3ddevimpl;
198         HRESULT ret_value;
199
200         ret_value = d3ddevice_create(&d3ddevimpl, This->ddraw_owner, This, 1);
201         if (FAILED(ret_value)) return ret_value;
202
203         *ppObj = ICOM_INTERFACE(d3ddevimpl, IDirect3DDevice);
204         TRACE(" returning Direct3DDevice interface at %p.\n", *ppObj);
205         
206         InterlockedIncrement(&This->ref); /* No idea if this is correct.. Need to check using real Windows */
207         return ret_value;
208     }
209     else if (IsEqualGUID( &IID_IDirect3DTexture, riid ) ||
210              IsEqualGUID( &IID_IDirect3DTexture2, riid ))
211     {
212         HRESULT ret_value = S_OK;
213
214         /* Note: this is not exactly how Windows does it... But this seems not to hurt the only
215                  application I know creating a texture without this flag set and it will prevent
216                  bugs in other parts of Wine.
217         */
218         This->surface_desc.ddsCaps.dwCaps |= DDSCAPS_TEXTURE;
219
220         /* In case the texture surface was created before the D3D creation */
221         if (This->tex_private == NULL) {
222             if (This->ddraw_owner->d3d_private == NULL) {
223                 ERR("Texture created with no D3D object yet.. Not supported !\n");
224                 return E_NOINTERFACE;
225             }
226
227             ret_value = This->ddraw_owner->d3d_create_texture(This->ddraw_owner, This, FALSE, This->mip_main);
228             if (FAILED(ret_value)) return ret_value;
229         }
230         if (IsEqualGUID( &IID_IDirect3DTexture, riid )) {
231             *ppObj = ICOM_INTERFACE(This, IDirect3DTexture);
232             TRACE(" returning Direct3DTexture interface at %p.\n", *ppObj);
233         } else {
234             *ppObj = ICOM_INTERFACE(This, IDirect3DTexture2);
235             TRACE(" returning Direct3DTexture2 interface at %p.\n", *ppObj);
236         }
237         InterlockedIncrement(&This->ref);
238         return ret_value;
239     }
240 #endif
241
242     return E_NOINTERFACE;
243 }
244
245 /*** Callbacks */
246
247 BOOL
248 Main_DirectDrawSurface_attach(IDirectDrawSurfaceImpl *This,
249                               IDirectDrawSurfaceImpl *to)
250 {
251     return TRUE;
252 }
253
254 BOOL Main_DirectDrawSurface_detach(IDirectDrawSurfaceImpl *This)
255 {
256     return TRUE;
257 }
258
259 void
260 Main_DirectDrawSurface_lock_update(IDirectDrawSurfaceImpl* This, LPCRECT pRect,
261         DWORD dwFlags)
262 {
263 }
264
265 void
266 Main_DirectDrawSurface_unlock_update(IDirectDrawSurfaceImpl* This,
267                                      LPCRECT pRect)
268 {
269 }
270
271 void
272 Main_DirectDrawSurface_lose_surface(IDirectDrawSurfaceImpl* This)
273 {
274 }
275
276 void
277 Main_DirectDrawSurface_set_palette(IDirectDrawSurfaceImpl* This,
278                                    IDirectDrawPaletteImpl* pal)
279 {
280 }
281
282 void
283 Main_DirectDrawSurface_update_palette(IDirectDrawSurfaceImpl* This,
284                                       IDirectDrawPaletteImpl* pal,
285                                       DWORD dwStart, DWORD dwCount,
286                                       LPPALETTEENTRY palent)
287 {
288 }
289
290 HWND
291 Main_DirectDrawSurface_get_display_window(IDirectDrawSurfaceImpl* This)
292 {
293     return 0;
294 }
295
296 HRESULT
297 Main_DirectDrawSurface_get_gamma_ramp(IDirectDrawSurfaceImpl* This,
298                                       DWORD dwFlags,
299                                       LPDDGAMMARAMP lpGammaRamp)
300 {
301     HDC hDC;
302     HRESULT hr;
303     hr = This->get_dc(This, &hDC);
304     if (FAILED(hr)) return hr;
305     hr = GetDeviceGammaRamp(hDC, lpGammaRamp) ? DD_OK : DDERR_UNSUPPORTED;
306     This->release_dc(This, hDC);
307     return hr;
308 }
309
310 HRESULT
311 Main_DirectDrawSurface_set_gamma_ramp(IDirectDrawSurfaceImpl* This,
312                                       DWORD dwFlags,
313                                       LPDDGAMMARAMP lpGammaRamp)
314 {
315     HDC hDC;
316     HRESULT hr;
317     hr = This->get_dc(This, &hDC);
318     if (FAILED(hr)) return hr;
319     hr = SetDeviceGammaRamp(hDC, lpGammaRamp) ? DD_OK : DDERR_UNSUPPORTED;
320     This->release_dc(This, hDC);
321     return hr;
322 }
323
324
325 /*** Interface functions */
326
327 HRESULT WINAPI
328 Main_DirectDrawSurface_AddAttachedSurface(LPDIRECTDRAWSURFACE7 iface,
329                                           LPDIRECTDRAWSURFACE7 pAttach)
330 {
331     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
332     IDirectDrawSurfaceImpl* surf = ICOM_OBJECT(IDirectDrawSurfaceImpl,
333                                                IDirectDrawSurface7, pAttach);
334
335     TRACE("(%p)->(%p)\n",This,pAttach);
336
337     /* Does windows check this? */
338     if (surf == This)
339         return DDERR_CANNOTATTACHSURFACE; /* unchecked */
340
341     /* Does windows check this? */
342     if (surf->ddraw_owner != This->ddraw_owner)
343         return DDERR_CANNOTATTACHSURFACE; /* unchecked */
344
345     if (surf->surface_owner != NULL)
346         return DDERR_SURFACEALREADYATTACHED; /* unchecked */
347
348     /* TODO MSDN: "You can attach only z-buffer surfaces with this method."
349      * But apparently backbuffers and mipmaps can be attached too. */
350
351     /* Set MIPMAPSUBLEVEL if this seems to be one */
352     if (This->surface_desc.ddsCaps.dwCaps &
353         surf->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP) {
354         surf->surface_desc.ddsCaps.dwCaps2 |= DDSCAPS2_MIPMAPSUBLEVEL;
355         /* FIXME: we should probably also add to dwMipMapCount of this
356          * and all parent surfaces (update create_texture if you do) */
357     }
358
359     /* Callback to allow the surface to do something special now that it is
360      * attached. (e.g. maybe the Z-buffer tells the renderer to use it.) */
361     if (!surf->attach(surf, This))
362         return DDERR_CANNOTATTACHSURFACE;
363
364     /* check: Where should it go in the chain? This puts it on the head. */
365     if (This->attached)
366         This->attached->prev_attached = surf;
367     surf->next_attached = This->attached;
368     surf->prev_attached = NULL;
369     This->attached = surf;
370     surf->surface_owner = This;
371
372     IDirectDrawSurface7_AddRef(pAttach);
373
374     return DD_OK;
375 }
376
377 /* MSDN: "not currently implemented." */
378 HRESULT WINAPI
379 Main_DirectDrawSurface_AddOverlayDirtyRect(LPDIRECTDRAWSURFACE7 iface,
380                                            LPRECT pRect)
381 {
382     TRACE("(%p)->(%p)\n",iface,pRect);
383     return DDERR_UNSUPPORTED; /* unchecked */
384 }
385
386 /* MSDN: "not currently implemented." */
387 HRESULT WINAPI
388 Main_DirectDrawSurface_BltBatch(LPDIRECTDRAWSURFACE7 iface,
389                                 LPDDBLTBATCH pBatch, DWORD dwCount,
390                                 DWORD dwFlags)
391 {
392     TRACE("(%p)->(%p,%ld,%08lx)\n",iface,pBatch,dwCount,dwFlags);
393     return DDERR_UNSUPPORTED; /* unchecked */
394 }
395
396 HRESULT WINAPI
397 Main_DirectDrawSurface_ChangeUniquenessValue(LPDIRECTDRAWSURFACE7 iface)
398 {
399     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
400     volatile IDirectDrawSurfaceImpl* vThis = This;
401
402     TRACE("(%p)\n",This);
403     /* A uniquness value of 0 is apparently special.
404      * This needs to be checked. */
405     while (1)
406     {
407         DWORD old_uniqueness_value = vThis->uniqueness_value;
408         DWORD new_uniqueness_value = old_uniqueness_value+1;
409
410         if (old_uniqueness_value == 0) break;
411         if (new_uniqueness_value == 0) new_uniqueness_value = 1;
412
413         if (InterlockedCompareExchange((LONG*)&vThis->uniqueness_value,
414                                        old_uniqueness_value,
415                                        new_uniqueness_value)
416             == old_uniqueness_value)
417             break;
418     }
419
420     return DD_OK;
421 }
422
423 HRESULT WINAPI
424 Main_DirectDrawSurface_DeleteAttachedSurface(LPDIRECTDRAWSURFACE7 iface,
425                                              DWORD dwFlags,
426                                              LPDIRECTDRAWSURFACE7 pAttach)
427 {
428     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
429     IDirectDrawSurfaceImpl* surf = ICOM_OBJECT(IDirectDrawSurfaceImpl,
430                                                IDirectDrawSurface7, pAttach);
431
432     TRACE("(%p)->(%08lx,%p)\n",This,dwFlags,pAttach);
433
434     if (!surf || (surf->surface_owner != This))
435         return DDERR_SURFACENOTATTACHED; /* unchecked */
436
437     surf->detach(surf);
438
439     /* Remove MIPMAPSUBLEVEL if this seemed to be one */
440     if (This->surface_desc.ddsCaps.dwCaps &
441         surf->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP) {
442         surf->surface_desc.ddsCaps.dwCaps2 &= ~DDSCAPS2_MIPMAPSUBLEVEL;
443         /* FIXME: we should probably also subtract from dwMipMapCount of this
444          * and all parent surfaces */
445     }
446
447     if (surf->next_attached)
448         surf->next_attached->prev_attached = surf->prev_attached;
449     if (surf->prev_attached)
450         surf->prev_attached->next_attached = surf->next_attached;
451     if (This->attached == surf)
452         This->attached = surf->next_attached;
453
454     IDirectDrawSurface7_Release(pAttach);
455
456     return DD_OK;
457 }
458
459 HRESULT WINAPI
460 Main_DirectDrawSurface_EnumAttachedSurfaces(LPDIRECTDRAWSURFACE7 iface,
461                                             LPVOID context,
462                                             LPDDENUMSURFACESCALLBACK7 cb)
463 {
464     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
465     IDirectDrawSurfaceImpl* surf;
466
467     TRACE("(%p)->(%p,%p)\n",This,context,cb);
468
469     for (surf = This->attached; surf != NULL; surf = surf->next_attached)
470     {
471         /* check: != DDENUMRET_OK or == DDENUMRET_CANCEL? */
472         if (cb(ICOM_INTERFACE(surf, IDirectDrawSurface7), &surf->surface_desc,
473                context) == DDENUMRET_CANCEL)
474             break;
475     }
476
477     return DD_OK;
478 }
479
480 HRESULT WINAPI
481 Main_DirectDrawSurface_EnumOverlayZOrders(LPDIRECTDRAWSURFACE7 iface,
482                                           DWORD dwFlags, LPVOID context,
483                                           LPDDENUMSURFACESCALLBACK7 cb)
484 {
485     TRACE("(%p)->(%08lx,%p,%p)\n",iface,dwFlags,context,cb);
486     return DD_OK;
487 }
488
489 BOOL Main_DirectDrawSurface_flip_data(IDirectDrawSurfaceImpl* front,
490                                       IDirectDrawSurfaceImpl* back,
491                                       DWORD dwFlags)
492 {
493     /* uniqueness_value? */
494     /* This is necessary. But is it safe? */
495     {
496         HDC tmp = front->hDC;
497         front->hDC = back->hDC;
498         back->hDC = tmp;
499     }
500
501     {
502         BOOL tmp = front->dc_in_use;
503         front->dc_in_use = back->dc_in_use;
504         back->dc_in_use = tmp;
505     }
506
507     {
508         FLATPTR tmp = front->global.fpVidMem;
509         front->global.fpVidMem = back->global.fpVidMem;
510         back->global.fpVidMem = tmp;
511     }
512
513     {
514         ULONG_PTR tmp = front->global_more.hKernelSurface;
515         front->global_more.hKernelSurface = back->global_more.hKernelSurface;
516         back->global_more.hKernelSurface = tmp;
517     }
518
519     return TRUE;
520 }
521
522 /* This is unnecessarely complicated :-) */
523 #define MEASUREMENT_WINDOW 5
524 #define NUMBER_OF_WINDOWS 10
525
526 static LONGLONG perf_freq;
527 static LONGLONG perf_storage[NUMBER_OF_WINDOWS];
528 static LONGLONG prev_time = 0;
529 static unsigned int current_window;
530 static unsigned int measurements_in_window;
531 static unsigned int valid_windows;
532
533 HRESULT WINAPI
534 Main_DirectDrawSurface_Flip(LPDIRECTDRAWSURFACE7 iface,
535                             LPDIRECTDRAWSURFACE7 override, DWORD dwFlags)
536 {
537     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
538     IDirectDrawSurfaceImpl* target;
539     HRESULT hr;
540
541     TRACE("(%p)->(%p,%08lx)\n",This,override,dwFlags);
542
543     if (TRACE_ON(ddraw_fps)) {
544         LONGLONG current_time;
545         LONGLONG frame_duration;
546         QueryPerformanceCounter((LARGE_INTEGER *) &current_time);
547
548         if (prev_time != 0) {
549             LONGLONG total_time = 0;
550             int tot_meas;
551             
552             frame_duration = current_time - prev_time;
553             prev_time = current_time;
554             
555             perf_storage[current_window] += frame_duration;
556             measurements_in_window++;
557             
558             if (measurements_in_window >= MEASUREMENT_WINDOW) {
559                 current_window++;
560                 valid_windows++;
561
562                 if (valid_windows < NUMBER_OF_WINDOWS) {
563                     unsigned int i;
564                     tot_meas = valid_windows * MEASUREMENT_WINDOW;
565                     for (i = 0; i < valid_windows; i++) {
566                         total_time += perf_storage[i];
567                     }
568                 } else {
569                     int i;
570                     tot_meas = NUMBER_OF_WINDOWS * MEASUREMENT_WINDOW;
571                     for (i = 0; i < NUMBER_OF_WINDOWS; i++) {
572                         total_time += perf_storage[i];
573                     }
574                 }
575
576                 TRACE_(ddraw_fps)(" %9.5f\n", (double) (perf_freq * tot_meas) / (double) total_time);
577                 
578                 if (current_window >= NUMBER_OF_WINDOWS) {
579                     current_window = 0;
580                 }
581                 perf_storage[current_window] = 0;
582                 measurements_in_window = 0;
583             }
584         } else {
585             prev_time = current_time;
586             memset(perf_storage, 0, sizeof(perf_storage));
587             current_window = 0;
588             valid_windows = 0;
589             measurements_in_window = 0;
590             QueryPerformanceFrequency((LARGE_INTEGER *) &perf_freq);
591         }
592     }
593     
594     /* MSDN: "This method can be called only for a surface that has the
595      * DDSCAPS_FLIP and DDSCAPS_FRONTBUFFER capabilities." */
596     if ((This->surface_desc.ddsCaps.dwCaps&(DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER))
597         != (DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER))
598         return DDERR_NOTFLIPPABLE;
599
600     if (This->aux_flip)
601         if (This->aux_flip(This->aux_ctx, This->aux_data))
602             return DD_OK;
603
604     /* 1. find the flip target */
605     /* XXX I don't think this algorithm works for more than 1 backbuffer. */
606     if (override == NULL)
607     {
608         static DDSCAPS2 back_caps = { DDSCAPS_BACKBUFFER };
609         LPDIRECTDRAWSURFACE7 tgt;
610
611         hr = IDirectDrawSurface7_GetAttachedSurface(iface, &back_caps, &tgt);
612         if (FAILED(hr)) return DDERR_NOTFLIPPABLE; /* unchecked */
613
614         target = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7,
615                              tgt);
616         IDirectDrawSurface7_Release(tgt);
617     }
618     else
619     {
620         BOOL on_chain = FALSE;
621         IDirectDrawSurfaceImpl* surf;
622
623         /* MSDN: "The method fails if the specified [override] surface is not
624          * a member of the flipping chain." */
625
626         /* Verify that override is on this flip chain. We assume that
627          * surf is the head of the flipping chain, because it's the front
628          * buffer. */
629         target = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7,
630                              override);
631
632         /* Either target is (indirectly) attached to This or This is
633          * (indirectly) attached to target. */
634         for (surf = target; surf != NULL; surf = surf->surface_owner)
635         {
636             if (surf == This)
637             {
638                 on_chain = TRUE;
639                 break;
640             }
641         }
642
643         if (!on_chain)
644             return DDERR_INVALIDPARAMS; /* unchecked */
645     }
646
647     TRACE("flip to backbuffer: %p\n",target);
648     if (TRACE_ON(ddraw_flip)) {
649         static unsigned int flip_count = 0;
650         IDirectDrawPaletteImpl *palette;
651         char buf[32];
652         FILE *f;
653
654         /* Hack for paletted games... */
655         palette = target->palette;
656         target->palette = This->palette;
657         
658         sprintf(buf, "flip_%08d.ppm", flip_count++);
659         TRACE_(ddraw_flip)("Dumping file %s to disk.\n", buf);
660         f = fopen(buf, "wb");
661         DDRAW_dump_surface_to_disk(target, f, 8);
662         target->palette = palette;
663     }
664
665     if (This->flip_data(This, target, dwFlags))
666         This->flip_update(This, dwFlags);
667     
668     return DD_OK;
669 }
670
671 static PrivateData* find_private_data(IDirectDrawSurfaceImpl *This,
672                                       REFGUID tag)
673 {
674     PrivateData* data;
675     for (data = This->private_data; data != NULL; data = data->next)
676     {
677         if (IsEqualGUID(&data->tag, tag)) break;
678     }
679
680     return data;
681 }
682
683 HRESULT WINAPI
684 Main_DirectDrawSurface_FreePrivateData(LPDIRECTDRAWSURFACE7 iface, REFGUID tag)
685 {
686     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
687     PrivateData *data;
688
689     data = find_private_data(This, tag);
690     if (data == NULL) return DDERR_NOTFOUND;
691
692     if (data->prev)
693         data->prev->next = data->next;
694     if (data->next)
695         data->next->prev = data->prev;
696
697     if (data->flags & DDSPD_IUNKNOWNPTR)
698     {
699         if (data->ptr.object != NULL)
700             IUnknown_Release(data->ptr.object);
701     }
702     else
703         HeapFree(GetProcessHeap(), 0, data->ptr.data);
704
705     HeapFree(GetProcessHeap(), 0, data);
706
707     return DD_OK;
708 }
709
710 HRESULT WINAPI
711 Main_DirectDrawSurface_GetAttachedSurface(LPDIRECTDRAWSURFACE7 iface,
712                                           LPDDSCAPS2 pCaps,
713                                           LPDIRECTDRAWSURFACE7* ppSurface)
714 {
715     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
716     IDirectDrawSurfaceImpl* surf;
717     IDirectDrawSurfaceImpl* found = NULL;
718     DDSCAPS2 our_caps;
719     
720     if (TRACE_ON(ddraw)) {
721         TRACE("(%p)->Looking for caps: %lx,%lx,%lx,%lx output: %p\n",This,pCaps->dwCaps, pCaps->dwCaps2,
722               pCaps->dwCaps3, pCaps->dwCaps4, ppSurface);
723         TRACE("   Caps are : "); DDRAW_dump_DDSCAPS2(pCaps); TRACE("\n");
724     }
725
726     our_caps = *pCaps;
727     if ((This->ddraw_owner->local.dwLocalFlags & DDRAWILCL_DIRECTDRAW7) == 0) {
728         /* As this is not a DirectDraw7 application, remove the garbage that some games
729            put in the new fields of the DDSCAPS2 structure. */
730         our_caps.dwCaps2 = 0;
731         our_caps.dwCaps3 = 0;
732         our_caps.dwCaps4 = 0;
733         if (TRACE_ON(ddraw)) {
734             TRACE("   Real caps are : "); DDRAW_dump_DDSCAPS2(&our_caps); TRACE("\n");
735         }
736     }
737     
738     for (surf = This->attached; surf != NULL; surf = surf->next_attached)
739     {
740         if (TRACE_ON(ddraw)) {
741             TRACE("Surface: (%p) caps: %lx,%lx,%lx,%lx \n",surf ,
742                   surf->surface_desc.ddsCaps.dwCaps,
743                   surf->surface_desc.ddsCaps.dwCaps2,
744                   surf->surface_desc.ddsCaps.dwCaps3,
745                   surf->surface_desc.ddsCaps.dwCaps4);
746             TRACE("   Surface caps are : "); DDRAW_dump_DDSCAPS2(&(surf->surface_desc.ddsCaps)); TRACE("\n");
747         }
748         if (((surf->surface_desc.ddsCaps.dwCaps & our_caps.dwCaps) == our_caps.dwCaps) &&
749             ((surf->surface_desc.ddsCaps.dwCaps2 & our_caps.dwCaps2) == our_caps.dwCaps2))
750         {
751             /* MSDN: "This method fails if more than one surface is attached
752              * that matches the capabilities requested." */
753             if (found != NULL)
754             {
755                 FIXME("More than one attached surface matches requested caps.  What should we do here?\n");
756                 /* Previous code returned 'DDERR_NOTFOUND'.  That appears not
757                    to be correct, given what 3DMark expects from MipMapped surfaces.
758                    We shall just continue instead. */
759             }
760
761             found = surf;
762         }
763     }
764
765     if (found == NULL) {
766         TRACE("Did not find any valid surface\n");
767         return DDERR_NOTFOUND;
768     }
769
770     *ppSurface = ICOM_INTERFACE(found, IDirectDrawSurface7);
771
772     if (TRACE_ON(ddraw)) {
773         TRACE("Returning surface %p with description : \n", *ppSurface);
774         DDRAW_dump_surface_desc(&(found->surface_desc));
775     }
776     
777     /* XXX d3dframe.cpp sometimes AddRefs things that it gets from us. */
778     IDirectDrawSurface7_AddRef(ICOM_INTERFACE(found, IDirectDrawSurface7));
779     return DD_OK;
780 }
781
782 HRESULT WINAPI
783 Main_DirectDrawSurface_GetBltStatus(LPDIRECTDRAWSURFACE7 iface, DWORD dwFlags)
784 {
785     TRACE("(%p)->(%08lx)\n",iface,dwFlags);
786
787     switch (dwFlags)
788     {
789     case DDGBS_CANBLT:
790     case DDGBS_ISBLTDONE:
791         return DD_OK;
792
793     default:
794         return DDERR_INVALIDPARAMS;
795     }
796 }
797
798 HRESULT WINAPI
799 Main_DirectDrawSurface_GetCaps(LPDIRECTDRAWSURFACE7 iface, LPDDSCAPS2 pCaps)
800 {
801     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
802
803     TRACE("(%p)->(%p)\n",This,pCaps);
804     *pCaps = This->surface_desc.ddsCaps;
805     return DD_OK;
806 }
807
808 HRESULT WINAPI
809 Main_DirectDrawSurface_GetClipper(LPDIRECTDRAWSURFACE7 iface,
810                                   LPDIRECTDRAWCLIPPER* ppClipper)
811 {
812     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
813
814     TRACE("(%p)->(%p)\n",This,ppClipper);
815     if (This->clipper == NULL)
816         return DDERR_NOCLIPPERATTACHED;
817
818     *ppClipper = ICOM_INTERFACE(This->clipper, IDirectDrawClipper);
819     IDirectDrawClipper_AddRef(ICOM_INTERFACE(This->clipper,
820                                              IDirectDrawClipper));
821     return DD_OK;
822 }
823
824 HRESULT WINAPI
825 Main_DirectDrawSurface_GetColorKey(LPDIRECTDRAWSURFACE7 iface, DWORD dwFlags,
826                                    LPDDCOLORKEY pCKey)
827 {
828     /* There is a DDERR_NOCOLORKEY error, but how do we know if a color key
829      * isn't there? That's like saying that an int isn't there. (Which MS
830      * has done in other docs.) */
831
832     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
833
834     TRACE("(%p)->(%08lx,%p)\n",This,dwFlags,pCKey);
835     if (TRACE_ON(ddraw)) {
836         TRACE(" - colorkey flags : ");
837         DDRAW_dump_colorkeyflag(dwFlags);
838     }
839
840     switch (dwFlags)
841     {
842     case DDCKEY_DESTBLT:
843         *pCKey = This->surface_desc.ddckCKDestBlt;
844         break;
845
846     case DDCKEY_DESTOVERLAY:
847         *pCKey = This->surface_desc.u3.ddckCKDestOverlay;
848         break;
849
850     case DDCKEY_SRCBLT:
851         *pCKey = This->surface_desc.ddckCKSrcBlt;
852         break;
853
854     case DDCKEY_SRCOVERLAY:
855         *pCKey = This->surface_desc.ddckCKSrcOverlay;
856         break;
857
858     default:
859         return DDERR_INVALIDPARAMS;
860     }
861
862     return DD_OK;
863 }
864
865 /* XXX We need to do something with the DC if the surface gets lost. */
866 HRESULT WINAPI
867 Main_DirectDrawSurface_GetDC(LPDIRECTDRAWSURFACE7 iface, HDC *phDC)
868 {
869     DDSURFACEDESC2 ddsd;
870     HRESULT hr;
871     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
872
873     TRACE("(%p)->(%p)\n",This,phDC);
874     CHECK_LOST(This);
875
876     LOCK_OBJECT(This);
877
878     if (This->dc_in_use)
879     {
880         UNLOCK_OBJECT(This);
881         return DDERR_DCALREADYCREATED;
882     }
883
884     /* Lock as per MSDN.
885      * Strange: Lock lists DDERR_SURFACEBUSY as an error, meaning that another
886      * thread has it locked, but GetDC does not. */
887     ddsd.dwSize = sizeof(ddsd);
888     hr = IDirectDrawSurface7_Lock(iface, NULL, &ddsd, 0, 0);
889     if (FAILED(hr))
890     {
891         UNLOCK_OBJECT(This);
892         return hr;
893     }
894
895     hr = This->get_dc(This, &This->hDC);
896     if (SUCCEEDED(hr))
897     {
898         TRACE("returning %p\n",This->hDC);
899
900         *phDC = This->hDC;
901         This->dc_in_use = TRUE;
902     }
903     else WARN("No DC! Prepare for trouble\n");
904
905     UNLOCK_OBJECT(This);
906     return hr;
907 }
908
909 HRESULT WINAPI
910 Main_DirectDrawSurface_GetDDInterface(LPDIRECTDRAWSURFACE7 iface, LPVOID* pDD)
911 {
912     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
913
914     TRACE("(%p)->(%p)\n",This,pDD);
915     *pDD = ICOM_INTERFACE(This->ddraw_owner, IDirectDraw7);
916     IDirectDraw7_AddRef(ICOM_INTERFACE(This->ddraw_owner, IDirectDraw7));
917     return DD_OK;
918 }
919
920 HRESULT WINAPI
921 Main_DirectDrawSurface_GetFlipStatus(LPDIRECTDRAWSURFACE7 iface, DWORD dwFlags)
922 {
923     /* XXX: DDERR_INVALIDSURFACETYPE */
924
925     TRACE("(%p)->(%08lx)\n",iface,dwFlags);
926     switch (dwFlags)
927     {
928     case DDGFS_CANFLIP:
929     case DDGFS_ISFLIPDONE:
930         return DD_OK;
931
932     default:
933         return DDERR_INVALIDPARAMS;
934     }
935 }
936
937 HRESULT WINAPI
938 Main_DirectDrawSurface_GetLOD(LPDIRECTDRAWSURFACE7 iface, LPDWORD pdwMaxLOD)
939 {
940     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
941
942     TRACE("(%p)->(%p)\n",This,pdwMaxLOD);
943     CHECK_TEXTURE(This);
944
945     *pdwMaxLOD = This->max_lod;
946     return DD_OK;
947 }
948
949 HRESULT WINAPI
950 Main_DirectDrawSurface_GetOverlayPosition(LPDIRECTDRAWSURFACE7 iface,
951                                           LPLONG pX, LPLONG pY)
952 {
953     return DDERR_NOTAOVERLAYSURFACE;
954 }
955
956 HRESULT WINAPI
957 Main_DirectDrawSurface_GetPalette(LPDIRECTDRAWSURFACE7 iface,
958                                   LPDIRECTDRAWPALETTE* ppPalette)
959 {
960     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
961
962     TRACE("(%p)->(%p)\n",This,ppPalette);
963     if (This->palette == NULL)
964         return DDERR_NOPALETTEATTACHED;
965
966     *ppPalette = ICOM_INTERFACE(This->palette, IDirectDrawPalette);
967     IDirectDrawPalette_AddRef(ICOM_INTERFACE(This->palette,
968                                              IDirectDrawPalette));
969     return DD_OK;
970 }
971
972 HRESULT WINAPI
973 Main_DirectDrawSurface_GetPixelFormat(LPDIRECTDRAWSURFACE7 iface,
974                                       LPDDPIXELFORMAT pDDPixelFormat)
975 {
976     /* What is DDERR_INVALIDSURFACETYPE for here? */
977     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
978
979     TRACE("(%p)->(%p)\n",This,pDDPixelFormat);
980     DD_STRUCT_COPY_BYSIZE(pDDPixelFormat,&This->surface_desc.u4.ddpfPixelFormat);
981     return DD_OK;
982 }
983
984 HRESULT WINAPI
985 Main_DirectDrawSurface_GetPriority(LPDIRECTDRAWSURFACE7 iface,
986                                    LPDWORD pdwPriority)
987 {
988     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
989
990     TRACE("(%p)->(%p)\n",This,pdwPriority);
991     CHECK_TEXTURE(This);
992
993     *pdwPriority = This->priority;
994     return DD_OK;
995 }
996
997 HRESULT WINAPI
998 Main_DirectDrawSurface_GetPrivateData(LPDIRECTDRAWSURFACE7 iface,
999                                       REFGUID tag, LPVOID pBuffer,
1000                                       LPDWORD pcbBufferSize)
1001 {
1002     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1003     PrivateData* data;
1004
1005     TRACE("(%p)->(%p), size = %ld\n", This, pBuffer, *pcbBufferSize);
1006
1007     data = find_private_data(This, tag);
1008     if (data == NULL) return DDERR_NOTFOUND;
1009
1010     /* This may not be right. */
1011     if ((data->flags & DDSPD_VOLATILE)
1012         && data->uniqueness_value != This->uniqueness_value)
1013         return DDERR_EXPIRED;
1014
1015     if (*pcbBufferSize < data->size)
1016     {
1017         *pcbBufferSize = data->size;
1018         return DDERR_MOREDATA;
1019     }
1020
1021     if (data->flags & DDSPD_IUNKNOWNPTR)
1022     {
1023         *(LPUNKNOWN *)pBuffer = data->ptr.object;
1024         IUnknown_AddRef(data->ptr.object);
1025     }
1026     else
1027     {
1028         memcpy(pBuffer, data->ptr.data, data->size);
1029     }
1030
1031     return DD_OK;
1032 }
1033
1034 HRESULT WINAPI
1035 Main_DirectDrawSurface_GetSurfaceDesc(LPDIRECTDRAWSURFACE7 iface,
1036                                       LPDDSURFACEDESC2 pDDSD)
1037 {
1038     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1039
1040     TRACE("(%p)->(%p)\n",This,pDDSD);
1041     if ((pDDSD->dwSize < sizeof(DDSURFACEDESC)) ||
1042         (pDDSD->dwSize > sizeof(DDSURFACEDESC2))) {
1043         ERR("Impossible/Strange struct size %ld.\n",pDDSD->dwSize);
1044         return DDERR_GENERIC;
1045     }
1046
1047     DD_STRUCT_COPY_BYSIZE(pDDSD,&This->surface_desc);
1048     if (TRACE_ON(ddraw)) {
1049       DDRAW_dump_surface_desc(pDDSD);
1050     }
1051     return DD_OK;
1052 }
1053
1054 HRESULT WINAPI
1055 Main_DirectDrawSurface_GetUniquenessValue(LPDIRECTDRAWSURFACE7 iface,
1056                                           LPDWORD pValue)
1057 {
1058     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1059
1060     TRACE("(%p)->(%p)\n",This,pValue);
1061     *pValue = This->uniqueness_value;
1062     return DD_OK;
1063 }
1064
1065 HRESULT WINAPI
1066 Main_DirectDrawSurface_Initialize(LPDIRECTDRAWSURFACE7 iface,
1067                                   LPDIRECTDRAW pDD, LPDDSURFACEDESC2 pDDSD)
1068 {
1069     TRACE("(%p)->(%p,%p)\n",iface,pDD,pDDSD);
1070     return DDERR_ALREADYINITIALIZED;
1071 }
1072
1073 HRESULT WINAPI
1074 Main_DirectDrawSurface_IsLost(LPDIRECTDRAWSURFACE7 iface)
1075 {
1076     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1077
1078     TRACE("(%p) is%s lost\n",This, (This->lost ? "" : " not"));
1079     return This->lost ? DDERR_SURFACELOST : DD_OK;
1080 }
1081
1082
1083 /* XXX This doesn't actually do any locking or keep track of the locked
1084  * rectangles. The behaviour is poorly documented. */
1085 HRESULT WINAPI
1086 Main_DirectDrawSurface_Lock(LPDIRECTDRAWSURFACE7 iface, LPRECT prect,
1087                             LPDDSURFACEDESC2 pDDSD, DWORD flags, HANDLE h)
1088 {
1089     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1090
1091     if (TRACE_ON(ddraw)) {
1092         TRACE("(%p)->Lock(%p,%p,%08lx,%08lx)\n",This,prect,pDDSD,flags,(DWORD)h);
1093         TRACE(" - locking flags : "); DDRAW_dump_lockflag(flags);
1094     }
1095     if (WARN_ON(ddraw)) {
1096         if (flags & ~(DDLOCK_WAIT|DDLOCK_READONLY|DDLOCK_WRITEONLY)) {
1097             WARN(" - unsupported locking flag : "); DDRAW_dump_lockflag(flags & ~(DDLOCK_WAIT|DDLOCK_READONLY|DDLOCK_WRITEONLY));
1098         }
1099     }
1100
1101     /* If the surface is already locked, return busy */
1102     if (This->locked) {
1103         WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1104         return DDERR_SURFACEBUSY;
1105     }
1106
1107     /* First, copy the Surface description */
1108     DD_STRUCT_COPY_BYSIZE(pDDSD,&(This->surface_desc));
1109
1110     /* Used to optimize the D3D Device locking */
1111     This->lastlocktype = flags & (DDLOCK_READONLY|DDLOCK_WRITEONLY);
1112     
1113     /* If asked only for a part, change the surface pointer.
1114      * (Not documented.) */
1115     if (prect != NULL) {
1116         TRACE(" lprect: %ldx%ld-%ldx%ld\n",
1117                 prect->left,prect->top,prect->right,prect->bottom);
1118         /* First do some sanity checkings on the rectangle we receive.
1119            DungeonSiege seems to gives us once a very bad rectangle for example */
1120         if ((prect->top < 0) ||
1121             (prect->left < 0) ||
1122             (prect->bottom < 0) ||
1123             (prect->right < 0) ||
1124             (prect->left >= prect->right) ||
1125             (prect->top >= prect->bottom) ||
1126             (prect->left >= This->surface_desc.dwWidth) ||
1127             (prect->right > This->surface_desc.dwWidth) ||
1128             (prect->top >= This->surface_desc.dwHeight) ||
1129             (prect->bottom > This->surface_desc.dwHeight)) {
1130             ERR(" Invalid values in LPRECT !!!\n");
1131             return DDERR_INVALIDPARAMS;
1132         }
1133
1134         This->lock_update(This, prect, flags);
1135
1136         if (pDDSD->u4.ddpfPixelFormat.dwFlags & DDPF_FOURCC) {
1137             int blksize;
1138             switch(pDDSD->u4.ddpfPixelFormat.dwFourCC) {
1139                 case MAKE_FOURCC('D','X','T','1') : blksize = 8; break;
1140                 case MAKE_FOURCC('D','X','T','3') : blksize = 16; break;
1141                 case MAKE_FOURCC('D','X','T','5') : blksize = 16; break;
1142                 default: return DDERR_INVALIDPIXELFORMAT;
1143             }
1144             pDDSD->lpSurface = (char *)This->surface_desc.lpSurface
1145                 + prect->top/4 * (pDDSD->dwWidth+3)/4 * blksize
1146                 + prect->left/4 * blksize;
1147         } else
1148             pDDSD->lpSurface = (char *)This->surface_desc.lpSurface
1149                 + prect->top * This->surface_desc.u1.lPitch
1150                 + prect->left * GET_BPP(This->surface_desc);
1151     } else {
1152         This->lock_update(This, NULL, flags);
1153     }
1154
1155     This->locked = TRUE;
1156
1157     TRACE("locked surface returning description : \n");
1158     if (TRACE_ON(ddraw)) DDRAW_dump_surface_desc(pDDSD);
1159     
1160     return DD_OK;
1161 }
1162
1163 HRESULT WINAPI
1164 Main_DirectDrawSurface_PageLock(LPDIRECTDRAWSURFACE7 iface, DWORD dwFlags)
1165 {
1166     /* Some surface types should return DDERR_CANTPAGELOCK. */
1167     return DD_OK;
1168 }
1169
1170 HRESULT WINAPI
1171 Main_DirectDrawSurface_PageUnlock(LPDIRECTDRAWSURFACE7 iface, DWORD dwFlags)
1172 {
1173     /* Some surface types should return DDERR_CANTPAGEUNLOCK, and we should
1174      * keep track so we can return DDERR_NOTPAGELOCKED as appropriate. */
1175     return DD_OK;
1176 }
1177
1178 HRESULT WINAPI
1179 Main_DirectDrawSurface_ReleaseDC(LPDIRECTDRAWSURFACE7 iface, HDC hDC)
1180 {
1181     HRESULT hr;
1182     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1183
1184     TRACE("(%p)->(%p)\n",This,hDC);
1185
1186     if (!This->dc_in_use || This->hDC != hDC)
1187         return DDERR_INVALIDPARAMS;
1188
1189     This->release_dc(This, hDC);
1190
1191     hr = IDirectDrawSurface7_Unlock(iface, NULL);
1192     if (FAILED(hr)) return hr;
1193
1194     This->dc_in_use = FALSE;
1195     This->hDC = 0;
1196
1197     return DD_OK;
1198 }
1199
1200 /* Restore */
1201
1202 HRESULT WINAPI
1203 Main_DirectDrawSurface_SetClipper(LPDIRECTDRAWSURFACE7 iface,
1204                                   LPDIRECTDRAWCLIPPER pDDClipper)
1205 {
1206     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1207
1208     TRACE("(%p)->(%p)\n",This,pDDClipper);
1209     if (pDDClipper == ICOM_INTERFACE(This->clipper, IDirectDrawClipper))
1210         return DD_OK;
1211
1212     if (This->clipper != NULL)
1213         IDirectDrawClipper_Release(ICOM_INTERFACE(This->clipper,
1214                                                   IDirectDrawClipper));
1215
1216     This->clipper = ICOM_OBJECT(IDirectDrawClipperImpl, IDirectDrawClipper,
1217                                 pDDClipper);
1218     if (pDDClipper != NULL)
1219         IDirectDrawClipper_AddRef(pDDClipper);
1220
1221     return DD_OK;
1222 }
1223
1224 HRESULT WINAPI
1225 Main_DirectDrawSurface_SetColorKey(LPDIRECTDRAWSURFACE7 iface,
1226                                    DWORD dwFlags, LPDDCOLORKEY pCKey)
1227 {
1228     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1229     
1230     TRACE("(%p)->(%08lx,%p)\n",This,dwFlags,pCKey);
1231
1232     if (TRACE_ON(ddraw)) {
1233         TRACE(" - colorkey flags : ");
1234         DDRAW_dump_colorkeyflag(dwFlags);
1235     }
1236
1237     if ((dwFlags & DDCKEY_COLORSPACE) != 0) {
1238         FIXME(" colorkey value not supported (%08lx) !\n", dwFlags);
1239         return DDERR_INVALIDPARAMS;
1240     }
1241     
1242     /* TODO: investigate if this function can take multiple bits set at the same
1243              time (ie setting multiple colorkey values at the same time with only
1244              one API call).
1245     */
1246     if (pCKey) {
1247         switch (dwFlags & ~DDCKEY_COLORSPACE) {
1248             case DDCKEY_DESTBLT:
1249                 This->surface_desc.ddckCKDestBlt = *pCKey;
1250                 This->surface_desc.dwFlags |= DDSD_CKDESTBLT;
1251                 break;
1252
1253             case DDCKEY_DESTOVERLAY:
1254                 This->surface_desc.u3.ddckCKDestOverlay = *pCKey;
1255                 This->surface_desc.dwFlags |= DDSD_CKDESTOVERLAY;
1256                 break;
1257
1258             case DDCKEY_SRCOVERLAY:
1259                 This->surface_desc.ddckCKSrcOverlay = *pCKey;
1260                 This->surface_desc.dwFlags |= DDSD_CKSRCOVERLAY;
1261                 break;
1262
1263             case DDCKEY_SRCBLT:
1264                 This->surface_desc.ddckCKSrcBlt = *pCKey;
1265                 This->surface_desc.dwFlags |= DDSD_CKSRCBLT;
1266                 break;
1267
1268             default:
1269                 return DDERR_INVALIDPARAMS;
1270         }
1271     } else {
1272         switch (dwFlags & ~DDCKEY_COLORSPACE) {
1273             case DDCKEY_DESTBLT:
1274                 This->surface_desc.dwFlags &= ~DDSD_CKDESTBLT;
1275                 break;
1276
1277             case DDCKEY_DESTOVERLAY:
1278                 This->surface_desc.dwFlags &= ~DDSD_CKDESTOVERLAY;
1279                 break;
1280
1281             case DDCKEY_SRCOVERLAY:
1282                 This->surface_desc.dwFlags &= ~DDSD_CKSRCOVERLAY;
1283                 break;
1284
1285             case DDCKEY_SRCBLT:
1286                 This->surface_desc.dwFlags &= ~DDSD_CKSRCBLT;
1287                 break;
1288
1289             default:
1290                 return DDERR_INVALIDPARAMS;
1291         }
1292     }
1293
1294     if (This->aux_setcolorkey_cb) This->aux_setcolorkey_cb(This, dwFlags, pCKey);
1295
1296     return DD_OK;
1297 }
1298
1299 HRESULT WINAPI
1300 Main_DirectDrawSurface_SetLOD(LPDIRECTDRAWSURFACE7 iface, DWORD dwMaxLOD)
1301 {
1302     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1303
1304     TRACE("(%p)->(%08lx)\n",This,dwMaxLOD);
1305     CHECK_TEXTURE(This);
1306
1307     This->max_lod = dwMaxLOD;
1308     return DD_OK;
1309 }
1310
1311 HRESULT WINAPI
1312 Main_DirectDrawSurface_SetOverlayPosition(LPDIRECTDRAWSURFACE7 iface,
1313                                           LONG X, LONG Y)
1314 {
1315     return DDERR_NOTAOVERLAYSURFACE;
1316 }
1317
1318 HRESULT WINAPI
1319 Main_DirectDrawSurface_SetPalette(LPDIRECTDRAWSURFACE7 iface,
1320                                   LPDIRECTDRAWPALETTE pPalette)
1321 {
1322     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1323     IDirectDrawPalette *pal_to_rel = NULL;
1324
1325     TRACE("(%p)->(%p)\n",This,pPalette);
1326     if (pPalette == ICOM_INTERFACE(This->palette, IDirectDrawPalette))
1327         return DD_OK;
1328
1329     if (This->palette != NULL) {
1330         if (This->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
1331             This->palette->global.dwFlags &= ~DDPCAPS_PRIMARYSURFACE;
1332         pal_to_rel = ICOM_INTERFACE(This->palette, IDirectDrawPalette);
1333     }
1334
1335     This->palette = ICOM_OBJECT(IDirectDrawPaletteImpl, IDirectDrawPalette,
1336                                 pPalette);
1337     if (pPalette != NULL) {
1338         IDirectDrawPalette_AddRef(pPalette);
1339         if (This->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
1340             This->palette->global.dwFlags |= DDPCAPS_PRIMARYSURFACE;
1341     }
1342
1343     This->set_palette(This, This->palette);
1344
1345     /* Do the palette release at the end to prevent doing some 'loop' when removing
1346      * the surface maintaining the last reference on a palette.
1347      */
1348     if (pal_to_rel != NULL)
1349         IDirectDrawPalette_Release(pal_to_rel);
1350
1351     return DD_OK;
1352 }
1353
1354 HRESULT WINAPI
1355 Main_DirectDrawSurface_SetPriority(LPDIRECTDRAWSURFACE7 iface,
1356                                    DWORD dwPriority)
1357 {
1358     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1359
1360     TRACE("(%p)->(%08lx)\n",This,dwPriority);
1361     CHECK_TEXTURE(This);
1362
1363     This->priority = dwPriority;
1364     return DD_OK;
1365 }
1366
1367 /* Be careful when locking this: it is risky to call the object's AddRef
1368  * or Release holding a lock. */
1369 HRESULT WINAPI
1370 Main_DirectDrawSurface_SetPrivateData(LPDIRECTDRAWSURFACE7 iface,
1371                                       REFGUID tag, LPVOID pData,
1372                                       DWORD cbSize, DWORD dwFlags)
1373 {
1374     PrivateData* data;
1375     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1376
1377     TRACE("(%p)->(%p), size=%ld\n", This, pData, cbSize);
1378
1379     data = find_private_data(This, tag);
1380     if (data == NULL)
1381     {
1382         data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data));
1383         if (data == NULL) return DDERR_OUTOFMEMORY;
1384
1385         data->tag = *tag;
1386         data->flags = dwFlags;
1387         data->uniqueness_value = This->uniqueness_value;
1388
1389         if (dwFlags & DDSPD_IUNKNOWNPTR)
1390         {
1391             data->ptr.object = (LPUNKNOWN)pData;
1392             data->size = sizeof(LPUNKNOWN);
1393             IUnknown_AddRef(data->ptr.object);
1394         }
1395         else
1396         {
1397             data->ptr.data = HeapAlloc(GetProcessHeap(), 0, cbSize);
1398             if (data->ptr.data == NULL)
1399             {
1400                 HeapFree(GetProcessHeap(), 0, data);
1401                 return DDERR_OUTOFMEMORY;
1402             }
1403
1404             data->size = cbSize;
1405             memcpy(data->ptr.data, pData, data->size);
1406         }
1407
1408         /* link it in */
1409         data->next = This->private_data;
1410         data->prev = NULL;
1411         if (This->private_data)
1412             This->private_data->prev = data;
1413         This->private_data = data;
1414
1415         return DD_OK;
1416     }
1417     else
1418     {
1419         /* I don't actually know how windows handles this case. The only
1420          * reason I don't just call FreePrivateData is because I want to
1421          * guarantee SetPrivateData working when using LPUNKNOWN or data
1422          * that is no larger than the old data. */
1423
1424         FIXME("Replacing existing private data not implemented yet.\n");
1425         return E_FAIL;
1426     }
1427 }
1428
1429 /* SetSurfaceDesc */
1430
1431 HRESULT WINAPI
1432 Main_DirectDrawSurface_Unlock(LPDIRECTDRAWSURFACE7 iface, LPRECT pRect)
1433 {
1434     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1435
1436     TRACE("(%p)->Unlock(%p)\n",This,pRect);
1437
1438     if (!This->locked) {
1439         WARN("Surface not locked - returing DDERR_NOTLOCKED\n");
1440         return DDERR_NOTLOCKED;
1441     }
1442
1443     This->locked = FALSE;
1444     This->unlock_update(This, pRect);
1445     if (This->aux_unlock)
1446         This->aux_unlock(This->aux_ctx, This->aux_data, pRect);
1447
1448     return DD_OK;
1449 }
1450
1451 HRESULT WINAPI
1452 Main_DirectDrawSurface_UpdateOverlay(LPDIRECTDRAWSURFACE7 iface,
1453                                      LPRECT pSrcRect,
1454                                      LPDIRECTDRAWSURFACE7 pDstSurface,
1455                                      LPRECT pDstRect, DWORD dwFlags,
1456                                      LPDDOVERLAYFX pFX)
1457 {
1458     return DDERR_UNSUPPORTED;
1459 }
1460
1461 /* MSDN: "not currently implemented." */
1462 HRESULT WINAPI
1463 Main_DirectDrawSurface_UpdateOverlayDisplay(LPDIRECTDRAWSURFACE7 iface,
1464                                             DWORD dwFlags)
1465 {
1466     return DDERR_UNSUPPORTED;
1467 }
1468
1469 HRESULT WINAPI
1470 Main_DirectDrawSurface_UpdateOverlayZOrder(LPDIRECTDRAWSURFACE7 iface,
1471                                            DWORD dwFlags,
1472                                            LPDIRECTDRAWSURFACE7 pDDSRef)
1473 {
1474     return DDERR_NOTAOVERLAYSURFACE;
1475 }