|  | /*		DirectDrawSurface base implementation | 
|  | * | 
|  | * Copyright 1997-2000 Marcus Meissner | 
|  | * Copyright 1998-2000 Lionel Ulmer (most of Direct3D stuff) | 
|  | * Copyright 2000-2001 TransGaming Technologies Inc. | 
|  | * | 
|  | * This library is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU Lesser General Public | 
|  | * License as published by the Free Software Foundation; either | 
|  | * version 2.1 of the License, or (at your option) any later version. | 
|  | * | 
|  | * This library is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | * Lesser General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU Lesser General Public | 
|  | * License along with this library; if not, write to the Free Software | 
|  | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | 
|  | */ | 
|  | #include "config.h" | 
|  | #include "wine/port.h" | 
|  |  | 
|  | #include <assert.h> | 
|  | #include <string.h> | 
|  |  | 
|  | #define COBJMACROS | 
|  | #define NONAMELESSUNION | 
|  | #define NONAMELESSSTRUCT | 
|  |  | 
|  | #include "winerror.h" | 
|  | #include "wine/debug.h" | 
|  | #include "ddraw_private.h" | 
|  | #include "opengl_private.h" | 
|  |  | 
|  | WINE_DEFAULT_DEBUG_CHANNEL(ddraw); | 
|  | WINE_DECLARE_DEBUG_CHANNEL(ddraw_flip); | 
|  | WINE_DECLARE_DEBUG_CHANNEL(ddraw_fps); | 
|  |  | 
|  | /** Creation/Destruction functions */ | 
|  |  | 
|  | HRESULT | 
|  | Main_DirectDrawSurface_Construct(IDirectDrawSurfaceImpl *This, | 
|  | IDirectDrawImpl *pDD, | 
|  | const DDSURFACEDESC2 *pDDSD) | 
|  | { | 
|  | TRACE("(%p)->(%p,%p)\n", This, pDD, pDDSD); | 
|  |  | 
|  | if (pDDSD != &This->surface_desc) { | 
|  | This->surface_desc.dwSize = sizeof(This->surface_desc); | 
|  | DD_STRUCT_COPY_BYSIZE(&(This->surface_desc),pDDSD); | 
|  | } | 
|  | This->uniqueness_value = 1; /* unchecked */ | 
|  | This->ref = 1; | 
|  |  | 
|  | This->local.lpSurfMore = &This->more; | 
|  | This->local.lpGbl = &This->global; | 
|  | This->local.dwProcessId = GetCurrentProcessId(); | 
|  | This->local.dwFlags = 0; /* FIXME */ | 
|  | This->local.ddsCaps.dwCaps = This->surface_desc.ddsCaps.dwCaps; | 
|  | /* FIXME: more local stuff */ | 
|  | This->more.lpDD_lcl = &pDD->local; | 
|  | This->more.ddsCapsEx.dwCaps2 = This->surface_desc.ddsCaps.dwCaps2; | 
|  | This->more.ddsCapsEx.dwCaps3 = This->surface_desc.ddsCaps.dwCaps3; | 
|  | This->more.ddsCapsEx.dwCaps4 = This->surface_desc.ddsCaps.dwCaps4; | 
|  | /* FIXME: more more stuff */ | 
|  | This->gmore = &This->global_more; | 
|  | This->global.u3.lpDD = pDD->local.lpGbl; | 
|  | /* FIXME: more global stuff */ | 
|  |  | 
|  | This->final_release = Main_DirectDrawSurface_final_release; | 
|  | This->late_allocate = Main_DirectDrawSurface_late_allocate; | 
|  | This->attach = Main_DirectDrawSurface_attach; | 
|  | This->detach = Main_DirectDrawSurface_detach; | 
|  | This->lock_update = Main_DirectDrawSurface_lock_update; | 
|  | This->unlock_update = Main_DirectDrawSurface_unlock_update; | 
|  | This->lose_surface = Main_DirectDrawSurface_lose_surface; | 
|  | This->set_palette    = Main_DirectDrawSurface_set_palette; | 
|  | This->update_palette = Main_DirectDrawSurface_update_palette; | 
|  | This->get_display_window = Main_DirectDrawSurface_get_display_window; | 
|  | This->get_gamma_ramp = Main_DirectDrawSurface_get_gamma_ramp; | 
|  | This->set_gamma_ramp = Main_DirectDrawSurface_set_gamma_ramp; | 
|  |  | 
|  | ICOM_INIT_INTERFACE(This, IDirectDrawSurface3, | 
|  | DDRAW_IDDS3_Thunk_VTable); | 
|  | ICOM_INIT_INTERFACE(This, IDirectDrawGammaControl, | 
|  | DDRAW_IDDGC_VTable); | 
|  |  | 
|  | /* There is no generic implementation of IDDS7 or texture */ | 
|  |  | 
|  | Main_DirectDraw_AddSurface(pDD, This); | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | void Main_DirectDrawSurface_final_release(IDirectDrawSurfaceImpl* This) | 
|  | { | 
|  | Main_DirectDraw_RemoveSurface(This->ddraw_owner, This); | 
|  | } | 
|  |  | 
|  | HRESULT Main_DirectDrawSurface_late_allocate(IDirectDrawSurfaceImpl* This) | 
|  | { | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | static void Main_DirectDrawSurface_Destroy(IDirectDrawSurfaceImpl* This) | 
|  | { | 
|  | if (This->palette) { | 
|  | IDirectDrawPalette_Release(ICOM_INTERFACE(This->palette, IDirectDrawPalette)); | 
|  | This->palette = NULL; | 
|  | } | 
|  | This->final_release(This); | 
|  | if (This->private != This+1) HeapFree(GetProcessHeap(), 0, This->private); | 
|  | if (This->tex_private) HeapFree(GetProcessHeap(), 0, This->tex_private); | 
|  | HeapFree(GetProcessHeap(), 0, This); | 
|  | } | 
|  |  | 
|  | void Main_DirectDrawSurface_ForceDestroy(IDirectDrawSurfaceImpl* This) | 
|  | { | 
|  | WARN("destroying surface %p with refcnt %lu\n", This, This->ref); | 
|  | Main_DirectDrawSurface_Destroy(This); | 
|  | } | 
|  |  | 
|  | ULONG WINAPI Main_DirectDrawSurface_Release(LPDIRECTDRAWSURFACE7 iface) | 
|  | { | 
|  | IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface; | 
|  | ULONG ref = InterlockedDecrement(&This->ref); | 
|  |  | 
|  | TRACE("(%p)->(): decreasing from %ld\n", This, ref + 1); | 
|  |  | 
|  | if (ref == 0) | 
|  | { | 
|  | if (This->aux_release) | 
|  | This->aux_release(This->aux_ctx, This->aux_data); | 
|  | Main_DirectDrawSurface_Destroy(This); | 
|  |  | 
|  | TRACE("released surface %p\n", This); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | return ref; | 
|  | } | 
|  |  | 
|  | ULONG WINAPI Main_DirectDrawSurface_AddRef(LPDIRECTDRAWSURFACE7 iface) | 
|  | { | 
|  | IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface; | 
|  | ULONG ref = InterlockedIncrement(&This->ref); | 
|  |  | 
|  | TRACE("(%p)->(): increasing from %ld\n", This, ref - 1); | 
|  |  | 
|  | return ref; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDrawSurface_QueryInterface(LPDIRECTDRAWSURFACE7 iface, REFIID riid, | 
|  | LPVOID* ppObj) | 
|  | { | 
|  | IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface; | 
|  | TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppObj); | 
|  |  | 
|  | *ppObj = NULL; | 
|  |  | 
|  | if (IsEqualGUID(&IID_IUnknown, riid) | 
|  | || IsEqualGUID(&IID_IDirectDrawSurface7, riid) | 
|  | || IsEqualGUID(&IID_IDirectDrawSurface4, riid)) | 
|  | { | 
|  | InterlockedIncrement(&This->ref); | 
|  | *ppObj = ICOM_INTERFACE(This, IDirectDrawSurface7); | 
|  | return S_OK; | 
|  | } | 
|  | else if (IsEqualGUID(&IID_IDirectDrawSurface, riid) | 
|  | || IsEqualGUID(&IID_IDirectDrawSurface2, riid) | 
|  | || IsEqualGUID(&IID_IDirectDrawSurface3, riid)) | 
|  | { | 
|  | InterlockedIncrement(&This->ref); | 
|  | *ppObj = ICOM_INTERFACE(This, IDirectDrawSurface3); | 
|  | return S_OK; | 
|  | } | 
|  | else if (IsEqualGUID(&IID_IDirectDrawGammaControl, riid)) | 
|  | { | 
|  | InterlockedIncrement(&This->ref); | 
|  | *ppObj = ICOM_INTERFACE(This, IDirectDrawGammaControl); | 
|  | return S_OK; | 
|  | } | 
|  | #ifdef HAVE_OPENGL | 
|  | /* interfaces following here require OpenGL */ | 
|  | if( !opengl_initialized ) | 
|  | return E_NOINTERFACE; | 
|  |  | 
|  | if ( IsEqualGUID( &IID_D3DDEVICE_OpenGL, riid ) || | 
|  | IsEqualGUID( &IID_IDirect3DHALDevice, riid) ) | 
|  | { | 
|  | IDirect3DDeviceImpl *d3ddevimpl; | 
|  | HRESULT ret_value; | 
|  |  | 
|  | ret_value = d3ddevice_create(&d3ddevimpl, This->ddraw_owner, This, 1); | 
|  | if (FAILED(ret_value)) return ret_value; | 
|  |  | 
|  | *ppObj = ICOM_INTERFACE(d3ddevimpl, IDirect3DDevice); | 
|  | TRACE(" returning Direct3DDevice interface at %p.\n", *ppObj); | 
|  |  | 
|  | InterlockedIncrement(&This->ref); /* No idea if this is correct.. Need to check using real Windows */ | 
|  | return ret_value; | 
|  | } | 
|  | else if (IsEqualGUID( &IID_IDirect3DTexture, riid ) || | 
|  | IsEqualGUID( &IID_IDirect3DTexture2, riid )) | 
|  | { | 
|  | HRESULT ret_value = S_OK; | 
|  |  | 
|  | /* Note: this is not exactly how Windows does it... But this seems not to hurt the only | 
|  | application I know creating a texture without this flag set and it will prevent | 
|  | bugs in other parts of Wine. | 
|  | */ | 
|  | This->surface_desc.ddsCaps.dwCaps |= DDSCAPS_TEXTURE; | 
|  |  | 
|  | /* In case the texture surface was created before the D3D creation */ | 
|  | if (This->tex_private == NULL) { | 
|  | if (This->ddraw_owner->d3d_private == NULL) { | 
|  | ERR("Texture created with no D3D object yet.. Not supported !\n"); | 
|  | return E_NOINTERFACE; | 
|  | } | 
|  |  | 
|  | ret_value = This->ddraw_owner->d3d_create_texture(This->ddraw_owner, This, FALSE, This->mip_main); | 
|  | if (FAILED(ret_value)) return ret_value; | 
|  | } | 
|  | if (IsEqualGUID( &IID_IDirect3DTexture, riid )) { | 
|  | *ppObj = ICOM_INTERFACE(This, IDirect3DTexture); | 
|  | TRACE(" returning Direct3DTexture interface at %p.\n", *ppObj); | 
|  | } else { | 
|  | *ppObj = ICOM_INTERFACE(This, IDirect3DTexture2); | 
|  | TRACE(" returning Direct3DTexture2 interface at %p.\n", *ppObj); | 
|  | } | 
|  | InterlockedIncrement(&This->ref); | 
|  | return ret_value; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | return E_NOINTERFACE; | 
|  | } | 
|  |  | 
|  | /*** Callbacks */ | 
|  |  | 
|  | BOOL | 
|  | Main_DirectDrawSurface_attach(IDirectDrawSurfaceImpl *This, | 
|  | IDirectDrawSurfaceImpl *to) | 
|  | { | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | BOOL Main_DirectDrawSurface_detach(IDirectDrawSurfaceImpl *This) | 
|  | { | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | void | 
|  | Main_DirectDrawSurface_lock_update(IDirectDrawSurfaceImpl* This, LPCRECT pRect, | 
|  | DWORD dwFlags) | 
|  | { | 
|  | } | 
|  |  | 
|  | void | 
|  | Main_DirectDrawSurface_unlock_update(IDirectDrawSurfaceImpl* This, | 
|  | LPCRECT pRect) | 
|  | { | 
|  | } | 
|  |  | 
|  | void | 
|  | Main_DirectDrawSurface_lose_surface(IDirectDrawSurfaceImpl* This) | 
|  | { | 
|  | } | 
|  |  | 
|  | void | 
|  | Main_DirectDrawSurface_set_palette(IDirectDrawSurfaceImpl* This, | 
|  | IDirectDrawPaletteImpl* pal) | 
|  | { | 
|  | } | 
|  |  | 
|  | void | 
|  | Main_DirectDrawSurface_update_palette(IDirectDrawSurfaceImpl* This, | 
|  | IDirectDrawPaletteImpl* pal, | 
|  | DWORD dwStart, DWORD dwCount, | 
|  | LPPALETTEENTRY palent) | 
|  | { | 
|  | } | 
|  |  | 
|  | HWND | 
|  | Main_DirectDrawSurface_get_display_window(IDirectDrawSurfaceImpl* This) | 
|  | { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | HRESULT | 
|  | Main_DirectDrawSurface_get_gamma_ramp(IDirectDrawSurfaceImpl* This, | 
|  | DWORD dwFlags, | 
|  | LPDDGAMMARAMP lpGammaRamp) | 
|  | { | 
|  | HDC hDC; | 
|  | HRESULT hr; | 
|  | hr = This->get_dc(This, &hDC); | 
|  | if (FAILED(hr)) return hr; | 
|  | hr = GetDeviceGammaRamp(hDC, lpGammaRamp) ? DD_OK : DDERR_UNSUPPORTED; | 
|  | This->release_dc(This, hDC); | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | HRESULT | 
|  | Main_DirectDrawSurface_set_gamma_ramp(IDirectDrawSurfaceImpl* This, | 
|  | DWORD dwFlags, | 
|  | LPDDGAMMARAMP lpGammaRamp) | 
|  | { | 
|  | HDC hDC; | 
|  | HRESULT hr; | 
|  | hr = This->get_dc(This, &hDC); | 
|  | if (FAILED(hr)) return hr; | 
|  | hr = SetDeviceGammaRamp(hDC, lpGammaRamp) ? DD_OK : DDERR_UNSUPPORTED; | 
|  | This->release_dc(This, hDC); | 
|  | return hr; | 
|  | } | 
|  |  | 
|  |  | 
|  | /*** Interface functions */ | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDrawSurface_AddAttachedSurface(LPDIRECTDRAWSURFACE7 iface, | 
|  | LPDIRECTDRAWSURFACE7 pAttach) | 
|  | { | 
|  | IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface; | 
|  | IDirectDrawSurfaceImpl* surf = ICOM_OBJECT(IDirectDrawSurfaceImpl, | 
|  | IDirectDrawSurface7, pAttach); | 
|  |  | 
|  | TRACE("(%p)->(%p)\n",This,pAttach); | 
|  |  | 
|  | /* Does windows check this? */ | 
|  | if (surf == This) | 
|  | return DDERR_CANNOTATTACHSURFACE; /* unchecked */ | 
|  |  | 
|  | /* Does windows check this? */ | 
|  | if (surf->ddraw_owner != This->ddraw_owner) | 
|  | return DDERR_CANNOTATTACHSURFACE; /* unchecked */ | 
|  |  | 
|  | if (surf->surface_owner != NULL) | 
|  | return DDERR_SURFACEALREADYATTACHED; /* unchecked */ | 
|  |  | 
|  | /* TODO MSDN: "You can attach only z-buffer surfaces with this method." | 
|  | * But apparently backbuffers and mipmaps can be attached too. */ | 
|  |  | 
|  | /* Set MIPMAPSUBLEVEL if this seems to be one */ | 
|  | if (This->surface_desc.ddsCaps.dwCaps & | 
|  | surf->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP) { | 
|  | surf->surface_desc.ddsCaps.dwCaps2 |= DDSCAPS2_MIPMAPSUBLEVEL; | 
|  | /* FIXME: we should probably also add to dwMipMapCount of this | 
|  | * and all parent surfaces (update create_texture if you do) */ | 
|  | } | 
|  |  | 
|  | /* Callback to allow the surface to do something special now that it is | 
|  | * attached. (e.g. maybe the Z-buffer tells the renderer to use it.) */ | 
|  | if (!surf->attach(surf, This)) | 
|  | return DDERR_CANNOTATTACHSURFACE; | 
|  |  | 
|  | /* check: Where should it go in the chain? This puts it on the head. */ | 
|  | if (This->attached) | 
|  | This->attached->prev_attached = surf; | 
|  | surf->next_attached = This->attached; | 
|  | surf->prev_attached = NULL; | 
|  | This->attached = surf; | 
|  | surf->surface_owner = This; | 
|  |  | 
|  | IDirectDrawSurface7_AddRef(pAttach); | 
|  |  | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | /* MSDN: "not currently implemented." */ | 
|  | HRESULT WINAPI | 
|  | Main_DirectDrawSurface_AddOverlayDirtyRect(LPDIRECTDRAWSURFACE7 iface, | 
|  | LPRECT pRect) | 
|  | { | 
|  | TRACE("(%p)->(%p)\n",iface,pRect); | 
|  | return DDERR_UNSUPPORTED; /* unchecked */ | 
|  | } | 
|  |  | 
|  | /* MSDN: "not currently implemented." */ | 
|  | HRESULT WINAPI | 
|  | Main_DirectDrawSurface_BltBatch(LPDIRECTDRAWSURFACE7 iface, | 
|  | LPDDBLTBATCH pBatch, DWORD dwCount, | 
|  | DWORD dwFlags) | 
|  | { | 
|  | TRACE("(%p)->(%p,%ld,%08lx)\n",iface,pBatch,dwCount,dwFlags); | 
|  | return DDERR_UNSUPPORTED; /* unchecked */ | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDrawSurface_ChangeUniquenessValue(LPDIRECTDRAWSURFACE7 iface) | 
|  | { | 
|  | IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface; | 
|  | volatile IDirectDrawSurfaceImpl* vThis = This; | 
|  |  | 
|  | TRACE("(%p)\n",This); | 
|  | /* A uniquness value of 0 is apparently special. | 
|  | * This needs to be checked. */ | 
|  | while (1) | 
|  | { | 
|  | DWORD old_uniqueness_value = vThis->uniqueness_value; | 
|  | DWORD new_uniqueness_value = old_uniqueness_value+1; | 
|  |  | 
|  | if (old_uniqueness_value == 0) break; | 
|  | if (new_uniqueness_value == 0) new_uniqueness_value = 1; | 
|  |  | 
|  | if (InterlockedCompareExchange((LONG*)&vThis->uniqueness_value, | 
|  | old_uniqueness_value, | 
|  | new_uniqueness_value) | 
|  | == old_uniqueness_value) | 
|  | break; | 
|  | } | 
|  |  | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDrawSurface_DeleteAttachedSurface(LPDIRECTDRAWSURFACE7 iface, | 
|  | DWORD dwFlags, | 
|  | LPDIRECTDRAWSURFACE7 pAttach) | 
|  | { | 
|  | IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface; | 
|  | IDirectDrawSurfaceImpl* surf = ICOM_OBJECT(IDirectDrawSurfaceImpl, | 
|  | IDirectDrawSurface7, pAttach); | 
|  |  | 
|  | TRACE("(%p)->(%08lx,%p)\n",This,dwFlags,pAttach); | 
|  |  | 
|  | if (!surf || (surf->surface_owner != This)) | 
|  | return DDERR_SURFACENOTATTACHED; /* unchecked */ | 
|  |  | 
|  | surf->detach(surf); | 
|  |  | 
|  | /* Remove MIPMAPSUBLEVEL if this seemed to be one */ | 
|  | if (This->surface_desc.ddsCaps.dwCaps & | 
|  | surf->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP) { | 
|  | surf->surface_desc.ddsCaps.dwCaps2 &= ~DDSCAPS2_MIPMAPSUBLEVEL; | 
|  | /* FIXME: we should probably also subtract from dwMipMapCount of this | 
|  | * and all parent surfaces */ | 
|  | } | 
|  |  | 
|  | if (surf->next_attached) | 
|  | surf->next_attached->prev_attached = surf->prev_attached; | 
|  | if (surf->prev_attached) | 
|  | surf->prev_attached->next_attached = surf->next_attached; | 
|  | if (This->attached == surf) | 
|  | This->attached = surf->next_attached; | 
|  |  | 
|  | IDirectDrawSurface7_Release(pAttach); | 
|  |  | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDrawSurface_EnumAttachedSurfaces(LPDIRECTDRAWSURFACE7 iface, | 
|  | LPVOID context, | 
|  | LPDDENUMSURFACESCALLBACK7 cb) | 
|  | { | 
|  | IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface; | 
|  | IDirectDrawSurfaceImpl* surf; | 
|  | DDSURFACEDESC2 desc; | 
|  |  | 
|  | TRACE("(%p)->(%p,%p)\n",This,context,cb); | 
|  |  | 
|  | for (surf = This->attached; surf != NULL; surf = surf->next_attached) | 
|  | { | 
|  | LPDIRECTDRAWSURFACE7 isurf = ICOM_INTERFACE(surf, IDirectDrawSurface7); | 
|  |  | 
|  | if (TRACE_ON(ddraw)) { | 
|  | TRACE("  => enumerating surface %p (priv. %p) with description:\n", isurf, surf); | 
|  | DDRAW_dump_surface_desc(&surf->surface_desc); | 
|  | } | 
|  |  | 
|  | IDirectDrawSurface7_AddRef(isurf); | 
|  | desc = surf->surface_desc; | 
|  | /* check: != DDENUMRET_OK or == DDENUMRET_CANCEL? */ | 
|  | if (cb(isurf, &desc, context) == DDENUMRET_CANCEL) | 
|  | break; | 
|  | } | 
|  |  | 
|  | TRACE(" end of enumeration.\n"); | 
|  |  | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDrawSurface_EnumOverlayZOrders(LPDIRECTDRAWSURFACE7 iface, | 
|  | DWORD dwFlags, LPVOID context, | 
|  | LPDDENUMSURFACESCALLBACK7 cb) | 
|  | { | 
|  | TRACE("(%p)->(%08lx,%p,%p)\n",iface,dwFlags,context,cb); | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | BOOL Main_DirectDrawSurface_flip_data(IDirectDrawSurfaceImpl* front, | 
|  | IDirectDrawSurfaceImpl* back, | 
|  | DWORD dwFlags) | 
|  | { | 
|  | /* uniqueness_value? */ | 
|  | /* This is necessary. But is it safe? */ | 
|  | { | 
|  | HDC tmp = front->hDC; | 
|  | front->hDC = back->hDC; | 
|  | back->hDC = tmp; | 
|  | } | 
|  |  | 
|  | { | 
|  | BOOL tmp = front->dc_in_use; | 
|  | front->dc_in_use = back->dc_in_use; | 
|  | back->dc_in_use = tmp; | 
|  | } | 
|  |  | 
|  | { | 
|  | FLATPTR tmp = front->global.fpVidMem; | 
|  | front->global.fpVidMem = back->global.fpVidMem; | 
|  | back->global.fpVidMem = tmp; | 
|  | } | 
|  |  | 
|  | { | 
|  | ULONG_PTR tmp = front->global_more.hKernelSurface; | 
|  | front->global_more.hKernelSurface = back->global_more.hKernelSurface; | 
|  | back->global_more.hKernelSurface = tmp; | 
|  | } | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | /* This is unnecessarely complicated :-) */ | 
|  | #define MEASUREMENT_WINDOW 5 | 
|  | #define NUMBER_OF_WINDOWS 10 | 
|  |  | 
|  | static LONGLONG perf_freq; | 
|  | static LONGLONG perf_storage[NUMBER_OF_WINDOWS]; | 
|  | static LONGLONG prev_time = 0; | 
|  | static unsigned int current_window; | 
|  | static unsigned int measurements_in_window; | 
|  | static unsigned int valid_windows; | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDrawSurface_Flip(LPDIRECTDRAWSURFACE7 iface, | 
|  | LPDIRECTDRAWSURFACE7 override, DWORD dwFlags) | 
|  | { | 
|  | IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface; | 
|  | IDirectDrawSurfaceImpl* target; | 
|  | HRESULT hr; | 
|  |  | 
|  | TRACE("(%p)->(%p,%08lx)\n",This,override,dwFlags); | 
|  |  | 
|  | if (TRACE_ON(ddraw_fps)) { | 
|  | LONGLONG current_time; | 
|  | LONGLONG frame_duration; | 
|  | QueryPerformanceCounter((LARGE_INTEGER *) ¤t_time); | 
|  |  | 
|  | if (prev_time != 0) { | 
|  | LONGLONG total_time = 0; | 
|  | int tot_meas; | 
|  |  | 
|  | frame_duration = current_time - prev_time; | 
|  | prev_time = current_time; | 
|  |  | 
|  | perf_storage[current_window] += frame_duration; | 
|  | measurements_in_window++; | 
|  |  | 
|  | if (measurements_in_window >= MEASUREMENT_WINDOW) { | 
|  | current_window++; | 
|  | valid_windows++; | 
|  |  | 
|  | if (valid_windows < NUMBER_OF_WINDOWS) { | 
|  | unsigned int i; | 
|  | tot_meas = valid_windows * MEASUREMENT_WINDOW; | 
|  | for (i = 0; i < valid_windows; i++) { | 
|  | total_time += perf_storage[i]; | 
|  | } | 
|  | } else { | 
|  | int i; | 
|  | tot_meas = NUMBER_OF_WINDOWS * MEASUREMENT_WINDOW; | 
|  | for (i = 0; i < NUMBER_OF_WINDOWS; i++) { | 
|  | total_time += perf_storage[i]; | 
|  | } | 
|  | } | 
|  |  | 
|  | TRACE_(ddraw_fps)(" %9.5f\n", (double) (perf_freq * tot_meas) / (double) total_time); | 
|  |  | 
|  | if (current_window >= NUMBER_OF_WINDOWS) { | 
|  | current_window = 0; | 
|  | } | 
|  | perf_storage[current_window] = 0; | 
|  | measurements_in_window = 0; | 
|  | } | 
|  | } else { | 
|  | prev_time = current_time; | 
|  | memset(perf_storage, 0, sizeof(perf_storage)); | 
|  | current_window = 0; | 
|  | valid_windows = 0; | 
|  | measurements_in_window = 0; | 
|  | QueryPerformanceFrequency((LARGE_INTEGER *) &perf_freq); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* MSDN: "This method can be called only for a surface that has the | 
|  | * DDSCAPS_FLIP and DDSCAPS_FRONTBUFFER capabilities." */ | 
|  | if ((This->surface_desc.ddsCaps.dwCaps&(DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER)) | 
|  | != (DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER)) | 
|  | return DDERR_NOTFLIPPABLE; | 
|  |  | 
|  | if (This->aux_flip) | 
|  | if (This->aux_flip(This->aux_ctx, This->aux_data)) | 
|  | return DD_OK; | 
|  |  | 
|  | /* 1. find the flip target */ | 
|  | /* XXX I don't think this algorithm works for more than 1 backbuffer. */ | 
|  | if (override == NULL) | 
|  | { | 
|  | static DDSCAPS2 back_caps = { DDSCAPS_BACKBUFFER }; | 
|  | LPDIRECTDRAWSURFACE7 tgt; | 
|  |  | 
|  | hr = IDirectDrawSurface7_GetAttachedSurface(iface, &back_caps, &tgt); | 
|  | if (FAILED(hr)) return DDERR_NOTFLIPPABLE; /* unchecked */ | 
|  |  | 
|  | target = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, | 
|  | tgt); | 
|  | IDirectDrawSurface7_Release(tgt); | 
|  | } | 
|  | else | 
|  | { | 
|  | BOOL on_chain = FALSE; | 
|  | IDirectDrawSurfaceImpl* surf; | 
|  |  | 
|  | /* MSDN: "The method fails if the specified [override] surface is not | 
|  | * a member of the flipping chain." */ | 
|  |  | 
|  | /* Verify that override is on this flip chain. We assume that | 
|  | * surf is the head of the flipping chain, because it's the front | 
|  | * buffer. */ | 
|  | target = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, | 
|  | override); | 
|  |  | 
|  | /* Either target is (indirectly) attached to This or This is | 
|  | * (indirectly) attached to target. */ | 
|  | for (surf = target; surf != NULL; surf = surf->surface_owner) | 
|  | { | 
|  | if (surf == This) | 
|  | { | 
|  | on_chain = TRUE; | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (!on_chain) | 
|  | return DDERR_INVALIDPARAMS; /* unchecked */ | 
|  | } | 
|  |  | 
|  | TRACE("flip to backbuffer: %p\n",target); | 
|  | if (TRACE_ON(ddraw_flip)) { | 
|  | static unsigned int flip_count = 0; | 
|  | IDirectDrawPaletteImpl *palette; | 
|  | char buf[32]; | 
|  | FILE *f; | 
|  |  | 
|  | /* Hack for paletted games... */ | 
|  | palette = target->palette; | 
|  | target->palette = This->palette; | 
|  |  | 
|  | sprintf(buf, "flip_%08d.ppm", flip_count++); | 
|  | TRACE_(ddraw_flip)("Dumping file %s to disk.\n", buf); | 
|  | f = fopen(buf, "wb"); | 
|  | DDRAW_dump_surface_to_disk(target, f, 8); | 
|  | target->palette = palette; | 
|  | } | 
|  |  | 
|  | if (This->flip_data(This, target, dwFlags)) | 
|  | This->flip_update(This, dwFlags); | 
|  |  | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | static PrivateData* find_private_data(IDirectDrawSurfaceImpl *This, | 
|  | REFGUID tag) | 
|  | { | 
|  | PrivateData* data; | 
|  | for (data = This->private_data; data != NULL; data = data->next) | 
|  | { | 
|  | if (IsEqualGUID(&data->tag, tag)) break; | 
|  | } | 
|  |  | 
|  | return data; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDrawSurface_FreePrivateData(LPDIRECTDRAWSURFACE7 iface, REFGUID tag) | 
|  | { | 
|  | IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface; | 
|  | PrivateData *data; | 
|  |  | 
|  | data = find_private_data(This, tag); | 
|  | if (data == NULL) return DDERR_NOTFOUND; | 
|  |  | 
|  | if (data->prev) | 
|  | data->prev->next = data->next; | 
|  | if (data->next) | 
|  | data->next->prev = data->prev; | 
|  |  | 
|  | if (data->flags & DDSPD_IUNKNOWNPTR) | 
|  | { | 
|  | if (data->ptr.object != NULL) | 
|  | IUnknown_Release(data->ptr.object); | 
|  | } | 
|  | else | 
|  | HeapFree(GetProcessHeap(), 0, data->ptr.data); | 
|  |  | 
|  | HeapFree(GetProcessHeap(), 0, data); | 
|  |  | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDrawSurface_GetAttachedSurface(LPDIRECTDRAWSURFACE7 iface, | 
|  | LPDDSCAPS2 pCaps, | 
|  | LPDIRECTDRAWSURFACE7* ppSurface) | 
|  | { | 
|  | IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface; | 
|  | IDirectDrawSurfaceImpl* surf; | 
|  | IDirectDrawSurfaceImpl* found = NULL; | 
|  | DDSCAPS2 our_caps; | 
|  |  | 
|  | if (TRACE_ON(ddraw)) { | 
|  | TRACE("(%p)->Looking for caps: %lx,%lx,%lx,%lx output: %p\n",This,pCaps->dwCaps, pCaps->dwCaps2, | 
|  | pCaps->dwCaps3, pCaps->dwCaps4, ppSurface); | 
|  | TRACE("   Caps are : "); DDRAW_dump_DDSCAPS2(pCaps); TRACE("\n"); | 
|  | } | 
|  |  | 
|  | our_caps = *pCaps; | 
|  | if ((This->ddraw_owner->local.dwLocalFlags & DDRAWILCL_DIRECTDRAW7) == 0) { | 
|  | /* As this is not a DirectDraw7 application, remove the garbage that some games | 
|  | put in the new fields of the DDSCAPS2 structure. */ | 
|  | our_caps.dwCaps2 = 0; | 
|  | our_caps.dwCaps3 = 0; | 
|  | our_caps.dwCaps4 = 0; | 
|  | if (TRACE_ON(ddraw)) { | 
|  | TRACE("   Real caps are : "); DDRAW_dump_DDSCAPS2(&our_caps); TRACE("\n"); | 
|  | } | 
|  | } | 
|  |  | 
|  | for (surf = This->attached; surf != NULL; surf = surf->next_attached) | 
|  | { | 
|  | if (TRACE_ON(ddraw)) { | 
|  | TRACE("Surface: (%p) caps: %lx,%lx,%lx,%lx\n", surf, | 
|  | surf->surface_desc.ddsCaps.dwCaps, | 
|  | surf->surface_desc.ddsCaps.dwCaps2, | 
|  | surf->surface_desc.ddsCaps.dwCaps3, | 
|  | surf->surface_desc.ddsCaps.dwCaps4); | 
|  | TRACE("   Surface caps are : "); DDRAW_dump_DDSCAPS2(&(surf->surface_desc.ddsCaps)); TRACE("\n"); | 
|  | } | 
|  | if (((surf->surface_desc.ddsCaps.dwCaps & our_caps.dwCaps) == our_caps.dwCaps) && | 
|  | ((surf->surface_desc.ddsCaps.dwCaps2 & our_caps.dwCaps2) == our_caps.dwCaps2)) | 
|  | { | 
|  | /* MSDN: "This method fails if more than one surface is attached | 
|  | * that matches the capabilities requested." */ | 
|  | if (found != NULL) | 
|  | { | 
|  | FIXME("More than one attached surface matches requested caps.  What should we do here?\n"); | 
|  | /* Previous code returned 'DDERR_NOTFOUND'.  That appears not | 
|  | to be correct, given what 3DMark expects from MipMapped surfaces. | 
|  | We shall just continue instead. */ | 
|  | } | 
|  |  | 
|  | found = surf; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (found == NULL) { | 
|  | TRACE("Did not find any valid surface\n"); | 
|  | return DDERR_NOTFOUND; | 
|  | } | 
|  |  | 
|  | *ppSurface = ICOM_INTERFACE(found, IDirectDrawSurface7); | 
|  |  | 
|  | if (TRACE_ON(ddraw)) { | 
|  | TRACE("Returning surface %p with description :\n", *ppSurface); | 
|  | DDRAW_dump_surface_desc(&(found->surface_desc)); | 
|  | } | 
|  |  | 
|  | /* XXX d3dframe.cpp sometimes AddRefs things that it gets from us. */ | 
|  | IDirectDrawSurface7_AddRef(ICOM_INTERFACE(found, IDirectDrawSurface7)); | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDrawSurface_GetBltStatus(LPDIRECTDRAWSURFACE7 iface, DWORD dwFlags) | 
|  | { | 
|  | TRACE("(%p)->(%08lx)\n",iface,dwFlags); | 
|  |  | 
|  | switch (dwFlags) | 
|  | { | 
|  | case DDGBS_CANBLT: | 
|  | case DDGBS_ISBLTDONE: | 
|  | return DD_OK; | 
|  |  | 
|  | default: | 
|  | return DDERR_INVALIDPARAMS; | 
|  | } | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDrawSurface_GetCaps(LPDIRECTDRAWSURFACE7 iface, LPDDSCAPS2 pCaps) | 
|  | { | 
|  | IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface; | 
|  |  | 
|  | TRACE("(%p)->(%p)\n",This,pCaps); | 
|  | *pCaps = This->surface_desc.ddsCaps; | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDrawSurface_GetClipper(LPDIRECTDRAWSURFACE7 iface, | 
|  | LPDIRECTDRAWCLIPPER* ppClipper) | 
|  | { | 
|  | IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface; | 
|  |  | 
|  | TRACE("(%p)->(%p)\n",This,ppClipper); | 
|  | if (This->clipper == NULL) | 
|  | return DDERR_NOCLIPPERATTACHED; | 
|  |  | 
|  | *ppClipper = ICOM_INTERFACE(This->clipper, IDirectDrawClipper); | 
|  | IDirectDrawClipper_AddRef(ICOM_INTERFACE(This->clipper, | 
|  | IDirectDrawClipper)); | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDrawSurface_GetColorKey(LPDIRECTDRAWSURFACE7 iface, DWORD dwFlags, | 
|  | LPDDCOLORKEY pCKey) | 
|  | { | 
|  | /* There is a DDERR_NOCOLORKEY error, but how do we know if a color key | 
|  | * isn't there? That's like saying that an int isn't there. (Which MS | 
|  | * has done in other docs.) */ | 
|  |  | 
|  | IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface; | 
|  |  | 
|  | TRACE("(%p)->(%08lx,%p)\n",This,dwFlags,pCKey); | 
|  | if (TRACE_ON(ddraw)) { | 
|  | TRACE(" - colorkey flags : "); | 
|  | DDRAW_dump_colorkeyflag(dwFlags); | 
|  | } | 
|  |  | 
|  | switch (dwFlags) | 
|  | { | 
|  | case DDCKEY_DESTBLT: | 
|  | *pCKey = This->surface_desc.ddckCKDestBlt; | 
|  | break; | 
|  |  | 
|  | case DDCKEY_DESTOVERLAY: | 
|  | *pCKey = This->surface_desc.u3.ddckCKDestOverlay; | 
|  | break; | 
|  |  | 
|  | case DDCKEY_SRCBLT: | 
|  | *pCKey = This->surface_desc.ddckCKSrcBlt; | 
|  | break; | 
|  |  | 
|  | case DDCKEY_SRCOVERLAY: | 
|  | *pCKey = This->surface_desc.ddckCKSrcOverlay; | 
|  | break; | 
|  |  | 
|  | default: | 
|  | return DDERR_INVALIDPARAMS; | 
|  | } | 
|  |  | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | /* XXX We need to do something with the DC if the surface gets lost. */ | 
|  | HRESULT WINAPI | 
|  | Main_DirectDrawSurface_GetDC(LPDIRECTDRAWSURFACE7 iface, HDC *phDC) | 
|  | { | 
|  | DDSURFACEDESC2 ddsd; | 
|  | HRESULT hr; | 
|  | IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface; | 
|  |  | 
|  | TRACE("(%p)->(%p)\n",This,phDC); | 
|  | CHECK_LOST(This); | 
|  |  | 
|  | LOCK_OBJECT(This); | 
|  |  | 
|  | if (This->dc_in_use) | 
|  | { | 
|  | UNLOCK_OBJECT(This); | 
|  | return DDERR_DCALREADYCREATED; | 
|  | } | 
|  |  | 
|  | /* Lock as per MSDN. | 
|  | * Strange: Lock lists DDERR_SURFACEBUSY as an error, meaning that another | 
|  | * thread has it locked, but GetDC does not. */ | 
|  | ddsd.dwSize = sizeof(ddsd); | 
|  | hr = IDirectDrawSurface7_Lock(iface, NULL, &ddsd, 0, 0); | 
|  | if (FAILED(hr)) | 
|  | { | 
|  | UNLOCK_OBJECT(This); | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | hr = This->get_dc(This, &This->hDC); | 
|  |  | 
|  | if ((This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) && | 
|  | (This->palette == NULL)) { | 
|  | IDirectDrawImpl *ddraw = This->ddraw_owner; | 
|  | IDirectDrawSurfaceImpl *surf; | 
|  |  | 
|  | for (surf = ddraw->surfaces; surf != NULL; surf = surf->next_ddraw) { | 
|  | if (((surf->surface_desc.ddsCaps.dwCaps & (DDSCAPS_PRIMARYSURFACE | DDSCAPS_FRONTBUFFER)) == (DDSCAPS_PRIMARYSURFACE | DDSCAPS_FRONTBUFFER)) && | 
|  | (surf->palette != NULL)) { | 
|  | RGBQUAD col[256]; | 
|  | IDirectDrawPaletteImpl *pal = surf->palette; | 
|  | unsigned int n; | 
|  | for (n=0; n<256; n++) { | 
|  | col[n].rgbRed   = pal->palents[n].peRed; | 
|  | col[n].rgbGreen = pal->palents[n].peGreen; | 
|  | col[n].rgbBlue  = pal->palents[n].peBlue; | 
|  | col[n].rgbReserved = 0; | 
|  | } | 
|  | SetDIBColorTable(This->hDC, 0, 256, col); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | } | 
|  |  | 
|  | if (SUCCEEDED(hr)) | 
|  | { | 
|  | TRACE("returning %p\n",This->hDC); | 
|  |  | 
|  | *phDC = This->hDC; | 
|  | This->dc_in_use = TRUE; | 
|  | } | 
|  | else WARN("No DC! Prepare for trouble\n"); | 
|  |  | 
|  | UNLOCK_OBJECT(This); | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDrawSurface_GetDDInterface(LPDIRECTDRAWSURFACE7 iface, LPVOID* pDD) | 
|  | { | 
|  | IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface; | 
|  |  | 
|  | TRACE("(%p)->(%p)\n",This,pDD); | 
|  | *pDD = ICOM_INTERFACE(This->ddraw_owner, IDirectDraw7); | 
|  | IDirectDraw7_AddRef(ICOM_INTERFACE(This->ddraw_owner, IDirectDraw7)); | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDrawSurface_GetFlipStatus(LPDIRECTDRAWSURFACE7 iface, DWORD dwFlags) | 
|  | { | 
|  | /* XXX: DDERR_INVALIDSURFACETYPE */ | 
|  |  | 
|  | TRACE("(%p)->(%08lx)\n",iface,dwFlags); | 
|  | switch (dwFlags) | 
|  | { | 
|  | case DDGFS_CANFLIP: | 
|  | case DDGFS_ISFLIPDONE: | 
|  | return DD_OK; | 
|  |  | 
|  | default: | 
|  | return DDERR_INVALIDPARAMS; | 
|  | } | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDrawSurface_GetLOD(LPDIRECTDRAWSURFACE7 iface, LPDWORD pdwMaxLOD) | 
|  | { | 
|  | IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface; | 
|  |  | 
|  | TRACE("(%p)->(%p)\n",This,pdwMaxLOD); | 
|  | CHECK_TEXTURE(This); | 
|  |  | 
|  | *pdwMaxLOD = This->max_lod; | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDrawSurface_GetOverlayPosition(LPDIRECTDRAWSURFACE7 iface, | 
|  | LPLONG pX, LPLONG pY) | 
|  | { | 
|  | return DDERR_NOTAOVERLAYSURFACE; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDrawSurface_GetPalette(LPDIRECTDRAWSURFACE7 iface, | 
|  | LPDIRECTDRAWPALETTE* ppPalette) | 
|  | { | 
|  | IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface; | 
|  |  | 
|  | TRACE("(%p)->(%p)\n",This,ppPalette); | 
|  | if (This->palette == NULL) | 
|  | return DDERR_NOPALETTEATTACHED; | 
|  |  | 
|  | *ppPalette = ICOM_INTERFACE(This->palette, IDirectDrawPalette); | 
|  | IDirectDrawPalette_AddRef(ICOM_INTERFACE(This->palette, | 
|  | IDirectDrawPalette)); | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDrawSurface_GetPixelFormat(LPDIRECTDRAWSURFACE7 iface, | 
|  | LPDDPIXELFORMAT pDDPixelFormat) | 
|  | { | 
|  | /* What is DDERR_INVALIDSURFACETYPE for here? */ | 
|  | IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface; | 
|  |  | 
|  | TRACE("(%p)->(%p)\n",This,pDDPixelFormat); | 
|  | DD_STRUCT_COPY_BYSIZE(pDDPixelFormat,&This->surface_desc.u4.ddpfPixelFormat); | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDrawSurface_GetPriority(LPDIRECTDRAWSURFACE7 iface, | 
|  | LPDWORD pdwPriority) | 
|  | { | 
|  | IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface; | 
|  |  | 
|  | TRACE("(%p)->(%p)\n",This,pdwPriority); | 
|  | CHECK_TEXTURE(This); | 
|  |  | 
|  | *pdwPriority = This->priority; | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDrawSurface_GetPrivateData(LPDIRECTDRAWSURFACE7 iface, | 
|  | REFGUID tag, LPVOID pBuffer, | 
|  | LPDWORD pcbBufferSize) | 
|  | { | 
|  | IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface; | 
|  | PrivateData* data; | 
|  |  | 
|  | TRACE("(%p)->(%p), size = %ld\n", This, pBuffer, *pcbBufferSize); | 
|  |  | 
|  | data = find_private_data(This, tag); | 
|  | if (data == NULL) return DDERR_NOTFOUND; | 
|  |  | 
|  | /* This may not be right. */ | 
|  | if ((data->flags & DDSPD_VOLATILE) | 
|  | && data->uniqueness_value != This->uniqueness_value) | 
|  | return DDERR_EXPIRED; | 
|  |  | 
|  | if (*pcbBufferSize < data->size) | 
|  | { | 
|  | *pcbBufferSize = data->size; | 
|  | return DDERR_MOREDATA; | 
|  | } | 
|  |  | 
|  | if (data->flags & DDSPD_IUNKNOWNPTR) | 
|  | { | 
|  | *(LPUNKNOWN *)pBuffer = data->ptr.object; | 
|  | IUnknown_AddRef(data->ptr.object); | 
|  | } | 
|  | else | 
|  | { | 
|  | memcpy(pBuffer, data->ptr.data, data->size); | 
|  | } | 
|  |  | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDrawSurface_GetSurfaceDesc(LPDIRECTDRAWSURFACE7 iface, | 
|  | LPDDSURFACEDESC2 pDDSD) | 
|  | { | 
|  | IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface; | 
|  |  | 
|  | TRACE("(%p)->(%p)\n",This,pDDSD); | 
|  | if ((pDDSD->dwSize < sizeof(DDSURFACEDESC)) || | 
|  | (pDDSD->dwSize > sizeof(DDSURFACEDESC2))) { | 
|  | ERR("Impossible/Strange struct size %ld.\n",pDDSD->dwSize); | 
|  | return DDERR_GENERIC; | 
|  | } | 
|  |  | 
|  | DD_STRUCT_COPY_BYSIZE(pDDSD,&This->surface_desc); | 
|  | if (TRACE_ON(ddraw)) { | 
|  | DDRAW_dump_surface_desc(pDDSD); | 
|  | } | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDrawSurface_GetUniquenessValue(LPDIRECTDRAWSURFACE7 iface, | 
|  | LPDWORD pValue) | 
|  | { | 
|  | IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface; | 
|  |  | 
|  | TRACE("(%p)->(%p)\n",This,pValue); | 
|  | *pValue = This->uniqueness_value; | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDrawSurface_Initialize(LPDIRECTDRAWSURFACE7 iface, | 
|  | LPDIRECTDRAW pDD, LPDDSURFACEDESC2 pDDSD) | 
|  | { | 
|  | TRACE("(%p)->(%p,%p)\n",iface,pDD,pDDSD); | 
|  | return DDERR_ALREADYINITIALIZED; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDrawSurface_IsLost(LPDIRECTDRAWSURFACE7 iface) | 
|  | { | 
|  | IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface; | 
|  |  | 
|  | TRACE("(%p) is%s lost\n",This, (This->lost ? "" : " not")); | 
|  | return This->lost ? DDERR_SURFACELOST : DD_OK; | 
|  | } | 
|  |  | 
|  |  | 
|  | /* XXX This doesn't actually do any locking or keep track of the locked | 
|  | * rectangles. The behaviour is poorly documented. */ | 
|  | HRESULT WINAPI | 
|  | Main_DirectDrawSurface_Lock(LPDIRECTDRAWSURFACE7 iface, LPRECT prect, | 
|  | LPDDSURFACEDESC2 pDDSD, DWORD flags, HANDLE h) | 
|  | { | 
|  | IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface; | 
|  |  | 
|  | if (TRACE_ON(ddraw)) { | 
|  | TRACE("(%p)->Lock(%p,%p,%08lx,%p)\n",This,prect,pDDSD,flags,h); | 
|  | TRACE(" - locking flags : "); DDRAW_dump_lockflag(flags); | 
|  | } | 
|  | if (WARN_ON(ddraw)) { | 
|  | if (flags & ~(DDLOCK_WAIT|DDLOCK_READONLY|DDLOCK_WRITEONLY)) { | 
|  | WARN(" - unsupported locking flag : "); DDRAW_dump_lockflag(flags & ~(DDLOCK_WAIT|DDLOCK_READONLY|DDLOCK_WRITEONLY)); | 
|  | } | 
|  | } | 
|  | if (NULL != h) { | 
|  | return DDERR_INVALIDPARAMS; | 
|  | } | 
|  | if (NULL == pDDSD) { | 
|  | return DDERR_INVALIDPARAMS; | 
|  | } | 
|  |  | 
|  | /* If the surface is already locked, return busy */ | 
|  | if (This->locked) { | 
|  | WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n"); | 
|  | return DDERR_SURFACEBUSY; | 
|  | } | 
|  |  | 
|  | /* First, copy the Surface description */ | 
|  | DD_STRUCT_COPY_BYSIZE(pDDSD,&(This->surface_desc)); | 
|  |  | 
|  | /* Used to optimize the D3D Device locking */ | 
|  | This->lastlocktype = flags & (DDLOCK_READONLY|DDLOCK_WRITEONLY); | 
|  |  | 
|  | /* If asked only for a part, change the surface pointer. | 
|  | * (Not documented.) */ | 
|  | if (prect != NULL) { | 
|  | TRACE("	lprect: %ldx%ld-%ldx%ld\n", | 
|  | prect->left,prect->top,prect->right,prect->bottom); | 
|  | /* First do some sanity checkings on the rectangle we receive. | 
|  | DungeonSiege seems to gives us once a very bad rectangle for example */ | 
|  | if ((prect->top < 0) || | 
|  | (prect->left < 0) || | 
|  | (prect->bottom < 0) || | 
|  | (prect->right < 0) || | 
|  | (prect->left >= prect->right) || | 
|  | (prect->top >= prect->bottom) || | 
|  | (prect->left >= This->surface_desc.dwWidth) || | 
|  | (prect->right > This->surface_desc.dwWidth) || | 
|  | (prect->top >= This->surface_desc.dwHeight) || | 
|  | (prect->bottom > This->surface_desc.dwHeight)) { | 
|  | ERR(" Invalid values in LPRECT !!!\n"); | 
|  | return DDERR_INVALIDPARAMS; | 
|  | } | 
|  |  | 
|  | This->lock_update(This, prect, flags); | 
|  |  | 
|  | if (pDDSD->u4.ddpfPixelFormat.dwFlags & DDPF_FOURCC) { | 
|  | int blksize; | 
|  | switch(pDDSD->u4.ddpfPixelFormat.dwFourCC) { | 
|  | case MAKE_FOURCC('D','X','T','1') : blksize = 8; break; | 
|  | case MAKE_FOURCC('D','X','T','3') : blksize = 16; break; | 
|  | case MAKE_FOURCC('D','X','T','5') : blksize = 16; break; | 
|  | default: return DDERR_INVALIDPIXELFORMAT; | 
|  | } | 
|  | pDDSD->lpSurface = (char *)This->surface_desc.lpSurface | 
|  | + prect->top/4 * (pDDSD->dwWidth+3)/4 * blksize | 
|  | + prect->left/4 * blksize; | 
|  | } else | 
|  | pDDSD->lpSurface = (char *)This->surface_desc.lpSurface | 
|  | + prect->top * This->surface_desc.u1.lPitch | 
|  | + prect->left * GET_BPP(This->surface_desc); | 
|  | } else { | 
|  | This->lock_update(This, NULL, flags); | 
|  | } | 
|  |  | 
|  | This->locked = TRUE; | 
|  |  | 
|  | TRACE("locked surface returning description :\n"); | 
|  | if (TRACE_ON(ddraw)) DDRAW_dump_surface_desc(pDDSD); | 
|  |  | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDrawSurface_PageLock(LPDIRECTDRAWSURFACE7 iface, DWORD dwFlags) | 
|  | { | 
|  | /* Some surface types should return DDERR_CANTPAGELOCK. */ | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDrawSurface_PageUnlock(LPDIRECTDRAWSURFACE7 iface, DWORD dwFlags) | 
|  | { | 
|  | /* Some surface types should return DDERR_CANTPAGEUNLOCK, and we should | 
|  | * keep track so we can return DDERR_NOTPAGELOCKED as appropriate. */ | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDrawSurface_ReleaseDC(LPDIRECTDRAWSURFACE7 iface, HDC hDC) | 
|  | { | 
|  | HRESULT hr; | 
|  | IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface; | 
|  |  | 
|  | TRACE("(%p)->(%p)\n",This,hDC); | 
|  |  | 
|  | if (!This->dc_in_use || This->hDC != hDC) | 
|  | return DDERR_INVALIDPARAMS; | 
|  |  | 
|  | This->release_dc(This, hDC); | 
|  |  | 
|  | hr = IDirectDrawSurface7_Unlock(iface, NULL); | 
|  | if (FAILED(hr)) return hr; | 
|  |  | 
|  | This->dc_in_use = FALSE; | 
|  | This->hDC = 0; | 
|  |  | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | /* Restore */ | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDrawSurface_SetClipper(LPDIRECTDRAWSURFACE7 iface, | 
|  | LPDIRECTDRAWCLIPPER pDDClipper) | 
|  | { | 
|  | IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface; | 
|  |  | 
|  | TRACE("(%p)->(%p)\n",This,pDDClipper); | 
|  | if (pDDClipper == ICOM_INTERFACE(This->clipper, IDirectDrawClipper)) | 
|  | return DD_OK; | 
|  |  | 
|  | if (This->clipper != NULL) | 
|  | IDirectDrawClipper_Release(ICOM_INTERFACE(This->clipper, | 
|  | IDirectDrawClipper)); | 
|  |  | 
|  | This->clipper = ICOM_OBJECT(IDirectDrawClipperImpl, IDirectDrawClipper, | 
|  | pDDClipper); | 
|  | if (pDDClipper != NULL) | 
|  | IDirectDrawClipper_AddRef(pDDClipper); | 
|  |  | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDrawSurface_SetColorKey(LPDIRECTDRAWSURFACE7 iface, | 
|  | DWORD dwFlags, LPDDCOLORKEY pCKey) | 
|  | { | 
|  | IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface; | 
|  |  | 
|  | TRACE("(%p)->(%08lx,%p)\n",This,dwFlags,pCKey); | 
|  |  | 
|  | if (TRACE_ON(ddraw)) { | 
|  | TRACE(" - colorkey flags : "); | 
|  | DDRAW_dump_colorkeyflag(dwFlags); | 
|  | } | 
|  |  | 
|  | if ((dwFlags & DDCKEY_COLORSPACE) != 0) { | 
|  | FIXME(" colorkey value not supported (%08lx) !\n", dwFlags); | 
|  | return DDERR_INVALIDPARAMS; | 
|  | } | 
|  |  | 
|  | /* TODO: investigate if this function can take multiple bits set at the same | 
|  | time (ie setting multiple colorkey values at the same time with only | 
|  | one API call). | 
|  | */ | 
|  | if (pCKey) { | 
|  | switch (dwFlags & ~DDCKEY_COLORSPACE) { | 
|  | case DDCKEY_DESTBLT: | 
|  | This->surface_desc.ddckCKDestBlt = *pCKey; | 
|  | This->surface_desc.dwFlags |= DDSD_CKDESTBLT; | 
|  | break; | 
|  |  | 
|  | case DDCKEY_DESTOVERLAY: | 
|  | This->surface_desc.u3.ddckCKDestOverlay = *pCKey; | 
|  | This->surface_desc.dwFlags |= DDSD_CKDESTOVERLAY; | 
|  | break; | 
|  |  | 
|  | case DDCKEY_SRCOVERLAY: | 
|  | This->surface_desc.ddckCKSrcOverlay = *pCKey; | 
|  | This->surface_desc.dwFlags |= DDSD_CKSRCOVERLAY; | 
|  | break; | 
|  |  | 
|  | case DDCKEY_SRCBLT: | 
|  | This->surface_desc.ddckCKSrcBlt = *pCKey; | 
|  | This->surface_desc.dwFlags |= DDSD_CKSRCBLT; | 
|  | break; | 
|  |  | 
|  | default: | 
|  | return DDERR_INVALIDPARAMS; | 
|  | } | 
|  | } else { | 
|  | switch (dwFlags & ~DDCKEY_COLORSPACE) { | 
|  | case DDCKEY_DESTBLT: | 
|  | This->surface_desc.dwFlags &= ~DDSD_CKDESTBLT; | 
|  | break; | 
|  |  | 
|  | case DDCKEY_DESTOVERLAY: | 
|  | This->surface_desc.dwFlags &= ~DDSD_CKDESTOVERLAY; | 
|  | break; | 
|  |  | 
|  | case DDCKEY_SRCOVERLAY: | 
|  | This->surface_desc.dwFlags &= ~DDSD_CKSRCOVERLAY; | 
|  | break; | 
|  |  | 
|  | case DDCKEY_SRCBLT: | 
|  | This->surface_desc.dwFlags &= ~DDSD_CKSRCBLT; | 
|  | break; | 
|  |  | 
|  | default: | 
|  | return DDERR_INVALIDPARAMS; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (This->aux_setcolorkey_cb) This->aux_setcolorkey_cb(This, dwFlags, pCKey); | 
|  |  | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDrawSurface_SetLOD(LPDIRECTDRAWSURFACE7 iface, DWORD dwMaxLOD) | 
|  | { | 
|  | IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface; | 
|  |  | 
|  | TRACE("(%p)->(%08lx)\n",This,dwMaxLOD); | 
|  | CHECK_TEXTURE(This); | 
|  |  | 
|  | This->max_lod = dwMaxLOD; | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDrawSurface_SetOverlayPosition(LPDIRECTDRAWSURFACE7 iface, | 
|  | LONG X, LONG Y) | 
|  | { | 
|  | return DDERR_NOTAOVERLAYSURFACE; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDrawSurface_SetPalette(LPDIRECTDRAWSURFACE7 iface, | 
|  | LPDIRECTDRAWPALETTE pPalette) | 
|  | { | 
|  | IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface; | 
|  | IDirectDrawPalette *pal_to_rel = NULL; | 
|  |  | 
|  | TRACE("(%p)->(%p)\n",This,pPalette); | 
|  | if (pPalette == ICOM_INTERFACE(This->palette, IDirectDrawPalette)) | 
|  | return DD_OK; | 
|  |  | 
|  | if (This->palette != NULL) { | 
|  | if (This->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) | 
|  | This->palette->global.dwFlags &= ~DDPCAPS_PRIMARYSURFACE; | 
|  | pal_to_rel = ICOM_INTERFACE(This->palette, IDirectDrawPalette); | 
|  | } | 
|  |  | 
|  | This->palette = ICOM_OBJECT(IDirectDrawPaletteImpl, IDirectDrawPalette, | 
|  | pPalette); | 
|  | if (pPalette != NULL) { | 
|  | IDirectDrawPalette_AddRef(pPalette); | 
|  | if (This->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) | 
|  | This->palette->global.dwFlags |= DDPCAPS_PRIMARYSURFACE; | 
|  | } | 
|  |  | 
|  | This->set_palette(This, This->palette); | 
|  |  | 
|  | /* Do the palette release at the end to prevent doing some 'loop' when removing | 
|  | * the surface maintaining the last reference on a palette. | 
|  | */ | 
|  | if (pal_to_rel != NULL) | 
|  | IDirectDrawPalette_Release(pal_to_rel); | 
|  |  | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDrawSurface_SetPriority(LPDIRECTDRAWSURFACE7 iface, | 
|  | DWORD dwPriority) | 
|  | { | 
|  | IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface; | 
|  |  | 
|  | TRACE("(%p)->(%08lx)\n",This,dwPriority); | 
|  | CHECK_TEXTURE(This); | 
|  |  | 
|  | This->priority = dwPriority; | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | /* Be careful when locking this: it is risky to call the object's AddRef | 
|  | * or Release holding a lock. */ | 
|  | HRESULT WINAPI | 
|  | Main_DirectDrawSurface_SetPrivateData(LPDIRECTDRAWSURFACE7 iface, | 
|  | REFGUID tag, LPVOID pData, | 
|  | DWORD cbSize, DWORD dwFlags) | 
|  | { | 
|  | PrivateData* data; | 
|  | IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface; | 
|  |  | 
|  | TRACE("(%p)->(%p), size=%ld\n", This, pData, cbSize); | 
|  |  | 
|  | data = find_private_data(This, tag); | 
|  | if (data == NULL) | 
|  | { | 
|  | data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data)); | 
|  | if (data == NULL) return DDERR_OUTOFMEMORY; | 
|  |  | 
|  | data->tag = *tag; | 
|  | data->flags = dwFlags; | 
|  | data->uniqueness_value = This->uniqueness_value; | 
|  |  | 
|  | if (dwFlags & DDSPD_IUNKNOWNPTR) | 
|  | { | 
|  | data->ptr.object = (LPUNKNOWN)pData; | 
|  | data->size = sizeof(LPUNKNOWN); | 
|  | IUnknown_AddRef(data->ptr.object); | 
|  | } | 
|  | else | 
|  | { | 
|  | data->ptr.data = HeapAlloc(GetProcessHeap(), 0, cbSize); | 
|  | if (data->ptr.data == NULL) | 
|  | { | 
|  | HeapFree(GetProcessHeap(), 0, data); | 
|  | return DDERR_OUTOFMEMORY; | 
|  | } | 
|  |  | 
|  | data->size = cbSize; | 
|  | memcpy(data->ptr.data, pData, data->size); | 
|  | } | 
|  |  | 
|  | /* link it in */ | 
|  | data->next = This->private_data; | 
|  | data->prev = NULL; | 
|  | if (This->private_data) | 
|  | This->private_data->prev = data; | 
|  | This->private_data = data; | 
|  |  | 
|  | return DD_OK; | 
|  | } | 
|  | else | 
|  | { | 
|  | /* I don't actually know how windows handles this case. The only | 
|  | * reason I don't just call FreePrivateData is because I want to | 
|  | * guarantee SetPrivateData working when using LPUNKNOWN or data | 
|  | * that is no larger than the old data. */ | 
|  |  | 
|  | FIXME("Replacing existing private data not implemented yet.\n"); | 
|  | return E_FAIL; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* SetSurfaceDesc */ | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDrawSurface_Unlock(LPDIRECTDRAWSURFACE7 iface, LPRECT pRect) | 
|  | { | 
|  | IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface; | 
|  |  | 
|  | TRACE("(%p)->Unlock(%p)\n",This,pRect); | 
|  |  | 
|  | if (!This->locked) { | 
|  | WARN("Surface not locked - returing DDERR_NOTLOCKED\n"); | 
|  | return DDERR_NOTLOCKED; | 
|  | } | 
|  |  | 
|  | This->locked = FALSE; | 
|  | This->unlock_update(This, pRect); | 
|  | if (This->aux_unlock) | 
|  | This->aux_unlock(This->aux_ctx, This->aux_data, pRect); | 
|  |  | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDrawSurface_UpdateOverlay(LPDIRECTDRAWSURFACE7 iface, | 
|  | LPRECT pSrcRect, | 
|  | LPDIRECTDRAWSURFACE7 pDstSurface, | 
|  | LPRECT pDstRect, DWORD dwFlags, | 
|  | LPDDOVERLAYFX pFX) | 
|  | { | 
|  | return DDERR_UNSUPPORTED; | 
|  | } | 
|  |  | 
|  | /* MSDN: "not currently implemented." */ | 
|  | HRESULT WINAPI | 
|  | Main_DirectDrawSurface_UpdateOverlayDisplay(LPDIRECTDRAWSURFACE7 iface, | 
|  | DWORD dwFlags) | 
|  | { | 
|  | return DDERR_UNSUPPORTED; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDrawSurface_UpdateOverlayZOrder(LPDIRECTDRAWSURFACE7 iface, | 
|  | DWORD dwFlags, | 
|  | LPDIRECTDRAWSURFACE7 pDDSRef) | 
|  | { | 
|  | return DDERR_NOTAOVERLAYSURFACE; | 
|  | } |