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