reactos/dll/directx/wine/d3d8/device.c
Joachim Henze 81cffd7658 [D3D8][D3D9][DDRAW][D3DCOMPILER_43][WINED3D] Revert to Wine Staging 3.3
Avoid regressions CORE-14955 "Ddraw fullscreen crashes" and CORE-15652

This brings us back to before guilty commit 0.4.10-dev-55-g
7af3969e9f

and therefore downgrades
dll/directx/wine/
D3D8,D3D9,DDRAW,D3DCOMPILER_43,WINED3D
to WineStaging 3.3.
Also downgrades related header sdk/include/reactos/wine/wined3d.h
and for the first time also media/doc/README.WINE

Same versions of these dlls we had in every ros rls since 0.4.10rls.
Amine Khaldi agreed to perform this revert also for master now.

Purpose of this revert is to fix crashes when Ddraw apps switch
into fullscreen with VBEMP and inbuilt Mesa.
I tested, before:
 DxDiag crashed when switching to fullscreen (CORE-14955),
 Diablo II crashed immediately (CORE-15652),
 Monster-Truck-Madness 2 demo crashed after main menu

Afterwards all of these apps do run.
DXTN does still work after that, even with VBEMP and inbuilt Mesa.

squashed commit of 0.4.13-RC-2-g
67dd70e5ef
and 0.4.13-RC-3-g
9f1e2cd172
2019-10-03 18:38:29 +02:00

3386 lines
116 KiB
C

