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