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