/*
* IDirect3DDevice8 implementation
*
* Copyright 2002-2004 Jason Edmeades
* Copyright 2004 Christian Costa
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#include <math.h>
#include <stdarg.h>
#include "windef.h"
#include "winbase.h"
#include "winuser.h"
#include "wingdi.h"
#include "wine/debug.h"
#include "d3d8_private.h"
WINE_DEFAULT_DEBUG_CHANNEL(d3d8);
static void STDMETHODCALLTYPE d3d8_null_wined3d_object_destroyed(void *parent) {}
static const struct wined3d_parent_ops d3d8_null_wined3d_parent_ops =
{
d3d8_null_wined3d_object_destroyed,
};
D3DFORMAT d3dformat_from_wined3dformat(enum wined3d_format_id format)
{
BYTE *c = (BYTE *)&format;
/* Don't translate FOURCC formats */
if (isprint(c[0]) && isprint(c[1]) && isprint(c[2]) && isprint(c[3])) return format;
switch(format)
{
case WINED3DFMT_UNKNOWN: return D3DFMT_UNKNOWN;
case WINED3DFMT_B8G8R8_UNORM: return D3DFMT_R8G8B8;
case WINED3DFMT_B8G8R8A8_UNORM: return D3DFMT_A8R8G8B8;
case WINED3DFMT_B8G8R8X8_UNORM: return D3DFMT_X8R8G8B8;
case WINED3DFMT_B5G6R5_UNORM: return D3DFMT_R5G6B5;
case WINED3DFMT_B5G5R5X1_UNORM: return D3DFMT_X1R5G5B5;
case WINED3DFMT_B5G5R5A1_UNORM: return D3DFMT_A1R5G5B5;
case WINED3DFMT_B4G4R4A4_UNORM: return D3DFMT_A4R4G4B4;
case WINED3DFMT_B2G3R3_UNORM: return D3DFMT_R3G3B2;
case WINED3DFMT_A8_UNORM: return D3DFMT_A8;
case WINED3DFMT_B2G3R3A8_UNORM: return D3DFMT_A8R3G3B2;
case WINED3DFMT_B4G4R4X4_UNORM: return D3DFMT_X4R4G4B4;
case WINED3DFMT_R10G10B10A2_UNORM: return D3DFMT_A2B10G10R10;
case WINED3DFMT_R16G16_UNORM: return D3DFMT_G16R16;
case WINED3DFMT_P8_UINT_A8_UNORM: return D3DFMT_A8P8;
case WINED3DFMT_P8_UINT: return D3DFMT_P8;
case WINED3DFMT_L8_UNORM: return D3DFMT_L8;
case WINED3DFMT_L8A8_UNORM: return D3DFMT_A8L8;
case WINED3DFMT_L4A4_UNORM: return D3DFMT_A4L4;
case WINED3DFMT_R8G8_SNORM: return D3DFMT_V8U8;
case WINED3DFMT_R5G5_SNORM_L6_UNORM: return D3DFMT_L6V5U5;
case WINED3DFMT_R8G8_SNORM_L8X8_UNORM: return D3DFMT_X8L8V8U8;
case WINED3DFMT_R8G8B8A8_SNORM: return D3DFMT_Q8W8V8U8;
case WINED3DFMT_R16G16_SNORM: return D3DFMT_V16U16;
case WINED3DFMT_R10G11B11_SNORM: return D3DFMT_W11V11U10;
case WINED3DFMT_R10G10B10_SNORM_A2_UNORM: return D3DFMT_A2W10V10U10;
case WINED3DFMT_D16_LOCKABLE: return D3DFMT_D16_LOCKABLE;
case WINED3DFMT_D32_UNORM: return D3DFMT_D32;
case WINED3DFMT_S1_UINT_D15_UNORM: return D3DFMT_D15S1;
case WINED3DFMT_D24_UNORM_S8_UINT: return D3DFMT_D24S8;
case WINED3DFMT_X8D24_UNORM: return D3DFMT_D24X8;
case WINED3DFMT_S4X4_UINT_D24_UNORM: return D3DFMT_D24X4S4;
case WINED3DFMT_D16_UNORM: return D3DFMT_D16;
case WINED3DFMT_R16_UINT: return D3DFMT_INDEX16;
case WINED3DFMT_R32_UINT: return D3DFMT_INDEX32;
default:
FIXME("Unhandled wined3d format %#x.\n", format);
return D3DFMT_UNKNOWN;
}
}
enum wined3d_format_id wined3dformat_from_d3dformat(D3DFORMAT format)
{
BYTE *c = (BYTE *)&format;
/* Don't translate FOURCC formats */
if (isprint(c[0]) && isprint(c[1]) && isprint(c[2]) && isprint(c[3])) return format;
switch(format)
{
case D3DFMT_UNKNOWN: return WINED3DFMT_UNKNOWN;
case D3DFMT_R8G8B8: return WINED3DFMT_B8G8R8_UNORM;
case D3DFMT_A8R8G8B8: return WINED3DFMT_B8G8R8A8_UNORM;
case D3DFMT_X8R8G8B8: return WINED3DFMT_B8G8R8X8_UNORM;
case D3DFMT_R5G6B5: return WINED3DFMT_B5G6R5_UNORM;
case D3DFMT_X1R5G5B5: return WINED3DFMT_B5G5R5X1_UNORM;
case D3DFMT_A1R5G5B5: return WINED3DFMT_B5G5R5A1_UNORM;
case D3DFMT_A4R4G4B4: return WINED3DFMT_B4G4R4A4_UNORM;
case D3DFMT_R3G3B2: return WINED3DFMT_B2G3R3_UNORM;
case D3DFMT_A8: return WINED3DFMT_A8_UNORM;
case D3DFMT_A8R3G3B2: return WINED3DFMT_B2G3R3A8_UNORM;
case D3DFMT_X4R4G4B4: return WINED3DFMT_B4G4R4X4_UNORM;
case D3DFMT_A2B10G10R10: return WINED3DFMT_R10G10B10A2_UNORM;
case D3DFMT_G16R16: return WINED3DFMT_R16G16_UNORM;
case D3DFMT_A8P8: return WINED3DFMT_P8_UINT_A8_UNORM;
case D3DFMT_P8: return WINED3DFMT_P8_UINT;
case D3DFMT_L8: return WINED3DFMT_L8_UNORM;
case D3DFMT_A8L8: return WINED3DFMT_L8A8_UNORM;
case D3DFMT_A4L4: return WINED3DFMT_L4A4_UNORM;
case D3DFMT_V8U8: return WINED3DFMT_R8G8_SNORM;
case D3DFMT_L6V5U5: return WINED3DFMT_R5G5_SNORM_L6_UNORM;
case D3DFMT_X8L8V8U8: return WINED3DFMT_R8G8_SNORM_L8X8_UNORM;
case D3DFMT_Q8W8V8U8: return WINED3DFMT_R8G8B8A8_SNORM;
case D3DFMT_V16U16: return WINED3DFMT_R16G16_SNORM;
case D3DFMT_W11V11U10: return WINED3DFMT_R10G11B11_SNORM;
case D3DFMT_A2W10V10U10: return WINED3DFMT_R10G10B10_SNORM_A2_UNORM;
case D3DFMT_D16_LOCKABLE: return WINED3DFMT_D16_LOCKABLE;
case D3DFMT_D32: return WINED3DFMT_D32_UNORM;
case D3DFMT_D15S1: return WINED3DFMT_S1_UINT_D15_UNORM;
case D3DFMT_D24S8: return WINED3DFMT_D24_UNORM_S8_UINT;
case D3DFMT_D24X8: return WINED3DFMT_X8D24_UNORM;
case D3DFMT_D24X4S4: return WINED3DFMT_S4X4_UINT_D24_UNORM;
case D3DFMT_D16: return WINED3DFMT_D16_UNORM;
case D3DFMT_INDEX16: return WINED3DFMT_R16_UINT;
case D3DFMT_INDEX32: return WINED3DFMT_R32_UINT;
default:
FIXME("Unhandled D3DFORMAT %#x.\n", format);
return WINED3DFMT_UNKNOWN;
}
}
unsigned int wined3dmapflags_from_d3dmapflags(unsigned int flags)
{
static const unsigned int handled = D3DLOCK_NOSYSLOCK
| D3DLOCK_NOOVERWRITE
| D3DLOCK_DISCARD
| D3DLOCK_NO_DIRTY_UPDATE;
unsigned int wined3d_flags;
wined3d_flags = flags & handled;
if (!(flags & (D3DLOCK_NOOVERWRITE | D3DLOCK_DISCARD)))
wined3d_flags |= WINED3D_MAP_READ;
if (!(flags & D3DLOCK_READONLY))
wined3d_flags |= WINED3D_MAP_WRITE;
if (!(wined3d_flags & (WINED3D_MAP_READ | WINED3D_MAP_WRITE)))
wined3d_flags |= WINED3D_MAP_READ | WINED3D_MAP_WRITE;
flags &= ~(handled | D3DLOCK_READONLY);
if (flags)
FIXME("Unhandled flags %#x.\n", flags);
return wined3d_flags;
}
static UINT vertex_count_from_primitive_count(D3DPRIMITIVETYPE primitive_type, UINT primitive_count)
{
switch (primitive_type)
{
case D3DPT_POINTLIST:
return primitive_count;
case D3DPT_LINELIST:
return primitive_count * 2;
case D3DPT_LINESTRIP:
return primitive_count + 1;
case D3DPT_TRIANGLELIST:
return primitive_count * 3;
case D3DPT_TRIANGLESTRIP:
case D3DPT_TRIANGLEFAN:
return primitive_count + 2;
default:
FIXME("Unhandled primitive type %#x.\n", primitive_type);
return 0;
}
}
static D3DSWAPEFFECT d3dswapeffect_from_wined3dswapeffect(enum wined3d_swap_effect effect)
{
switch (effect)
{
case WINED3D_SWAP_EFFECT_DISCARD:
return D3DSWAPEFFECT_DISCARD;
case WINED3D_SWAP_EFFECT_SEQUENTIAL:
return D3DSWAPEFFECT_FLIP;
case WINED3D_SWAP_EFFECT_COPY:
return D3DSWAPEFFECT_COPY;
case WINED3D_SWAP_EFFECT_COPY_VSYNC:
return D3DSWAPEFFECT_COPY_VSYNC;
default:
FIXME("Unhandled swap effect %#x.\n", effect);
return D3DSWAPEFFECT_FLIP;
}
}
static void present_parameters_from_wined3d_swapchain_desc(D3DPRESENT_PARAMETERS *present_parameters,
const struct wined3d_swapchain_desc *swapchain_desc)
{
present_parameters->BackBufferWidth = swapchain_desc->backbuffer_width;
present_parameters->BackBufferHeight = swapchain_desc->backbuffer_height;
present_parameters->BackBufferFormat = d3dformat_from_wined3dformat(swapchain_desc->backbuffer_format);
present_parameters->BackBufferCount = swapchain_desc->backbuffer_count;
present_parameters->MultiSampleType = swapchain_desc->multisample_type;
present_parameters->SwapEffect = d3dswapeffect_from_wined3dswapeffect(swapchain_desc->swap_effect);
present_parameters->hDeviceWindow = swapchain_desc->device_window;
present_parameters->Windowed = swapchain_desc->windowed;
present_parameters->EnableAutoDepthStencil = swapchain_desc->enable_auto_depth_stencil;
present_parameters->AutoDepthStencilFormat
= d3dformat_from_wined3dformat(swapchain_desc->auto_depth_stencil_format);
present_parameters->Flags = swapchain_desc->flags & D3DPRESENTFLAGS_MASK;
present_parameters->FullScreen_RefreshRateInHz = swapchain_desc->refresh_rate;
present_parameters->FullScreen_PresentationInterval = swapchain_desc->swap_interval;
}
static enum wined3d_swap_effect wined3dswapeffect_from_d3dswapeffect(D3DSWAPEFFECT effect)
{
switch (effect)
{
case D3DSWAPEFFECT_DISCARD:
return WINED3D_SWAP_EFFECT_DISCARD;
case D3DSWAPEFFECT_FLIP:
return WINED3D_SWAP_EFFECT_SEQUENTIAL;
case D3DSWAPEFFECT_COPY:
return WINED3D_SWAP_EFFECT_COPY;
case D3DSWAPEFFECT_COPY_VSYNC:
return WINED3D_SWAP_EFFECT_COPY_VSYNC;
default:
FIXME("Unhandled swap effect %#x.\n", effect);
return WINED3D_SWAP_EFFECT_SEQUENTIAL;
}
}
static BOOL wined3d_swapchain_desc_from_present_parameters(struct wined3d_swapchain_desc *swapchain_desc,
const D3DPRESENT_PARAMETERS *present_parameters)
{
if (!present_parameters->SwapEffect || present_parameters->SwapEffect > D3DSWAPEFFECT_COPY_VSYNC)
{
WARN("Invalid swap effect %u passed.\n", present_parameters->SwapEffect);
return FALSE;
}
if (present_parameters->BackBufferCount > 3
|| ((present_parameters->SwapEffect == D3DSWAPEFFECT_COPY
|| present_parameters->SwapEffect == D3DSWAPEFFECT_COPY_VSYNC)
&& present_parameters->BackBufferCount > 1))
{
WARN("Invalid backbuffer count %u.\n", present_parameters->BackBufferCount);
return FALSE;
}
swapchain_desc->backbuffer_width = present_parameters->BackBufferWidth;
swapchain_desc->backbuffer_height = present_parameters->BackBufferHeight;
swapchain_desc->backbuffer_format = wined3dformat_from_d3dformat(present_parameters->BackBufferFormat);
swapchain_desc->backbuffer_count = max(1, present_parameters->BackBufferCount);
swapchain_desc->backbuffer_usage = WINED3DUSAGE_RENDERTARGET;
swapchain_desc->multisample_type = present_parameters->MultiSampleType;
swapchain_desc->multisample_quality = 0; /* d3d9 only */
swapchain_desc->swap_effect = wined3dswapeffect_from_d3dswapeffect(present_parameters->SwapEffect);
swapchain_desc->device_window = present_parameters->hDeviceWindow;
swapchain_desc->windowed = present_parameters->Windowed;
swapchain_desc->enable_auto_depth_stencil = present_parameters->EnableAutoDepthStencil;
swapchain_desc->auto_depth_stencil_format
= wined3dformat_from_d3dformat(present_parameters->AutoDepthStencilFormat);
swapchain_desc->flags
= (present_parameters->Flags & D3DPRESENTFLAGS_MASK) | WINED3D_SWAPCHAIN_ALLOW_MODE_SWITCH;
swapchain_desc->refresh_rate = present_parameters->FullScreen_RefreshRateInHz;
swapchain_desc->swap_interval = present_parameters->FullScreen_PresentationInterval;
swapchain_desc->auto_restore_display_mode = TRUE;
if (present_parameters->Flags & ~D3DPRESENTFLAGS_MASK)
FIXME("Unhandled flags %#x.\n", present_parameters->Flags & ~D3DPRESENTFLAGS_MASK);
return TRUE;
}
void d3dcaps_from_wined3dcaps(D3DCAPS8 *caps, const WINED3DCAPS *wined3d_caps)
{
caps->DeviceType = (D3DDEVTYPE)wined3d_caps->DeviceType;
caps->AdapterOrdinal = wined3d_caps->AdapterOrdinal;
caps->Caps = wined3d_caps->Caps;
caps->Caps2 = wined3d_caps->Caps2;
caps->Caps3 = wined3d_caps->Caps3;
caps->PresentationIntervals = wined3d_caps->PresentationIntervals;
caps->CursorCaps = wined3d_caps->CursorCaps;
caps->DevCaps = wined3d_caps->DevCaps;
caps->PrimitiveMiscCaps = wined3d_caps->PrimitiveMiscCaps;
caps->RasterCaps = wined3d_caps->RasterCaps;
caps->ZCmpCaps = wined3d_caps->ZCmpCaps;
caps->SrcBlendCaps = wined3d_caps->SrcBlendCaps;
caps->DestBlendCaps = wined3d_caps->DestBlendCaps;
caps->AlphaCmpCaps = wined3d_caps->AlphaCmpCaps;
caps->ShadeCaps = wined3d_caps->ShadeCaps;
caps->TextureCaps = wined3d_caps->TextureCaps;
caps->TextureFilterCaps = wined3d_caps->TextureFilterCaps;
caps->CubeTextureFilterCaps = wined3d_caps->CubeTextureFilterCaps;
caps->VolumeTextureFilterCaps = wined3d_caps->VolumeTextureFilterCaps;
caps->TextureAddressCaps = wined3d_caps->TextureAddressCaps;
caps->VolumeTextureAddressCaps = wined3d_caps->VolumeTextureAddressCaps;
caps->LineCaps = wined3d_caps->LineCaps;
caps->MaxTextureWidth = wined3d_caps->MaxTextureWidth;
caps->MaxTextureHeight = wined3d_caps->MaxTextureHeight;
caps->MaxVolumeExtent = wined3d_caps->MaxVolumeExtent;
caps->MaxTextureRepeat = wined3d_caps->MaxTextureRepeat;
caps->MaxTextureAspectRatio = wined3d_caps->MaxTextureAspectRatio;
caps->MaxAnisotropy = wined3d_caps->MaxAnisotropy;
caps->MaxVertexW = wined3d_caps->MaxVertexW;
caps->GuardBandLeft = wined3d_caps->GuardBandLeft;
caps->GuardBandTop = wined3d_caps->GuardBandTop;
caps->GuardBandRight = wined3d_caps->GuardBandRight;
caps->GuardBandBottom = wined3d_caps->GuardBandBottom;
caps->ExtentsAdjust = wined3d_caps->ExtentsAdjust;
caps->StencilCaps = wined3d_caps->StencilCaps;
caps->FVFCaps = wined3d_caps->FVFCaps;
caps->TextureOpCaps = wined3d_caps->TextureOpCaps;
caps->MaxTextureBlendStages = wined3d_caps->MaxTextureBlendStages;
caps->MaxSimultaneousTextures = wined3d_caps->MaxSimultaneousTextures;
caps->VertexProcessingCaps = wined3d_caps->VertexProcessingCaps;
caps->MaxActiveLights = wined3d_caps->MaxActiveLights;
caps->MaxUserClipPlanes = wined3d_caps->MaxUserClipPlanes;
caps->MaxVertexBlendMatrices = wined3d_caps->MaxVertexBlendMatrices;
caps->MaxVertexBlendMatrixIndex = wined3d_caps->MaxVertexBlendMatrixIndex;
caps->MaxPointSize = wined3d_caps->MaxPointSize;
caps->MaxPrimitiveCount = wined3d_caps->MaxPrimitiveCount;
caps->MaxVertexIndex = wined3d_caps->MaxVertexIndex;
caps->MaxStreams = wined3d_caps->MaxStreams;
caps->MaxStreamStride = wined3d_caps->MaxStreamStride;
caps->VertexShaderVersion = wined3d_caps->VertexShaderVersion;
caps->MaxVertexShaderConst = wined3d_caps->MaxVertexShaderConst;
caps->PixelShaderVersion = wined3d_caps->PixelShaderVersion;
caps->MaxPixelShaderValue = wined3d_caps->PixelShader1xMaxValue;
/* D3D8 doesn't support SM 2.0 or higher, so clamp to 1.x */
if (caps->PixelShaderVersion)
caps->PixelShaderVersion = D3DPS_VERSION(1, 4);
else
caps->PixelShaderVersion = D3DPS_VERSION(0, 0);
if (caps->VertexShaderVersion)
caps->VertexShaderVersion = D3DVS_VERSION(1, 1);
else
caps->VertexShaderVersion = D3DVS_VERSION(0, 0);
caps->MaxVertexShaderConst = min(D3D8_MAX_VERTEX_SHADER_CONSTANTF, caps->MaxVertexShaderConst);
caps->StencilCaps &= ~WINED3DSTENCILCAPS_TWOSIDED;
}
/* Handle table functions */
static DWORD d3d8_allocate_handle(struct d3d8_handle_table *t, void *object, enum d3d8_handle_type type)
{
struct d3d8_handle_entry *entry;
if (t->free_entries)
{
DWORD index = t->free_entries - t->entries;
/* Use a free handle */
entry = t->free_entries;
if (entry->type != D3D8_HANDLE_FREE)
{
ERR("Handle %u(%p) is in the free list, but has type %#x.\n", index, entry, entry->type);
return D3D8_INVALID_HANDLE;
}
t->free_entries = entry->object;
entry->object = object;
entry->type = type;
return index;
}
if (!(t->entry_count < t->table_size))
{
/* Grow the table */
UINT new_size = t->table_size + (t->table_size >> 1);
struct d3d8_handle_entry *new_entries;
if (!(new_entries = heap_realloc(t->entries, new_size * sizeof(*t->entries))))
{
ERR("Failed to grow the handle table.\n");
return D3D8_INVALID_HANDLE;
}
t->entries = new_entries;
t->table_size = new_size;
}
entry = &t->entries[t->entry_count];
entry->object = object;
entry->type = type;
return t->entry_count++;
}
static void *d3d8_free_handle(struct d3d8_handle_table *t, DWORD handle, enum d3d8_handle_type type)
{
struct d3d8_handle_entry *entry;
void *object;
if (handle == D3D8_INVALID_HANDLE || handle >= t->entry_count)
{
WARN("Invalid handle %u passed.\n", handle);
return NULL;
}
entry = &t->entries[handle];
if (entry->type != type)
{
WARN("Handle %u(%p) is not of type %#x.\n", handle, entry, type);
return NULL;
}
object = entry->object;
entry->object = t->free_entries;
entry->type = D3D8_HANDLE_FREE;
t->free_entries = entry;
return object;
}
static void *d3d8_get_object(struct d3d8_handle_table *t, DWORD handle, enum d3d8_handle_type type)
{
struct d3d8_handle_entry *entry;
if (handle == D3D8_INVALID_HANDLE || handle >= t->entry_count)
{
WARN("Invalid handle %u passed.\n", handle);
return NULL;
}
entry = &t->entries[handle];
if (entry->type != type)
{
WARN("Handle %u(%p) is not of type %#x.\n", handle, entry, type);
return NULL;
}
return entry->object;
}
static HRESULT WINAPI d3d8_device_QueryInterface(IDirect3DDevice8 *iface, REFIID riid, void **out)
{
TRACE("iface %p, riid %s, out %p.\n",
iface, debugstr_guid(riid), out);
if (IsEqualGUID(riid, &IID_IDirect3DDevice8)
|| IsEqualGUID(riid, &IID_IUnknown))
{
IDirect3DDevice8_AddRef(iface);
*out = iface;
return S_OK;
}
WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
*out = NULL;
return E_NOINTERFACE;
}
static ULONG WINAPI d3d8_device_AddRef(IDirect3DDevice8 *iface)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
ULONG ref = InterlockedIncrement(&device->ref);
TRACE("%p increasing refcount to %u.\n", iface, ref);
return ref;
}
static ULONG WINAPI d3d8_device_Release(IDirect3DDevice8 *iface)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
ULONG ref;
if (device->inDestruction)
return 0;
ref = InterlockedDecrement(&device->ref);
TRACE("%p decreasing refcount to %u.\n", iface, ref);
if (!ref)
{
IDirect3D8 *parent = device->d3d_parent;
unsigned i;
TRACE("Releasing wined3d device %p.\n", device->wined3d_device);
wined3d_mutex_lock();
device->inDestruction = TRUE;
for (i = 0; i < device->numConvertedDecls; ++i)
{
d3d8_vertex_declaration_destroy(device->decls[i].declaration);
}
heap_free(device->decls);
if (device->vertex_buffer)
wined3d_buffer_decref(device->vertex_buffer);
if (device->index_buffer)
wined3d_buffer_decref(device->index_buffer);
wined3d_device_uninit_3d(device->wined3d_device);
wined3d_device_release_focus_window(device->wined3d_device);
wined3d_device_decref(device->wined3d_device);
heap_free(device->handle_table.entries);
heap_free(device);
wined3d_mutex_unlock();
IDirect3D8_Release(parent);
}
return ref;
}
static HRESULT WINAPI d3d8_device_TestCooperativeLevel(IDirect3DDevice8 *iface)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
TRACE("iface %p.\n", iface);
TRACE("device state: %#x.\n", device->device_state);
switch (device->device_state)
{
default:
case D3D8_DEVICE_STATE_OK:
return D3D_OK;
case D3D8_DEVICE_STATE_LOST:
return D3DERR_DEVICELOST;
case D3D8_DEVICE_STATE_NOT_RESET:
return D3DERR_DEVICENOTRESET;
}
}
static UINT WINAPI d3d8_device_GetAvailableTextureMem(IDirect3DDevice8 *iface)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
UINT ret;
TRACE("iface %p.\n", iface);
wined3d_mutex_lock();
ret = wined3d_device_get_available_texture_mem(device->wined3d_device);
wined3d_mutex_unlock();
return ret;
}
static HRESULT WINAPI d3d8_device_ResourceManagerDiscardBytes(IDirect3DDevice8 *iface, DWORD byte_count)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
TRACE("iface %p, byte_count %u.\n", iface, byte_count);
if (byte_count)
FIXME("Byte count ignored.\n");
wined3d_mutex_lock();
wined3d_device_evict_managed_resources(device->wined3d_device);
wined3d_mutex_unlock();
return D3D_OK;
}
static HRESULT WINAPI d3d8_device_GetDirect3D(IDirect3DDevice8 *iface, IDirect3D8 **d3d8)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
TRACE("iface %p, d3d8 %p.\n", iface, d3d8);
if (!d3d8)
return D3DERR_INVALIDCALL;
return IDirect3D8_QueryInterface(device->d3d_parent, &IID_IDirect3D8, (void **)d3d8);
}
static HRESULT WINAPI d3d8_device_GetDeviceCaps(IDirect3DDevice8 *iface, D3DCAPS8 *caps)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
WINED3DCAPS wined3d_caps;
HRESULT hr;
TRACE("iface %p, caps %p.\n", iface, caps);
if (!caps)
return D3DERR_INVALIDCALL;
wined3d_mutex_lock();
hr = wined3d_device_get_device_caps(device->wined3d_device, &wined3d_caps);
wined3d_mutex_unlock();
d3dcaps_from_wined3dcaps(caps, &wined3d_caps);
return hr;
}
static HRESULT WINAPI d3d8_device_GetDisplayMode(IDirect3DDevice8 *iface, D3DDISPLAYMODE *mode)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
struct wined3d_display_mode wined3d_mode;
HRESULT hr;
TRACE("iface %p, mode %p.\n", iface, mode);
wined3d_mutex_lock();
hr = wined3d_device_get_display_mode(device->wined3d_device, 0, &wined3d_mode, NULL);
wined3d_mutex_unlock();
if (SUCCEEDED(hr))
{
mode->Width = wined3d_mode.width;
mode->Height = wined3d_mode.height;
mode->RefreshRate = wined3d_mode.refresh_rate;
mode->Format = d3dformat_from_wined3dformat(wined3d_mode.format_id);
}
return hr;
}
static HRESULT WINAPI d3d8_device_GetCreationParameters(IDirect3DDevice8 *iface,
D3DDEVICE_CREATION_PARAMETERS *parameters)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
TRACE("iface %p, parameters %p.\n", iface, parameters);
wined3d_mutex_lock();
wined3d_device_get_creation_parameters(device->wined3d_device,
(struct wined3d_device_creation_parameters *)parameters);
wined3d_mutex_unlock();
return D3D_OK;
}
static HRESULT WINAPI d3d8_device_SetCursorProperties(IDirect3DDevice8 *iface,
UINT hotspot_x, UINT hotspot_y, IDirect3DSurface8 *bitmap)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
struct d3d8_surface *bitmap_impl = unsafe_impl_from_IDirect3DSurface8(bitmap);
HRESULT hr;
TRACE("iface %p, hotspot_x %u, hotspot_y %u, bitmap %p.\n",
iface, hotspot_x, hotspot_y, bitmap);
if (!bitmap)
{
WARN("No cursor bitmap, returning D3DERR_INVALIDCALL.\n");
return D3DERR_INVALIDCALL;
}
wined3d_mutex_lock();
hr = wined3d_device_set_cursor_properties(device->wined3d_device,
hotspot_x, hotspot_y, bitmap_impl->wined3d_texture, bitmap_impl->sub_resource_idx);
wined3d_mutex_unlock();
return hr;
}
static void WINAPI d3d8_device_SetCursorPosition(IDirect3DDevice8 *iface, UINT x, UINT y, DWORD flags)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
TRACE("iface %p, x %u, y %u, flags %#x.\n", iface, x, y, flags);
wined3d_mutex_lock();
wined3d_device_set_cursor_position(device->wined3d_device, x, y, flags);
wined3d_mutex_unlock();
}
static BOOL WINAPI d3d8_device_ShowCursor(IDirect3DDevice8 *iface, BOOL show)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
BOOL ret;
TRACE("iface %p, show %#x.\n", iface, show);
wined3d_mutex_lock();
ret = wined3d_device_show_cursor(device->wined3d_device, show);
wined3d_mutex_unlock();
return ret;
}
static HRESULT WINAPI d3d8_device_CreateAdditionalSwapChain(IDirect3DDevice8 *iface,
D3DPRESENT_PARAMETERS *present_parameters, IDirect3DSwapChain8 **swapchain)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
struct wined3d_swapchain_desc desc;
struct d3d8_swapchain *object;
UINT i, count;
HRESULT hr;
TRACE("iface %p, present_parameters %p, swapchain %p.\n",
iface, present_parameters, swapchain);
if (!present_parameters->Windowed)
{
WARN("Trying to create an additional fullscreen swapchain, returning D3DERR_INVALIDCALL.\n");
return D3DERR_INVALIDCALL;
}
wined3d_mutex_lock();
count = wined3d_device_get_swapchain_count(device->wined3d_device);
for (i = 0; i < count; ++i)
{
struct wined3d_swapchain *wined3d_swapchain;
wined3d_swapchain = wined3d_device_get_swapchain(device->wined3d_device, i);
wined3d_swapchain_get_desc(wined3d_swapchain, &desc);
if (!desc.windowed)
{
wined3d_mutex_unlock();
WARN("Trying to create an additional swapchain in fullscreen mode, returning D3DERR_INVALIDCALL.\n");
return D3DERR_INVALIDCALL;
}
}
wined3d_mutex_unlock();
if (!wined3d_swapchain_desc_from_present_parameters(&desc, present_parameters))
return D3DERR_INVALIDCALL;
if (SUCCEEDED(hr = d3d8_swapchain_create(device, &desc, &object)))
*swapchain = &object->IDirect3DSwapChain8_iface;
present_parameters_from_wined3d_swapchain_desc(present_parameters, &desc);
return hr;
}
static HRESULT CDECL reset_enum_callback(struct wined3d_resource *resource)
{
struct wined3d_resource_desc desc;
IDirect3DBaseTexture8 *texture;
struct d3d8_surface *surface;
IUnknown *parent;
wined3d_resource_get_desc(resource, &desc);
if (desc.access & WINED3D_RESOURCE_ACCESS_CPU)
return D3D_OK;
if (desc.resource_type != WINED3D_RTYPE_TEXTURE_2D)
{
WARN("Resource %p in pool D3DPOOL_DEFAULT blocks the Reset call.\n", resource);
return D3DERR_DEVICELOST;
}
parent = wined3d_resource_get_parent(resource);
if (parent && SUCCEEDED(IUnknown_QueryInterface(parent, &IID_IDirect3DBaseTexture8, (void **)&texture)))
{
IDirect3DBaseTexture8_Release(texture);
WARN("Texture %p (resource %p) in pool D3DPOOL_DEFAULT blocks the Reset call.\n", texture, resource);
return D3DERR_DEVICELOST;
}
surface = wined3d_texture_get_sub_resource_parent(wined3d_texture_from_resource(resource), 0);
if (!surface->resource.refcount)
return D3D_OK;
WARN("Surface %p in pool D3DPOOL_DEFAULT blocks the Reset call.\n", surface);
return D3DERR_DEVICELOST;
}
static HRESULT WINAPI d3d8_device_Reset(IDirect3DDevice8 *iface,
D3DPRESENT_PARAMETERS *present_parameters)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
struct wined3d_swapchain_desc swapchain_desc;
HRESULT hr;
TRACE("iface %p, present_parameters %p.\n", iface, present_parameters);
if (device->device_state == D3D8_DEVICE_STATE_LOST)
{
WARN("App not active, returning D3DERR_DEVICELOST.\n");
return D3DERR_DEVICELOST;
}
if (!wined3d_swapchain_desc_from_present_parameters(&swapchain_desc, present_parameters))
return D3DERR_INVALIDCALL;
wined3d_mutex_lock();
if (device->vertex_buffer)
{
wined3d_buffer_decref(device->vertex_buffer);
device->vertex_buffer = NULL;
device->vertex_buffer_size = 0;
}
if (device->index_buffer)
{
wined3d_buffer_decref(device->index_buffer);
device->index_buffer = NULL;
device->index_buffer_size = 0;
}
if (SUCCEEDED(hr = wined3d_device_reset(device->wined3d_device, &swapchain_desc,
NULL, reset_enum_callback, TRUE)))
{
present_parameters->BackBufferCount = swapchain_desc.backbuffer_count;
wined3d_device_set_render_state(device->wined3d_device, WINED3D_RS_POINTSIZE_MIN, 0);
wined3d_device_set_render_state(device->wined3d_device, WINED3D_RS_ZENABLE,
!!swapchain_desc.enable_auto_depth_stencil);
device->device_state = D3D8_DEVICE_STATE_OK;
}
else
{
device->device_state = D3D8_DEVICE_STATE_NOT_RESET;
}
wined3d_mutex_unlock();
return hr;
}
static HRESULT WINAPI d3d8_device_Present(IDirect3DDevice8 *iface, const RECT *src_rect,
const RECT *dst_rect, HWND dst_window_override, const RGNDATA *dirty_region)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
TRACE("iface %p, src_rect %s, dst_rect %s, dst_window_override %p, dirty_region %p.\n",
iface, wine_dbgstr_rect(src_rect), wine_dbgstr_rect(dst_rect), dst_window_override, dirty_region);
/* Fraps does not hook IDirect3DDevice8::Present regardless of the hotpatch
* attribute. It only hooks IDirect3DSwapChain8::Present. Yet it properly
* shows a framerate on Windows in applications that only call the device
* method, like e.g. the dx8 sdk samples. The conclusion is that native
* calls the swapchain's public method from the device. */
return IDirect3DSwapChain8_Present(&device->implicit_swapchain->IDirect3DSwapChain8_iface,
src_rect, dst_rect, dst_window_override, dirty_region);
}
static HRESULT WINAPI d3d8_device_GetBackBuffer(IDirect3DDevice8 *iface,
UINT backbuffer_idx, D3DBACKBUFFER_TYPE backbuffer_type, IDirect3DSurface8 **backbuffer)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
struct wined3d_swapchain *wined3d_swapchain;
struct wined3d_texture *wined3d_texture;
struct d3d8_surface *surface_impl;
TRACE("iface %p, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
iface, backbuffer_idx, backbuffer_type, backbuffer);
/* backbuffer_type is ignored by native. */
/* No need to check for backbuffer == NULL, Windows crashes in that case. */
wined3d_mutex_lock();
wined3d_swapchain = device->implicit_swapchain->wined3d_swapchain;
if (!(wined3d_texture = wined3d_swapchain_get_back_buffer(wined3d_swapchain, backbuffer_idx)))
{
wined3d_mutex_unlock();
*backbuffer = NULL;
return D3DERR_INVALIDCALL;
}
surface_impl = wined3d_texture_get_sub_resource_parent(wined3d_texture, 0);
*backbuffer = &surface_impl->IDirect3DSurface8_iface;
IDirect3DSurface8_AddRef(*backbuffer);
wined3d_mutex_unlock();
return D3D_OK;
}
static HRESULT WINAPI d3d8_device_GetRasterStatus(IDirect3DDevice8 *iface, D3DRASTER_STATUS *raster_status)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
HRESULT hr;
TRACE("iface %p, raster_status %p.\n", iface, raster_status);
wined3d_mutex_lock();
hr = wined3d_device_get_raster_status(device->wined3d_device, 0, (struct wined3d_raster_status *)raster_status);
wined3d_mutex_unlock();
return hr;
}
static void WINAPI d3d8_device_SetGammaRamp(IDirect3DDevice8 *iface, DWORD flags, const D3DGAMMARAMP *ramp)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
TRACE("iface %p, flags %#x, ramp %p.\n", iface, flags, ramp);
/* Note: D3DGAMMARAMP is compatible with struct wined3d_gamma_ramp. */
wined3d_mutex_lock();
wined3d_device_set_gamma_ramp(device->wined3d_device, 0, flags, (const struct wined3d_gamma_ramp *)ramp);
wined3d_mutex_unlock();
}
static void WINAPI d3d8_device_GetGammaRamp(IDirect3DDevice8 *iface, D3DGAMMARAMP *ramp)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
TRACE("iface %p, ramp %p.\n", iface, ramp);
/* Note: D3DGAMMARAMP is compatible with struct wined3d_gamma_ramp. */
wined3d_mutex_lock();
wined3d_device_get_gamma_ramp(device->wined3d_device, 0, (struct wined3d_gamma_ramp *)ramp);
wined3d_mutex_unlock();
}
static HRESULT WINAPI d3d8_device_CreateTexture(IDirect3DDevice8 *iface,
UINT width, UINT height, UINT levels, DWORD usage, D3DFORMAT format,
D3DPOOL pool, IDirect3DTexture8 **texture)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
struct d3d8_texture *object;
HRESULT hr;
TRACE("iface %p, width %u, height %u, levels %u, usage %#x, format %#x, pool %#x, texture %p.\n",
iface, width, height, levels, usage, format, pool, texture);
if (!format)
return D3DERR_INVALIDCALL;
*texture = NULL;
if (!(object = heap_alloc_zero(sizeof(*object))))
return D3DERR_OUTOFVIDEOMEMORY;
hr = texture_init(object, device, width, height, levels, usage, format, pool);
if (FAILED(hr))
{
WARN("Failed to initialize texture, hr %#x.\n", hr);
heap_free(object);
return hr;
}
TRACE("Created texture %p.\n", object);
*texture = (IDirect3DTexture8 *)&object->IDirect3DBaseTexture8_iface;
return D3D_OK;
}
static HRESULT WINAPI d3d8_device_CreateVolumeTexture(IDirect3DDevice8 *iface,
UINT width, UINT height, UINT depth, UINT levels, DWORD usage, D3DFORMAT format,
D3DPOOL pool, IDirect3DVolumeTexture8 **texture)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
struct d3d8_texture *object;
HRESULT hr;
TRACE("iface %p, width %u, height %u, depth %u, levels %u, usage %#x, format %#x, pool %#x, texture %p.\n",
iface, width, height, depth, levels, usage, format, pool, texture);
if (!format)
return D3DERR_INVALIDCALL;
*texture = NULL;
if (!(object = heap_alloc_zero(sizeof(*object))))
return D3DERR_OUTOFVIDEOMEMORY;
hr = volumetexture_init(object, device, width, height, depth, levels, usage, format, pool);
if (FAILED(hr))
{
WARN("Failed to initialize volume texture, hr %#x.\n", hr);
heap_free(object);
return hr;
}
TRACE("Created volume texture %p.\n", object);
*texture = (IDirect3DVolumeTexture8 *)&object->IDirect3DBaseTexture8_iface;
return D3D_OK;
}
static HRESULT WINAPI d3d8_device_CreateCubeTexture(IDirect3DDevice8 *iface, UINT edge_length,
UINT levels, DWORD usage, D3DFORMAT format, D3DPOOL pool, IDirect3DCubeTexture8 **texture)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
struct d3d8_texture *object;
HRESULT hr;
TRACE("iface %p, edge_length %u, levels %u, usage %#x, format %#x, pool %#x, texture %p.\n",
iface, edge_length, levels, usage, format, pool, texture);
if (!format)
return D3DERR_INVALIDCALL;
*texture = NULL;
if (!(object = heap_alloc_zero(sizeof(*object))))
return D3DERR_OUTOFVIDEOMEMORY;
hr = cubetexture_init(object, device, edge_length, levels, usage, format, pool);
if (FAILED(hr))
{
WARN("Failed to initialize cube texture, hr %#x.\n", hr);
heap_free(object);
return hr;
}
TRACE("Created cube texture %p.\n", object);
*texture = (IDirect3DCubeTexture8 *)&object->IDirect3DBaseTexture8_iface;
return hr;
}
static HRESULT WINAPI d3d8_device_CreateVertexBuffer(IDirect3DDevice8 *iface, UINT size,
DWORD usage, DWORD fvf, D3DPOOL pool, IDirect3DVertexBuffer8 **buffer)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
struct d3d8_vertexbuffer *object;
HRESULT hr;
TRACE("iface %p, size %u, usage %#x, fvf %#x, pool %#x, buffer %p.\n",
iface, size, usage, fvf, pool, buffer);
if (!(object = heap_alloc_zero(sizeof(*object))))
return D3DERR_OUTOFVIDEOMEMORY;
hr = vertexbuffer_init(object, device, size, usage, fvf, pool);
if (FAILED(hr))
{
WARN("Failed to initialize vertex buffer, hr %#x.\n", hr);
heap_free(object);
return hr;
}
TRACE("Created vertex buffer %p.\n", object);
*buffer = &object->IDirect3DVertexBuffer8_iface;
return D3D_OK;
}
static HRESULT WINAPI d3d8_device_CreateIndexBuffer(IDirect3DDevice8 *iface, UINT size,
DWORD usage, D3DFORMAT format, D3DPOOL pool, IDirect3DIndexBuffer8 **buffer)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
struct d3d8_indexbuffer *object;
HRESULT hr;
TRACE("iface %p, size %u, usage %#x, format %#x, pool %#x, buffer %p.\n",
iface, size, usage, format, pool, buffer);
if (!(object = heap_alloc_zero(sizeof(*object))))
return D3DERR_OUTOFVIDEOMEMORY;
hr = indexbuffer_init(object, device, size, usage, format, pool);
if (FAILED(hr))
{
WARN("Failed to initialize index buffer, hr %#x.\n", hr);
heap_free(object);
return hr;
}
TRACE("Created index buffer %p.\n", object);
*buffer = &object->IDirect3DIndexBuffer8_iface;
return D3D_OK;
}
static HRESULT d3d8_device_create_surface(struct d3d8_device *device, UINT width, UINT height,
D3DFORMAT format, DWORD flags, IDirect3DSurface8 **surface, UINT usage, D3DPOOL pool,
D3DMULTISAMPLE_TYPE multisample_type, DWORD multisample_quality)
{
struct wined3d_resource_desc desc;
struct d3d8_surface *surface_impl;
struct wined3d_texture *texture;
HRESULT hr;
TRACE("device %p, width %u, height %u, format %#x, flags %#x, surface %p, "
"usage %#x, pool %#x, multisample_type %#x, multisample_quality %u.\n",
device, width, height, format, flags, surface,
usage, pool, multisample_type, multisample_quality);
desc.resource_type = WINED3D_RTYPE_TEXTURE_2D;
desc.format = wined3dformat_from_d3dformat(format);
desc.multisample_type = multisample_type;
desc.multisample_quality = multisample_quality;
desc.usage = usage & WINED3DUSAGE_MASK;
if (pool == D3DPOOL_SCRATCH)
desc.usage |= WINED3DUSAGE_SCRATCH;
desc.access = wined3daccess_from_d3dpool(pool, usage)
| WINED3D_RESOURCE_ACCESS_MAP_R | WINED3D_RESOURCE_ACCESS_MAP_W;
desc.width = width;
desc.height = height;
desc.depth = 1;
desc.size = 0;
wined3d_mutex_lock();
if (FAILED(hr = wined3d_texture_create(device->wined3d_device, &desc,
1, 1, flags, NULL, NULL, &d3d8_null_wined3d_parent_ops, &texture)))
{
wined3d_mutex_unlock();
WARN("Failed to create texture, hr %#x.\n", hr);
return hr;
}
surface_impl = wined3d_texture_get_sub_resource_parent(texture, 0);
surface_impl->parent_device = &device->IDirect3DDevice8_iface;
*surface = &surface_impl->IDirect3DSurface8_iface;
IDirect3DSurface8_AddRef(*surface);
wined3d_texture_decref(texture);
wined3d_mutex_unlock();
return D3D_OK;
}
static HRESULT WINAPI d3d8_device_CreateRenderTarget(IDirect3DDevice8 *iface, UINT width,
UINT height, D3DFORMAT format, D3DMULTISAMPLE_TYPE multisample_type, BOOL lockable,
IDirect3DSurface8 **surface)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
DWORD flags = 0;
TRACE("iface %p, width %u, height %u, format %#x, multisample_type %#x, lockable %#x, surface %p.\n",
iface, width, height, format, multisample_type, lockable, surface);
if (!format)
return D3DERR_INVALIDCALL;
*surface = NULL;
if (lockable)
flags |= WINED3D_TEXTURE_CREATE_MAPPABLE;
return d3d8_device_create_surface(device, width, height, format, flags, surface,
D3DUSAGE_RENDERTARGET, D3DPOOL_DEFAULT, multisample_type, 0);
}
static HRESULT WINAPI d3d8_device_CreateDepthStencilSurface(IDirect3DDevice8 *iface,
UINT width, UINT height, D3DFORMAT format, D3DMULTISAMPLE_TYPE multisample_type,
IDirect3DSurface8 **surface)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
TRACE("iface %p, width %u, height %u, format %#x, multisample_type %#x, surface %p.\n",
iface, width, height, format, multisample_type, surface);
if (!format)
return D3DERR_INVALIDCALL;
*surface = NULL;
/* TODO: Verify that Discard is false */
return d3d8_device_create_surface(device, width, height, format, WINED3D_TEXTURE_CREATE_MAPPABLE,
surface, D3DUSAGE_DEPTHSTENCIL, D3DPOOL_DEFAULT, multisample_type, 0);
}
/* IDirect3DDevice8Impl::CreateImageSurface returns surface with pool type SYSTEMMEM */
static HRESULT WINAPI d3d8_device_CreateImageSurface(IDirect3DDevice8 *iface, UINT width,
UINT height, D3DFORMAT format, IDirect3DSurface8 **surface)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
TRACE("iface %p, width %u, height %u, format %#x, surface %p.\n",
iface, width, height, format, surface);
*surface = NULL;
return d3d8_device_create_surface(device, width, height, format, WINED3D_TEXTURE_CREATE_MAPPABLE,
surface, 0, D3DPOOL_SYSTEMMEM, D3DMULTISAMPLE_NONE, 0);
}
static HRESULT WINAPI d3d8_device_CopyRects(IDirect3DDevice8 *iface,
IDirect3DSurface8 *src_surface, const RECT *src_rects, UINT rect_count,
IDirect3DSurface8 *dst_surface, const POINT *dst_points)
{
struct d3d8_surface *src = unsafe_impl_from_IDirect3DSurface8(src_surface);
struct d3d8_surface *dst = unsafe_impl_from_IDirect3DSurface8(dst_surface);
enum wined3d_format_id src_format, dst_format;
struct wined3d_sub_resource_desc wined3d_desc;
UINT src_w, src_h;
TRACE("iface %p, src_surface %p, src_rects %p, rect_count %u, dst_surface %p, dst_points %p.\n",
iface, src_surface, src_rects, rect_count, dst_surface, dst_points);
/* Check that the source texture is in WINED3D_POOL_SYSTEM_MEM and the
* destination texture is in WINED3D_POOL_DEFAULT. */
wined3d_mutex_lock();
wined3d_texture_get_sub_resource_desc(src->wined3d_texture, src->sub_resource_idx, &wined3d_desc);
if (wined3d_desc.usage & WINED3DUSAGE_DEPTHSTENCIL)
{
WARN("Source %p is a depth stencil surface, returning D3DERR_INVALIDCALL.\n", src_surface);
wined3d_mutex_unlock();
return D3DERR_INVALIDCALL;
}
src_format = wined3d_desc.format;
src_w = wined3d_desc.width;
src_h = wined3d_desc.height;
wined3d_texture_get_sub_resource_desc(dst->wined3d_texture, dst->sub_resource_idx, &wined3d_desc);
if (wined3d_desc.usage & WINED3DUSAGE_DEPTHSTENCIL)
{
WARN("Destination %p is a depth stencil surface, returning D3DERR_INVALIDCALL.\n", dst_surface);
wined3d_mutex_unlock();
return D3DERR_INVALIDCALL;
}
dst_format = wined3d_desc.format;
/* Check that the source and destination formats match */
if (src_format != dst_format)
{
WARN("Source %p format must match the destination %p format, returning D3DERR_INVALIDCALL.\n",
src_surface, dst_surface);
wined3d_mutex_unlock();
return D3DERR_INVALIDCALL;
}
/* Quick if complete copy ... */
if (!rect_count && !src_rects && !dst_points)
{
RECT rect = {0, 0, src_w, src_h};
wined3d_texture_blt(dst->wined3d_texture, dst->sub_resource_idx, &rect,
src->wined3d_texture, src->sub_resource_idx, &rect, 0, NULL, WINED3D_TEXF_POINT);
}
else
{
unsigned int i;
/* Copy rect by rect */
if (src_rects && dst_points)
{
for (i = 0; i < rect_count; ++i)
{
UINT w = src_rects[i].right - src_rects[i].left;
UINT h = src_rects[i].bottom - src_rects[i].top;
RECT dst_rect = {dst_points[i].x, dst_points[i].y,
dst_points[i].x + w, dst_points[i].y + h};
wined3d_texture_blt(dst->wined3d_texture, dst->sub_resource_idx, &dst_rect,
src->wined3d_texture, src->sub_resource_idx, &src_rects[i], 0, NULL, WINED3D_TEXF_POINT);
}
}
else
{
for (i = 0; i < rect_count; ++i)
{
UINT w = src_rects[i].right - src_rects[i].left;
UINT h = src_rects[i].bottom - src_rects[i].top;
RECT dst_rect = {0, 0, w, h};
wined3d_texture_blt(dst->wined3d_texture, dst->sub_resource_idx, &dst_rect,
src->wined3d_texture, src->sub_resource_idx, &src_rects[i], 0, NULL, WINED3D_TEXF_POINT);
}
}
}
wined3d_mutex_unlock();
return WINED3D_OK;
}
static HRESULT WINAPI d3d8_device_UpdateTexture(IDirect3DDevice8 *iface,
IDirect3DBaseTexture8 *src_texture, IDirect3DBaseTexture8 *dst_texture)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
struct d3d8_texture *src_impl, *dst_impl;
HRESULT hr;
TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
src_impl = unsafe_impl_from_IDirect3DBaseTexture8(src_texture);
dst_impl = unsafe_impl_from_IDirect3DBaseTexture8(dst_texture);
wined3d_mutex_lock();
hr = wined3d_device_update_texture(device->wined3d_device,
src_impl->wined3d_texture, dst_impl->wined3d_texture);
wined3d_mutex_unlock();
return hr;
}
static HRESULT WINAPI d3d8_device_GetFrontBuffer(IDirect3DDevice8 *iface, IDirect3DSurface8 *dst_surface)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
struct d3d8_surface *dst_impl = unsafe_impl_from_IDirect3DSurface8(dst_surface);
HRESULT hr;
TRACE("iface %p, dst_surface %p.\n", iface, dst_surface);
if (!dst_surface)
{
WARN("Invalid destination surface passed.\n");
return D3DERR_INVALIDCALL;
}
wined3d_mutex_lock();
hr = wined3d_swapchain_get_front_buffer_data(device->implicit_swapchain->wined3d_swapchain,
dst_impl->wined3d_texture, dst_impl->sub_resource_idx);
wined3d_mutex_unlock();
return hr;
}
static HRESULT WINAPI d3d8_device_SetRenderTarget(IDirect3DDevice8 *iface,
IDirect3DSurface8 *render_target, IDirect3DSurface8 *depth_stencil)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
struct d3d8_surface *rt_impl = unsafe_impl_from_IDirect3DSurface8(render_target);
struct d3d8_surface *ds_impl = unsafe_impl_from_IDirect3DSurface8(depth_stencil);
struct wined3d_rendertarget_view *original_dsv, *rtv;
HRESULT hr = D3D_OK;
TRACE("iface %p, render_target %p, depth_stencil %p.\n", iface, render_target, depth_stencil);
if (rt_impl && d3d8_surface_get_device(rt_impl) != device)
{
WARN("Render target surface does not match device.\n");
return D3DERR_INVALIDCALL;
}
wined3d_mutex_lock();
if (ds_impl)
{
struct wined3d_sub_resource_desc ds_desc, rt_desc;
struct wined3d_rendertarget_view *original_rtv;
struct d3d8_surface *original_surface;
/* If no render target is passed in check the size against the current RT */
if (!render_target)
{
if (!(original_rtv = wined3d_device_get_rendertarget_view(device->wined3d_device, 0)))
{
wined3d_mutex_unlock();
return D3DERR_NOTFOUND;
}
original_surface = wined3d_rendertarget_view_get_sub_resource_parent(original_rtv);
wined3d_texture_get_sub_resource_desc(original_surface->wined3d_texture,
original_surface->sub_resource_idx, &rt_desc);
}
else
wined3d_texture_get_sub_resource_desc(rt_impl->wined3d_texture,
rt_impl->sub_resource_idx, &rt_desc);
wined3d_texture_get_sub_resource_desc(ds_impl->wined3d_texture, ds_impl->sub_resource_idx, &ds_desc);
if (ds_desc.width < rt_desc.width || ds_desc.height < rt_desc.height)
{
WARN("Depth stencil is smaller than the render target, returning D3DERR_INVALIDCALL\n");
wined3d_mutex_unlock();
return D3DERR_INVALIDCALL;
}
if (ds_desc.multisample_type != rt_desc.multisample_type
|| ds_desc.multisample_quality != rt_desc.multisample_quality)
{
WARN("Multisample settings do not match, returning D3DERR_INVALIDCALL\n");
wined3d_mutex_unlock();
return D3DERR_INVALIDCALL;
}
}
original_dsv = wined3d_device_get_depth_stencil_view(device->wined3d_device);
rtv = ds_impl ? d3d8_surface_acquire_rendertarget_view(ds_impl) : NULL;
wined3d_device_set_depth_stencil_view(device->wined3d_device, rtv);
d3d8_surface_release_rendertarget_view(ds_impl, rtv);
rtv = render_target ? d3d8_surface_acquire_rendertarget_view(rt_impl) : NULL;
if (render_target && FAILED(hr = wined3d_device_set_rendertarget_view(device->wined3d_device, 0, rtv, TRUE)))
wined3d_device_set_depth_stencil_view(device->wined3d_device, original_dsv);
d3d8_surface_release_rendertarget_view(rt_impl, rtv);
wined3d_mutex_unlock();
return hr;
}
static HRESULT WINAPI d3d8_device_GetRenderTarget(IDirect3DDevice8 *iface, IDirect3DSurface8 **render_target)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
struct wined3d_rendertarget_view *wined3d_rtv;
struct d3d8_surface *surface_impl;
HRESULT hr;
TRACE("iface %p, render_target %p.\n", iface, render_target);
if (!render_target)
return D3DERR_INVALIDCALL;
wined3d_mutex_lock();
if ((wined3d_rtv = wined3d_device_get_rendertarget_view(device->wined3d_device, 0)))
{
/* We want the sub resource parent here, since the view itself may be
* internal to wined3d and may not have a parent. */
surface_impl = wined3d_rendertarget_view_get_sub_resource_parent(wined3d_rtv);
*render_target = &surface_impl->IDirect3DSurface8_iface;
IDirect3DSurface8_AddRef(*render_target);
hr = D3D_OK;
}
else
{
ERR("Failed to get wined3d render target.\n");
*render_target = NULL;
hr = D3DERR_NOTFOUND;
}
wined3d_mutex_unlock();
return hr;
}
static HRESULT WINAPI d3d8_device_GetDepthStencilSurface(IDirect3DDevice8 *iface, IDirect3DSurface8 **depth_stencil)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
struct wined3d_rendertarget_view *wined3d_dsv;
struct d3d8_surface *surface_impl;
HRESULT hr = D3D_OK;
TRACE("iface %p, depth_stencil %p.\n", iface, depth_stencil);
if (!depth_stencil)
return D3DERR_INVALIDCALL;
wined3d_mutex_lock();
if ((wined3d_dsv = wined3d_device_get_depth_stencil_view(device->wined3d_device)))
{
/* We want the sub resource parent here, since the view itself may be
* internal to wined3d and may not have a parent. */
surface_impl = wined3d_rendertarget_view_get_sub_resource_parent(wined3d_dsv);
*depth_stencil = &surface_impl->IDirect3DSurface8_iface;
IDirect3DSurface8_AddRef(*depth_stencil);
}
else
{
hr = D3DERR_NOTFOUND;
*depth_stencil = NULL;
}
wined3d_mutex_unlock();
return hr;
}
static HRESULT WINAPI d3d8_device_BeginScene(IDirect3DDevice8 *iface)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
HRESULT hr;
TRACE("iface %p.\n", iface);
wined3d_mutex_lock();
hr = wined3d_device_begin_scene(device->wined3d_device);
wined3d_mutex_unlock();
return hr;
}
static HRESULT WINAPI DECLSPEC_HOTPATCH d3d8_device_EndScene(IDirect3DDevice8 *iface)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
HRESULT hr;
TRACE("iface %p.\n", iface);
wined3d_mutex_lock();
hr = wined3d_device_end_scene(device->wined3d_device);
wined3d_mutex_unlock();
return hr;
}
static HRESULT WINAPI d3d8_device_Clear(IDirect3DDevice8 *iface, DWORD rect_count,
const D3DRECT *rects, DWORD flags, D3DCOLOR color, float z, DWORD stencil)
{
const struct wined3d_color c =
{
((color >> 16) & 0xff) / 255.0f,
((color >> 8) & 0xff) / 255.0f,
(color & 0xff) / 255.0f,
((color >> 24) & 0xff) / 255.0f,
};
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
HRESULT hr;
TRACE("iface %p, rect_count %u, rects %p, flags %#x, color 0x%08x, z %.8e, stencil %u.\n",
iface, rect_count, rects, flags, color, z, stencil);
if (rect_count && !rects)
{
WARN("count %u with NULL rects.\n", rect_count);
rect_count = 0;
}
wined3d_mutex_lock();
hr = wined3d_device_clear(device->wined3d_device, rect_count, (const RECT *)rects, flags, &c, z, stencil);
wined3d_mutex_unlock();
return hr;
}
static HRESULT WINAPI d3d8_device_SetTransform(IDirect3DDevice8 *iface,
D3DTRANSFORMSTATETYPE state, const D3DMATRIX *matrix)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
/* Note: D3DMATRIX is compatible with struct wined3d_matrix. */
wined3d_mutex_lock();
wined3d_device_set_transform(device->wined3d_device, state, (const struct wined3d_matrix *)matrix);
wined3d_mutex_unlock();
return D3D_OK;
}
static HRESULT WINAPI d3d8_device_GetTransform(IDirect3DDevice8 *iface,
D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
/* Note: D3DMATRIX is compatible with struct wined3d_matrix. */
wined3d_mutex_lock();
wined3d_device_get_transform(device->wined3d_device, state, (struct wined3d_matrix *)matrix);
wined3d_mutex_unlock();
return D3D_OK;
}
static HRESULT WINAPI d3d8_device_MultiplyTransform(IDirect3DDevice8 *iface,
D3DTRANSFORMSTATETYPE state, const D3DMATRIX *matrix)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
/* Note: D3DMATRIX is compatible with struct wined3d_matrix. */
wined3d_mutex_lock();
wined3d_device_multiply_transform(device->wined3d_device, state, (const struct wined3d_matrix *)matrix);
wined3d_mutex_unlock();
return D3D_OK;
}
static HRESULT WINAPI d3d8_device_SetViewport(IDirect3DDevice8 *iface, const D3DVIEWPORT8 *viewport)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
struct wined3d_viewport vp;
TRACE("iface %p, viewport %p.\n", iface, viewport);
vp.x = viewport->X;
vp.y = viewport->Y;
vp.width = viewport->Width;
vp.height = viewport->Height;
vp.min_z = viewport->MinZ;
vp.max_z = viewport->MaxZ;
wined3d_mutex_lock();
wined3d_device_set_viewport(device->wined3d_device, &vp);
wined3d_mutex_unlock();
return D3D_OK;
}
static HRESULT WINAPI d3d8_device_GetViewport(IDirect3DDevice8 *iface, D3DVIEWPORT8 *viewport)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
struct wined3d_viewport wined3d_viewport;
TRACE("iface %p, viewport %p.\n", iface, viewport);
wined3d_mutex_lock();
wined3d_device_get_viewport(device->wined3d_device, &wined3d_viewport);
wined3d_mutex_unlock();
viewport->X = wined3d_viewport.x;
viewport->Y = wined3d_viewport.y;
viewport->Width = wined3d_viewport.width;
viewport->Height = wined3d_viewport.height;
viewport->MinZ = wined3d_viewport.min_z;
viewport->MaxZ = wined3d_viewport.max_z;
return D3D_OK;
}
static HRESULT WINAPI d3d8_device_SetMaterial(IDirect3DDevice8 *iface, const D3DMATERIAL8 *material)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
TRACE("iface %p, material %p.\n", iface, material);
/* Note: D3DMATERIAL8 is compatible with struct wined3d_material. */
wined3d_mutex_lock();
wined3d_device_set_material(device->wined3d_device, (const struct wined3d_material *)material);
wined3d_mutex_unlock();
return D3D_OK;
}
static HRESULT WINAPI d3d8_device_GetMaterial(IDirect3DDevice8 *iface, D3DMATERIAL8 *material)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
TRACE("iface %p, material %p.\n", iface, material);
/* Note: D3DMATERIAL8 is compatible with struct wined3d_material. */
wined3d_mutex_lock();
wined3d_device_get_material(device->wined3d_device, (struct wined3d_material *)material);
wined3d_mutex_unlock();
return D3D_OK;
}
static HRESULT WINAPI d3d8_device_SetLight(IDirect3DDevice8 *iface, DWORD index, const D3DLIGHT8 *light)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
HRESULT hr;
TRACE("iface %p, index %u, light %p.\n", iface, index, light);
/* Note: D3DLIGHT8 is compatible with struct wined3d_light. */
wined3d_mutex_lock();
hr = wined3d_device_set_light(device->wined3d_device, index, (const struct wined3d_light *)light);
wined3d_mutex_unlock();
return hr;
}
static HRESULT WINAPI d3d8_device_GetLight(IDirect3DDevice8 *iface, DWORD index, D3DLIGHT8 *light)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
HRESULT hr;
TRACE("iface %p, index %u, light %p.\n", iface, index, light);
/* Note: D3DLIGHT8 is compatible with struct wined3d_light. */
wined3d_mutex_lock();
hr = wined3d_device_get_light(device->wined3d_device, index, (struct wined3d_light *)light);
wined3d_mutex_unlock();
return hr;
}
static HRESULT WINAPI d3d8_device_LightEnable(IDirect3DDevice8 *iface, DWORD index, BOOL enable)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
HRESULT hr;
TRACE("iface %p, index %u, enable %#x.\n", iface, index, enable);
wined3d_mutex_lock();
hr = wined3d_device_set_light_enable(device->wined3d_device, index, enable);
wined3d_mutex_unlock();
return hr;
}
static HRESULT WINAPI d3d8_device_GetLightEnable(IDirect3DDevice8 *iface, DWORD index, BOOL *enable)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
HRESULT hr;
TRACE("iface %p, index %u, enable %p.\n", iface, index, enable);
wined3d_mutex_lock();
hr = wined3d_device_get_light_enable(device->wined3d_device, index, enable);
wined3d_mutex_unlock();
return hr;
}
static HRESULT WINAPI d3d8_device_SetClipPlane(IDirect3DDevice8 *iface, DWORD index, const float *plane)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
HRESULT hr;
TRACE("iface %p, index %u, plane %p.\n", iface, index, plane);
wined3d_mutex_lock();
hr = wined3d_device_set_clip_plane(device->wined3d_device, index, (const struct wined3d_vec4 *)plane);
wined3d_mutex_unlock();
return hr;
}
static HRESULT WINAPI d3d8_device_GetClipPlane(IDirect3DDevice8 *iface, DWORD index, float *plane)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
HRESULT hr;
TRACE("iface %p, index %u, plane %p.\n", iface, index, plane);
wined3d_mutex_lock();
hr = wined3d_device_get_clip_plane(device->wined3d_device, index, (struct wined3d_vec4 *)plane);
wined3d_mutex_unlock();
return hr;
}
static HRESULT WINAPI d3d8_device_SetRenderState(IDirect3DDevice8 *iface,
D3DRENDERSTATETYPE state, DWORD value)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
TRACE("iface %p, state %#x, value %#x.\n", iface, state, value);
wined3d_mutex_lock();
switch (state)
{
case D3DRS_ZBIAS:
wined3d_device_set_render_state(device->wined3d_device, WINED3D_RS_DEPTHBIAS, value);
break;
default:
wined3d_device_set_render_state(device->wined3d_device, state, value);
}
wined3d_mutex_unlock();
return D3D_OK;
}
static HRESULT WINAPI d3d8_device_GetRenderState(IDirect3DDevice8 *iface,
D3DRENDERSTATETYPE state, DWORD *value)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
TRACE("iface %p, state %#x, value %p.\n", iface, state, value);
wined3d_mutex_lock();
switch (state)
{
case D3DRS_ZBIAS:
*value = wined3d_device_get_render_state(device->wined3d_device, WINED3D_RS_DEPTHBIAS);
break;
default:
*value = wined3d_device_get_render_state(device->wined3d_device, state);
}
wined3d_mutex_unlock();
return D3D_OK;
}
static HRESULT WINAPI d3d8_device_BeginStateBlock(IDirect3DDevice8 *iface)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
HRESULT hr;
TRACE("iface %p.\n", iface);
wined3d_mutex_lock();
hr = wined3d_device_begin_stateblock(device->wined3d_device);
wined3d_mutex_unlock();
return hr;
}
static HRESULT WINAPI d3d8_device_EndStateBlock(IDirect3DDevice8 *iface, DWORD *token)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
struct wined3d_stateblock *stateblock;
HRESULT hr;
TRACE("iface %p, token %p.\n", iface, token);
/* Tell wineD3D to endstateblock before anything else (in case we run out
* of memory later and cause locking problems)
*/
wined3d_mutex_lock();
hr = wined3d_device_end_stateblock(device->wined3d_device, &stateblock);
if (FAILED(hr))
{
WARN("Failed to end the state block, %#x.\n", hr);
wined3d_mutex_unlock();
return hr;
}
*token = d3d8_allocate_handle(&device->handle_table, stateblock, D3D8_HANDLE_SB);
wined3d_mutex_unlock();
if (*token == D3D8_INVALID_HANDLE)
{
ERR("Failed to create a handle\n");
wined3d_mutex_lock();
wined3d_stateblock_decref(stateblock);
wined3d_mutex_unlock();
return E_FAIL;
}
++*token;
TRACE("Returning %#x (%p).\n", *token, stateblock);
return hr;
}
static HRESULT WINAPI d3d8_device_ApplyStateBlock(IDirect3DDevice8 *iface, DWORD token)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
struct wined3d_stateblock *stateblock;
TRACE("iface %p, token %#x.\n", iface, token);
if (!token)
return D3D_OK;
wined3d_mutex_lock();
stateblock = d3d8_get_object(&device->handle_table, token - 1, D3D8_HANDLE_SB);
if (!stateblock)
{
WARN("Invalid handle (%#x) passed.\n", token);
wined3d_mutex_unlock();
return D3DERR_INVALIDCALL;
}
wined3d_stateblock_apply(stateblock);
wined3d_mutex_unlock();
return D3D_OK;
}
static HRESULT WINAPI d3d8_device_CaptureStateBlock(IDirect3DDevice8 *iface, DWORD token)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
struct wined3d_stateblock *stateblock;
TRACE("iface %p, token %#x.\n", iface, token);
wined3d_mutex_lock();
stateblock = d3d8_get_object(&device->handle_table, token - 1, D3D8_HANDLE_SB);
if (!stateblock)
{
WARN("Invalid handle (%#x) passed.\n", token);
wined3d_mutex_unlock();
return D3DERR_INVALIDCALL;
}
wined3d_stateblock_capture(stateblock);
wined3d_mutex_unlock();
return D3D_OK;
}
static HRESULT WINAPI d3d8_device_DeleteStateBlock(IDirect3DDevice8 *iface, DWORD token)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
struct wined3d_stateblock *stateblock;
TRACE("iface %p, token %#x.\n", iface, token);
wined3d_mutex_lock();
stateblock = d3d8_free_handle(&device->handle_table, token - 1, D3D8_HANDLE_SB);
if (!stateblock)
{
WARN("Invalid handle (%#x) passed.\n", token);
wined3d_mutex_unlock();
return D3DERR_INVALIDCALL;
}
if (wined3d_stateblock_decref(stateblock))
{
ERR("Stateblock %p has references left, this shouldn't happen.\n", stateblock);
}
wined3d_mutex_unlock();
return D3D_OK;
}
static HRESULT WINAPI d3d8_device_CreateStateBlock(IDirect3DDevice8 *iface,
D3DSTATEBLOCKTYPE type, DWORD *handle)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
struct wined3d_stateblock *stateblock;
HRESULT hr;
TRACE("iface %p, type %#x, handle %p.\n", iface, type, handle);
if (type != D3DSBT_ALL
&& type != D3DSBT_PIXELSTATE
&& type != D3DSBT_VERTEXSTATE)
{
WARN("Unexpected stateblock type, returning D3DERR_INVALIDCALL\n");
return D3DERR_INVALIDCALL;
}
wined3d_mutex_lock();
hr = wined3d_stateblock_create(device->wined3d_device, (enum wined3d_stateblock_type)type, &stateblock);
if (FAILED(hr))
{
wined3d_mutex_unlock();
ERR("Failed to create the state block, hr %#x\n", hr);
return hr;
}
*handle = d3d8_allocate_handle(&device->handle_table, stateblock, D3D8_HANDLE_SB);
wined3d_mutex_unlock();
if (*handle == D3D8_INVALID_HANDLE)
{
ERR("Failed to allocate a handle.\n");
wined3d_mutex_lock();
wined3d_stateblock_decref(stateblock);
wined3d_mutex_unlock();
return E_FAIL;
}
++*handle;
TRACE("Returning %#x (%p).\n", *handle, stateblock);
return hr;
}
static HRESULT WINAPI d3d8_device_SetClipStatus(IDirect3DDevice8 *iface, const D3DCLIPSTATUS8 *clip_status)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
HRESULT hr;
TRACE("iface %p, clip_status %p.\n", iface, clip_status);
/* FIXME: Verify that D3DCLIPSTATUS8 ~= struct wined3d_clip_status. */
wined3d_mutex_lock();
hr = wined3d_device_set_clip_status(device->wined3d_device, (const struct wined3d_clip_status *)clip_status);
wined3d_mutex_unlock();
return hr;
}
static HRESULT WINAPI d3d8_device_GetClipStatus(IDirect3DDevice8 *iface, D3DCLIPSTATUS8 *clip_status)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
HRESULT hr;
TRACE("iface %p, clip_status %p.\n", iface, clip_status);
wined3d_mutex_lock();
hr = wined3d_device_get_clip_status(device->wined3d_device, (struct wined3d_clip_status *)clip_status);
wined3d_mutex_unlock();
return hr;
}
static HRESULT WINAPI d3d8_device_GetTexture(IDirect3DDevice8 *iface, DWORD stage, IDirect3DBaseTexture8 **texture)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
struct wined3d_texture *wined3d_texture;
struct d3d8_texture *texture_impl;
TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
if (!texture)
return D3DERR_INVALIDCALL;
wined3d_mutex_lock();
if ((wined3d_texture = wined3d_device_get_texture(device->wined3d_device, stage)))
{
texture_impl = wined3d_texture_get_parent(wined3d_texture);
*texture = &texture_impl->IDirect3DBaseTexture8_iface;
IDirect3DBaseTexture8_AddRef(*texture);
}
else
{
*texture = NULL;
}
wined3d_mutex_unlock();
return D3D_OK;
}
static HRESULT WINAPI d3d8_device_SetTexture(IDirect3DDevice8 *iface, DWORD stage, IDirect3DBaseTexture8 *texture)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
struct d3d8_texture *texture_impl;
HRESULT hr;
TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
texture_impl = unsafe_impl_from_IDirect3DBaseTexture8(texture);
wined3d_mutex_lock();
hr = wined3d_device_set_texture(device->wined3d_device, stage,
texture_impl ? texture_impl->wined3d_texture : NULL);
wined3d_mutex_unlock();
return hr;
}
static const struct tss_lookup
{
BOOL sampler_state;
union
{
enum wined3d_texture_stage_state texture_state;
enum wined3d_sampler_state sampler_state;
} u;
}
tss_lookup[] =
{
{FALSE, {WINED3D_TSS_INVALID}}, /* 0, unused */
{FALSE, {WINED3D_TSS_COLOR_OP}}, /* 1, D3DTSS_COLOROP */
{FALSE, {WINED3D_TSS_COLOR_ARG1}}, /* 2, D3DTSS_COLORARG1 */
{FALSE, {WINED3D_TSS_COLOR_ARG2}}, /* 3, D3DTSS_COLORARG2 */
{FALSE, {WINED3D_TSS_ALPHA_OP}}, /* 4, D3DTSS_ALPHAOP */
{FALSE, {WINED3D_TSS_ALPHA_ARG1}}, /* 5, D3DTSS_ALPHAARG1 */
{FALSE, {WINED3D_TSS_ALPHA_ARG2}}, /* 6, D3DTSS_ALPHAARG2 */
{FALSE, {WINED3D_TSS_BUMPENV_MAT00}}, /* 7, D3DTSS_BUMPENVMAT00 */
{FALSE, {WINED3D_TSS_BUMPENV_MAT01}}, /* 8, D3DTSS_BUMPENVMAT01 */
{FALSE, {WINED3D_TSS_BUMPENV_MAT10}}, /* 9, D3DTSS_BUMPENVMAT10 */
{FALSE, {WINED3D_TSS_BUMPENV_MAT11}}, /* 10, D3DTSS_BUMPENVMAT11 */
{FALSE, {WINED3D_TSS_TEXCOORD_INDEX}}, /* 11, D3DTSS_TEXCOORDINDEX */
{FALSE, {WINED3D_TSS_INVALID}}, /* 12, unused */
{TRUE, {WINED3D_SAMP_ADDRESS_U}}, /* 13, D3DTSS_ADDRESSU */
{TRUE, {WINED3D_SAMP_ADDRESS_V}}, /* 14, D3DTSS_ADDRESSV */
{TRUE, {WINED3D_SAMP_BORDER_COLOR}}, /* 15, D3DTSS_BORDERCOLOR */
{TRUE, {WINED3D_SAMP_MAG_FILTER}}, /* 16, D3DTSS_MAGFILTER */
{TRUE, {WINED3D_SAMP_MIN_FILTER}}, /* 17, D3DTSS_MINFILTER */
{TRUE, {WINED3D_SAMP_MIP_FILTER}}, /* 18, D3DTSS_MIPFILTER */
{TRUE, {WINED3D_SAMP_MIPMAP_LOD_BIAS}}, /* 19, D3DTSS_MIPMAPLODBIAS */
{TRUE, {WINED3D_SAMP_MAX_MIP_LEVEL}}, /* 20, D3DTSS_MAXMIPLEVEL */
{TRUE, {WINED3D_SAMP_MAX_ANISOTROPY}}, /* 21, D3DTSS_MAXANISOTROPY */
{FALSE, {WINED3D_TSS_BUMPENV_LSCALE}}, /* 22, D3DTSS_BUMPENVLSCALE */
{FALSE, {WINED3D_TSS_BUMPENV_LOFFSET}}, /* 23, D3DTSS_BUMPENVLOFFSET */
{FALSE, {WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS}}, /* 24, D3DTSS_TEXTURETRANSFORMFLAGS */
{TRUE, {WINED3D_SAMP_ADDRESS_W}}, /* 25, D3DTSS_ADDRESSW */
{FALSE, {WINED3D_TSS_COLOR_ARG0}}, /* 26, D3DTSS_COLORARG0 */
{FALSE, {WINED3D_TSS_ALPHA_ARG0}}, /* 27, D3DTSS_ALPHAARG0 */
{FALSE, {WINED3D_TSS_RESULT_ARG}}, /* 28, D3DTSS_RESULTARG */
};
static HRESULT WINAPI d3d8_device_GetTextureStageState(IDirect3DDevice8 *iface,
DWORD stage, D3DTEXTURESTAGESTATETYPE Type, DWORD *value)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
const struct tss_lookup *l;
TRACE("iface %p, stage %u, state %#x, value %p.\n", iface, stage, Type, value);
if (Type >= sizeof(tss_lookup) / sizeof(*tss_lookup))
{
WARN("Invalid Type %#x passed.\n", Type);
return D3D_OK;
}
l = &tss_lookup[Type];
wined3d_mutex_lock();
if (l->sampler_state)
*value = wined3d_device_get_sampler_state(device->wined3d_device, stage, l->u.sampler_state);
else
*value = wined3d_device_get_texture_stage_state(device->wined3d_device, stage, l->u.texture_state);
wined3d_mutex_unlock();
return D3D_OK;
}
static HRESULT WINAPI d3d8_device_SetTextureStageState(IDirect3DDevice8 *iface,
DWORD stage, D3DTEXTURESTAGESTATETYPE type, DWORD value)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
const struct tss_lookup *l;
TRACE("iface %p, stage %u, state %#x, value %#x.\n", iface, stage, type, value);
if (type >= sizeof(tss_lookup) / sizeof(*tss_lookup))
{
WARN("Invalid type %#x passed.\n", type);
return D3D_OK;
}
l = &tss_lookup[type];
wined3d_mutex_lock();
if (l->sampler_state)
wined3d_device_set_sampler_state(device->wined3d_device, stage, l->u.sampler_state, value);
else
wined3d_device_set_texture_stage_state(device->wined3d_device, stage, l->u.texture_state, value);
wined3d_mutex_unlock();
return D3D_OK;
}
static HRESULT WINAPI d3d8_device_ValidateDevice(IDirect3DDevice8 *iface, DWORD *pass_count)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
HRESULT hr;
TRACE("iface %p, pass_count %p.\n", iface, pass_count);
wined3d_mutex_lock();
hr = wined3d_device_validate_device(device->wined3d_device, pass_count);
wined3d_mutex_unlock();
return hr;
}
static HRESULT WINAPI d3d8_device_GetInfo(IDirect3DDevice8 *iface,
DWORD info_id, void *info, DWORD info_size)
{
FIXME("iface %p, info_id %#x, info %p, info_size %u stub!\n", iface, info_id, info, info_size);
return D3D_OK;
}
static HRESULT WINAPI d3d8_device_SetPaletteEntries(IDirect3DDevice8 *iface,
UINT palette_idx, const PALETTEENTRY *entries)
{
WARN("iface %p, palette_idx %u, entries %p unimplemented\n", iface, palette_idx, entries);
/* GPUs stopped supporting palettized textures with the Shader Model 1 generation. Wined3d
* does not have a d3d8/9-style palette API */
return D3D_OK;
}
static HRESULT WINAPI d3d8_device_GetPaletteEntries(IDirect3DDevice8 *iface,
UINT palette_idx, PALETTEENTRY *entries)
{
FIXME("iface %p, palette_idx %u, entries %p unimplemented.\n", iface, palette_idx, entries);
return D3DERR_INVALIDCALL;
}
static HRESULT WINAPI d3d8_device_SetCurrentTexturePalette(IDirect3DDevice8 *iface, UINT palette_idx)
{
WARN("iface %p, palette_idx %u unimplemented.\n", iface, palette_idx);
return D3D_OK;
}
static HRESULT WINAPI d3d8_device_GetCurrentTexturePalette(IDirect3DDevice8 *iface, UINT *palette_idx)
{
FIXME("iface %p, palette_idx %p unimplemented.\n", iface, palette_idx);
return D3DERR_INVALIDCALL;
}
static HRESULT WINAPI d3d8_device_DrawPrimitive(IDirect3DDevice8 *iface,
D3DPRIMITIVETYPE primitive_type, UINT start_vertex, UINT primitive_count)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
HRESULT hr;
TRACE("iface %p, primitive_type %#x, start_vertex %u, primitive_count %u.\n",
iface, primitive_type, start_vertex, primitive_count);
wined3d_mutex_lock();
wined3d_device_set_primitive_type(device->wined3d_device, primitive_type, 0);
hr = wined3d_device_draw_primitive(device->wined3d_device, start_vertex,
vertex_count_from_primitive_count(primitive_type, primitive_count));
wined3d_mutex_unlock();
return hr;
}
static HRESULT WINAPI d3d8_device_DrawIndexedPrimitive(IDirect3DDevice8 *iface,
D3DPRIMITIVETYPE primitive_type, UINT min_vertex_idx, UINT vertex_count,
UINT start_idx, UINT primitive_count)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
HRESULT hr;
TRACE("iface %p, primitive_type %#x, min_vertex_idx %u, vertex_count %u, start_idx %u, primitive_count %u.\n",
iface, primitive_type, min_vertex_idx, vertex_count, start_idx, primitive_count);
wined3d_mutex_lock();
wined3d_device_set_primitive_type(device->wined3d_device, primitive_type, 0);
hr = wined3d_device_draw_indexed_primitive(device->wined3d_device, start_idx,
vertex_count_from_primitive_count(primitive_type, primitive_count));
wined3d_mutex_unlock();
return hr;
}
/* The caller is responsible for wined3d locking */
static HRESULT d3d8_device_prepare_vertex_buffer(struct d3d8_device *device, UINT min_size)
{
HRESULT hr;
if (device->vertex_buffer_size < min_size || !device->vertex_buffer)
{
UINT size = max(device->vertex_buffer_size * 2, min_size);
struct wined3d_buffer_desc desc;
struct wined3d_buffer *buffer;
TRACE("Growing vertex buffer to %u bytes\n", size);
desc.byte_width = size;
desc.usage = WINED3DUSAGE_DYNAMIC | WINED3DUSAGE_WRITEONLY;
desc.bind_flags = WINED3D_BIND_VERTEX_BUFFER;
desc.access = WINED3D_RESOURCE_ACCESS_GPU | WINED3D_RESOURCE_ACCESS_MAP_R | WINED3D_RESOURCE_ACCESS_MAP_W;
desc.misc_flags = 0;
desc.structure_byte_stride = 0;
if (FAILED(hr = wined3d_buffer_create(device->wined3d_device, &desc,
NULL, NULL, &d3d8_null_wined3d_parent_ops, &buffer)))
{
ERR("Failed to create vertex buffer, hr %#x.\n", hr);
return hr;
}
if (device->vertex_buffer)
wined3d_buffer_decref(device->vertex_buffer);
device->vertex_buffer = buffer;
device->vertex_buffer_size = size;
device->vertex_buffer_pos = 0;
}
return D3D_OK;
}
static HRESULT WINAPI d3d8_device_DrawPrimitiveUP(IDirect3DDevice8 *iface,
D3DPRIMITIVETYPE primitive_type, UINT primitive_count, const void *data,
UINT stride)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
HRESULT hr;
UINT vtx_count = vertex_count_from_primitive_count(primitive_type, primitive_count);
struct wined3d_map_desc wined3d_map_desc;
struct wined3d_box wined3d_box = {0};
UINT size = vtx_count * stride;
struct wined3d_resource *vb;
UINT vb_pos, align;
TRACE("iface %p, primitive_type %#x, primitive_count %u, data %p, stride %u.\n",
iface, primitive_type, primitive_count, data, stride);
if (!primitive_count)
{
WARN("primitive_count is 0, returning D3D_OK\n");
return D3D_OK;
}
wined3d_mutex_lock();
hr = d3d8_device_prepare_vertex_buffer(device, size);
if (FAILED(hr))
goto done;
vb_pos = device->vertex_buffer_pos;
align = vb_pos % stride;
if (align) align = stride - align;
if (vb_pos + size + align > device->vertex_buffer_size)
vb_pos = 0;
else
vb_pos += align;
wined3d_box.left = vb_pos;
wined3d_box.right = vb_pos + size;
vb = wined3d_buffer_get_resource(device->vertex_buffer);
if (FAILED(wined3d_resource_map(vb, 0, &wined3d_map_desc, &wined3d_box,
WINED3D_MAP_WRITE | (vb_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD))))
goto done;
memcpy(wined3d_map_desc.data, data, size);
wined3d_resource_unmap(vb, 0);
device->vertex_buffer_pos = vb_pos + size;
hr = wined3d_device_set_stream_source(device->wined3d_device, 0, device->vertex_buffer, 0, stride);
if (FAILED(hr))
goto done;
wined3d_device_set_primitive_type(device->wined3d_device, primitive_type, 0);
hr = wined3d_device_draw_primitive(device->wined3d_device, vb_pos / stride, vtx_count);
wined3d_device_set_stream_source(device->wined3d_device, 0, NULL, 0, 0);
done:
wined3d_mutex_unlock();
return hr;
}
/* The caller is responsible for wined3d locking */
static HRESULT d3d8_device_prepare_index_buffer(struct d3d8_device *device, UINT min_size)
{
HRESULT hr;
if (device->index_buffer_size < min_size || !device->index_buffer)
{
UINT size = max(device->index_buffer_size * 2, min_size);
struct wined3d_buffer_desc desc;
struct wined3d_buffer *buffer;
TRACE("Growing index buffer to %u bytes\n", size);
desc.byte_width = size;
desc.usage = WINED3DUSAGE_DYNAMIC | WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_STATICDECL;
desc.bind_flags = WINED3D_BIND_INDEX_BUFFER;
desc.access = WINED3D_RESOURCE_ACCESS_GPU | WINED3D_RESOURCE_ACCESS_MAP_R | WINED3D_RESOURCE_ACCESS_MAP_W;
desc.misc_flags = 0;
desc.structure_byte_stride = 0;
if (FAILED(hr = wined3d_buffer_create(device->wined3d_device, &desc,
NULL, NULL, &d3d8_null_wined3d_parent_ops, &buffer)))
{
ERR("Failed to create index buffer, hr %#x.\n", hr);
return hr;
}
if (device->index_buffer)
wined3d_buffer_decref(device->index_buffer);
device->index_buffer = buffer;
device->index_buffer_size = size;
device->index_buffer_pos = 0;
}
return D3D_OK;
}
static HRESULT WINAPI d3d8_device_DrawIndexedPrimitiveUP(IDirect3DDevice8 *iface,
D3DPRIMITIVETYPE primitive_type, UINT min_vertex_idx, UINT vertex_count,
UINT primitive_count, const void *index_data, D3DFORMAT index_format,
const void *vertex_data, UINT vertex_stride)
{
UINT idx_count = vertex_count_from_primitive_count(primitive_type, primitive_count);
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
UINT idx_fmt_size = index_format == D3DFMT_INDEX16 ? 2 : 4;
UINT vtx_size = vertex_count * vertex_stride;
UINT idx_size = idx_count * idx_fmt_size;
struct wined3d_map_desc wined3d_map_desc;
struct wined3d_box wined3d_box = {0};
struct wined3d_resource *ib, *vb;
UINT vb_pos, ib_pos, align;
HRESULT hr;
TRACE("iface %p, primitive_type %#x, min_vertex_idx %u, vertex_count %u, primitive_count %u, "
"index_data %p, index_format %#x, vertex_data %p, vertex_stride %u.\n",
iface, primitive_type, min_vertex_idx, vertex_count, primitive_count,
index_data, index_format, vertex_data, vertex_stride);
if (!primitive_count)
{
WARN("primitive_count is 0, returning D3D_OK\n");
return D3D_OK;
}
wined3d_mutex_lock();
hr = d3d8_device_prepare_vertex_buffer(device, vtx_size);
if (FAILED(hr))
goto done;
vb_pos = device->vertex_buffer_pos;
align = vb_pos % vertex_stride;
if (align) align = vertex_stride - align;
if (vb_pos + vtx_size + align > device->vertex_buffer_size)
vb_pos = 0;
else
vb_pos += align;
wined3d_box.left = vb_pos;
wined3d_box.right = vb_pos + vtx_size;
vb = wined3d_buffer_get_resource(device->vertex_buffer);
if (FAILED(hr = wined3d_resource_map(vb, 0, &wined3d_map_desc, &wined3d_box,
WINED3D_MAP_WRITE | (vb_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD))))
goto done;
memcpy(wined3d_map_desc.data, (char *)vertex_data + min_vertex_idx * vertex_stride, vtx_size);
wined3d_resource_unmap(vb, 0);
device->vertex_buffer_pos = vb_pos + vtx_size;
hr = d3d8_device_prepare_index_buffer(device, idx_size);
if (FAILED(hr))
goto done;
ib_pos = device->index_buffer_pos;
align = ib_pos % idx_fmt_size;
if (align) align = idx_fmt_size - align;
if (ib_pos + idx_size + align > device->index_buffer_size)
ib_pos = 0;
else
ib_pos += align;
wined3d_box.left = ib_pos;
wined3d_box.right = ib_pos + idx_size;
ib = wined3d_buffer_get_resource(device->index_buffer);
if (FAILED(hr = wined3d_resource_map(ib, 0, &wined3d_map_desc, &wined3d_box,
WINED3D_MAP_WRITE | (ib_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD))))
goto done;
memcpy(wined3d_map_desc.data, index_data, idx_size);
wined3d_resource_unmap(ib, 0);
device->index_buffer_pos = ib_pos + idx_size;
hr = wined3d_device_set_stream_source(device->wined3d_device, 0, device->vertex_buffer, 0, vertex_stride);
if (FAILED(hr))
goto done;
wined3d_device_set_index_buffer(device->wined3d_device, device->index_buffer,
wined3dformat_from_d3dformat(index_format), 0);
wined3d_device_set_base_vertex_index(device->wined3d_device, vb_pos / vertex_stride - min_vertex_idx);
wined3d_device_set_primitive_type(device->wined3d_device, primitive_type, 0);
hr = wined3d_device_draw_indexed_primitive(device->wined3d_device, ib_pos / idx_fmt_size, idx_count);
wined3d_device_set_stream_source(device->wined3d_device, 0, NULL, 0, 0);
wined3d_device_set_index_buffer(device->wined3d_device, NULL, WINED3DFMT_UNKNOWN, 0);
wined3d_device_set_base_vertex_index(device->wined3d_device, 0);
done:
wined3d_mutex_unlock();
return hr;
}
static HRESULT WINAPI d3d8_device_ProcessVertices(IDirect3DDevice8 *iface, UINT src_start_idx,
UINT dst_idx, UINT vertex_count, IDirect3DVertexBuffer8 *dst_buffer, DWORD flags)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
struct d3d8_vertexbuffer *dst = unsafe_impl_from_IDirect3DVertexBuffer8(dst_buffer);
HRESULT hr;
TRACE("iface %p, src_start_idx %u, dst_idx %u, vertex_count %u, dst_buffer %p, flags %#x.\n",
iface, src_start_idx, dst_idx, vertex_count, dst_buffer, flags);
wined3d_mutex_lock();
hr = wined3d_device_process_vertices(device->wined3d_device, src_start_idx, dst_idx,
vertex_count, dst->wined3d_buffer, NULL, flags, dst->fvf);
wined3d_mutex_unlock();
return hr;
}
static HRESULT WINAPI d3d8_device_CreateVertexShader(IDirect3DDevice8 *iface,
const DWORD *declaration, const DWORD *byte_code, DWORD *shader, DWORD usage)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
struct d3d8_vertex_shader *object;
DWORD shader_handle;
DWORD handle;
HRESULT hr;
TRACE("iface %p, declaration %p, byte_code %p, shader %p, usage %#x.\n",
iface, declaration, byte_code, shader, usage);
if (!(object = heap_alloc_zero(sizeof(*object))))
{
*shader = 0;
return E_OUTOFMEMORY;
}
wined3d_mutex_lock();
handle = d3d8_allocate_handle(&device->handle_table, object, D3D8_HANDLE_VS);
wined3d_mutex_unlock();
if (handle == D3D8_INVALID_HANDLE)
{
ERR("Failed to allocate vertex shader handle.\n");
heap_free(object);
*shader = 0;
return E_OUTOFMEMORY;
}
shader_handle = handle + VS_HIGHESTFIXEDFXF + 1;
hr = d3d8_vertex_shader_init(object, device, declaration, byte_code, shader_handle, usage);
if (FAILED(hr))
{
WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
wined3d_mutex_lock();
d3d8_free_handle(&device->handle_table, handle, D3D8_HANDLE_VS);
wined3d_mutex_unlock();
heap_free(object);
*shader = 0;
return hr;
}
TRACE("Created vertex shader %p (handle %#x).\n", object, shader_handle);
*shader = shader_handle;
return D3D_OK;
}
static struct d3d8_vertex_declaration *d3d8_device_get_fvf_declaration(struct d3d8_device *device, DWORD fvf)
{
struct d3d8_vertex_declaration *d3d8_declaration;
struct FvfToDecl *convertedDecls = device->decls;
int p, low, high; /* deliberately signed */
HRESULT hr;
TRACE("Searching for declaration for fvf %08x... ", fvf);
low = 0;
high = device->numConvertedDecls - 1;
while (low <= high)
{
p = (low + high) >> 1;
TRACE("%d ", p);
if (convertedDecls[p].fvf == fvf)
{
TRACE("found %p\n", convertedDecls[p].declaration);
return convertedDecls[p].declaration;
}
if (convertedDecls[p].fvf < fvf)
low = p + 1;
else
high = p - 1;
}
TRACE("not found. Creating and inserting at position %d.\n", low);
if (!(d3d8_declaration = heap_alloc(sizeof(*d3d8_declaration))))
return NULL;
if (FAILED(hr = d3d8_vertex_declaration_init_fvf(d3d8_declaration, device, fvf)))
{
WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
heap_free(d3d8_declaration);
return NULL;
}
if (device->declArraySize == device->numConvertedDecls)
{
UINT grow = device->declArraySize / 2;
if (!(convertedDecls = heap_realloc(convertedDecls,
sizeof(*convertedDecls) * (device->numConvertedDecls + grow))))
{
d3d8_vertex_declaration_destroy(d3d8_declaration);
return NULL;
}
device->decls = convertedDecls;
device->declArraySize += grow;
}
memmove(convertedDecls + low + 1, convertedDecls + low,
sizeof(*convertedDecls) * (device->numConvertedDecls - low));
convertedDecls[low].declaration = d3d8_declaration;
convertedDecls[low].fvf = fvf;
++device->numConvertedDecls;
TRACE("Returning %p. %u decls in array.\n", d3d8_declaration, device->numConvertedDecls);
return d3d8_declaration;
}
static HRESULT WINAPI d3d8_device_SetVertexShader(IDirect3DDevice8 *iface, DWORD shader)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
struct d3d8_vertex_shader *shader_impl;
TRACE("iface %p, shader %#x.\n", iface, shader);
if (VS_HIGHESTFIXEDFXF >= shader)
{
TRACE("Setting FVF, %#x\n", shader);
wined3d_mutex_lock();
wined3d_device_set_vertex_declaration(device->wined3d_device,
d3d8_device_get_fvf_declaration(device, shader)->wined3d_vertex_declaration);
wined3d_device_set_vertex_shader(device->wined3d_device, NULL);
wined3d_mutex_unlock();
return D3D_OK;
}
TRACE("Setting shader\n");
wined3d_mutex_lock();
if (!(shader_impl = d3d8_get_object(&device->handle_table, shader - (VS_HIGHESTFIXEDFXF + 1), D3D8_HANDLE_VS)))
{
WARN("Invalid handle (%#x) passed.\n", shader);
wined3d_mutex_unlock();
return D3DERR_INVALIDCALL;
}
wined3d_device_set_vertex_declaration(device->wined3d_device,
shader_impl->vertex_declaration->wined3d_vertex_declaration);
wined3d_device_set_vertex_shader(device->wined3d_device, shader_impl->wined3d_shader);
wined3d_mutex_unlock();
return D3D_OK;
}
static HRESULT WINAPI d3d8_device_GetVertexShader(IDirect3DDevice8 *iface, DWORD *shader)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
struct wined3d_vertex_declaration *wined3d_declaration;
struct d3d8_vertex_declaration *d3d8_declaration;
TRACE("iface %p, shader %p.\n", iface, shader);
wined3d_mutex_lock();
if ((wined3d_declaration = wined3d_device_get_vertex_declaration(device->wined3d_device)))
{
d3d8_declaration = wined3d_vertex_declaration_get_parent(wined3d_declaration);
*shader = d3d8_declaration->shader_handle;
}
else
{
*shader = 0;
}
wined3d_mutex_unlock();
TRACE("Returning %#x.\n", *shader);
return D3D_OK;
}
static HRESULT WINAPI d3d8_device_DeleteVertexShader(IDirect3DDevice8 *iface, DWORD shader)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
struct d3d8_vertex_shader *shader_impl;
TRACE("iface %p, shader %#x.\n", iface, shader);
wined3d_mutex_lock();
if (!(shader_impl = d3d8_free_handle(&device->handle_table, shader - (VS_HIGHESTFIXEDFXF + 1), D3D8_HANDLE_VS)))
{
WARN("Invalid handle (%#x) passed.\n", shader);
wined3d_mutex_unlock();
return D3DERR_INVALIDCALL;
}
if (shader_impl->wined3d_shader
&& wined3d_device_get_vertex_shader(device->wined3d_device) == shader_impl->wined3d_shader)
IDirect3DDevice8_SetVertexShader(iface, 0);
wined3d_mutex_unlock();
d3d8_vertex_shader_destroy(shader_impl);
return D3D_OK;
}
static HRESULT WINAPI d3d8_device_SetVertexShaderConstant(IDirect3DDevice8 *iface,
DWORD start_register, const void *data, DWORD count)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
HRESULT hr;
TRACE("iface %p, start_register %u, data %p, count %u.\n",
iface, start_register, data, count);
if (start_register + count > D3D8_MAX_VERTEX_SHADER_CONSTANTF)
{
WARN("Trying to access %u constants, but d3d8 only supports %u\n",
start_register + count, D3D8_MAX_VERTEX_SHADER_CONSTANTF);
return D3DERR_INVALIDCALL;
}
wined3d_mutex_lock();
hr = wined3d_device_set_vs_consts_f(device->wined3d_device, start_register, count, data);
wined3d_mutex_unlock();
return hr;
}
static HRESULT WINAPI d3d8_device_GetVertexShaderConstant(IDirect3DDevice8 *iface,
DWORD start_register, void *data, DWORD count)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
HRESULT hr;
TRACE("iface %p, start_register %u, data %p, count %u.\n",
iface, start_register, data, count);
if (start_register + count > D3D8_MAX_VERTEX_SHADER_CONSTANTF)
{
WARN("Trying to access %u constants, but d3d8 only supports %u\n",
start_register + count, D3D8_MAX_VERTEX_SHADER_CONSTANTF);
return D3DERR_INVALIDCALL;
}
wined3d_mutex_lock();
hr = wined3d_device_get_vs_consts_f(device->wined3d_device, start_register, count, data);
wined3d_mutex_unlock();
return hr;
}
static HRESULT WINAPI d3d8_device_GetVertexShaderDeclaration(IDirect3DDevice8 *iface,
DWORD shader, void *data, DWORD *data_size)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
struct d3d8_vertex_declaration *declaration;
struct d3d8_vertex_shader *shader_impl;
TRACE("iface %p, shader %#x, data %p, data_size %p.\n",
iface, shader, data, data_size);
wined3d_mutex_lock();
shader_impl = d3d8_get_object(&device->handle_table, shader - (VS_HIGHESTFIXEDFXF + 1), D3D8_HANDLE_VS);
wined3d_mutex_unlock();
if (!shader_impl)
{
WARN("Invalid handle (%#x) passed.\n", shader);
return D3DERR_INVALIDCALL;
}
declaration = shader_impl->vertex_declaration;
if (!data)
{
*data_size = declaration->elements_size;
return D3D_OK;
}
/* MSDN claims that if *data_size is smaller than the required size
* we should write the required size and return D3DERR_MOREDATA.
* That's not actually true. */
if (*data_size < declaration->elements_size)
return D3DERR_INVALIDCALL;
memcpy(data, declaration->elements, declaration->elements_size);
return D3D_OK;
}
static HRESULT WINAPI d3d8_device_GetVertexShaderFunction(IDirect3DDevice8 *iface,
DWORD shader, void *data, DWORD *data_size)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
struct d3d8_vertex_shader *shader_impl = NULL;
HRESULT hr;
TRACE("iface %p, shader %#x, data %p, data_size %p.\n",
iface, shader, data, data_size);
wined3d_mutex_lock();
if (!(shader_impl = d3d8_get_object(&device->handle_table, shader - (VS_HIGHESTFIXEDFXF + 1), D3D8_HANDLE_VS)))
{
WARN("Invalid handle (%#x) passed.\n", shader);
wined3d_mutex_unlock();
return D3DERR_INVALIDCALL;
}
if (!shader_impl->wined3d_shader)
{
wined3d_mutex_unlock();
*data_size = 0;
return D3D_OK;
}
hr = wined3d_shader_get_byte_code(shader_impl->wined3d_shader, data, data_size);
wined3d_mutex_unlock();
return hr;
}
static HRESULT WINAPI d3d8_device_SetIndices(IDirect3DDevice8 *iface,
IDirect3DIndexBuffer8 *buffer, UINT base_vertex_idx)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
struct d3d8_indexbuffer *ib = unsafe_impl_from_IDirect3DIndexBuffer8(buffer);
TRACE("iface %p, buffer %p, base_vertex_idx %u.\n", iface, buffer, base_vertex_idx);
/* WineD3D takes an INT(due to d3d9), but d3d8 uses UINTs. Do I have to add a check here that
* the UINT doesn't cause an overflow in the INT? It seems rather unlikely because such large
* vertex buffers can't be created to address them with an index that requires the 32nd bit
* (4 Byte minimum vertex size * 2^31-1 -> 8 gb buffer. The index sign would be the least
* problem)
*/
wined3d_mutex_lock();
wined3d_device_set_base_vertex_index(device->wined3d_device, base_vertex_idx);
wined3d_device_set_index_buffer(device->wined3d_device,
ib ? ib->wined3d_buffer : NULL, ib ? ib->format : WINED3DFMT_UNKNOWN, 0);
wined3d_mutex_unlock();
return D3D_OK;
}
static HRESULT WINAPI d3d8_device_GetIndices(IDirect3DDevice8 *iface,
IDirect3DIndexBuffer8 **buffer, UINT *base_vertex_index)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
enum wined3d_format_id wined3d_format;
struct wined3d_buffer *wined3d_buffer;
struct d3d8_indexbuffer *buffer_impl;
TRACE("iface %p, buffer %p, base_vertex_index %p.\n", iface, buffer, base_vertex_index);
if (!buffer)
return D3DERR_INVALIDCALL;
/* The case from UINT to INT is safe because d3d8 will never set negative values */
wined3d_mutex_lock();
*base_vertex_index = wined3d_device_get_base_vertex_index(device->wined3d_device);
if ((wined3d_buffer = wined3d_device_get_index_buffer(device->wined3d_device, &wined3d_format, NULL)))
{
buffer_impl = wined3d_buffer_get_parent(wined3d_buffer);
*buffer = &buffer_impl->IDirect3DIndexBuffer8_iface;
IDirect3DIndexBuffer8_AddRef(*buffer);
}
else
{
*buffer = NULL;
}
wined3d_mutex_unlock();
return D3D_OK;
}
static HRESULT WINAPI d3d8_device_CreatePixelShader(IDirect3DDevice8 *iface,
const DWORD *byte_code, DWORD *shader)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
struct d3d8_pixel_shader *object;
DWORD shader_handle;
DWORD handle;
HRESULT hr;
TRACE("iface %p, byte_code %p, shader %p.\n", iface, byte_code, shader);
if (!shader)
return D3DERR_INVALIDCALL;
if (!(object = heap_alloc_zero(sizeof(*object))))
return E_OUTOFMEMORY;
wined3d_mutex_lock();
handle = d3d8_allocate_handle(&device->handle_table, object, D3D8_HANDLE_PS);
wined3d_mutex_unlock();
if (handle == D3D8_INVALID_HANDLE)
{
ERR("Failed to allocate pixel shader handle.\n");
heap_free(object);
return E_OUTOFMEMORY;
}
shader_handle = handle + VS_HIGHESTFIXEDFXF + 1;
hr = d3d8_pixel_shader_init(object, device, byte_code, shader_handle);
if (FAILED(hr))
{
WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
wined3d_mutex_lock();
d3d8_free_handle(&device->handle_table, handle, D3D8_HANDLE_PS);
wined3d_mutex_unlock();
heap_free(object);
*shader = 0;
return hr;
}
TRACE("Created pixel shader %p (handle %#x).\n", object, shader_handle);
*shader = shader_handle;
return D3D_OK;
}
static HRESULT WINAPI d3d8_device_SetPixelShader(IDirect3DDevice8 *iface, DWORD shader)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
struct d3d8_pixel_shader *shader_impl;
TRACE("iface %p, shader %#x.\n", iface, shader);
wined3d_mutex_lock();
if (!shader)
{
wined3d_device_set_pixel_shader(device->wined3d_device, NULL);
wined3d_mutex_unlock();
return D3D_OK;
}
if (!(shader_impl = d3d8_get_object(&device->handle_table, shader - (VS_HIGHESTFIXEDFXF + 1), D3D8_HANDLE_PS)))
{
WARN("Invalid handle (%#x) passed.\n", shader);
wined3d_mutex_unlock();
return D3DERR_INVALIDCALL;
}
TRACE("Setting shader %p.\n", shader_impl);
wined3d_device_set_pixel_shader(device->wined3d_device, shader_impl->wined3d_shader);
wined3d_mutex_unlock();
return D3D_OK;
}
static HRESULT WINAPI d3d8_device_GetPixelShader(IDirect3DDevice8 *iface, DWORD *shader)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
struct wined3d_shader *object;
TRACE("iface %p, shader %p.\n", iface, shader);
if (!shader)
return D3DERR_INVALIDCALL;
wined3d_mutex_lock();
if ((object = wined3d_device_get_pixel_shader(device->wined3d_device)))
{
struct d3d8_pixel_shader *d3d8_shader;
d3d8_shader = wined3d_shader_get_parent(object);
*shader = d3d8_shader->handle;
}
else
{
*shader = 0;
}
wined3d_mutex_unlock();
TRACE("Returning %#x.\n", *shader);
return D3D_OK;
}
static HRESULT WINAPI d3d8_device_DeletePixelShader(IDirect3DDevice8 *iface, DWORD shader)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
struct d3d8_pixel_shader *shader_impl;
TRACE("iface %p, shader %#x.\n", iface, shader);
wined3d_mutex_lock();
if (!(shader_impl = d3d8_free_handle(&device->handle_table, shader - (VS_HIGHESTFIXEDFXF + 1), D3D8_HANDLE_PS)))
{
WARN("Invalid handle (%#x) passed.\n", shader);
wined3d_mutex_unlock();
return D3DERR_INVALIDCALL;
}
if (wined3d_device_get_pixel_shader(device->wined3d_device) == shader_impl->wined3d_shader)
IDirect3DDevice8_SetPixelShader(iface, 0);
wined3d_mutex_unlock();
d3d8_pixel_shader_destroy(shader_impl);
return D3D_OK;
}
static HRESULT WINAPI d3d8_device_SetPixelShaderConstant(IDirect3DDevice8 *iface,
DWORD start_register, const void *data, DWORD count)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
HRESULT hr;
TRACE("iface %p, start_register %u, data %p, count %u.\n",
iface, start_register, data, count);
wined3d_mutex_lock();
hr = wined3d_device_set_ps_consts_f(device->wined3d_device, start_register, count, data);
wined3d_mutex_unlock();
return hr;
}
static HRESULT WINAPI d3d8_device_GetPixelShaderConstant(IDirect3DDevice8 *iface,
DWORD start_register, void *data, DWORD count)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
HRESULT hr;
TRACE("iface %p, start_register %u, data %p, count %u.\n",
iface, start_register, data, count);
wined3d_mutex_lock();
hr = wined3d_device_get_ps_consts_f(device->wined3d_device, start_register, count, data);
wined3d_mutex_unlock();
return hr;
}
static HRESULT WINAPI d3d8_device_GetPixelShaderFunction(IDirect3DDevice8 *iface,
DWORD shader, void *data, DWORD *data_size)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
struct d3d8_pixel_shader *shader_impl = NULL;
HRESULT hr;
TRACE("iface %p, shader %#x, data %p, data_size %p.\n",
iface, shader, data, data_size);
wined3d_mutex_lock();
if (!(shader_impl = d3d8_get_object(&device->handle_table, shader - (VS_HIGHESTFIXEDFXF + 1), D3D8_HANDLE_PS)))
{
WARN("Invalid handle (%#x) passed.\n", shader);
wined3d_mutex_unlock();
return D3DERR_INVALIDCALL;
}
hr = wined3d_shader_get_byte_code(shader_impl->wined3d_shader, data, data_size);
wined3d_mutex_unlock();
return hr;
}
static HRESULT WINAPI d3d8_device_DrawRectPatch(IDirect3DDevice8 *iface, UINT handle,
const float *segment_count, const D3DRECTPATCH_INFO *patch_info)
{
FIXME("iface %p, handle %#x, segment_count %p, patch_info %p unimplemented.\n",
iface, handle, segment_count, patch_info);
return D3D_OK;
}
static HRESULT WINAPI d3d8_device_DrawTriPatch(IDirect3DDevice8 *iface, UINT handle,
const float *segment_count, const D3DTRIPATCH_INFO *patch_info)
{
FIXME("iface %p, handle %#x, segment_count %p, patch_info %p unimplemented.\n",
iface, handle, segment_count, patch_info);
return D3D_OK;
}
static HRESULT WINAPI d3d8_device_DeletePatch(IDirect3DDevice8 *iface, UINT handle)
{
FIXME("iface %p, handle %#x unimplemented.\n", iface, handle);
return D3DERR_INVALIDCALL;
}
static HRESULT WINAPI d3d8_device_SetStreamSource(IDirect3DDevice8 *iface,
UINT stream_idx, IDirect3DVertexBuffer8 *buffer, UINT stride)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
struct d3d8_vertexbuffer *buffer_impl = unsafe_impl_from_IDirect3DVertexBuffer8(buffer);
HRESULT hr;
TRACE("iface %p, stream_idx %u, buffer %p, stride %u.\n",
iface, stream_idx, buffer, stride);
wined3d_mutex_lock();
hr = wined3d_device_set_stream_source(device->wined3d_device, stream_idx,
buffer_impl ? buffer_impl->wined3d_buffer : NULL, 0, stride);
wined3d_mutex_unlock();
return hr;
}
static HRESULT WINAPI d3d8_device_GetStreamSource(IDirect3DDevice8 *iface,
UINT stream_idx, IDirect3DVertexBuffer8 **buffer, UINT *stride)
{
struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
struct d3d8_vertexbuffer *buffer_impl;
struct wined3d_buffer *wined3d_buffer = NULL;
HRESULT hr;
TRACE("iface %p, stream_idx %u, buffer %p, stride %p.\n",
iface, stream_idx, buffer, stride);
if (!buffer)
return D3DERR_INVALIDCALL;
wined3d_mutex_lock();
hr = wined3d_device_get_stream_source(device->wined3d_device, stream_idx, &wined3d_buffer, 0, stride);
if (SUCCEEDED(hr) && wined3d_buffer)
{
buffer_impl = wined3d_buffer_get_parent(wined3d_buffer);
*buffer = &buffer_impl->IDirect3DVertexBuffer8_iface;
IDirect3DVertexBuffer8_AddRef(*buffer);
}
else
{
if (FAILED(hr))
ERR("Failed to get wined3d stream source, hr %#x.\n", hr);
*buffer = NULL;
}
wined3d_mutex_unlock();
return hr;
}
static const struct IDirect3DDevice8Vtbl d3d8_device_vtbl =
{
d3d8_device_QueryInterface,
d3d8_device_AddRef,
d3d8_device_Release,
d3d8_device_TestCooperativeLevel,
d3d8_device_GetAvailableTextureMem,
d3d8_device_ResourceManagerDiscardBytes,
d3d8_device_GetDirect3D,
d3d8_device_GetDeviceCaps,
d3d8_device_GetDisplayMode,
d3d8_device_GetCreationParameters,
d3d8_device_SetCursorProperties,
d3d8_device_SetCursorPosition,
d3d8_device_ShowCursor,
d3d8_device_CreateAdditionalSwapChain,
d3d8_device_Reset,
d3d8_device_Present,
d3d8_device_GetBackBuffer,
d3d8_device_GetRasterStatus,
d3d8_device_SetGammaRamp,
d3d8_device_GetGammaRamp,
d3d8_device_CreateTexture,
d3d8_device_CreateVolumeTexture,
d3d8_device_CreateCubeTexture,
d3d8_device_CreateVertexBuffer,
d3d8_device_CreateIndexBuffer,
d3d8_device_CreateRenderTarget,
d3d8_device_CreateDepthStencilSurface,
d3d8_device_CreateImageSurface,
d3d8_device_CopyRects,
d3d8_device_UpdateTexture,
d3d8_device_GetFrontBuffer,
d3d8_device_SetRenderTarget,
d3d8_device_GetRenderTarget,
d3d8_device_GetDepthStencilSurface,
d3d8_device_BeginScene,
d3d8_device_EndScene,
d3d8_device_Clear,
d3d8_device_SetTransform,
d3d8_device_GetTransform,
d3d8_device_MultiplyTransform,
d3d8_device_SetViewport,
d3d8_device_GetViewport,
d3d8_device_SetMaterial,
d3d8_device_GetMaterial,
d3d8_device_SetLight,
d3d8_device_GetLight,
d3d8_device_LightEnable,
d3d8_device_GetLightEnable,
d3d8_device_SetClipPlane,
d3d8_device_GetClipPlane,
d3d8_device_SetRenderState,
d3d8_device_GetRenderState,
d3d8_device_BeginStateBlock,
d3d8_device_EndStateBlock,
d3d8_device_ApplyStateBlock,
d3d8_device_CaptureStateBlock,
d3d8_device_DeleteStateBlock,
d3d8_device_CreateStateBlock,
d3d8_device_SetClipStatus,
d3d8_device_GetClipStatus,
d3d8_device_GetTexture,
d3d8_device_SetTexture,
d3d8_device_GetTextureStageState,
d3d8_device_SetTextureStageState,
d3d8_device_ValidateDevice,
d3d8_device_GetInfo,
d3d8_device_SetPaletteEntries,
d3d8_device_GetPaletteEntries,
d3d8_device_SetCurrentTexturePalette,
d3d8_device_GetCurrentTexturePalette,
d3d8_device_DrawPrimitive,
d3d8_device_DrawIndexedPrimitive,
d3d8_device_DrawPrimitiveUP,
d3d8_device_DrawIndexedPrimitiveUP,
d3d8_device_ProcessVertices,
d3d8_device_CreateVertexShader,
d3d8_device_SetVertexShader,
d3d8_device_GetVertexShader,
d3d8_device_DeleteVertexShader,
d3d8_device_SetVertexShaderConstant,
d3d8_device_GetVertexShaderConstant,
d3d8_device_GetVertexShaderDeclaration,
d3d8_device_GetVertexShaderFunction,
d3d8_device_SetStreamSource,
d3d8_device_GetStreamSource,
d3d8_device_SetIndices,
d3d8_device_GetIndices,
d3d8_device_CreatePixelShader,
d3d8_device_SetPixelShader,
d3d8_device_GetPixelShader,
d3d8_device_DeletePixelShader,
d3d8_device_SetPixelShaderConstant,
d3d8_device_GetPixelShaderConstant,
d3d8_device_GetPixelShaderFunction,
d3d8_device_DrawRectPatch,
d3d8_device_DrawTriPatch,
d3d8_device_DeletePatch,
};
static inline struct d3d8_device *device_from_device_parent(struct wined3d_device_parent *device_parent)
{
return CONTAINING_RECORD(device_parent, struct d3d8_device, device_parent);
}
static void CDECL device_parent_wined3d_device_created(struct wined3d_device_parent *device_parent,
struct wined3d_device *device)
{
TRACE("device_parent %p, device %p\n", device_parent, device);
}
static void CDECL device_parent_mode_changed(struct wined3d_device_parent *device_parent)
{
TRACE("device_parent %p.\n", device_parent);
}
static void CDECL device_parent_activate(struct wined3d_device_parent *device_parent, BOOL activate)
{
struct d3d8_device *device = device_from_device_parent(device_parent);
TRACE("device_parent %p, activate %#x.\n", device_parent, activate);
if (!activate)
InterlockedCompareExchange(&device->device_state, D3D8_DEVICE_STATE_LOST, D3D8_DEVICE_STATE_OK);
else
InterlockedCompareExchange(&device->device_state, D3D8_DEVICE_STATE_NOT_RESET, D3D8_DEVICE_STATE_LOST);
}
static HRESULT CDECL device_parent_surface_created(struct wined3d_device_parent *device_parent,
struct wined3d_texture *wined3d_texture, unsigned int sub_resource_idx,
void **parent, const struct wined3d_parent_ops **parent_ops)
{
struct d3d8_surface *d3d_surface;
TRACE("device_parent %p, wined3d_texture %p, sub_resource_idx %u, parent %p, parent_ops %p.\n",
device_parent, wined3d_texture, sub_resource_idx, parent, parent_ops);
if (!(d3d_surface = heap_alloc_zero(sizeof(*d3d_surface))))
return E_OUTOFMEMORY;
surface_init(d3d_surface, wined3d_texture, sub_resource_idx, parent_ops);
*parent = d3d_surface;
TRACE("Created surface %p.\n", d3d_surface);
return D3D_OK;
}
static HRESULT CDECL device_parent_volume_created(struct wined3d_device_parent *device_parent,
struct wined3d_texture *wined3d_texture, unsigned int sub_resource_idx,
void **parent, const struct wined3d_parent_ops **parent_ops)
{
struct d3d8_volume *d3d_volume;
TRACE("device_parent %p, texture %p, sub_resource_idx %u, parent %p, parent_ops %p.\n",
device_parent, wined3d_texture, sub_resource_idx, parent, parent_ops);
if (!(d3d_volume = heap_alloc_zero(sizeof(*d3d_volume))))
return E_OUTOFMEMORY;
volume_init(d3d_volume, wined3d_texture, sub_resource_idx, parent_ops);
*parent = d3d_volume;
TRACE("Created volume %p.\n", d3d_volume);
return D3D_OK;
}
static HRESULT CDECL device_parent_create_swapchain_texture(struct wined3d_device_parent *device_parent,
void *container_parent, const struct wined3d_resource_desc *desc, DWORD texture_flags,
struct wined3d_texture **texture)
{
struct d3d8_device *device = device_from_device_parent(device_parent);
struct d3d8_surface *d3d_surface;
HRESULT hr;
TRACE("device_parent %p, container_parent %p, desc %p, texture flags %#x, texture %p.\n",
device_parent, container_parent, desc, texture_flags, texture);
if (FAILED(hr = wined3d_texture_create(device->wined3d_device, desc, 1, 1,
texture_flags | WINED3D_TEXTURE_CREATE_MAPPABLE, NULL, &device->IDirect3DDevice8_iface,
&d3d8_null_wined3d_parent_ops, texture)))
{
WARN("Failed to create texture, hr %#x.\n", hr);
return hr;
}
d3d_surface = wined3d_texture_get_sub_resource_parent(*texture, 0);
d3d_surface->parent_device = &device->IDirect3DDevice8_iface;
return hr;
}
static HRESULT CDECL device_parent_create_swapchain(struct wined3d_device_parent *device_parent,
struct wined3d_swapchain_desc *desc, struct wined3d_swapchain **swapchain)
{
struct d3d8_device *device = device_from_device_parent(device_parent);
struct d3d8_swapchain *d3d_swapchain;
HRESULT hr;
TRACE("device_parent %p, desc %p, swapchain %p.\n", device_parent, desc, swapchain);
if (FAILED(hr = d3d8_swapchain_create(device, desc, &d3d_swapchain)))
{
WARN("Failed to create swapchain, hr %#x.\n", hr);
*swapchain = NULL;
return hr;
}
*swapchain = d3d_swapchain->wined3d_swapchain;
wined3d_swapchain_incref(*swapchain);
IDirect3DSwapChain8_Release(&d3d_swapchain->IDirect3DSwapChain8_iface);
return hr;
}
static const struct wined3d_device_parent_ops d3d8_wined3d_device_parent_ops =
{
device_parent_wined3d_device_created,
device_parent_mode_changed,
device_parent_activate,
device_parent_surface_created,
device_parent_volume_created,
device_parent_create_swapchain_texture,
device_parent_create_swapchain,
};
static void setup_fpu(void)
{
#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
WORD cw;
__asm__ volatile ("fnstcw %0" : "=m" (cw));
cw = (cw & ~0xf3f) | 0x3f;
__asm__ volatile ("fldcw %0" : : "m" (cw));
#elif defined(__i386__) && defined(_MSC_VER)
WORD cw;
__asm fnstcw cw;
cw = (cw & ~0xf3f) | 0x3f;
__asm fldcw cw;
#else
FIXME("FPU setup not implemented for this platform.\n");
#endif
}
HRESULT device_init(struct d3d8_device *device, struct d3d8 *parent, struct wined3d *wined3d, UINT adapter,
D3DDEVTYPE device_type, HWND focus_window, DWORD flags, D3DPRESENT_PARAMETERS *parameters)
{
struct wined3d_swapchain_desc swapchain_desc;
struct wined3d_swapchain *wined3d_swapchain;
HRESULT hr;
device->IDirect3DDevice8_iface.lpVtbl = &d3d8_device_vtbl;
device->device_parent.ops = &d3d8_wined3d_device_parent_ops;
device->ref = 1;
if (!(device->handle_table.entries = heap_alloc_zero(D3D8_INITIAL_HANDLE_TABLE_SIZE
* sizeof(*device->handle_table.entries))))
{
ERR("Failed to allocate handle table memory.\n");
return E_OUTOFMEMORY;
}
device->handle_table.table_size = D3D8_INITIAL_HANDLE_TABLE_SIZE;
if (!(flags & D3DCREATE_FPU_PRESERVE)) setup_fpu();
wined3d_mutex_lock();
hr = wined3d_device_create(wined3d, adapter, device_type, focus_window, flags, 4,
&device->device_parent, &device->wined3d_device);
if (FAILED(hr))
{
WARN("Failed to create wined3d device, hr %#x.\n", hr);
wined3d_mutex_unlock();
heap_free(device->handle_table.entries);
return hr;
}
if (!parameters->Windowed)
{
HWND device_window = parameters->hDeviceWindow;
if (!focus_window)
focus_window = device_window;
if (FAILED(hr = wined3d_device_acquire_focus_window(device->wined3d_device, focus_window)))
{
ERR("Failed to acquire focus window, hr %#x.\n", hr);
wined3d_device_decref(device->wined3d_device);
wined3d_mutex_unlock();
heap_free(device->handle_table.entries);
return hr;
}
if (!device_window)
device_window = focus_window;
wined3d_device_setup_fullscreen_window(device->wined3d_device, device_window,
parameters->BackBufferWidth,
parameters->BackBufferHeight);
}
if (flags & D3DCREATE_MULTITHREADED)
wined3d_device_set_multithreaded(device->wined3d_device);
if (!wined3d_swapchain_desc_from_present_parameters(&swapchain_desc, parameters))
{
wined3d_device_release_focus_window(device->wined3d_device);
wined3d_device_decref(device->wined3d_device);
wined3d_mutex_unlock();
heap_free(device->handle_table.entries);
return D3DERR_INVALIDCALL;
}
if (FAILED(hr = wined3d_device_init_3d(device->wined3d_device, &swapchain_desc)))
{
WARN("Failed to initialize 3D, hr %#x.\n", hr);
wined3d_device_release_focus_window(device->wined3d_device);
wined3d_device_decref(device->wined3d_device);
wined3d_mutex_unlock();
heap_free(device->handle_table.entries);
return hr;
}
wined3d_device_set_render_state(device->wined3d_device,
WINED3D_RS_ZENABLE, !!swapchain_desc.enable_auto_depth_stencil);
wined3d_device_set_render_state(device->wined3d_device, WINED3D_RS_POINTSIZE_MIN, 0);
wined3d_mutex_unlock();
present_parameters_from_wined3d_swapchain_desc(parameters, &swapchain_desc);
device->declArraySize = 16;
if (!(device->decls = heap_alloc(device->declArraySize * sizeof(*device->decls))))
{
ERR("Failed to allocate FVF vertex declaration map memory.\n");
hr = E_OUTOFMEMORY;
goto err;
}
wined3d_swapchain = wined3d_device_get_swapchain(device->wined3d_device, 0);
device->implicit_swapchain = wined3d_swapchain_get_parent(wined3d_swapchain);
device->d3d_parent = &parent->IDirect3D8_iface;
IDirect3D8_AddRef(device->d3d_parent);
return D3D_OK;
err:
wined3d_mutex_lock();
wined3d_device_uninit_3d(device->wined3d_device);
wined3d_device_release_focus_window(device->wined3d_device);
wined3d_device_decref(device->wined3d_device);
wined3d_mutex_unlock();
heap_free(device->handle_table.entries);
return hr;
}