1517 lines
42 KiB
C
1517 lines
42 KiB
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 "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(!riid)
|
|
return DDERR_INVALIDPARAMS;
|
|
|
|
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;
|
|
}
|