Logo Search packages:      
Sourcecode: wine version File versions

main.c

/*          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 <assert.h>
#include <string.h>

#define COBJMACROS
#define NONAMELESSUNION
#define NONAMELESSSTRUCT

#include "winerror.h"
#include "mesa_private.h"
#include "wine/debug.h"
#include "ddraw_private.h"
#include "dsurface/main.h"
#include "ddraw/main.h"
#include "dsurface/thunks.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;

    TRACE("(%p)->(%p,%p)\n",This,context,cb);

    for (surf = This->attached; surf != NULL; surf = surf->next_attached)
    {
      /* check: != DDENUMRET_OK or == DDENUMRET_CANCEL? */
      if (cb(ICOM_INTERFACE(surf, IDirectDrawSurface7), &surf->surface_desc,
             context) == DDENUMRET_CANCEL)
          break;
    }

    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 *) &current_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 (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;

    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,%08lx)\n",This,prect,pDDSD,flags,(DWORD)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 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;

    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;
          }
      }

      /* 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. */

      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;
}

Generated by  Doxygen 1.6.0   Back to index