Use the front buffer palette for DC operations on off-screen buffers.
[wine/multimedia.git] / dlls / ddraw / surface_main.c
blobfd10394f0555734db702c832d9eb3e2e8b49ab51
1 /* DirectDrawSurface base implementation
3 * Copyright 1997-2000 Marcus Meissner
4 * Copyright 1998-2000 Lionel Ulmer (most of Direct3D stuff)
5 * Copyright 2000-2001 TransGaming Technologies Inc.
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.
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.
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
21 #include "config.h"
22 #include "wine/port.h"
24 #include <assert.h>
25 #include <string.h>
27 #define COBJMACROS
28 #define NONAMELESSUNION
29 #define NONAMELESSSTRUCT
31 #include "winerror.h"
32 #include "wine/debug.h"
33 #include "ddraw_private.h"
34 #include "opengl_private.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
37 WINE_DECLARE_DEBUG_CHANNEL(ddraw_flip);
38 WINE_DECLARE_DEBUG_CHANNEL(ddraw_fps);
40 /** Creation/Destruction functions */
42 HRESULT
43 Main_DirectDrawSurface_Construct(IDirectDrawSurfaceImpl *This,
44 IDirectDrawImpl *pDD,
45 const DDSURFACEDESC2 *pDDSD)
47 TRACE("(%p)->(%p,%p)\n", This, pDD, pDDSD);
49 if (pDDSD != &This->surface_desc) {
50 This->surface_desc.dwSize = sizeof(This->surface_desc);
51 DD_STRUCT_COPY_BYSIZE(&(This->surface_desc),pDDSD);
53 This->uniqueness_value = 1; /* unchecked */
54 This->ref = 1;
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 */
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;
84 ICOM_INIT_INTERFACE(This, IDirectDrawSurface3,
85 DDRAW_IDDS3_Thunk_VTable);
86 ICOM_INIT_INTERFACE(This, IDirectDrawGammaControl,
87 DDRAW_IDDGC_VTable);
89 /* There is no generic implementation of IDDS7 or texture */
91 Main_DirectDraw_AddSurface(pDD, This);
92 return DD_OK;
95 void Main_DirectDrawSurface_final_release(IDirectDrawSurfaceImpl* This)
97 Main_DirectDraw_RemoveSurface(This->ddraw_owner, This);
100 HRESULT Main_DirectDrawSurface_late_allocate(IDirectDrawSurfaceImpl* This)
102 return DD_OK;
105 static void Main_DirectDrawSurface_Destroy(IDirectDrawSurfaceImpl* This)
107 if (This->palette) {
108 IDirectDrawPalette_Release(ICOM_INTERFACE(This->palette, IDirectDrawPalette));
109 This->palette = NULL;
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);
117 void Main_DirectDrawSurface_ForceDestroy(IDirectDrawSurfaceImpl* This)
119 WARN("destroying surface %p with refcnt %lu\n", This, This->ref);
120 Main_DirectDrawSurface_Destroy(This);
123 ULONG WINAPI Main_DirectDrawSurface_Release(LPDIRECTDRAWSURFACE7 iface)
125 IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
126 ULONG ref = InterlockedDecrement(&This->ref);
128 TRACE("(%p)->(): decreasing from %ld\n", This, ref + 1);
130 if (ref == 0)
132 if (This->aux_release)
133 This->aux_release(This->aux_ctx, This->aux_data);
134 Main_DirectDrawSurface_Destroy(This);
136 TRACE("released surface %p\n", This);
138 return 0;
141 return ref;
144 ULONG WINAPI Main_DirectDrawSurface_AddRef(LPDIRECTDRAWSURFACE7 iface)
146 IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
147 ULONG ref = InterlockedIncrement(&This->ref);
149 TRACE("(%p)->(): increasing from %ld\n", This, ref - 1);
151 return ref;
154 HRESULT WINAPI
155 Main_DirectDrawSurface_QueryInterface(LPDIRECTDRAWSURFACE7 iface, REFIID riid,
156 LPVOID* ppObj)
158 IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
159 TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppObj);
161 *ppObj = NULL;
163 if (IsEqualGUID(&IID_IUnknown, riid)
164 || IsEqualGUID(&IID_IDirectDrawSurface7, riid)
165 || IsEqualGUID(&IID_IDirectDrawSurface4, riid))
167 InterlockedIncrement(&This->ref);
168 *ppObj = ICOM_INTERFACE(This, IDirectDrawSurface7);
169 return S_OK;
171 else if (IsEqualGUID(&IID_IDirectDrawSurface, riid)
172 || IsEqualGUID(&IID_IDirectDrawSurface2, riid)
173 || IsEqualGUID(&IID_IDirectDrawSurface3, riid))
175 InterlockedIncrement(&This->ref);
176 *ppObj = ICOM_INTERFACE(This, IDirectDrawSurface3);
177 return S_OK;
179 else if (IsEqualGUID(&IID_IDirectDrawGammaControl, riid))
181 InterlockedIncrement(&This->ref);
182 *ppObj = ICOM_INTERFACE(This, IDirectDrawGammaControl);
183 return S_OK;
185 #ifdef HAVE_OPENGL
186 /* interfaces following here require OpenGL */
187 if( !opengl_initialized )
188 return E_NOINTERFACE;
190 if ( IsEqualGUID( &IID_D3DDEVICE_OpenGL, riid ) ||
191 IsEqualGUID( &IID_IDirect3DHALDevice, riid) )
193 IDirect3DDeviceImpl *d3ddevimpl;
194 HRESULT ret_value;
196 ret_value = d3ddevice_create(&d3ddevimpl, This->ddraw_owner, This, 1);
197 if (FAILED(ret_value)) return ret_value;
199 *ppObj = ICOM_INTERFACE(d3ddevimpl, IDirect3DDevice);
200 TRACE(" returning Direct3DDevice interface at %p.\n", *ppObj);
202 InterlockedIncrement(&This->ref); /* No idea if this is correct.. Need to check using real Windows */
203 return ret_value;
205 else if (IsEqualGUID( &IID_IDirect3DTexture, riid ) ||
206 IsEqualGUID( &IID_IDirect3DTexture2, riid ))
208 HRESULT ret_value = S_OK;
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.
214 This->surface_desc.ddsCaps.dwCaps |= DDSCAPS_TEXTURE;
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;
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;
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);
233 InterlockedIncrement(&This->ref);
234 return ret_value;
236 #endif
238 return E_NOINTERFACE;
241 /*** Callbacks */
243 BOOL
244 Main_DirectDrawSurface_attach(IDirectDrawSurfaceImpl *This,
245 IDirectDrawSurfaceImpl *to)
247 return TRUE;
250 BOOL Main_DirectDrawSurface_detach(IDirectDrawSurfaceImpl *This)
252 return TRUE;
255 void
256 Main_DirectDrawSurface_lock_update(IDirectDrawSurfaceImpl* This, LPCRECT pRect,
257 DWORD dwFlags)
261 void
262 Main_DirectDrawSurface_unlock_update(IDirectDrawSurfaceImpl* This,
263 LPCRECT pRect)
267 void
268 Main_DirectDrawSurface_lose_surface(IDirectDrawSurfaceImpl* This)
272 void
273 Main_DirectDrawSurface_set_palette(IDirectDrawSurfaceImpl* This,
274 IDirectDrawPaletteImpl* pal)
278 void
279 Main_DirectDrawSurface_update_palette(IDirectDrawSurfaceImpl* This,
280 IDirectDrawPaletteImpl* pal,
281 DWORD dwStart, DWORD dwCount,
282 LPPALETTEENTRY palent)
286 HWND
287 Main_DirectDrawSurface_get_display_window(IDirectDrawSurfaceImpl* This)
289 return 0;
292 HRESULT
293 Main_DirectDrawSurface_get_gamma_ramp(IDirectDrawSurfaceImpl* This,
294 DWORD dwFlags,
295 LPDDGAMMARAMP lpGammaRamp)
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;
306 HRESULT
307 Main_DirectDrawSurface_set_gamma_ramp(IDirectDrawSurfaceImpl* This,
308 DWORD dwFlags,
309 LPDDGAMMARAMP lpGammaRamp)
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;
321 /*** Interface functions */
323 HRESULT WINAPI
324 Main_DirectDrawSurface_AddAttachedSurface(LPDIRECTDRAWSURFACE7 iface,
325 LPDIRECTDRAWSURFACE7 pAttach)
327 IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
328 IDirectDrawSurfaceImpl* surf = ICOM_OBJECT(IDirectDrawSurfaceImpl,
329 IDirectDrawSurface7, pAttach);
331 TRACE("(%p)->(%p)\n",This,pAttach);
333 /* Does windows check this? */
334 if (surf == This)
335 return DDERR_CANNOTATTACHSURFACE; /* unchecked */
337 /* Does windows check this? */
338 if (surf->ddraw_owner != This->ddraw_owner)
339 return DDERR_CANNOTATTACHSURFACE; /* unchecked */
341 if (surf->surface_owner != NULL)
342 return DDERR_SURFACEALREADYATTACHED; /* unchecked */
344 /* TODO MSDN: "You can attach only z-buffer surfaces with this method."
345 * But apparently backbuffers and mipmaps can be attached too. */
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) */
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;
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;
368 IDirectDrawSurface7_AddRef(pAttach);
370 return DD_OK;
373 /* MSDN: "not currently implemented." */
374 HRESULT WINAPI
375 Main_DirectDrawSurface_AddOverlayDirtyRect(LPDIRECTDRAWSURFACE7 iface,
376 LPRECT pRect)
378 TRACE("(%p)->(%p)\n",iface,pRect);
379 return DDERR_UNSUPPORTED; /* unchecked */
382 /* MSDN: "not currently implemented." */
383 HRESULT WINAPI
384 Main_DirectDrawSurface_BltBatch(LPDIRECTDRAWSURFACE7 iface,
385 LPDDBLTBATCH pBatch, DWORD dwCount,
386 DWORD dwFlags)
388 TRACE("(%p)->(%p,%ld,%08lx)\n",iface,pBatch,dwCount,dwFlags);
389 return DDERR_UNSUPPORTED; /* unchecked */
392 HRESULT WINAPI
393 Main_DirectDrawSurface_ChangeUniquenessValue(LPDIRECTDRAWSURFACE7 iface)
395 IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
396 volatile IDirectDrawSurfaceImpl* vThis = This;
398 TRACE("(%p)\n",This);
399 /* A uniquness value of 0 is apparently special.
400 * This needs to be checked. */
401 while (1)
403 DWORD old_uniqueness_value = vThis->uniqueness_value;
404 DWORD new_uniqueness_value = old_uniqueness_value+1;
406 if (old_uniqueness_value == 0) break;
407 if (new_uniqueness_value == 0) new_uniqueness_value = 1;
409 if (InterlockedCompareExchange((LONG*)&vThis->uniqueness_value,
410 old_uniqueness_value,
411 new_uniqueness_value)
412 == old_uniqueness_value)
413 break;
416 return DD_OK;
419 HRESULT WINAPI
420 Main_DirectDrawSurface_DeleteAttachedSurface(LPDIRECTDRAWSURFACE7 iface,
421 DWORD dwFlags,
422 LPDIRECTDRAWSURFACE7 pAttach)
424 IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
425 IDirectDrawSurfaceImpl* surf = ICOM_OBJECT(IDirectDrawSurfaceImpl,
426 IDirectDrawSurface7, pAttach);
428 TRACE("(%p)->(%08lx,%p)\n",This,dwFlags,pAttach);
430 if (!surf || (surf->surface_owner != This))
431 return DDERR_SURFACENOTATTACHED; /* unchecked */
433 surf->detach(surf);
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 */
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;
450 IDirectDrawSurface7_Release(pAttach);
452 return DD_OK;
455 HRESULT WINAPI
456 Main_DirectDrawSurface_EnumAttachedSurfaces(LPDIRECTDRAWSURFACE7 iface,
457 LPVOID context,
458 LPDDENUMSURFACESCALLBACK7 cb)
460 IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
461 IDirectDrawSurfaceImpl* surf;
462 DDSURFACEDESC2 desc;
464 TRACE("(%p)->(%p,%p)\n",This,context,cb);
466 for (surf = This->attached; surf != NULL; surf = surf->next_attached)
468 LPDIRECTDRAWSURFACE7 isurf = ICOM_INTERFACE(surf, IDirectDrawSurface7);
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);
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;
482 TRACE(" end of enumeration.\n");
484 return DD_OK;
487 HRESULT WINAPI
488 Main_DirectDrawSurface_EnumOverlayZOrders(LPDIRECTDRAWSURFACE7 iface,
489 DWORD dwFlags, LPVOID context,
490 LPDDENUMSURFACESCALLBACK7 cb)
492 TRACE("(%p)->(%08lx,%p,%p)\n",iface,dwFlags,context,cb);
493 return DD_OK;
496 BOOL Main_DirectDrawSurface_flip_data(IDirectDrawSurfaceImpl* front,
497 IDirectDrawSurfaceImpl* back,
498 DWORD dwFlags)
500 /* uniqueness_value? */
501 /* This is necessary. But is it safe? */
503 HDC tmp = front->hDC;
504 front->hDC = back->hDC;
505 back->hDC = tmp;
509 BOOL tmp = front->dc_in_use;
510 front->dc_in_use = back->dc_in_use;
511 back->dc_in_use = tmp;
515 FLATPTR tmp = front->global.fpVidMem;
516 front->global.fpVidMem = back->global.fpVidMem;
517 back->global.fpVidMem = tmp;
521 ULONG_PTR tmp = front->global_more.hKernelSurface;
522 front->global_more.hKernelSurface = back->global_more.hKernelSurface;
523 back->global_more.hKernelSurface = tmp;
526 return TRUE;
529 /* This is unnecessarely complicated :-) */
530 #define MEASUREMENT_WINDOW 5
531 #define NUMBER_OF_WINDOWS 10
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;
540 HRESULT WINAPI
541 Main_DirectDrawSurface_Flip(LPDIRECTDRAWSURFACE7 iface,
542 LPDIRECTDRAWSURFACE7 override, DWORD dwFlags)
544 IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
545 IDirectDrawSurfaceImpl* target;
546 HRESULT hr;
548 TRACE("(%p)->(%p,%08lx)\n",This,override,dwFlags);
550 if (TRACE_ON(ddraw_fps)) {
551 LONGLONG current_time;
552 LONGLONG frame_duration;
553 QueryPerformanceCounter((LARGE_INTEGER *) &current_time);
555 if (prev_time != 0) {
556 LONGLONG total_time = 0;
557 int tot_meas;
559 frame_duration = current_time - prev_time;
560 prev_time = current_time;
562 perf_storage[current_window] += frame_duration;
563 measurements_in_window++;
565 if (measurements_in_window >= MEASUREMENT_WINDOW) {
566 current_window++;
567 valid_windows++;
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];
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];
583 TRACE_(ddraw_fps)(" %9.5f\n", (double) (perf_freq * tot_meas) / (double) total_time);
585 if (current_window >= NUMBER_OF_WINDOWS) {
586 current_window = 0;
588 perf_storage[current_window] = 0;
589 measurements_in_window = 0;
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);
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;
607 if (This->aux_flip)
608 if (This->aux_flip(This->aux_ctx, This->aux_data))
609 return DD_OK;
611 /* 1. find the flip target */
612 /* XXX I don't think this algorithm works for more than 1 backbuffer. */
613 if (override == NULL)
615 static DDSCAPS2 back_caps = { DDSCAPS_BACKBUFFER };
616 LPDIRECTDRAWSURFACE7 tgt;
618 hr = IDirectDrawSurface7_GetAttachedSurface(iface, &back_caps, &tgt);
619 if (FAILED(hr)) return DDERR_NOTFLIPPABLE; /* unchecked */
621 target = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7,
622 tgt);
623 IDirectDrawSurface7_Release(tgt);
625 else
627 BOOL on_chain = FALSE;
628 IDirectDrawSurfaceImpl* surf;
630 /* MSDN: "The method fails if the specified [override] surface is not
631 * a member of the flipping chain." */
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);
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)
643 if (surf == This)
645 on_chain = TRUE;
646 break;
650 if (!on_chain)
651 return DDERR_INVALIDPARAMS; /* unchecked */
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;
661 /* Hack for paletted games... */
662 palette = target->palette;
663 target->palette = This->palette;
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;
672 if (This->flip_data(This, target, dwFlags))
673 This->flip_update(This, dwFlags);
675 return DD_OK;
678 static PrivateData* find_private_data(IDirectDrawSurfaceImpl *This,
679 REFGUID tag)
681 PrivateData* data;
682 for (data = This->private_data; data != NULL; data = data->next)
684 if (IsEqualGUID(&data->tag, tag)) break;
687 return data;
690 HRESULT WINAPI
691 Main_DirectDrawSurface_FreePrivateData(LPDIRECTDRAWSURFACE7 iface, REFGUID tag)
693 IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
694 PrivateData *data;
696 data = find_private_data(This, tag);
697 if (data == NULL) return DDERR_NOTFOUND;
699 if (data->prev)
700 data->prev->next = data->next;
701 if (data->next)
702 data->next->prev = data->prev;
704 if (data->flags & DDSPD_IUNKNOWNPTR)
706 if (data->ptr.object != NULL)
707 IUnknown_Release(data->ptr.object);
709 else
710 HeapFree(GetProcessHeap(), 0, data->ptr.data);
712 HeapFree(GetProcessHeap(), 0, data);
714 return DD_OK;
717 HRESULT WINAPI
718 Main_DirectDrawSurface_GetAttachedSurface(LPDIRECTDRAWSURFACE7 iface,
719 LPDDSCAPS2 pCaps,
720 LPDIRECTDRAWSURFACE7* ppSurface)
722 IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
723 IDirectDrawSurfaceImpl* surf;
724 IDirectDrawSurfaceImpl* found = NULL;
725 DDSCAPS2 our_caps;
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");
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");
745 for (surf = This->attached; surf != NULL; surf = surf->next_attached)
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");
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))
758 /* MSDN: "This method fails if more than one surface is attached
759 * that matches the capabilities requested." */
760 if (found != NULL)
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. */
768 found = surf;
772 if (found == NULL) {
773 TRACE("Did not find any valid surface\n");
774 return DDERR_NOTFOUND;
777 *ppSurface = ICOM_INTERFACE(found, IDirectDrawSurface7);
779 if (TRACE_ON(ddraw)) {
780 TRACE("Returning surface %p with description :\n", *ppSurface);
781 DDRAW_dump_surface_desc(&(found->surface_desc));
784 /* XXX d3dframe.cpp sometimes AddRefs things that it gets from us. */
785 IDirectDrawSurface7_AddRef(ICOM_INTERFACE(found, IDirectDrawSurface7));
786 return DD_OK;
789 HRESULT WINAPI
790 Main_DirectDrawSurface_GetBltStatus(LPDIRECTDRAWSURFACE7 iface, DWORD dwFlags)
792 TRACE("(%p)->(%08lx)\n",iface,dwFlags);
794 switch (dwFlags)
796 case DDGBS_CANBLT:
797 case DDGBS_ISBLTDONE:
798 return DD_OK;
800 default:
801 return DDERR_INVALIDPARAMS;
805 HRESULT WINAPI
806 Main_DirectDrawSurface_GetCaps(LPDIRECTDRAWSURFACE7 iface, LPDDSCAPS2 pCaps)
808 IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
810 TRACE("(%p)->(%p)\n",This,pCaps);
811 *pCaps = This->surface_desc.ddsCaps;
812 return DD_OK;
815 HRESULT WINAPI
816 Main_DirectDrawSurface_GetClipper(LPDIRECTDRAWSURFACE7 iface,
817 LPDIRECTDRAWCLIPPER* ppClipper)
819 IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
821 TRACE("(%p)->(%p)\n",This,ppClipper);
822 if (This->clipper == NULL)
823 return DDERR_NOCLIPPERATTACHED;
825 *ppClipper = ICOM_INTERFACE(This->clipper, IDirectDrawClipper);
826 IDirectDrawClipper_AddRef(ICOM_INTERFACE(This->clipper,
827 IDirectDrawClipper));
828 return DD_OK;
831 HRESULT WINAPI
832 Main_DirectDrawSurface_GetColorKey(LPDIRECTDRAWSURFACE7 iface, DWORD dwFlags,
833 LPDDCOLORKEY pCKey)
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.) */
839 IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
841 TRACE("(%p)->(%08lx,%p)\n",This,dwFlags,pCKey);
842 if (TRACE_ON(ddraw)) {
843 TRACE(" - colorkey flags : ");
844 DDRAW_dump_colorkeyflag(dwFlags);
847 switch (dwFlags)
849 case DDCKEY_DESTBLT:
850 *pCKey = This->surface_desc.ddckCKDestBlt;
851 break;
853 case DDCKEY_DESTOVERLAY:
854 *pCKey = This->surface_desc.u3.ddckCKDestOverlay;
855 break;
857 case DDCKEY_SRCBLT:
858 *pCKey = This->surface_desc.ddckCKSrcBlt;
859 break;
861 case DDCKEY_SRCOVERLAY:
862 *pCKey = This->surface_desc.ddckCKSrcOverlay;
863 break;
865 default:
866 return DDERR_INVALIDPARAMS;
869 return DD_OK;
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)
876 DDSURFACEDESC2 ddsd;
877 HRESULT hr;
878 IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
880 TRACE("(%p)->(%p)\n",This,phDC);
881 CHECK_LOST(This);
883 LOCK_OBJECT(This);
885 if (This->dc_in_use)
887 UNLOCK_OBJECT(This);
888 return DDERR_DCALREADYCREATED;
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))
898 UNLOCK_OBJECT(This);
899 return hr;
902 hr = This->get_dc(This, &This->hDC);
904 if ((This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) &&
905 (This->palette == NULL)) {
906 IDirectDrawImpl *ddraw = This->ddraw_owner;
907 IDirectDrawSurfaceImpl *surf;
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;
921 SetDIBColorTable(This->hDC, 0, 256, col);
922 break;
928 if (SUCCEEDED(hr))
930 TRACE("returning %p\n",This->hDC);
932 *phDC = This->hDC;
933 This->dc_in_use = TRUE;
935 else WARN("No DC! Prepare for trouble\n");
937 UNLOCK_OBJECT(This);
938 return hr;
941 HRESULT WINAPI
942 Main_DirectDrawSurface_GetDDInterface(LPDIRECTDRAWSURFACE7 iface, LPVOID* pDD)
944 IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
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;
952 HRESULT WINAPI
953 Main_DirectDrawSurface_GetFlipStatus(LPDIRECTDRAWSURFACE7 iface, DWORD dwFlags)
955 /* XXX: DDERR_INVALIDSURFACETYPE */
957 TRACE("(%p)->(%08lx)\n",iface,dwFlags);
958 switch (dwFlags)
960 case DDGFS_CANFLIP:
961 case DDGFS_ISFLIPDONE:
962 return DD_OK;
964 default:
965 return DDERR_INVALIDPARAMS;
969 HRESULT WINAPI
970 Main_DirectDrawSurface_GetLOD(LPDIRECTDRAWSURFACE7 iface, LPDWORD pdwMaxLOD)
972 IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
974 TRACE("(%p)->(%p)\n",This,pdwMaxLOD);
975 CHECK_TEXTURE(This);
977 *pdwMaxLOD = This->max_lod;
978 return DD_OK;
981 HRESULT WINAPI
982 Main_DirectDrawSurface_GetOverlayPosition(LPDIRECTDRAWSURFACE7 iface,
983 LPLONG pX, LPLONG pY)
985 return DDERR_NOTAOVERLAYSURFACE;
988 HRESULT WINAPI
989 Main_DirectDrawSurface_GetPalette(LPDIRECTDRAWSURFACE7 iface,
990 LPDIRECTDRAWPALETTE* ppPalette)
992 IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
994 TRACE("(%p)->(%p)\n",This,ppPalette);
995 if (This->palette == NULL)
996 return DDERR_NOPALETTEATTACHED;
998 *ppPalette = ICOM_INTERFACE(This->palette, IDirectDrawPalette);
999 IDirectDrawPalette_AddRef(ICOM_INTERFACE(This->palette,
1000 IDirectDrawPalette));
1001 return DD_OK;
1004 HRESULT WINAPI
1005 Main_DirectDrawSurface_GetPixelFormat(LPDIRECTDRAWSURFACE7 iface,
1006 LPDDPIXELFORMAT pDDPixelFormat)
1008 /* What is DDERR_INVALIDSURFACETYPE for here? */
1009 IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1011 TRACE("(%p)->(%p)\n",This,pDDPixelFormat);
1012 DD_STRUCT_COPY_BYSIZE(pDDPixelFormat,&This->surface_desc.u4.ddpfPixelFormat);
1013 return DD_OK;
1016 HRESULT WINAPI
1017 Main_DirectDrawSurface_GetPriority(LPDIRECTDRAWSURFACE7 iface,
1018 LPDWORD pdwPriority)
1020 IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1022 TRACE("(%p)->(%p)\n",This,pdwPriority);
1023 CHECK_TEXTURE(This);
1025 *pdwPriority = This->priority;
1026 return DD_OK;
1029 HRESULT WINAPI
1030 Main_DirectDrawSurface_GetPrivateData(LPDIRECTDRAWSURFACE7 iface,
1031 REFGUID tag, LPVOID pBuffer,
1032 LPDWORD pcbBufferSize)
1034 IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1035 PrivateData* data;
1037 TRACE("(%p)->(%p), size = %ld\n", This, pBuffer, *pcbBufferSize);
1039 data = find_private_data(This, tag);
1040 if (data == NULL) return DDERR_NOTFOUND;
1042 /* This may not be right. */
1043 if ((data->flags & DDSPD_VOLATILE)
1044 && data->uniqueness_value != This->uniqueness_value)
1045 return DDERR_EXPIRED;
1047 if (*pcbBufferSize < data->size)
1049 *pcbBufferSize = data->size;
1050 return DDERR_MOREDATA;
1053 if (data->flags & DDSPD_IUNKNOWNPTR)
1055 *(LPUNKNOWN *)pBuffer = data->ptr.object;
1056 IUnknown_AddRef(data->ptr.object);
1058 else
1060 memcpy(pBuffer, data->ptr.data, data->size);
1063 return DD_OK;
1066 HRESULT WINAPI
1067 Main_DirectDrawSurface_GetSurfaceDesc(LPDIRECTDRAWSURFACE7 iface,
1068 LPDDSURFACEDESC2 pDDSD)
1070 IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
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;
1079 DD_STRUCT_COPY_BYSIZE(pDDSD,&This->surface_desc);
1080 if (TRACE_ON(ddraw)) {
1081 DDRAW_dump_surface_desc(pDDSD);
1083 return DD_OK;
1086 HRESULT WINAPI
1087 Main_DirectDrawSurface_GetUniquenessValue(LPDIRECTDRAWSURFACE7 iface,
1088 LPDWORD pValue)
1090 IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1092 TRACE("(%p)->(%p)\n",This,pValue);
1093 *pValue = This->uniqueness_value;
1094 return DD_OK;
1097 HRESULT WINAPI
1098 Main_DirectDrawSurface_Initialize(LPDIRECTDRAWSURFACE7 iface,
1099 LPDIRECTDRAW pDD, LPDDSURFACEDESC2 pDDSD)
1101 TRACE("(%p)->(%p,%p)\n",iface,pDD,pDDSD);
1102 return DDERR_ALREADYINITIALIZED;
1105 HRESULT WINAPI
1106 Main_DirectDrawSurface_IsLost(LPDIRECTDRAWSURFACE7 iface)
1108 IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1110 TRACE("(%p) is%s lost\n",This, (This->lost ? "" : " not"));
1111 return This->lost ? DDERR_SURFACELOST : DD_OK;
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)
1121 IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
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);
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));
1132 if (NULL != h) {
1133 return DDERR_INVALIDPARAMS;
1135 if (NULL == pDDSD) {
1136 return DDERR_INVALIDPARAMS;
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;
1145 /* First, copy the Surface description */
1146 DD_STRUCT_COPY_BYSIZE(pDDSD,&(This->surface_desc));
1148 /* Used to optimize the D3D Device locking */
1149 This->lastlocktype = flags & (DDLOCK_READONLY|DDLOCK_WRITEONLY);
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;
1172 This->lock_update(This, prect, flags);
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;
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);
1193 This->locked = TRUE;
1195 TRACE("locked surface returning description :\n");
1196 if (TRACE_ON(ddraw)) DDRAW_dump_surface_desc(pDDSD);
1198 return DD_OK;
1201 HRESULT WINAPI
1202 Main_DirectDrawSurface_PageLock(LPDIRECTDRAWSURFACE7 iface, DWORD dwFlags)
1204 /* Some surface types should return DDERR_CANTPAGELOCK. */
1205 return DD_OK;
1208 HRESULT WINAPI
1209 Main_DirectDrawSurface_PageUnlock(LPDIRECTDRAWSURFACE7 iface, DWORD dwFlags)
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;
1216 HRESULT WINAPI
1217 Main_DirectDrawSurface_ReleaseDC(LPDIRECTDRAWSURFACE7 iface, HDC hDC)
1219 HRESULT hr;
1220 IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1222 TRACE("(%p)->(%p)\n",This,hDC);
1224 if (!This->dc_in_use || This->hDC != hDC)
1225 return DDERR_INVALIDPARAMS;
1227 This->release_dc(This, hDC);
1229 hr = IDirectDrawSurface7_Unlock(iface, NULL);
1230 if (FAILED(hr)) return hr;
1232 This->dc_in_use = FALSE;
1233 This->hDC = 0;
1235 return DD_OK;
1238 /* Restore */
1240 HRESULT WINAPI
1241 Main_DirectDrawSurface_SetClipper(LPDIRECTDRAWSURFACE7 iface,
1242 LPDIRECTDRAWCLIPPER pDDClipper)
1244 IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1246 TRACE("(%p)->(%p)\n",This,pDDClipper);
1247 if (pDDClipper == ICOM_INTERFACE(This->clipper, IDirectDrawClipper))
1248 return DD_OK;
1250 if (This->clipper != NULL)
1251 IDirectDrawClipper_Release(ICOM_INTERFACE(This->clipper,
1252 IDirectDrawClipper));
1254 This->clipper = ICOM_OBJECT(IDirectDrawClipperImpl, IDirectDrawClipper,
1255 pDDClipper);
1256 if (pDDClipper != NULL)
1257 IDirectDrawClipper_AddRef(pDDClipper);
1259 return DD_OK;
1262 HRESULT WINAPI
1263 Main_DirectDrawSurface_SetColorKey(LPDIRECTDRAWSURFACE7 iface,
1264 DWORD dwFlags, LPDDCOLORKEY pCKey)
1266 IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1268 TRACE("(%p)->(%08lx,%p)\n",This,dwFlags,pCKey);
1270 if (TRACE_ON(ddraw)) {
1271 TRACE(" - colorkey flags : ");
1272 DDRAW_dump_colorkeyflag(dwFlags);
1275 if ((dwFlags & DDCKEY_COLORSPACE) != 0) {
1276 FIXME(" colorkey value not supported (%08lx) !\n", dwFlags);
1277 return DDERR_INVALIDPARAMS;
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).
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;
1291 case DDCKEY_DESTOVERLAY:
1292 This->surface_desc.u3.ddckCKDestOverlay = *pCKey;
1293 This->surface_desc.dwFlags |= DDSD_CKDESTOVERLAY;
1294 break;
1296 case DDCKEY_SRCOVERLAY:
1297 This->surface_desc.ddckCKSrcOverlay = *pCKey;
1298 This->surface_desc.dwFlags |= DDSD_CKSRCOVERLAY;
1299 break;
1301 case DDCKEY_SRCBLT:
1302 This->surface_desc.ddckCKSrcBlt = *pCKey;
1303 This->surface_desc.dwFlags |= DDSD_CKSRCBLT;
1304 break;
1306 default:
1307 return DDERR_INVALIDPARAMS;
1309 } else {
1310 switch (dwFlags & ~DDCKEY_COLORSPACE) {
1311 case DDCKEY_DESTBLT:
1312 This->surface_desc.dwFlags &= ~DDSD_CKDESTBLT;
1313 break;
1315 case DDCKEY_DESTOVERLAY:
1316 This->surface_desc.dwFlags &= ~DDSD_CKDESTOVERLAY;
1317 break;
1319 case DDCKEY_SRCOVERLAY:
1320 This->surface_desc.dwFlags &= ~DDSD_CKSRCOVERLAY;
1321 break;
1323 case DDCKEY_SRCBLT:
1324 This->surface_desc.dwFlags &= ~DDSD_CKSRCBLT;
1325 break;
1327 default:
1328 return DDERR_INVALIDPARAMS;
1332 if (This->aux_setcolorkey_cb) This->aux_setcolorkey_cb(This, dwFlags, pCKey);
1334 return DD_OK;
1337 HRESULT WINAPI
1338 Main_DirectDrawSurface_SetLOD(LPDIRECTDRAWSURFACE7 iface, DWORD dwMaxLOD)
1340 IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1342 TRACE("(%p)->(%08lx)\n",This,dwMaxLOD);
1343 CHECK_TEXTURE(This);
1345 This->max_lod = dwMaxLOD;
1346 return DD_OK;
1349 HRESULT WINAPI
1350 Main_DirectDrawSurface_SetOverlayPosition(LPDIRECTDRAWSURFACE7 iface,
1351 LONG X, LONG Y)
1353 return DDERR_NOTAOVERLAYSURFACE;
1356 HRESULT WINAPI
1357 Main_DirectDrawSurface_SetPalette(LPDIRECTDRAWSURFACE7 iface,
1358 LPDIRECTDRAWPALETTE pPalette)
1360 IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1361 IDirectDrawPalette *pal_to_rel = NULL;
1363 TRACE("(%p)->(%p)\n",This,pPalette);
1364 if (pPalette == ICOM_INTERFACE(This->palette, IDirectDrawPalette))
1365 return DD_OK;
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);
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;
1381 This->set_palette(This, This->palette);
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.
1386 if (pal_to_rel != NULL)
1387 IDirectDrawPalette_Release(pal_to_rel);
1389 return DD_OK;
1392 HRESULT WINAPI
1393 Main_DirectDrawSurface_SetPriority(LPDIRECTDRAWSURFACE7 iface,
1394 DWORD dwPriority)
1396 IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1398 TRACE("(%p)->(%08lx)\n",This,dwPriority);
1399 CHECK_TEXTURE(This);
1401 This->priority = dwPriority;
1402 return DD_OK;
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)
1412 PrivateData* data;
1413 IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1415 TRACE("(%p)->(%p), size=%ld\n", This, pData, cbSize);
1417 data = find_private_data(This, tag);
1418 if (data == NULL)
1420 data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data));
1421 if (data == NULL) return DDERR_OUTOFMEMORY;
1423 data->tag = *tag;
1424 data->flags = dwFlags;
1425 data->uniqueness_value = This->uniqueness_value;
1427 if (dwFlags & DDSPD_IUNKNOWNPTR)
1429 data->ptr.object = (LPUNKNOWN)pData;
1430 data->size = sizeof(LPUNKNOWN);
1431 IUnknown_AddRef(data->ptr.object);
1433 else
1435 data->ptr.data = HeapAlloc(GetProcessHeap(), 0, cbSize);
1436 if (data->ptr.data == NULL)
1438 HeapFree(GetProcessHeap(), 0, data);
1439 return DDERR_OUTOFMEMORY;
1442 data->size = cbSize;
1443 memcpy(data->ptr.data, pData, data->size);
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;
1453 return DD_OK;
1455 else
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. */
1462 FIXME("Replacing existing private data not implemented yet.\n");
1463 return E_FAIL;
1467 /* SetSurfaceDesc */
1469 HRESULT WINAPI
1470 Main_DirectDrawSurface_Unlock(LPDIRECTDRAWSURFACE7 iface, LPRECT pRect)
1472 IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1474 TRACE("(%p)->Unlock(%p)\n",This,pRect);
1476 if (!This->locked) {
1477 WARN("Surface not locked - returing DDERR_NOTLOCKED\n");
1478 return DDERR_NOTLOCKED;
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);
1486 return DD_OK;
1489 HRESULT WINAPI
1490 Main_DirectDrawSurface_UpdateOverlay(LPDIRECTDRAWSURFACE7 iface,
1491 LPRECT pSrcRect,
1492 LPDIRECTDRAWSURFACE7 pDstSurface,
1493 LPRECT pDstRect, DWORD dwFlags,
1494 LPDDOVERLAYFX pFX)
1496 return DDERR_UNSUPPORTED;
1499 /* MSDN: "not currently implemented." */
1500 HRESULT WINAPI
1501 Main_DirectDrawSurface_UpdateOverlayDisplay(LPDIRECTDRAWSURFACE7 iface,
1502 DWORD dwFlags)
1504 return DDERR_UNSUPPORTED;
1507 HRESULT WINAPI
1508 Main_DirectDrawSurface_UpdateOverlayZOrder(LPDIRECTDRAWSURFACE7 iface,
1509 DWORD dwFlags,
1510 LPDIRECTDRAWSURFACE7 pDDSRef)
1512 return DDERR_NOTAOVERLAYSURFACE;