device.c 152 KB
Newer Older
1 2 3
/*
 * IDirect3DDevice9 implementation
 *
4
 * Copyright 2002-2005 Jason Edmeades
5 6
 * Copyright 2002-2005 Raphael Junqueira
 * Copyright 2005 Oliver Stieber
7 8 9 10 11 12 13 14 15 16 17 18 19
 *
 * 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
20
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 22 23 24 25
 */

#include "config.h"
#include "d3d9_private.h"

26
WINE_DEFAULT_DEBUG_CHANNEL(d3d9);
27

28 29
static void STDMETHODCALLTYPE d3d9_null_wined3d_object_destroyed(void *parent) {}

30
const struct wined3d_parent_ops d3d9_null_wined3d_parent_ops =
31 32 33 34
{
    d3d9_null_wined3d_object_destroyed,
};

35
D3DFORMAT d3dformat_from_wined3dformat(enum wined3d_format_id format)
36 37 38 39 40 41 42 43 44
{
    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;
45 46 47 48 49 50 51 52
        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;
53
        case WINED3DFMT_A8_UNORM: return D3DFMT_A8;
54 55
        case WINED3DFMT_B2G3R3A8_UNORM: return D3DFMT_A8R3G3B2;
        case WINED3DFMT_B4G4R4X4_UNORM: return D3DFMT_X4R4G4B4;
56 57
        case WINED3DFMT_R10G10B10A2_UNORM: return D3DFMT_A2B10G10R10;
        case WINED3DFMT_R8G8B8A8_UNORM: return D3DFMT_A8B8G8R8;
58
        case WINED3DFMT_R8G8B8X8_UNORM: return D3DFMT_X8B8G8R8;
59
        case WINED3DFMT_R16G16_UNORM: return D3DFMT_G16R16;
60
        case WINED3DFMT_B10G10R10A2_UNORM: return D3DFMT_A2R10G10B10;
61
        case WINED3DFMT_R16G16B16A16_UNORM: return D3DFMT_A16B16G16R16;
62 63 64 65 66
        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;
67
        case WINED3DFMT_R8G8_SNORM: return D3DFMT_V8U8;
68 69
        case WINED3DFMT_R5G5_SNORM_L6_UNORM: return D3DFMT_L6V5U5;
        case WINED3DFMT_R8G8_SNORM_L8X8_UNORM: return D3DFMT_X8L8V8U8;
70 71
        case WINED3DFMT_R8G8B8A8_SNORM: return D3DFMT_Q8W8V8U8;
        case WINED3DFMT_R16G16_SNORM: return D3DFMT_V16U16;
72
        case WINED3DFMT_R10G10B10_SNORM_A2_UNORM: return D3DFMT_A2W10V10U10;
73
        case WINED3DFMT_D16_LOCKABLE: return D3DFMT_D16_LOCKABLE;
74 75
        case WINED3DFMT_D32_UNORM: return D3DFMT_D32;
        case WINED3DFMT_S1_UINT_D15_UNORM: return D3DFMT_D15S1;
76
        case WINED3DFMT_D24_UNORM_S8_UINT: return D3DFMT_D24S8;
77 78
        case WINED3DFMT_X8D24_UNORM: return D3DFMT_D24X8;
        case WINED3DFMT_S4X4_UINT_D24_UNORM: return D3DFMT_D24X4S4;
79
        case WINED3DFMT_D16_UNORM: return D3DFMT_D16;
80 81 82
        case WINED3DFMT_L16_UNORM: return D3DFMT_L16;
        case WINED3DFMT_D32_FLOAT: return D3DFMT_D32F_LOCKABLE;
        case WINED3DFMT_S8_UINT_D24_FLOAT: return D3DFMT_D24FS8;
83 84 85 86 87 88 89 90 91
        case WINED3DFMT_R16_UINT: return D3DFMT_INDEX16;
        case WINED3DFMT_R32_UINT: return D3DFMT_INDEX32;
        case WINED3DFMT_R16G16B16A16_SNORM: return D3DFMT_Q16W16V16U16;
        case WINED3DFMT_R16_FLOAT: return D3DFMT_R16F;
        case WINED3DFMT_R16G16_FLOAT: return D3DFMT_G16R16F;
        case WINED3DFMT_R16G16B16A16_FLOAT: return D3DFMT_A16B16G16R16F;
        case WINED3DFMT_R32_FLOAT: return D3DFMT_R32F;
        case WINED3DFMT_R32G32_FLOAT: return D3DFMT_G32R32F;
        case WINED3DFMT_R32G32B32A32_FLOAT: return D3DFMT_A32B32G32R32F;
92
        case WINED3DFMT_R8G8_SNORM_Cx: return D3DFMT_CxV8U8;
93
        default:
94
            FIXME("Unhandled wined3d format %#x.\n", format);
95 96 97 98
            return D3DFMT_UNKNOWN;
    }
}

99
enum wined3d_format_id wined3dformat_from_d3dformat(D3DFORMAT format)
100 101 102 103 104 105 106 107 108
{
    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;
109 110 111 112 113 114 115 116
        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;
117
        case D3DFMT_A8: return WINED3DFMT_A8_UNORM;
118 119
        case D3DFMT_A8R3G3B2: return WINED3DFMT_B2G3R3A8_UNORM;
        case D3DFMT_X4R4G4B4: return WINED3DFMT_B4G4R4X4_UNORM;
120 121
        case D3DFMT_A2B10G10R10: return WINED3DFMT_R10G10B10A2_UNORM;
        case D3DFMT_A8B8G8R8: return WINED3DFMT_R8G8B8A8_UNORM;
122
        case D3DFMT_X8B8G8R8: return WINED3DFMT_R8G8B8X8_UNORM;
123
        case D3DFMT_G16R16: return WINED3DFMT_R16G16_UNORM;
124
        case D3DFMT_A2R10G10B10: return WINED3DFMT_B10G10R10A2_UNORM;
125
        case D3DFMT_A16B16G16R16: return WINED3DFMT_R16G16B16A16_UNORM;
126 127 128 129 130
        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;
131
        case D3DFMT_V8U8: return WINED3DFMT_R8G8_SNORM;
132 133
        case D3DFMT_L6V5U5: return WINED3DFMT_R5G5_SNORM_L6_UNORM;
        case D3DFMT_X8L8V8U8: return WINED3DFMT_R8G8_SNORM_L8X8_UNORM;
134 135
        case D3DFMT_Q8W8V8U8: return WINED3DFMT_R8G8B8A8_SNORM;
        case D3DFMT_V16U16: return WINED3DFMT_R16G16_SNORM;
136
        case D3DFMT_A2W10V10U10: return WINED3DFMT_R10G10B10_SNORM_A2_UNORM;
137
        case D3DFMT_D16_LOCKABLE: return WINED3DFMT_D16_LOCKABLE;
138 139
        case D3DFMT_D32: return WINED3DFMT_D32_UNORM;
        case D3DFMT_D15S1: return WINED3DFMT_S1_UINT_D15_UNORM;
140
        case D3DFMT_D24S8: return WINED3DFMT_D24_UNORM_S8_UINT;
141 142
        case D3DFMT_D24X8: return WINED3DFMT_X8D24_UNORM;
        case D3DFMT_D24X4S4: return WINED3DFMT_S4X4_UINT_D24_UNORM;
143
        case D3DFMT_D16: return WINED3DFMT_D16_UNORM;
144 145 146
        case D3DFMT_L16: return WINED3DFMT_L16_UNORM;
        case D3DFMT_D32F_LOCKABLE: return WINED3DFMT_D32_FLOAT;
        case D3DFMT_D24FS8: return WINED3DFMT_S8_UINT_D24_FLOAT;
147 148 149 150 151 152 153 154 155
        case D3DFMT_INDEX16: return WINED3DFMT_R16_UINT;
        case D3DFMT_INDEX32: return WINED3DFMT_R32_UINT;
        case D3DFMT_Q16W16V16U16: return WINED3DFMT_R16G16B16A16_SNORM;
        case D3DFMT_R16F: return WINED3DFMT_R16_FLOAT;
        case D3DFMT_G16R16F: return WINED3DFMT_R16G16_FLOAT;
        case D3DFMT_A16B16G16R16F: return WINED3DFMT_R16G16B16A16_FLOAT;
        case D3DFMT_R32F: return WINED3DFMT_R32_FLOAT;
        case D3DFMT_G32R32F: return WINED3DFMT_R32G32_FLOAT;
        case D3DFMT_A32B32G32R32F: return WINED3DFMT_R32G32B32A32_FLOAT;
156
        case D3DFMT_CxV8U8: return WINED3DFMT_R8G8_SNORM_Cx;
157
        default:
158
            FIXME("Unhandled D3DFORMAT %#x.\n", format);
159 160 161
            return WINED3DFMT_UNKNOWN;
    }
}
162

163 164
unsigned int wined3dmapflags_from_d3dmapflags(unsigned int flags)
{
165
    static const unsigned int handled = D3DLOCK_NOSYSLOCK
166 167 168 169 170 171 172
            | D3DLOCK_NOOVERWRITE
            | D3DLOCK_DISCARD
            | D3DLOCK_DONOTWAIT
            | D3DLOCK_NO_DIRTY_UPDATE;
    unsigned int wined3d_flags;

    wined3d_flags = flags & handled;
173 174 175 176 177 178 179
    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);
180 181 182 183 184 185 186

    if (flags)
        FIXME("Unhandled flags %#x.\n", flags);

    return wined3d_flags;
}

187 188
static UINT vertex_count_from_primitive_count(D3DPRIMITIVETYPE primitive_type, UINT primitive_count)
{
189
    switch (primitive_type)
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
    {
        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:
208
            FIXME("Unhandled primitive type %#x.\n", primitive_type);
209 210 211 212
            return 0;
    }
}

213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
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_OVERLAY:
            return D3DSWAPEFFECT_OVERLAY;
        case WINED3D_SWAP_EFFECT_FLIP_SEQUENTIAL:
            return D3DSWAPEFFECT_FLIPEX;
        default:
            FIXME("Unhandled swap effect %#x.\n", effect);
            return D3DSWAPEFFECT_FLIP;
    }
}

233 234 235 236 237 238 239 240 241
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->MultiSampleQuality = swapchain_desc->multisample_quality;
242
    present_parameters->SwapEffect = d3dswapeffect_from_wined3dswapeffect(swapchain_desc->swap_effect);
243 244 245 246 247
    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);
248
    present_parameters->Flags = swapchain_desc->flags & D3DPRESENTFLAGS_MASK;
249 250 251 252
    present_parameters->FullScreen_RefreshRateInHz = swapchain_desc->refresh_rate;
    present_parameters->PresentationInterval = swapchain_desc->swap_interval;
}

253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272
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_OVERLAY:
            return WINED3D_SWAP_EFFECT_OVERLAY;
        case D3DSWAPEFFECT_FLIPEX:
            return WINED3D_SWAP_EFFECT_FLIP_SEQUENTIAL;
        default:
            FIXME("Unhandled swap effect %#x.\n", effect);
            return WINED3D_SWAP_EFFECT_SEQUENTIAL;
    }
}

273 274
static BOOL wined3d_swapchain_desc_from_present_parameters(struct wined3d_swapchain_desc *swapchain_desc,
        const D3DPRESENT_PARAMETERS *present_parameters, BOOL extended)
275
{
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
    D3DSWAPEFFECT highest_swapeffect = extended ? D3DSWAPEFFECT_FLIPEX : D3DSWAPEFFECT_COPY;
    UINT highest_bb_count = extended ? 30 : 3;

    if (!present_parameters->SwapEffect || present_parameters->SwapEffect > highest_swapeffect)
    {
        WARN("Invalid swap effect %u passed.\n", present_parameters->SwapEffect);
        return FALSE;
    }
    if (present_parameters->BackBufferCount > highest_bb_count
            || (present_parameters->SwapEffect == D3DSWAPEFFECT_COPY
            && present_parameters->BackBufferCount > 1))
    {
        WARN("Invalid backbuffer count %u.\n", present_parameters->BackBufferCount);
        return FALSE;
    }

292 293 294 295
    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);
296
    swapchain_desc->backbuffer_usage = WINED3DUSAGE_RENDERTARGET;
297 298
    swapchain_desc->multisample_type = present_parameters->MultiSampleType;
    swapchain_desc->multisample_quality = present_parameters->MultiSampleQuality;
299
    swapchain_desc->swap_effect = wined3dswapeffect_from_d3dswapeffect(present_parameters->SwapEffect);
300 301 302 303 304
    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);
305 306
    swapchain_desc->flags
            = (present_parameters->Flags & D3DPRESENTFLAGS_MASK) | WINED3D_SWAPCHAIN_ALLOW_MODE_SWITCH;
307 308 309
    swapchain_desc->refresh_rate = present_parameters->FullScreen_RefreshRateInHz;
    swapchain_desc->swap_interval = present_parameters->PresentationInterval;
    swapchain_desc->auto_restore_display_mode = TRUE;
310

311 312 313
    if (present_parameters->Flags & ~D3DPRESENTFLAGS_MASK)
        FIXME("Unhandled flags %#x.\n", present_parameters->Flags & ~D3DPRESENTFLAGS_MASK);

314
    return TRUE;
315 316
}

317 318
void d3dcaps_from_wined3dcaps(D3DCAPS9 *caps, const WINED3DCAPS *wined3d_caps)
{
319 320 321 322 323 324 325 326 327
    static const DWORD ps_minor_version[] = {0, 4, 0, 0};
    static const DWORD vs_minor_version[] = {0, 1, 0, 0};
    static const DWORD texture_filter_caps =
        D3DPTFILTERCAPS_MINFPOINT      | D3DPTFILTERCAPS_MINFLINEAR    | D3DPTFILTERCAPS_MINFANISOTROPIC |
        D3DPTFILTERCAPS_MINFPYRAMIDALQUAD                              | D3DPTFILTERCAPS_MINFGAUSSIANQUAD|
        D3DPTFILTERCAPS_MIPFPOINT      | D3DPTFILTERCAPS_MIPFLINEAR    | D3DPTFILTERCAPS_MAGFPOINT       |
        D3DPTFILTERCAPS_MAGFLINEAR     |D3DPTFILTERCAPS_MAGFANISOTROPIC|D3DPTFILTERCAPS_MAGFPYRAMIDALQUAD|
        D3DPTFILTERCAPS_MAGFGAUSSIANQUAD;

328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402
    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->PixelShader1xMaxValue             = wined3d_caps->PixelShader1xMaxValue;
    caps->DevCaps2                          = wined3d_caps->DevCaps2;
    caps->MaxNpatchTessellationLevel        = wined3d_caps->MaxNpatchTessellationLevel;
    caps->MasterAdapterOrdinal              = wined3d_caps->MasterAdapterOrdinal;
    caps->AdapterOrdinalInGroup             = wined3d_caps->AdapterOrdinalInGroup;
    caps->NumberOfAdaptersInGroup           = wined3d_caps->NumberOfAdaptersInGroup;
    caps->DeclTypes                         = wined3d_caps->DeclTypes;
    caps->NumSimultaneousRTs                = wined3d_caps->NumSimultaneousRTs;
    caps->StretchRectFilterCaps             = wined3d_caps->StretchRectFilterCaps;
    caps->VS20Caps.Caps                     = wined3d_caps->VS20Caps.caps;
    caps->VS20Caps.DynamicFlowControlDepth  = wined3d_caps->VS20Caps.dynamic_flow_control_depth;
    caps->VS20Caps.NumTemps                 = wined3d_caps->VS20Caps.temp_count;
    caps->VS20Caps.StaticFlowControlDepth   = wined3d_caps->VS20Caps.static_flow_control_depth;
    caps->PS20Caps.Caps                     = wined3d_caps->PS20Caps.caps;
    caps->PS20Caps.DynamicFlowControlDepth  = wined3d_caps->PS20Caps.dynamic_flow_control_depth;
    caps->PS20Caps.NumTemps                 = wined3d_caps->PS20Caps.temp_count;
    caps->PS20Caps.StaticFlowControlDepth   = wined3d_caps->PS20Caps.static_flow_control_depth;
    caps->PS20Caps.NumInstructionSlots      = wined3d_caps->PS20Caps.instruction_slot_count;
    caps->VertexTextureFilterCaps           = wined3d_caps->VertexTextureFilterCaps;
    caps->MaxVShaderInstructionsExecuted    = wined3d_caps->MaxVShaderInstructionsExecuted;
    caps->MaxPShaderInstructionsExecuted    = wined3d_caps->MaxPShaderInstructionsExecuted;
    caps->MaxVertexShader30InstructionSlots = wined3d_caps->MaxVertexShader30InstructionSlots;
    caps->MaxPixelShader30InstructionSlots  = wined3d_caps->MaxPixelShader30InstructionSlots;
403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476

    /* Some functionality is implemented in d3d9.dll, not wined3d.dll. Add the needed caps. */
    caps->DevCaps2 |= D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES;

    /* Filter wined3d caps. */
    caps->TextureFilterCaps &= texture_filter_caps;
    caps->CubeTextureFilterCaps &= texture_filter_caps;
    caps->VolumeTextureFilterCaps &= texture_filter_caps;

    caps->DevCaps &=
        D3DDEVCAPS_EXECUTESYSTEMMEMORY | D3DDEVCAPS_EXECUTEVIDEOMEMORY | D3DDEVCAPS_TLVERTEXSYSTEMMEMORY |
        D3DDEVCAPS_TLVERTEXVIDEOMEMORY | D3DDEVCAPS_TEXTURESYSTEMMEMORY| D3DDEVCAPS_TEXTUREVIDEOMEMORY   |
        D3DDEVCAPS_DRAWPRIMTLVERTEX    | D3DDEVCAPS_CANRENDERAFTERFLIP | D3DDEVCAPS_TEXTURENONLOCALVIDMEM|
        D3DDEVCAPS_DRAWPRIMITIVES2     | D3DDEVCAPS_SEPARATETEXTUREMEMORIES                              |
        D3DDEVCAPS_DRAWPRIMITIVES2EX   | D3DDEVCAPS_HWTRANSFORMANDLIGHT| D3DDEVCAPS_CANBLTSYSTONONLOCAL  |
        D3DDEVCAPS_HWRASTERIZATION     | D3DDEVCAPS_PUREDEVICE         | D3DDEVCAPS_QUINTICRTPATCHES     |
        D3DDEVCAPS_RTPATCHES           | D3DDEVCAPS_RTPATCHHANDLEZERO  | D3DDEVCAPS_NPATCHES;

    caps->ShadeCaps &=
        D3DPSHADECAPS_COLORGOURAUDRGB  | D3DPSHADECAPS_SPECULARGOURAUDRGB |
        D3DPSHADECAPS_ALPHAGOURAUDBLEND | D3DPSHADECAPS_FOGGOURAUD;

    caps->RasterCaps &=
        D3DPRASTERCAPS_DITHER          | D3DPRASTERCAPS_ZTEST          | D3DPRASTERCAPS_FOGVERTEX        |
        D3DPRASTERCAPS_FOGTABLE        | D3DPRASTERCAPS_MIPMAPLODBIAS  | D3DPRASTERCAPS_ZBUFFERLESSHSR   |
        D3DPRASTERCAPS_FOGRANGE        | D3DPRASTERCAPS_ANISOTROPY     | D3DPRASTERCAPS_WBUFFER          |
        D3DPRASTERCAPS_WFOG            | D3DPRASTERCAPS_ZFOG           | D3DPRASTERCAPS_COLORPERSPECTIVE |
        D3DPRASTERCAPS_SCISSORTEST     | D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS                              |
        D3DPRASTERCAPS_DEPTHBIAS       | D3DPRASTERCAPS_MULTISAMPLE_TOGGLE;

    caps->DevCaps2 &=
        D3DDEVCAPS2_STREAMOFFSET       | D3DDEVCAPS2_DMAPNPATCH        | D3DDEVCAPS2_ADAPTIVETESSRTPATCH |
        D3DDEVCAPS2_ADAPTIVETESSNPATCH | D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES                       |
        D3DDEVCAPS2_PRESAMPLEDDMAPNPATCH| D3DDEVCAPS2_VERTEXELEMENTSCANSHARESTREAMOFFSET;

    caps->Caps2 &=
        D3DCAPS2_FULLSCREENGAMMA       | D3DCAPS2_CANCALIBRATEGAMMA    | D3DCAPS2_RESERVED               |
        D3DCAPS2_CANMANAGERESOURCE     | D3DCAPS2_DYNAMICTEXTURES      | D3DCAPS2_CANAUTOGENMIPMAP;

    caps->VertexProcessingCaps &=
        D3DVTXPCAPS_TEXGEN             | D3DVTXPCAPS_MATERIALSOURCE7   | D3DVTXPCAPS_DIRECTIONALLIGHTS   |
        D3DVTXPCAPS_POSITIONALLIGHTS   | D3DVTXPCAPS_LOCALVIEWER       | D3DVTXPCAPS_TWEENING            |
        D3DVTXPCAPS_TEXGEN_SPHEREMAP   | D3DVTXPCAPS_NO_TEXGEN_NONLOCALVIEWER;

    caps->TextureCaps &=
        D3DPTEXTURECAPS_PERSPECTIVE    | D3DPTEXTURECAPS_POW2          | D3DPTEXTURECAPS_ALPHA           |
        D3DPTEXTURECAPS_SQUAREONLY     | D3DPTEXTURECAPS_TEXREPEATNOTSCALEDBYSIZE                        |
        D3DPTEXTURECAPS_ALPHAPALETTE   | D3DPTEXTURECAPS_NONPOW2CONDITIONAL                              |
        D3DPTEXTURECAPS_PROJECTED      | D3DPTEXTURECAPS_CUBEMAP       | D3DPTEXTURECAPS_VOLUMEMAP       |
        D3DPTEXTURECAPS_MIPMAP         | D3DPTEXTURECAPS_MIPVOLUMEMAP  | D3DPTEXTURECAPS_MIPCUBEMAP      |
        D3DPTEXTURECAPS_CUBEMAP_POW2   | D3DPTEXTURECAPS_VOLUMEMAP_POW2| D3DPTEXTURECAPS_NOPROJECTEDBUMPENV;

    caps->MaxVertexShaderConst = min(D3D9_MAX_VERTEX_SHADER_CONSTANTF, caps->MaxVertexShaderConst);
    caps->NumSimultaneousRTs = min(D3D9_MAX_SIMULTANEOUS_RENDERTARGETS, caps->NumSimultaneousRTs);

    if (caps->PixelShaderVersion > 3)
    {
        caps->PixelShaderVersion = D3DPS_VERSION(3, 0);
    }
    else
    {
        DWORD major = caps->PixelShaderVersion;
        caps->PixelShaderVersion = D3DPS_VERSION(major, ps_minor_version[major]);
    }

    if (caps->VertexShaderVersion > 3)
    {
        caps->VertexShaderVersion = D3DVS_VERSION(3, 0);
    }
    else
    {
        DWORD major = caps->VertexShaderVersion;
        caps->VertexShaderVersion = D3DVS_VERSION(major, vs_minor_version[major]);
    }
477 478
}

479
static HRESULT WINAPI d3d9_device_QueryInterface(IDirect3DDevice9Ex *iface, REFIID riid, void **out)
480
{
481
    TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
Henri Verbeet's avatar
Henri Verbeet committed
482

483 484 485
    if (IsEqualGUID(riid, &IID_IDirect3DDevice9)
            || IsEqualGUID(riid, &IID_IUnknown))
    {
486
        IDirect3DDevice9Ex_AddRef(iface);
487
        *out = iface;
H. Verbeet's avatar
H. Verbeet committed
488
        return S_OK;
489 490 491 492
    }

    if (IsEqualGUID(riid, &IID_IDirect3DDevice9Ex))
    {
493
        struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
494

495
        /* Find out if the creating d3d9 interface was created with Direct3DCreate9Ex.
496
         * It doesn't matter with which function the device was created. */
497
        if (!device->d3d_parent->extended)
498
        {
499 500
            WARN("IDirect3D9 instance wasn't created with CreateDirect3D9Ex, returning E_NOINTERFACE.\n");
            *out = NULL;
501 502
            return E_NOINTERFACE;
        }
503 504 505 506

        IDirect3DDevice9Ex_AddRef(iface);
        *out = iface;
        return S_OK;
507 508
    }

509 510 511
    WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));

    *out = NULL;
512 513 514
    return E_NOINTERFACE;
}

515
static ULONG WINAPI d3d9_device_AddRef(IDirect3DDevice9Ex *iface)
516
{
517 518
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
    ULONG refcount = InterlockedIncrement(&device->refcount);
519

520
    TRACE("%p increasing refcount to %u.\n", iface, refcount);
521

522
    return refcount;
523 524
}

525
static ULONG WINAPI DECLSPEC_HOTPATCH d3d9_device_Release(IDirect3DDevice9Ex *iface)
526
{
527 528
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
    ULONG refcount;
529

530
    if (device->in_destruction)
531 532
        return 0;

533
    refcount = InterlockedDecrement(&device->refcount);
534

535
    TRACE("%p decreasing refcount to %u.\n", iface, refcount);
536

537
    if (!refcount)
538 539
    {
        unsigned i;
540
        device->in_destruction = TRUE;
541

542 543 544 545 546
        wined3d_mutex_lock();
        for (i = 0; i < device->fvf_decl_count; ++i)
        {
            wined3d_vertex_declaration_decref(device->fvf_decls[i].decl);
        }
547
        heap_free(device->fvf_decls);
548

549 550
        if (device->vertex_buffer)
            wined3d_buffer_decref(device->vertex_buffer);
551 552
        if (device->index_buffer)
            wined3d_buffer_decref(device->index_buffer);
553

554
        heap_free(device->implicit_swapchains);
555

556 557 558 559
        wined3d_device_uninit_3d(device->wined3d_device);
        wined3d_device_release_focus_window(device->wined3d_device);
        wined3d_device_decref(device->wined3d_device);
        wined3d_mutex_unlock();
560

561
        IDirect3D9Ex_Release(&device->d3d_parent->IDirect3D9Ex_iface);
562

563
        heap_free(device);
564
    }
565

566
    return refcount;
567 568
}

569
static HRESULT WINAPI d3d9_device_TestCooperativeLevel(IDirect3DDevice9Ex *iface)
570
{
571
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
Henri Verbeet's avatar
Henri Verbeet committed
572 573

    TRACE("iface %p.\n", iface);
574

575 576 577 578 579 580
    TRACE("device state: %#x.\n", device->device_state);

    if (device->d3d_parent->extended)
        return D3D_OK;

    switch (device->device_state)
581
    {
582 583 584 585 586 587 588
        default:
        case D3D9_DEVICE_STATE_OK:
            return D3D_OK;
        case D3D9_DEVICE_STATE_LOST:
            return D3DERR_DEVICELOST;
        case D3D9_DEVICE_STATE_NOT_RESET:
            return D3DERR_DEVICENOTRESET;
589
    }
590 591
}

592
static UINT WINAPI d3d9_device_GetAvailableTextureMem(IDirect3DDevice9Ex *iface)
593
{
594
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
595
    UINT ret;
Henri Verbeet's avatar
Henri Verbeet committed
596 597

    TRACE("iface %p.\n", iface);
598

599
    wined3d_mutex_lock();
600
    ret = wined3d_device_get_available_texture_mem(device->wined3d_device);
601 602
    wined3d_mutex_unlock();

603
    return ret;
604 605
}

606
static HRESULT WINAPI d3d9_device_EvictManagedResources(IDirect3DDevice9Ex *iface)
607
{
608
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
Henri Verbeet's avatar
Henri Verbeet committed
609 610

    TRACE("iface %p.\n", iface);
611

612
    wined3d_mutex_lock();
613
    wined3d_device_evict_managed_resources(device->wined3d_device);
614 615
    wined3d_mutex_unlock();

616
    return D3D_OK;
617 618
}

619
static HRESULT WINAPI d3d9_device_GetDirect3D(IDirect3DDevice9Ex *iface, IDirect3D9 **d3d9)
620
{
621
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
622

623
    TRACE("iface %p, d3d9 %p.\n", iface, d3d9);
624

625
    if (!d3d9)
626
        return D3DERR_INVALIDCALL;
627

628
    return IDirect3D9Ex_QueryInterface(&device->d3d_parent->IDirect3D9Ex_iface, &IID_IDirect3D9, (void **)d3d9);
629 630
}

631
static HRESULT WINAPI d3d9_device_GetDeviceCaps(IDirect3DDevice9Ex *iface, D3DCAPS9 *caps)
632
{
633
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
634
    WINED3DCAPS wined3d_caps;
635
    HRESULT hr;
636

637
    TRACE("iface %p, caps %p.\n", iface, caps);
Henri Verbeet's avatar
Henri Verbeet committed
638

639
    if (!caps)
640
        return D3DERR_INVALIDCALL;
641 642

    memset(caps, 0, sizeof(*caps));
643 644

    wined3d_mutex_lock();
645
    hr = wined3d_device_get_device_caps(device->wined3d_device, &wined3d_caps);
646 647
    wined3d_mutex_unlock();

648
    d3dcaps_from_wined3dcaps(caps, &wined3d_caps);
649

650
    return hr;
651 652
}

653
static HRESULT WINAPI d3d9_device_GetDisplayMode(IDirect3DDevice9Ex *iface, UINT swapchain, D3DDISPLAYMODE *mode)
654
{
655
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
656
    struct wined3d_display_mode wined3d_mode;
657
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
658

659
    TRACE("iface %p, swapchain %u, mode %p.\n", iface, swapchain, mode);
660

661
    wined3d_mutex_lock();
662
    hr = wined3d_device_get_display_mode(device->wined3d_device, swapchain, &wined3d_mode, NULL);
663
    wined3d_mutex_unlock();
664

665
    if (SUCCEEDED(hr))
666 667 668 669 670 671
    {
        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);
    }
672

673
    return hr;
674 675
}

676 677
static HRESULT WINAPI d3d9_device_GetCreationParameters(IDirect3DDevice9Ex *iface,
        D3DDEVICE_CREATION_PARAMETERS *parameters)
678
{
679
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
Henri Verbeet's avatar
Henri Verbeet committed
680

681
    TRACE("iface %p, parameters %p.\n", iface, parameters);
682

683
    wined3d_mutex_lock();
684
    wined3d_device_get_creation_parameters(device->wined3d_device,
685
            (struct wined3d_device_creation_parameters *)parameters);
686 687
    wined3d_mutex_unlock();

688
    return D3D_OK;
689 690
}

691 692
static HRESULT WINAPI d3d9_device_SetCursorProperties(IDirect3DDevice9Ex *iface,
        UINT hotspot_x, UINT hotspot_y, IDirect3DSurface9 *bitmap)
693
{
694
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
695
    struct d3d9_surface *bitmap_impl = unsafe_impl_from_IDirect3DSurface9(bitmap);
696 697
    HRESULT hr;

Henri Verbeet's avatar
Henri Verbeet committed
698
    TRACE("iface %p, hotspot_x %u, hotspot_y %u, bitmap %p.\n",
699
            iface, hotspot_x, hotspot_y, bitmap);
Henri Verbeet's avatar
Henri Verbeet committed
700

701
    if (!bitmap)
702 703 704
    {
        WARN("No cursor bitmap, returning D3DERR_INVALIDCALL.\n");
        return D3DERR_INVALIDCALL;
705
    }
706

707
    wined3d_mutex_lock();
708
    hr = wined3d_device_set_cursor_properties(device->wined3d_device,
709
            hotspot_x, hotspot_y, bitmap_impl->wined3d_texture, bitmap_impl->sub_resource_idx);
710 711
    wined3d_mutex_unlock();

712
    return hr;
713 714
}

715
static void WINAPI d3d9_device_SetCursorPosition(IDirect3DDevice9Ex *iface, int x, int y, DWORD flags)
716
{
717
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
Henri Verbeet's avatar
Henri Verbeet committed
718

719
    TRACE("iface %p, x %u, y %u, flags %#x.\n", iface, x, y, flags);
720

721
    wined3d_mutex_lock();
722
    wined3d_device_set_cursor_position(device->wined3d_device, x, y, flags);
723
    wined3d_mutex_unlock();
724 725
}

726
static BOOL WINAPI d3d9_device_ShowCursor(IDirect3DDevice9Ex *iface, BOOL show)
727
{
728
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
729
    BOOL ret;
Henri Verbeet's avatar
Henri Verbeet committed
730

731
    TRACE("iface %p, show %#x.\n", iface, show);
732

733
    wined3d_mutex_lock();
734
    ret = wined3d_device_show_cursor(device->wined3d_device, show);
735 736
    wined3d_mutex_unlock();

737
    return ret;
738 739
}

740
static HRESULT WINAPI DECLSPEC_HOTPATCH d3d9_device_CreateAdditionalSwapChain(IDirect3DDevice9Ex *iface,
741 742
        D3DPRESENT_PARAMETERS *present_parameters, IDirect3DSwapChain9 **swapchain)
{
743
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
744
    struct wined3d_swapchain_desc desc;
745
    struct d3d9_swapchain *object;
746
    UINT i, count;
747 748 749 750 751
    HRESULT hr;

    TRACE("iface %p, present_parameters %p, swapchain %p.\n",
            iface, present_parameters, swapchain);

752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775
    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();

776 777 778
    if (!wined3d_swapchain_desc_from_present_parameters(&desc, present_parameters,
            device->d3d_parent->extended))
        return D3DERR_INVALIDCALL;
779
    if (SUCCEEDED(hr = d3d9_swapchain_create(device, &desc, &object)))
780
        *swapchain = (IDirect3DSwapChain9 *)&object->IDirect3DSwapChain9Ex_iface;
781
    present_parameters_from_wined3d_swapchain_desc(present_parameters, &desc);
782

783
    return hr;
784 785
}

786
static HRESULT WINAPI DECLSPEC_HOTPATCH d3d9_device_GetSwapChain(IDirect3DDevice9Ex *iface,
787 788
        UINT swapchain_idx, IDirect3DSwapChain9 **swapchain)
{
789
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
790 791 792 793 794
    HRESULT hr;

    TRACE("iface %p, swapchain_idx %u, swapchain %p.\n", iface, swapchain_idx, swapchain);

    wined3d_mutex_lock();
795
    if (swapchain_idx < device->implicit_swapchain_count)
796
    {
797 798 799
        *swapchain = (IDirect3DSwapChain9 *)&device->implicit_swapchains[swapchain_idx]->IDirect3DSwapChain9Ex_iface;
        IDirect3DSwapChain9Ex_AddRef(*swapchain);
        hr = D3D_OK;
800 801 802 803
    }
    else
    {
        *swapchain = NULL;
804
        hr = D3DERR_INVALIDCALL;
805 806 807 808 809 810
    }
    wined3d_mutex_unlock();

    return hr;
}

811
static UINT WINAPI d3d9_device_GetNumberOfSwapChains(IDirect3DDevice9Ex *iface)
812
{
813
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
814 815 816 817 818
    UINT count;

    TRACE("iface %p.\n", iface);

    wined3d_mutex_lock();
819
    count = wined3d_device_get_swapchain_count(device->wined3d_device);
820 821 822 823 824
    wined3d_mutex_unlock();

    return count;
}

825
static HRESULT CDECL reset_enum_callback(struct wined3d_resource *resource)
826
{
827
    struct wined3d_resource_desc desc;
828 829 830
    IDirect3DBaseTexture9 *texture;
    struct d3d9_surface *surface;
    IUnknown *parent;
831

832
    wined3d_resource_get_desc(resource, &desc);
833
    if (desc.access & WINED3D_RESOURCE_ACCESS_CPU)
834
        return D3D_OK;
835

836 837 838 839 840
    if (desc.resource_type != WINED3D_RTYPE_TEXTURE_2D)
    {
        WARN("Resource %p in pool D3DPOOL_DEFAULT blocks the Reset call.\n", resource);
        return D3DERR_INVALIDCALL;
    }
841

842 843 844 845 846 847
    parent = wined3d_resource_get_parent(resource);
    if (parent && SUCCEEDED(IUnknown_QueryInterface(parent, &IID_IDirect3DBaseTexture9, (void **)&texture)))
    {
        IDirect3DBaseTexture9_Release(texture);
        WARN("Texture %p (resource %p) in pool D3DPOOL_DEFAULT blocks the Reset call.\n", texture, resource);
        return D3DERR_INVALIDCALL;
848 849
    }

850 851 852 853 854 855
    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_INVALIDCALL;
856 857
}

858 859 860 861 862
static HRESULT d3d9_device_get_swapchains(struct d3d9_device *device)
{
    UINT i, new_swapchain_count = wined3d_device_get_swapchain_count(device->wined3d_device);
    struct wined3d_swapchain *wined3d_swapchain;

863
    if (!(device->implicit_swapchains = heap_alloc(new_swapchain_count * sizeof(*device->implicit_swapchains))))
864 865 866 867 868 869 870 871 872 873 874 875
        return E_OUTOFMEMORY;

    for (i = 0; i < new_swapchain_count; ++i)
    {
        wined3d_swapchain = wined3d_device_get_swapchain(device->wined3d_device, i);
        device->implicit_swapchains[i] = wined3d_swapchain_get_parent(wined3d_swapchain);
    }
    device->implicit_swapchain_count = new_swapchain_count;

    return D3D_OK;
}

876 877
static HRESULT d3d9_device_reset(struct d3d9_device *device,
        D3DPRESENT_PARAMETERS *present_parameters, D3DDISPLAYMODEEX *mode)
878
{
879
    BOOL extended = device->d3d_parent->extended;
880
    struct wined3d_swapchain_desc swapchain_desc;
881
    struct wined3d_display_mode wined3d_mode;
882 883
    struct wined3d_rendertarget_view *rtv;
    unsigned int i;
884 885
    HRESULT hr;

886
    if (!extended && device->device_state == D3D9_DEVICE_STATE_LOST)
887 888 889 890 891
    {
        WARN("App not active, returning D3DERR_DEVICELOST.\n");
        return D3DERR_DEVICELOST;
    }

892 893 894 895 896 897 898 899 900
    if (mode)
    {
        wined3d_mode.width = mode->Width;
        wined3d_mode.height = mode->Height;
        wined3d_mode.refresh_rate = mode->RefreshRate;
        wined3d_mode.format_id = wined3dformat_from_d3dformat(mode->Format);
        wined3d_mode.scanline_ordering = mode->ScanLineOrdering;
    }

901
    if (!wined3d_swapchain_desc_from_present_parameters(&swapchain_desc, present_parameters, extended))
902 903
        return D3DERR_INVALIDCALL;

904
    wined3d_mutex_lock();
905 906 907 908 909 910 911

    if (device->vertex_buffer)
    {
        wined3d_buffer_decref(device->vertex_buffer);
        device->vertex_buffer = NULL;
        device->vertex_buffer_size = 0;
    }
912

913 914 915 916 917 918
    if (device->index_buffer)
    {
        wined3d_buffer_decref(device->index_buffer);
        device->index_buffer = NULL;
        device->index_buffer_size = 0;
    }
919

920
    if (SUCCEEDED(hr = wined3d_device_reset(device->wined3d_device, &swapchain_desc,
921
            mode ? &wined3d_mode : NULL, reset_enum_callback, !extended)))
922
    {
923
        heap_free(device->implicit_swapchains);
924

925 926 927 928 929 930
        if (!extended)
        {
            wined3d_device_set_render_state(device->wined3d_device, WINED3D_RS_ZENABLE,
                    !!swapchain_desc.enable_auto_depth_stencil);
        }

931 932 933 934 935 936 937 938 939 940 941
        if (FAILED(hr = d3d9_device_get_swapchains(device)))
        {
            device->device_state = D3D9_DEVICE_STATE_NOT_RESET;
        }
        else
        {
            wined3d_swapchain_get_desc(device->implicit_swapchains[0]->wined3d_swapchain, &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;
942

943 944
            device->device_state = D3D9_DEVICE_STATE_OK;
        }
945 946 947 948 949 950 951 952 953

        if (!device->d3d_parent->extended)
            for (i = 0; i < ARRAY_SIZE(device->textures); ++i)
                device->textures[i] = NULL;

        rtv = wined3d_device_get_rendertarget_view(device->wined3d_device, 0);
        device->render_targets[0] = wined3d_rendertarget_view_get_sub_resource_parent(rtv);
        for (i = 1; i < ARRAY_SIZE(device->render_targets); ++i)
            device->render_targets[i] = NULL;
954
    }
955
    else if (!extended)
956
    {
957
        device->device_state = D3D9_DEVICE_STATE_NOT_RESET;
958
    }
959

960
    wined3d_mutex_unlock();
Henri Verbeet's avatar
Henri Verbeet committed
961

962
    return hr;
963 964
}

965 966 967 968 969 970 971 972 973 974
static HRESULT WINAPI DECLSPEC_HOTPATCH d3d9_device_Reset(IDirect3DDevice9Ex *iface,
        D3DPRESENT_PARAMETERS *present_parameters)
{
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);

    TRACE("iface %p, present_parameters %p.\n", iface, present_parameters);

    return d3d9_device_reset(device, present_parameters, NULL);
}

975 976
static HRESULT WINAPI DECLSPEC_HOTPATCH d3d9_device_Present(IDirect3DDevice9Ex *iface,
        const RECT *src_rect, const RECT *dst_rect, HWND dst_window_override, const RGNDATA *dirty_region)
977
{
978
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
979
    UINT i;
980
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
981 982

    TRACE("iface %p, src_rect %p, dst_rect %p, dst_window_override %p, dirty_region %p.\n",
983
            iface, src_rect, dst_rect, dst_window_override, dirty_region);
984

985 986 987
    if (device->device_state != D3D9_DEVICE_STATE_OK)
        return device->d3d_parent->extended ? S_PRESENT_OCCLUDED : D3DERR_DEVICELOST;

988 989 990
    if (dirty_region)
        FIXME("Ignoring dirty_region %p.\n", dirty_region);

991
    wined3d_mutex_lock();
992 993
    for (i = 0; i < device->implicit_swapchain_count; ++i)
    {
994 995
        if (FAILED(hr = wined3d_swapchain_present(device->implicit_swapchains[i]->wined3d_swapchain,
                src_rect, dst_rect, dst_window_override, 0)))
996 997 998 999 1000
        {
            wined3d_mutex_unlock();
            return hr;
        }
    }
1001 1002
    wined3d_mutex_unlock();

1003
    return D3D_OK;
1004
}
1005

1006 1007
static HRESULT WINAPI d3d9_device_GetBackBuffer(IDirect3DDevice9Ex *iface, UINT swapchain,
        UINT backbuffer_idx, D3DBACKBUFFER_TYPE backbuffer_type, IDirect3DSurface9 **backbuffer)
1008
{
1009
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1010
    HRESULT hr;
1011

Henri Verbeet's avatar
Henri Verbeet committed
1012
    TRACE("iface %p, swapchain %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
1013
            iface, swapchain, backbuffer_idx, backbuffer_type, backbuffer);
1014

1015 1016
    /* backbuffer_type is ignored by native. */

1017
    /* No need to check for backbuffer == NULL, Windows crashes in that case. */
1018
    *backbuffer = NULL;
1019

1020 1021
    wined3d_mutex_lock();
    if (swapchain >= device->implicit_swapchain_count)
1022 1023
    {
        wined3d_mutex_unlock();
1024
        WARN("Swapchain index %u is out of range, returning D3DERR_INVALIDCALL.\n", swapchain);
1025 1026 1027
        return D3DERR_INVALIDCALL;
    }

1028 1029
    hr = IDirect3DSwapChain9Ex_GetBackBuffer(&device->implicit_swapchains[swapchain]->IDirect3DSwapChain9Ex_iface,
            backbuffer_idx, backbuffer_type, backbuffer);
1030
    wined3d_mutex_unlock();
1031 1032

    return hr;
1033
}
1034

1035 1036
static HRESULT WINAPI d3d9_device_GetRasterStatus(IDirect3DDevice9Ex *iface,
        UINT swapchain, D3DRASTER_STATUS *raster_status)
1037
{
1038
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1039
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
1040

1041
    TRACE("iface %p, swapchain %u, raster_status %p.\n", iface, swapchain, raster_status);
1042

1043
    wined3d_mutex_lock();
1044 1045
    hr = wined3d_device_get_raster_status(device->wined3d_device,
            swapchain, (struct wined3d_raster_status *)raster_status);
1046 1047
    wined3d_mutex_unlock();

1048
    return hr;
1049 1050
}

1051
static HRESULT WINAPI d3d9_device_SetDialogBoxMode(IDirect3DDevice9Ex *iface, BOOL enable)
1052
{
1053
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1054
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
1055

1056
    TRACE("iface %p, enable %#x.\n", iface, enable);
1057

1058
    wined3d_mutex_lock();
1059
    hr = wined3d_device_set_dialog_box_mode(device->wined3d_device, enable);
1060 1061
    wined3d_mutex_unlock();

1062
    return hr;
1063 1064
}

1065 1066
static void WINAPI d3d9_device_SetGammaRamp(IDirect3DDevice9Ex *iface,
        UINT swapchain, DWORD flags, const D3DGAMMARAMP *ramp)
1067
{
1068
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
Henri Verbeet's avatar
Henri Verbeet committed
1069

1070
    TRACE("iface %p, swapchain %u, flags %#x, ramp %p.\n", iface, swapchain, flags, ramp);
1071

1072
    /* Note: D3DGAMMARAMP is compatible with struct wined3d_gamma_ramp. */
1073
    wined3d_mutex_lock();
1074
    wined3d_device_set_gamma_ramp(device->wined3d_device, swapchain, flags, (const struct wined3d_gamma_ramp *)ramp);
1075
    wined3d_mutex_unlock();
1076 1077
}

1078
static void WINAPI d3d9_device_GetGammaRamp(IDirect3DDevice9Ex *iface, UINT swapchain, D3DGAMMARAMP *ramp)
1079
{
1080
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
Henri Verbeet's avatar
Henri Verbeet committed
1081

1082
    TRACE("iface %p, swapchain %u, ramp %p.\n", iface, swapchain, ramp);
1083

1084
    /* Note: D3DGAMMARAMP is compatible with struct wined3d_gamma_ramp. */
1085
    wined3d_mutex_lock();
1086
    wined3d_device_get_gamma_ramp(device->wined3d_device, swapchain, (struct wined3d_gamma_ramp *)ramp);
1087
    wined3d_mutex_unlock();
1088 1089
}

1090
static HRESULT WINAPI d3d9_device_CreateTexture(IDirect3DDevice9Ex *iface,
1091 1092 1093
        UINT width, UINT height, UINT levels, DWORD usage, D3DFORMAT format,
        D3DPOOL pool, IDirect3DTexture9 **texture, HANDLE *shared_handle)
{
1094
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1095
    struct d3d9_texture *object;
1096
    BOOL set_mem = FALSE;
1097 1098 1099 1100 1101
    HRESULT hr;

    TRACE("iface %p, width %u, height %u, levels %u, usage %#x, format %#x, pool %#x, texture %p, shared_handle %p.\n",
            iface, width, height, levels, usage, format, pool, texture, shared_handle);

1102
    *texture = NULL;
1103
    if (shared_handle)
1104
    {
1105 1106 1107 1108 1109 1110
        if (!device->d3d_parent->extended)
        {
            WARN("Trying to create a shared or user memory texture on a non-ex device.\n");
            return E_NOTIMPL;
        }

1111 1112 1113 1114 1115 1116 1117
        if (pool == D3DPOOL_SYSTEMMEM)
        {
            if (levels != 1)
                return D3DERR_INVALIDCALL;
            set_mem = TRUE;
        }
        else
1118 1119 1120 1121 1122 1123
        {
            if (pool != D3DPOOL_DEFAULT)
            {
                WARN("Trying to create a shared texture in pool %#x.\n", pool);
                return D3DERR_INVALIDCALL;
            }
1124
            FIXME("Resource sharing not implemented, *shared_handle %p.\n", *shared_handle);
1125
        }
1126
    }
1127

1128
    if (!(object = heap_alloc_zero(sizeof(*object))))
1129 1130
        return D3DERR_OUTOFVIDEOMEMORY;

1131
    hr = texture_init(object, device, width, height, levels, usage, format, pool);
1132 1133 1134
    if (FAILED(hr))
    {
        WARN("Failed to initialize texture, hr %#x.\n", hr);
1135
        heap_free(object);
1136 1137 1138
        return hr;
    }

1139
    if (set_mem)
1140
        wined3d_texture_update_desc(object->wined3d_texture, width, height,
1141 1142
                wined3dformat_from_d3dformat(format), WINED3D_MULTISAMPLE_NONE, 0,
                *shared_handle, 0);
1143

1144
    TRACE("Created texture %p.\n", object);
1145
    *texture = (IDirect3DTexture9 *)&object->IDirect3DBaseTexture9_iface;
1146 1147 1148 1149

    return D3D_OK;
}

1150
static HRESULT WINAPI d3d9_device_CreateVolumeTexture(IDirect3DDevice9Ex *iface,
1151 1152 1153
        UINT width, UINT height, UINT depth, UINT levels, DWORD usage, D3DFORMAT format,
        D3DPOOL pool, IDirect3DVolumeTexture9 **texture, HANDLE *shared_handle)
{
1154
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1155
    struct d3d9_texture *object;
1156 1157
    HRESULT hr;

1158 1159 1160
    TRACE("iface %p, width %u, height %u, depth %u, levels %u, "
            "usage %#x, format %#x, pool %#x, texture %p, shared_handle %p.\n",
            iface, width, height, depth, levels,
1161 1162
            usage, format, pool, texture, shared_handle);

1163
    *texture = NULL;
1164
    if (shared_handle)
1165
    {
1166 1167 1168 1169 1170 1171
        if (!device->d3d_parent->extended)
        {
            WARN("Trying to create a shared volume texture on a non-ex device.\n");
            return E_NOTIMPL;
        }

1172 1173 1174 1175 1176
        if (pool != D3DPOOL_DEFAULT)
        {
            WARN("Trying to create a shared volume texture in pool %#x.\n", pool);
            return D3DERR_INVALIDCALL;
        }
1177
        FIXME("Resource sharing not implemented, *shared_handle %p.\n", *shared_handle);
1178
    }
1179

1180
    if (!(object = heap_alloc_zero(sizeof(*object))))
1181 1182
        return D3DERR_OUTOFVIDEOMEMORY;

1183
    hr = volumetexture_init(object, device, width, height, depth, levels, usage, format, pool);
1184 1185 1186
    if (FAILED(hr))
    {
        WARN("Failed to initialize volume texture, hr %#x.\n", hr);
1187
        heap_free(object);
1188 1189 1190 1191
        return hr;
    }

    TRACE("Created volume texture %p.\n", object);
1192
    *texture = (IDirect3DVolumeTexture9 *)&object->IDirect3DBaseTexture9_iface;
1193 1194 1195 1196

    return D3D_OK;
}

1197
static HRESULT WINAPI d3d9_device_CreateCubeTexture(IDirect3DDevice9Ex *iface,
1198 1199 1200
        UINT edge_length, UINT levels, DWORD usage, D3DFORMAT format, D3DPOOL pool,
        IDirect3DCubeTexture9 **texture, HANDLE *shared_handle)
{
1201
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1202
    struct d3d9_texture *object;
1203 1204 1205 1206 1207
    HRESULT hr;

    TRACE("iface %p, edge_length %u, levels %u, usage %#x, format %#x, pool %#x, texture %p, shared_handle %p.\n",
            iface, edge_length, levels, usage, format, pool, texture, shared_handle);

1208
    *texture = NULL;
1209
    if (shared_handle)
1210
    {
1211 1212 1213 1214 1215 1216
        if (!device->d3d_parent->extended)
        {
            WARN("Trying to create a shared cube texture on a non-ex device.\n");
            return E_NOTIMPL;
        }

1217 1218 1219 1220 1221
        if (pool != D3DPOOL_DEFAULT)
        {
            WARN("Trying to create a shared cube texture in pool %#x.\n", pool);
            return D3DERR_INVALIDCALL;
        }
1222
        FIXME("Resource sharing not implemented, *shared_handle %p.\n", *shared_handle);
1223
    }
1224

1225
    if (!(object = heap_alloc_zero(sizeof(*object))))
1226 1227
        return D3DERR_OUTOFVIDEOMEMORY;

1228
    hr = cubetexture_init(object, device, edge_length, levels, usage, format, pool);
1229 1230 1231
    if (FAILED(hr))
    {
        WARN("Failed to initialize cube texture, hr %#x.\n", hr);
1232
        heap_free(object);
1233 1234 1235 1236
        return hr;
    }

    TRACE("Created cube texture %p.\n", object);
1237
    *texture = (IDirect3DCubeTexture9 *)&object->IDirect3DBaseTexture9_iface;
1238 1239 1240 1241

    return D3D_OK;
}

1242
static HRESULT WINAPI d3d9_device_CreateVertexBuffer(IDirect3DDevice9Ex *iface, UINT size,
1243 1244
        DWORD usage, DWORD fvf, D3DPOOL pool, IDirect3DVertexBuffer9 **buffer,
        HANDLE *shared_handle)
1245
{
1246
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1247
    struct d3d9_vertexbuffer *object;
1248 1249 1250 1251 1252
    HRESULT hr;

    TRACE("iface %p, size %u, usage %#x, fvf %#x, pool %#x, buffer %p, shared_handle %p.\n",
            iface, size, usage, fvf, pool, buffer, shared_handle);

1253
    if (shared_handle)
1254
    {
1255 1256 1257 1258 1259 1260
        if (!device->d3d_parent->extended)
        {
            WARN("Trying to create a shared vertex buffer on a non-ex device.\n");
            return E_NOTIMPL;
        }

1261 1262 1263 1264 1265
        if (pool != D3DPOOL_DEFAULT)
        {
            WARN("Trying to create a shared vertex buffer in pool %#x.\n", pool);
            return D3DERR_NOTAVAILABLE;
        }
1266
        FIXME("Resource sharing not implemented, *shared_handle %p.\n", *shared_handle);
1267
    }
1268

1269
    if (!(object = heap_alloc_zero(sizeof(*object))))
1270 1271
        return D3DERR_OUTOFVIDEOMEMORY;

1272
    hr = vertexbuffer_init(object, device, size, usage, fvf, pool);
1273 1274 1275
    if (FAILED(hr))
    {
        WARN("Failed to initialize vertex buffer, hr %#x.\n", hr);
1276
        heap_free(object);
1277 1278 1279 1280
        return hr;
    }

    TRACE("Created vertex buffer %p.\n", object);
1281
    *buffer = &object->IDirect3DVertexBuffer9_iface;
1282 1283 1284 1285

    return D3D_OK;
}

1286
static HRESULT WINAPI d3d9_device_CreateIndexBuffer(IDirect3DDevice9Ex *iface, UINT size,
1287 1288
        DWORD usage, D3DFORMAT format, D3DPOOL pool, IDirect3DIndexBuffer9 **buffer,
        HANDLE *shared_handle)
1289
{
1290
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1291
    struct d3d9_indexbuffer *object;
1292 1293 1294 1295 1296
    HRESULT hr;

    TRACE("iface %p, size %u, usage %#x, format %#x, pool %#x, buffer %p, shared_handle %p.\n",
            iface, size, usage, format, pool, buffer, shared_handle);

1297
    if (shared_handle)
1298
    {
1299 1300 1301 1302 1303 1304
        if (!device->d3d_parent->extended)
        {
            WARN("Trying to create a shared index buffer on a non-ex device.\n");
            return E_NOTIMPL;
        }

1305 1306 1307 1308 1309
        if (pool != D3DPOOL_DEFAULT)
        {
            WARN("Trying to create a shared index buffer in pool %#x.\n", pool);
            return D3DERR_NOTAVAILABLE;
        }
1310
        FIXME("Resource sharing not implemented, *shared_handle %p.\n", *shared_handle);
1311
    }
1312

1313
    if (!(object = heap_alloc_zero(sizeof(*object))))
1314 1315
        return D3DERR_OUTOFVIDEOMEMORY;

1316
    hr = indexbuffer_init(object, device, size, usage, format, pool);
1317 1318 1319
    if (FAILED(hr))
    {
        WARN("Failed to initialize index buffer, hr %#x.\n", hr);
1320
        heap_free(object);
1321 1322 1323 1324
        return hr;
    }

    TRACE("Created index buffer %p.\n", object);
1325
    *buffer = &object->IDirect3DIndexBuffer9_iface;
1326 1327 1328 1329

    return D3D_OK;
}

1330
static HRESULT d3d9_device_create_surface(struct d3d9_device *device, UINT width, UINT height,
1331
        D3DFORMAT format, DWORD flags, IDirect3DSurface9 **surface, UINT usage, D3DPOOL pool,
1332
        D3DMULTISAMPLE_TYPE multisample_type, DWORD multisample_quality, void *user_mem)
1333
{
1334 1335 1336
    struct wined3d_resource_desc desc;
    struct d3d9_surface *surface_impl;
    struct wined3d_texture *texture;
1337
    HRESULT hr;
1338

1339
    TRACE("device %p, width %u, height %u, format %#x, flags %#x, surface %p.\n"
Henri Verbeet's avatar
Henri Verbeet committed
1340
            "usage %#x, pool %#x, multisample_type %#x, multisample_quality %u.\n",
1341
            device, width, height, format, flags, surface, usage, pool,
1342
            multisample_type, multisample_quality);
1343

1344
    desc.resource_type = WINED3D_RTYPE_TEXTURE_2D;
1345 1346 1347 1348
    desc.format = wined3dformat_from_d3dformat(format);
    desc.multisample_type = multisample_type;
    desc.multisample_quality = multisample_quality;
    desc.usage = usage & WINED3DUSAGE_MASK;
1349 1350
    if (pool == D3DPOOL_SCRATCH)
        desc.usage |= WINED3DUSAGE_SCRATCH;
1351 1352
    desc.access = wined3daccess_from_d3dpool(pool, usage)
            | WINED3D_RESOURCE_ACCESS_MAP_R | WINED3D_RESOURCE_ACCESS_MAP_W;
1353 1354 1355 1356
    desc.width = width;
    desc.height = height;
    desc.depth = 1;
    desc.size = 0;
1357

1358
    if (is_gdi_compat_wined3dformat(desc.format))
1359 1360
        flags |= WINED3D_TEXTURE_CREATE_GET_DC;

1361 1362
    wined3d_mutex_lock();

1363
    if (FAILED(hr = wined3d_texture_create(device->wined3d_device, &desc,
1364
            1, 1, flags, NULL, NULL, &d3d9_null_wined3d_parent_ops, &texture)))
1365
    {
1366 1367
        wined3d_mutex_unlock();
        WARN("Failed to create texture, hr %#x.\n", hr);
1368 1369
        if (hr == WINED3DERR_NOTAVAILABLE)
            hr = D3DERR_INVALIDCALL;
1370
        return hr;
1371 1372
    }

1373
    surface_impl = wined3d_texture_get_sub_resource_parent(texture, 0);
1374 1375 1376 1377
    surface_impl->parent_device = &device->IDirect3DDevice9Ex_iface;
    *surface = &surface_impl->IDirect3DSurface9_iface;
    IDirect3DSurface9_AddRef(*surface);

1378
    if (user_mem)
1379
        wined3d_texture_update_desc(texture, width, height,
1380
                desc.format, multisample_type, multisample_quality, user_mem, 0);
1381

1382 1383
    wined3d_texture_decref(texture);

1384
    wined3d_mutex_unlock();
1385

1386
    return D3D_OK;
1387 1388
}

1389
BOOL is_gdi_compat_wined3dformat(enum wined3d_format_id format)
1390 1391 1392
{
    switch (format)
    {
1393 1394 1395 1396 1397 1398
        case WINED3DFMT_B8G8R8A8_UNORM:
        case WINED3DFMT_B8G8R8X8_UNORM:
        case WINED3DFMT_B5G6R5_UNORM:
        case WINED3DFMT_B5G5R5X1_UNORM:
        case WINED3DFMT_B5G5R5A1_UNORM:
        case WINED3DFMT_B8G8R8_UNORM:
1399 1400 1401 1402 1403 1404
            return TRUE;
        default:
            return FALSE;
    }
}

1405 1406 1407
static HRESULT WINAPI d3d9_device_CreateRenderTarget(IDirect3DDevice9Ex *iface, UINT width, UINT height,
        D3DFORMAT format, D3DMULTISAMPLE_TYPE multisample_type, DWORD multisample_quality,
        BOOL lockable, IDirect3DSurface9 **surface, HANDLE *shared_handle)
1408
{
1409
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1410
    DWORD flags = 0;
Henri Verbeet's avatar
Henri Verbeet committed
1411 1412 1413

    TRACE("iface %p, width %u, height %u, format %#x, multisample_type %#x, multisample_quality %u.\n"
            "lockable %#x, surface %p, shared_handle %p.\n",
1414 1415
            iface, width, height, format, multisample_type, multisample_quality,
            lockable, surface, shared_handle);
1416

1417
    *surface = NULL;
1418
    if (shared_handle)
1419 1420 1421 1422 1423 1424 1425
    {
        if (!device->d3d_parent->extended)
        {
            WARN("Trying to create a shared render target on a non-ex device.\n");
            return E_NOTIMPL;
        }

1426
        FIXME("Resource sharing not implemented, *shared_handle %p.\n", *shared_handle);
1427
    }
1428

1429
    if (lockable)
1430
        flags |= WINED3D_TEXTURE_CREATE_MAPPABLE;
1431 1432

    return d3d9_device_create_surface(device, width, height, format, flags, surface,
1433
            D3DUSAGE_RENDERTARGET, D3DPOOL_DEFAULT, multisample_type, multisample_quality, NULL);
1434 1435
}

1436 1437 1438
static HRESULT WINAPI d3d9_device_CreateDepthStencilSurface(IDirect3DDevice9Ex *iface, UINT width, UINT height,
        D3DFORMAT format, D3DMULTISAMPLE_TYPE multisample_type, DWORD multisample_quality,
        BOOL discard, IDirect3DSurface9 **surface, HANDLE *shared_handle)
1439
{
1440
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1441
    DWORD flags = WINED3D_TEXTURE_CREATE_MAPPABLE;
Henri Verbeet's avatar
Henri Verbeet committed
1442 1443 1444

    TRACE("iface %p, width %u, height %u, format %#x, multisample_type %#x, multisample_quality %u.\n"
            "discard %#x, surface %p, shared_handle %p.\n",
1445 1446
            iface, width, height, format, multisample_type, multisample_quality,
            discard, surface, shared_handle);
1447

1448
    *surface = NULL;
1449
    if (shared_handle)
1450 1451 1452 1453 1454 1455 1456
    {
        if (!device->d3d_parent->extended)
        {
            WARN("Trying to create a shared depth stencil on a non-ex device.\n");
            return E_NOTIMPL;
        }

1457
        FIXME("Resource sharing not implemented, *shared_handle %p.\n", *shared_handle);
1458
    }
1459

1460
    if (discard)
1461
        flags |= WINED3D_TEXTURE_CREATE_DISCARD;
1462 1463

    return d3d9_device_create_surface(device, width, height, format, flags, surface,
1464
            D3DUSAGE_DEPTHSTENCIL, D3DPOOL_DEFAULT, multisample_type, multisample_quality, NULL);
1465 1466
}

1467

1468 1469 1470
static HRESULT WINAPI d3d9_device_UpdateSurface(IDirect3DDevice9Ex *iface,
        IDirect3DSurface9 *src_surface, const RECT *src_rect,
        IDirect3DSurface9 *dst_surface, const POINT *dst_point)
1471
{
1472
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1473 1474
    struct d3d9_surface *src = unsafe_impl_from_IDirect3DSurface9(src_surface);
    struct d3d9_surface *dst = unsafe_impl_from_IDirect3DSurface9(dst_surface);
1475
    struct wined3d_sub_resource_desc src_desc, dst_desc;
1476
    struct wined3d_box src_box;
1477
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
1478 1479

    TRACE("iface %p, src_surface %p, src_rect %p, dst_surface %p, dst_point %p.\n",
1480
            iface, src_surface, src_rect, dst_surface, dst_point);
1481

1482
    wined3d_mutex_lock();
1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494

    wined3d_texture_get_sub_resource_desc(src->wined3d_texture, src->sub_resource_idx, &src_desc);
    wined3d_texture_get_sub_resource_desc(dst->wined3d_texture, dst->sub_resource_idx, &dst_desc);
    if (src_desc.format != dst_desc.format)
    {
        wined3d_mutex_unlock();
        WARN("Surface formats (%#x/%#x) don't match.\n",
                d3dformat_from_wined3dformat(src_desc.format),
                d3dformat_from_wined3dformat(dst_desc.format));
        return D3DERR_INVALIDCALL;
    }

1495 1496 1497 1498 1499
    if (src_rect)
        wined3d_box_set(&src_box, src_rect->left, src_rect->top, src_rect->right, src_rect->bottom, 0, 1);
    else
        wined3d_box_set(&src_box, 0, 0, src_desc.width, src_desc.height, 0, 1);

1500 1501 1502
    hr = wined3d_device_copy_sub_resource_region(device->wined3d_device,
            wined3d_texture_get_resource(dst->wined3d_texture), dst->sub_resource_idx, dst_point ? dst_point->x : 0,
            dst_point ? dst_point->y : 0, 0, wined3d_texture_get_resource(src->wined3d_texture),
1503
            src->sub_resource_idx, &src_box);
1504 1505 1506
    if (SUCCEEDED(hr) && dst->texture)
        d3d9_texture_flag_auto_gen_mipmap(dst->texture);

1507 1508
    wined3d_mutex_unlock();

1509 1510 1511
    if (FAILED(hr))
        return D3DERR_INVALIDCALL;

1512
    return hr;
1513 1514
}

1515
static HRESULT WINAPI d3d9_device_UpdateTexture(IDirect3DDevice9Ex *iface,
1516 1517
        IDirect3DBaseTexture9 *src_texture, IDirect3DBaseTexture9 *dst_texture)
{
1518
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1519
    struct d3d9_texture *src_impl, *dst_impl;
1520
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
1521

1522
    TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
1523

1524 1525 1526
    src_impl = unsafe_impl_from_IDirect3DBaseTexture9(src_texture);
    dst_impl = unsafe_impl_from_IDirect3DBaseTexture9(dst_texture);

1527
    wined3d_mutex_lock();
1528
    hr = wined3d_device_update_texture(device->wined3d_device,
1529
            src_impl->wined3d_texture, dst_impl->wined3d_texture);
1530 1531
    if (SUCCEEDED(hr))
        d3d9_texture_flag_auto_gen_mipmap(dst_impl);
1532 1533
    wined3d_mutex_unlock();

1534
    return hr;
1535 1536
}

1537 1538
static HRESULT WINAPI d3d9_device_GetRenderTargetData(IDirect3DDevice9Ex *iface,
        IDirect3DSurface9 *render_target, IDirect3DSurface9 *dst_surface)
Henri Verbeet's avatar
Henri Verbeet committed
1539
{
1540 1541
    struct d3d9_surface *rt_impl = unsafe_impl_from_IDirect3DSurface9(render_target);
    struct d3d9_surface *dst_impl = unsafe_impl_from_IDirect3DSurface9(dst_surface);
1542
    struct wined3d_sub_resource_desc wined3d_desc;
1543
    RECT dst_rect, src_rect;
1544
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
1545

1546
    TRACE("iface %p, render_target %p, dst_surface %p.\n", iface, render_target, dst_surface);
1547

1548 1549 1550
    if (!render_target || !dst_surface)
        return D3DERR_INVALIDCALL;

1551
    wined3d_mutex_lock();
1552
    wined3d_texture_get_sub_resource_desc(dst_impl->wined3d_texture, dst_impl->sub_resource_idx, &wined3d_desc);
1553
    SetRect(&dst_rect, 0, 0, wined3d_desc.width, wined3d_desc.height);
1554

1555
    wined3d_texture_get_sub_resource_desc(rt_impl->wined3d_texture, rt_impl->sub_resource_idx, &wined3d_desc);
1556
    SetRect(&src_rect, 0, 0, wined3d_desc.width, wined3d_desc.height);
1557 1558 1559 1560 1561

    /* TODO: Check surface sizes, pools, etc. */
    if (wined3d_desc.multisample_type)
        hr = D3DERR_INVALIDCALL;
    else
1562 1563
        hr = wined3d_texture_blt(dst_impl->wined3d_texture, dst_impl->sub_resource_idx, &dst_rect,
                rt_impl->wined3d_texture, rt_impl->sub_resource_idx, &src_rect, 0, NULL, WINED3D_TEXF_POINT);
1564 1565
    wined3d_mutex_unlock();

1566
    return hr;
1567 1568
}

1569 1570
static HRESULT WINAPI d3d9_device_GetFrontBufferData(IDirect3DDevice9Ex *iface,
        UINT swapchain, IDirect3DSurface9 *dst_surface)
1571
{
1572
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1573
    struct d3d9_surface *dst_impl = unsafe_impl_from_IDirect3DSurface9(dst_surface);
1574
    HRESULT hr = D3DERR_INVALIDCALL;
Henri Verbeet's avatar
Henri Verbeet committed
1575

1576
    TRACE("iface %p, swapchain %u, dst_surface %p.\n", iface, swapchain, dst_surface);
1577

1578
    wined3d_mutex_lock();
1579 1580
    if (swapchain < device->implicit_swapchain_count)
        hr = wined3d_swapchain_get_front_buffer_data(device->implicit_swapchains[swapchain]->wined3d_swapchain,
1581
                dst_impl->wined3d_texture, dst_impl->sub_resource_idx);
1582 1583
    wined3d_mutex_unlock();

1584
    return hr;
1585 1586
}

1587
static HRESULT WINAPI d3d9_device_StretchRect(IDirect3DDevice9Ex *iface, IDirect3DSurface9 *src_surface,
1588
        const RECT *src_rect, IDirect3DSurface9 *dst_surface, const RECT *dst_rect, D3DTEXTUREFILTERTYPE filter)
Henri Verbeet's avatar
Henri Verbeet committed
1589
{
1590
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1591 1592
    struct d3d9_surface *src = unsafe_impl_from_IDirect3DSurface9(src_surface);
    struct d3d9_surface *dst = unsafe_impl_from_IDirect3DSurface9(dst_surface);
1593
    struct wined3d_sub_resource_desc src_desc, dst_desc;
1594
    HRESULT hr = D3DERR_INVALIDCALL;
1595
    RECT d, s;
1596

Henri Verbeet's avatar
Henri Verbeet committed
1597
    TRACE("iface %p, src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %#x.\n",
1598
            iface, src_surface, src_rect, dst_surface, dst_rect, filter);
1599 1600

    wined3d_mutex_lock();
1601
    wined3d_texture_get_sub_resource_desc(dst->wined3d_texture, dst->sub_resource_idx, &dst_desc);
1602 1603
    if (!dst_rect)
    {
1604
        SetRect(&d, 0, 0, dst_desc.width, dst_desc.height);
1605 1606
        dst_rect = &d;
    }
1607

1608
    wined3d_texture_get_sub_resource_desc(src->wined3d_texture, src->sub_resource_idx, &src_desc);
1609 1610
    if (!src_rect)
    {
1611
        SetRect(&s, 0, 0, src_desc.width, src_desc.height);
1612 1613
        src_rect = &s;
    }
1614 1615 1616

    if (src_desc.usage & WINED3DUSAGE_DEPTHSTENCIL)
    {
1617
        if (device->in_scene)
1618 1619 1620 1621 1622
        {
            WARN("Rejecting depth / stencil blit while in scene.\n");
            goto done;
        }

1623 1624
        if (src_rect->left || src_rect->top || src_rect->right != src_desc.width
                || src_rect->bottom != src_desc.height)
1625
        {
1626 1627 1628
            WARN("Rejecting depth / stencil blit with invalid source rect %s.\n",
                    wine_dbgstr_rect(src_rect));
            goto done;
1629
        }
1630 1631 1632

        if (dst_rect->left || dst_rect->top || dst_rect->right != dst_desc.width
                || dst_rect->bottom != dst_desc.height)
1633
        {
1634 1635 1636
            WARN("Rejecting depth / stencil blit with invalid destination rect %s.\n",
                    wine_dbgstr_rect(dst_rect));
            goto done;
1637
        }
1638

1639 1640 1641 1642 1643 1644 1645
        if (src_desc.width != dst_desc.width || src_desc.height != dst_desc.height)
        {
            WARN("Rejecting depth / stencil blit with mismatched surface sizes.\n");
            goto done;
        }
    }

1646 1647
    hr = wined3d_texture_blt(dst->wined3d_texture, dst->sub_resource_idx, dst_rect,
            src->wined3d_texture, src->sub_resource_idx, src_rect, 0, NULL, filter);
1648 1649
    if (hr == WINEDDERR_INVALIDRECT)
        hr = D3DERR_INVALIDCALL;
1650 1651
    if (SUCCEEDED(hr) && dst->texture)
        d3d9_texture_flag_auto_gen_mipmap(dst->texture);
1652

1653 1654
done:
    wined3d_mutex_unlock();
1655
    return hr;
1656 1657
}

1658 1659
static HRESULT WINAPI d3d9_device_ColorFill(IDirect3DDevice9Ex *iface,
        IDirect3DSurface9 *surface, const RECT *rect, D3DCOLOR color)
1660
{
1661
    const struct wined3d_color c =
1662 1663 1664 1665 1666 1667
    {
        ((color >> 16) & 0xff) / 255.0f,
        ((color >>  8) & 0xff) / 255.0f,
        (color & 0xff) / 255.0f,
        ((color >> 24) & 0xff) / 255.0f,
    };
1668
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1669
    struct d3d9_surface *surface_impl = unsafe_impl_from_IDirect3DSurface9(surface);
1670
    struct wined3d_sub_resource_desc desc;
1671
    struct wined3d_rendertarget_view *rtv;
1672
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
1673

1674
    TRACE("iface %p, surface %p, rect %p, color 0x%08x.\n", iface, surface, rect, color);
1675

1676 1677
    wined3d_mutex_lock();

1678 1679
    if (FAILED(wined3d_texture_get_sub_resource_desc(surface_impl->wined3d_texture,
            surface_impl->sub_resource_idx, &desc)))
1680 1681 1682 1683
    {
        wined3d_mutex_unlock();
        return D3DERR_INVALIDCALL;
    }
1684

1685
    if (desc.access & WINED3D_RESOURCE_ACCESS_CPU)
1686
    {
1687
        wined3d_mutex_unlock();
1688
        WARN("Colour fills are not allowed on surfaces with resource access %#x.\n", desc.access);
1689 1690
        return D3DERR_INVALIDCALL;
    }
1691 1692 1693 1694 1695 1696 1697
    if ((desc.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_TEXTURE)) == WINED3DUSAGE_TEXTURE)
    {
        wined3d_mutex_unlock();
        WARN("Colorfill is not allowed on non-RT textures, returning D3DERR_INVALIDCALL.\n");
        return D3DERR_INVALIDCALL;
    }
    if (desc.usage & WINED3DUSAGE_DEPTHSTENCIL)
1698
    {
1699 1700
        wined3d_mutex_unlock();
        WARN("Colorfill is not allowed on depth stencil surfaces, returning D3DERR_INVALIDCALL.\n");
1701 1702 1703
        return D3DERR_INVALIDCALL;
    }

1704
    rtv = d3d9_surface_acquire_rendertarget_view(surface_impl);
1705
    hr = wined3d_device_clear_rendertarget_view(device->wined3d_device,
1706 1707
            rtv, rect, WINED3DCLEAR_TARGET, &c, 0.0f, 0);
    d3d9_surface_release_rendertarget_view(surface_impl, rtv);
1708 1709
    if (SUCCEEDED(hr) && surface_impl->texture)
        d3d9_texture_flag_auto_gen_mipmap(surface_impl->texture);
1710 1711 1712

    wined3d_mutex_unlock();

1713
    return hr;
1714 1715
}

1716 1717
static HRESULT WINAPI d3d9_device_CreateOffscreenPlainSurface(IDirect3DDevice9Ex *iface,
        UINT width, UINT height, D3DFORMAT format, D3DPOOL pool, IDirect3DSurface9 **surface,
1718
        HANDLE *shared_handle)
1719
{
1720
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1721
    void *user_mem = NULL;
Henri Verbeet's avatar
Henri Verbeet committed
1722 1723

    TRACE("iface %p, width %u, height %u, format %#x, pool %#x, surface %p, shared_handle %p.\n",
1724
            iface, width, height, format, pool, surface, shared_handle);
1725

1726
    *surface = NULL;
1727
    if (pool == D3DPOOL_MANAGED)
1728
    {
1729
        WARN("Attempting to create a managed offscreen plain surface.\n");
1730
        return D3DERR_INVALIDCALL;
1731
    }
1732 1733 1734

    if (shared_handle)
    {
1735 1736 1737 1738 1739 1740
        if (!device->d3d_parent->extended)
        {
            WARN("Trying to create a shared or user memory surface on a non-ex device.\n");
            return E_NOTIMPL;
        }

1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753
        if (pool == D3DPOOL_SYSTEMMEM)
            user_mem = *shared_handle;
        else
        {
            if (pool != D3DPOOL_DEFAULT)
            {
                WARN("Trying to create a shared surface in pool %#x.\n", pool);
                return D3DERR_INVALIDCALL;
            }
            FIXME("Resource sharing not implemented, *shared_handle %p.\n", *shared_handle);
        }
    }

1754 1755 1756
    /* FIXME: Offscreen surfaces are supposed to be always lockable,
     * regardless of the pool they're created in. Should we set dynamic usage
     * here? */
1757
    return d3d9_device_create_surface(device, width, height, format,
1758
            WINED3D_TEXTURE_CREATE_MAPPABLE, surface, 0, pool, D3DMULTISAMPLE_NONE, 0, user_mem);
1759 1760
}

1761
static HRESULT WINAPI d3d9_device_SetRenderTarget(IDirect3DDevice9Ex *iface, DWORD idx, IDirect3DSurface9 *surface)
1762
{
1763
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1764
    struct d3d9_surface *surface_impl = unsafe_impl_from_IDirect3DSurface9(surface);
1765
    struct wined3d_rendertarget_view *rtv;
1766
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
1767

1768
    TRACE("iface %p, idx %u, surface %p.\n", iface, idx, surface);
1769

1770
    if (idx >= D3D9_MAX_SIMULTANEOUS_RENDERTARGETS)
1771
    {
1772
        WARN("Invalid index %u specified.\n", idx);
1773 1774 1775
        return D3DERR_INVALIDCALL;
    }

1776 1777
    if (!idx && !surface_impl)
    {
1778 1779 1780 1781 1782 1783 1784 1785
        WARN("Trying to set render target 0 to NULL.\n");
        return D3DERR_INVALIDCALL;
    }

    if (surface_impl && d3d9_surface_get_device(surface_impl) != device)
    {
        WARN("Render target surface does not match device.\n");
        return D3DERR_INVALIDCALL;
1786 1787
    }

1788
    wined3d_mutex_lock();
1789 1790 1791
    rtv = surface_impl ? d3d9_surface_acquire_rendertarget_view(surface_impl) : NULL;
    hr = wined3d_device_set_rendertarget_view(device->wined3d_device, idx, rtv, TRUE);
    d3d9_surface_release_rendertarget_view(surface_impl, rtv);
1792 1793
    if (SUCCEEDED(hr))
        device->render_targets[idx] = surface_impl;
1794 1795
    wined3d_mutex_unlock();

1796
    return hr;
1797
}
1798

1799
static HRESULT WINAPI d3d9_device_GetRenderTarget(IDirect3DDevice9Ex *iface, DWORD idx, IDirect3DSurface9 **surface)
1800
{
1801
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1802
    struct wined3d_rendertarget_view *wined3d_rtv;
1803
    struct d3d9_surface *surface_impl;
1804
    HRESULT hr = D3D_OK;
1805

1806
    TRACE("iface %p, idx %u, surface %p.\n", iface, idx, surface);
1807

1808
    if (!surface)
1809
        return D3DERR_INVALIDCALL;
1810

1811
    if (idx >= D3D9_MAX_SIMULTANEOUS_RENDERTARGETS)
1812
    {
1813
        WARN("Invalid index %u specified.\n", idx);
1814 1815 1816
        return D3DERR_INVALIDCALL;
    }

1817
    wined3d_mutex_lock();
1818
    if ((wined3d_rtv = wined3d_device_get_rendertarget_view(device->wined3d_device, idx)))
1819
    {
1820 1821 1822
        /* 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);
1823 1824
        *surface = &surface_impl->IDirect3DSurface9_iface;
        IDirect3DSurface9_AddRef(*surface);
1825
    }
1826 1827
    else
    {
1828
        hr = D3DERR_NOTFOUND;
1829
        *surface = NULL;
1830
    }
1831
    wined3d_mutex_unlock();
1832

1833
    return hr;
1834 1835
}

1836
static HRESULT WINAPI d3d9_device_SetDepthStencilSurface(IDirect3DDevice9Ex *iface, IDirect3DSurface9 *depth_stencil)
1837
{
1838
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1839
    struct d3d9_surface *ds_impl = unsafe_impl_from_IDirect3DSurface9(depth_stencil);
1840
    struct wined3d_rendertarget_view *rtv;
Henri Verbeet's avatar
Henri Verbeet committed
1841

1842
    TRACE("iface %p, depth_stencil %p.\n", iface, depth_stencil);
1843

1844
    wined3d_mutex_lock();
1845 1846 1847
    rtv = ds_impl ? d3d9_surface_acquire_rendertarget_view(ds_impl) : NULL;
    wined3d_device_set_depth_stencil_view(device->wined3d_device, rtv);
    d3d9_surface_release_rendertarget_view(ds_impl, rtv);
1848 1849
    wined3d_mutex_unlock();

1850
    return D3D_OK;
1851 1852
}

1853
static HRESULT WINAPI d3d9_device_GetDepthStencilSurface(IDirect3DDevice9Ex *iface, IDirect3DSurface9 **depth_stencil)
1854
{
1855
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1856
    struct wined3d_rendertarget_view *wined3d_dsv;
1857
    struct d3d9_surface *surface_impl;
1858
    HRESULT hr = D3D_OK;
1859

1860
    TRACE("iface %p, depth_stencil %p.\n", iface, depth_stencil);
Henri Verbeet's avatar
Henri Verbeet committed
1861

1862
    if (!depth_stencil)
1863
        return D3DERR_INVALIDCALL;
1864

1865
    wined3d_mutex_lock();
1866
    if ((wined3d_dsv = wined3d_device_get_depth_stencil_view(device->wined3d_device)))
1867
    {
1868 1869 1870
        /* 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);
1871 1872
        *depth_stencil = &surface_impl->IDirect3DSurface9_iface;
        IDirect3DSurface9_AddRef(*depth_stencil);
1873 1874 1875
    }
    else
    {
1876
        hr = D3DERR_NOTFOUND;
1877
        *depth_stencil = NULL;
1878
    }
1879 1880
    wined3d_mutex_unlock();

1881
    return hr;
1882 1883
}

1884
static HRESULT WINAPI d3d9_device_BeginScene(IDirect3DDevice9Ex *iface)
1885
{
1886
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1887
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
1888 1889

    TRACE("iface %p.\n", iface);
1890

1891
    wined3d_mutex_lock();
1892 1893
    if (SUCCEEDED(hr = wined3d_device_begin_scene(device->wined3d_device)))
        device->in_scene = TRUE;
1894 1895
    wined3d_mutex_unlock();

1896
    return hr;
1897 1898
}

1899
static HRESULT WINAPI DECLSPEC_HOTPATCH d3d9_device_EndScene(IDirect3DDevice9Ex *iface)
1900
{
1901
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1902
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
1903 1904

    TRACE("iface %p.\n", iface);
1905

1906
    wined3d_mutex_lock();
1907 1908
    if (SUCCEEDED(hr = wined3d_device_end_scene(device->wined3d_device)))
        device->in_scene = FALSE;
1909 1910
    wined3d_mutex_unlock();

1911
    return hr;
1912 1913
}

1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926
static void d3d9_rts_flag_auto_gen_mipmap(struct d3d9_device *device)
{
    unsigned int i;

    for (i = 0; i < ARRAY_SIZE(device->render_targets); ++i)
    {
        struct d3d9_surface *surface = device->render_targets[i];

        if (surface && surface->texture)
            d3d9_texture_flag_auto_gen_mipmap(surface->texture);
    }
}

1927
static HRESULT WINAPI d3d9_device_Clear(IDirect3DDevice9Ex *iface, DWORD rect_count,
1928
        const D3DRECT *rects, DWORD flags, D3DCOLOR color, float z, DWORD stencil)
1929
{
1930 1931 1932 1933 1934 1935 1936
    const struct wined3d_color c =
    {
        ((color >> 16) & 0xff) / 255.0f,
        ((color >>  8) & 0xff) / 255.0f,
        (color & 0xff) / 255.0f,
        ((color >> 24) & 0xff) / 255.0f,
    };
1937
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1938
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
1939 1940

    TRACE("iface %p, rect_count %u, rects %p, flags %#x, color 0x%08x, z %.8e, stencil %u.\n",
1941
            iface, rect_count, rects, flags, color, z, stencil);
1942

1943 1944 1945 1946 1947 1948
    if (rect_count && !rects)
    {
        WARN("count %u with NULL rects.\n", rect_count);
        rect_count = 0;
    }

1949
    wined3d_mutex_lock();
1950
    hr = wined3d_device_clear(device->wined3d_device, rect_count, (const RECT *)rects, flags, &c, z, stencil);
1951 1952
    if (SUCCEEDED(hr))
        d3d9_rts_flag_auto_gen_mipmap(device);
1953 1954
    wined3d_mutex_unlock();

1955
    return hr;
1956 1957
}

1958 1959
static HRESULT WINAPI d3d9_device_SetTransform(IDirect3DDevice9Ex *iface,
        D3DTRANSFORMSTATETYPE state, const D3DMATRIX *matrix)
1960
{
1961
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
Henri Verbeet's avatar
Henri Verbeet committed
1962

1963
    TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
1964

1965
    /* Note: D3DMATRIX is compatible with struct wined3d_matrix. */
1966
    wined3d_mutex_lock();
1967
    wined3d_device_set_transform(device->wined3d_device, state, (const struct wined3d_matrix *)matrix);
1968 1969
    wined3d_mutex_unlock();

1970
    return D3D_OK;
1971 1972
}

1973 1974
static HRESULT WINAPI d3d9_device_GetTransform(IDirect3DDevice9Ex *iface,
        D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
1975
{
1976
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
Henri Verbeet's avatar
Henri Verbeet committed
1977

1978
    TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
1979

1980
    /* Note: D3DMATRIX is compatible with struct wined3d_matrix. */
1981
    wined3d_mutex_lock();
1982
    wined3d_device_get_transform(device->wined3d_device, state, (struct wined3d_matrix *)matrix);
1983
    wined3d_mutex_unlock();
Henri Verbeet's avatar
Henri Verbeet committed
1984

1985
    return D3D_OK;
1986 1987
}

1988 1989
static HRESULT WINAPI d3d9_device_MultiplyTransform(IDirect3DDevice9Ex *iface,
        D3DTRANSFORMSTATETYPE state, const D3DMATRIX *matrix)
1990
{
1991
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
Henri Verbeet's avatar
Henri Verbeet committed
1992

1993
    TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
1994

1995
    /* Note: D3DMATRIX is compatible with struct wined3d_matrix. */
1996
    wined3d_mutex_lock();
1997
    wined3d_device_multiply_transform(device->wined3d_device, state, (const struct wined3d_matrix *)matrix);
1998 1999
    wined3d_mutex_unlock();

2000
    return D3D_OK;
2001 2002
}

2003
static HRESULT WINAPI d3d9_device_SetViewport(IDirect3DDevice9Ex *iface, const D3DVIEWPORT9 *viewport)
2004
{
2005
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2006
    struct wined3d_viewport vp;
Henri Verbeet's avatar
Henri Verbeet committed
2007

2008
    TRACE("iface %p, viewport %p.\n", iface, viewport);
2009

2010 2011 2012 2013 2014 2015 2016
    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;

2017
    wined3d_mutex_lock();
2018
    wined3d_device_set_viewport(device->wined3d_device, &vp);
2019 2020
    wined3d_mutex_unlock();

2021
    return D3D_OK;
2022 2023
}

2024
static HRESULT WINAPI d3d9_device_GetViewport(IDirect3DDevice9Ex *iface, D3DVIEWPORT9 *viewport)
2025
{
2026
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2027
    struct wined3d_viewport wined3d_viewport;
Henri Verbeet's avatar
Henri Verbeet committed
2028

2029
    TRACE("iface %p, viewport %p.\n", iface, viewport);
2030

2031
    wined3d_mutex_lock();
2032
    wined3d_device_get_viewport(device->wined3d_device, &wined3d_viewport);
2033 2034
    wined3d_mutex_unlock();

2035 2036 2037 2038 2039 2040 2041
    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;

2042
    return D3D_OK;
2043 2044
}

2045
static HRESULT WINAPI d3d9_device_SetMaterial(IDirect3DDevice9Ex *iface, const D3DMATERIAL9 *material)
2046
{
2047
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
Henri Verbeet's avatar
Henri Verbeet committed
2048

2049
    TRACE("iface %p, material %p.\n", iface, material);
2050

2051
    /* Note: D3DMATERIAL9 is compatible with struct wined3d_material. */
2052
    wined3d_mutex_lock();
2053
    wined3d_device_set_material(device->wined3d_device, (const struct wined3d_material *)material);
2054 2055
    wined3d_mutex_unlock();

2056
    return D3D_OK;
2057 2058
}

2059
static HRESULT WINAPI d3d9_device_GetMaterial(IDirect3DDevice9Ex *iface, D3DMATERIAL9 *material)
2060
{
2061
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
Henri Verbeet's avatar
Henri Verbeet committed
2062

2063
    TRACE("iface %p, material %p.\n", iface, material);
2064

2065
    /* Note: D3DMATERIAL9 is compatible with struct wined3d_material. */
2066
    wined3d_mutex_lock();
2067
    wined3d_device_get_material(device->wined3d_device, (struct wined3d_material *)material);
2068 2069
    wined3d_mutex_unlock();

2070
    return D3D_OK;
2071 2072
}

2073
static HRESULT WINAPI d3d9_device_SetLight(IDirect3DDevice9Ex *iface, DWORD index, const D3DLIGHT9 *light)
2074
{
2075
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2076
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
2077

2078
    TRACE("iface %p, index %u, light %p.\n", iface, index, light);
2079

2080
    /* Note: D3DLIGHT9 is compatible with struct wined3d_light. */
2081
    wined3d_mutex_lock();
2082
    hr = wined3d_device_set_light(device->wined3d_device, index, (const struct wined3d_light *)light);
2083 2084
    wined3d_mutex_unlock();

2085
    return hr;
2086 2087
}

2088
static HRESULT WINAPI d3d9_device_GetLight(IDirect3DDevice9Ex *iface, DWORD index, D3DLIGHT9 *light)
2089
{
2090
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2091
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
2092

2093
    TRACE("iface %p, index %u, light %p.\n", iface, index, light);
2094

2095
    /* Note: D3DLIGHT9 is compatible with struct wined3d_light. */
2096
    wined3d_mutex_lock();
2097
    hr = wined3d_device_get_light(device->wined3d_device, index, (struct wined3d_light *)light);
2098 2099
    wined3d_mutex_unlock();

2100
    return hr;
2101 2102
}

2103
static HRESULT WINAPI d3d9_device_LightEnable(IDirect3DDevice9Ex *iface, DWORD index, BOOL enable)
2104
{
2105
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2106
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
2107

2108
    TRACE("iface %p, index %u, enable %#x.\n", iface, index, enable);
2109

2110
    wined3d_mutex_lock();
2111
    hr = wined3d_device_set_light_enable(device->wined3d_device, index, enable);
2112 2113
    wined3d_mutex_unlock();

2114
    return hr;
2115 2116
}

2117
static HRESULT WINAPI d3d9_device_GetLightEnable(IDirect3DDevice9Ex *iface, DWORD index, BOOL *enable)
2118
{
2119
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2120
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
2121

2122
    TRACE("iface %p, index %u, enable %p.\n", iface, index, enable);
2123

2124
    wined3d_mutex_lock();
2125
    hr = wined3d_device_get_light_enable(device->wined3d_device, index, enable);
2126 2127
    wined3d_mutex_unlock();

2128
    return hr;
2129 2130
}

2131
static HRESULT WINAPI d3d9_device_SetClipPlane(IDirect3DDevice9Ex *iface, DWORD index, const float *plane)
2132
{
2133
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2134
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
2135

2136
    TRACE("iface %p, index %u, plane %p.\n", iface, index, plane);
2137

2138 2139
    index = min(index, device->max_user_clip_planes - 1);

2140
    wined3d_mutex_lock();
2141
    hr = wined3d_device_set_clip_plane(device->wined3d_device, index, (const struct wined3d_vec4 *)plane);
2142 2143
    wined3d_mutex_unlock();

2144
    return hr;
2145 2146
}

2147
static HRESULT WINAPI d3d9_device_GetClipPlane(IDirect3DDevice9Ex *iface, DWORD index, float *plane)
2148
{
2149
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2150
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
2151

2152
    TRACE("iface %p, index %u, plane %p.\n", iface, index, plane);
2153

2154 2155
    index = min(index, device->max_user_clip_planes - 1);

2156
    wined3d_mutex_lock();
2157
    hr = wined3d_device_get_clip_plane(device->wined3d_device, index, (struct wined3d_vec4 *)plane);
2158 2159
    wined3d_mutex_unlock();

2160
    return hr;
2161 2162
}

2163 2164
static HRESULT WINAPI DECLSPEC_HOTPATCH d3d9_device_SetRenderState(IDirect3DDevice9Ex *iface,
        D3DRENDERSTATETYPE state, DWORD value)
2165
{
2166
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
Henri Verbeet's avatar
Henri Verbeet committed
2167

2168
    TRACE("iface %p, state %#x, value %#x.\n", iface, state, value);
2169

2170
    wined3d_mutex_lock();
2171
    wined3d_device_set_render_state(device->wined3d_device, state, value);
2172 2173
    wined3d_mutex_unlock();

2174
    return D3D_OK;
2175 2176
}

2177 2178
static HRESULT WINAPI d3d9_device_GetRenderState(IDirect3DDevice9Ex *iface,
        D3DRENDERSTATETYPE state, DWORD *value)
2179
{
2180
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
Henri Verbeet's avatar
Henri Verbeet committed
2181

2182
    TRACE("iface %p, state %#x, value %p.\n", iface, state, value);
2183

2184
    wined3d_mutex_lock();
2185
    *value = wined3d_device_get_render_state(device->wined3d_device, state);
2186 2187
    wined3d_mutex_unlock();

2188
    return D3D_OK;
2189 2190
}

2191
static HRESULT WINAPI d3d9_device_CreateStateBlock(IDirect3DDevice9Ex *iface,
2192 2193
        D3DSTATEBLOCKTYPE type, IDirect3DStateBlock9 **stateblock)
{
2194
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2195
    struct d3d9_stateblock *object;
2196 2197 2198 2199 2200 2201 2202 2203 2204 2205
    HRESULT hr;

    TRACE("iface %p, type %#x, stateblock %p.\n", iface, type, stateblock);

    if (type != D3DSBT_ALL && type != D3DSBT_PIXELSTATE && type != D3DSBT_VERTEXSTATE)
    {
        WARN("Unexpected stateblock type, returning D3DERR_INVALIDCALL.\n");
        return D3DERR_INVALIDCALL;
    }

2206
    if (!(object = heap_alloc_zero(sizeof(*object))))
2207 2208
        return E_OUTOFMEMORY;

2209
    hr = stateblock_init(object, device, type, NULL);
2210 2211 2212
    if (FAILED(hr))
    {
        WARN("Failed to initialize stateblock, hr %#x.\n", hr);
2213
        heap_free(object);
2214 2215 2216 2217
        return hr;
    }

    TRACE("Created stateblock %p.\n", object);
2218
    *stateblock = &object->IDirect3DStateBlock9_iface;
2219 2220 2221 2222

    return D3D_OK;
}

2223
static HRESULT WINAPI d3d9_device_BeginStateBlock(IDirect3DDevice9Ex *iface)
2224
{
2225
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2226 2227 2228 2229 2230
    HRESULT hr;

    TRACE("iface %p.\n", iface);

    wined3d_mutex_lock();
2231
    hr = wined3d_device_begin_stateblock(device->wined3d_device);
2232 2233 2234 2235 2236
    wined3d_mutex_unlock();

    return hr;
}

2237
static HRESULT WINAPI d3d9_device_EndStateBlock(IDirect3DDevice9Ex *iface, IDirect3DStateBlock9 **stateblock)
2238
{
2239
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2240
    struct wined3d_stateblock *wined3d_stateblock;
2241
    struct d3d9_stateblock *object;
2242 2243 2244 2245 2246
    HRESULT hr;

    TRACE("iface %p, stateblock %p.\n", iface, stateblock);

    wined3d_mutex_lock();
2247
    hr = wined3d_device_end_stateblock(device->wined3d_device, &wined3d_stateblock);
2248 2249 2250
    wined3d_mutex_unlock();
    if (FAILED(hr))
    {
2251
       WARN("Failed to end the state block, hr %#x.\n", hr);
2252 2253 2254
       return hr;
    }

2255
    if (!(object = heap_alloc_zero(sizeof(*object))))
2256
    {
2257
        wined3d_mutex_lock();
2258
        wined3d_stateblock_decref(wined3d_stateblock);
2259
        wined3d_mutex_unlock();
2260 2261 2262
        return E_OUTOFMEMORY;
    }

2263
    hr = stateblock_init(object, device, 0, wined3d_stateblock);
2264 2265 2266
    if (FAILED(hr))
    {
        WARN("Failed to initialize stateblock, hr %#x.\n", hr);
2267
        wined3d_mutex_lock();
2268
        wined3d_stateblock_decref(wined3d_stateblock);
2269
        wined3d_mutex_unlock();
2270
        heap_free(object);
2271 2272 2273 2274
        return hr;
    }

    TRACE("Created stateblock %p.\n", object);
2275
    *stateblock = &object->IDirect3DStateBlock9_iface;
2276 2277 2278 2279

    return D3D_OK;
}

2280
static HRESULT WINAPI d3d9_device_SetClipStatus(IDirect3DDevice9Ex *iface, const D3DCLIPSTATUS9 *clip_status)
2281
{
2282
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2283
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
2284

2285
    TRACE("iface %p, clip_status %p.\n", iface, clip_status);
2286

2287
    wined3d_mutex_lock();
2288
    hr = wined3d_device_set_clip_status(device->wined3d_device, (const struct wined3d_clip_status *)clip_status);
2289 2290
    wined3d_mutex_unlock();

2291
    return hr;
2292 2293
}

2294
static HRESULT WINAPI d3d9_device_GetClipStatus(IDirect3DDevice9Ex *iface, D3DCLIPSTATUS9 *clip_status)
2295
{
2296
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2297
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
2298

2299
    TRACE("iface %p, clip_status %p.\n", iface, clip_status);
2300

2301
    wined3d_mutex_lock();
2302
    hr = wined3d_device_get_clip_status(device->wined3d_device, (struct wined3d_clip_status *)clip_status);
2303 2304
    wined3d_mutex_unlock();

2305
    return hr;
2306 2307
}

2308
static HRESULT WINAPI d3d9_device_GetTexture(IDirect3DDevice9Ex *iface, DWORD stage, IDirect3DBaseTexture9 **texture)
2309
{
2310
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2311
    struct wined3d_texture *wined3d_texture = NULL;
2312
    struct d3d9_texture *texture_impl;
2313

2314
    TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
2315

2316
    if (!texture)
2317 2318
        return D3DERR_INVALIDCALL;

2319
    wined3d_mutex_lock();
2320
    if ((wined3d_texture = wined3d_device_get_texture(device->wined3d_device, stage)))
2321
    {
2322
        texture_impl = wined3d_texture_get_parent(wined3d_texture);
2323 2324
        *texture = &texture_impl->IDirect3DBaseTexture9_iface;
        IDirect3DBaseTexture9_AddRef(*texture);
2325 2326 2327
    }
    else
    {
2328
        *texture = NULL;
2329
    }
2330
    wined3d_mutex_unlock();
2331

2332
    return D3D_OK;
2333 2334
}

2335
static HRESULT WINAPI d3d9_device_SetTexture(IDirect3DDevice9Ex *iface, DWORD stage, IDirect3DBaseTexture9 *texture)
2336
{
2337
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2338
    struct d3d9_texture *texture_impl;
2339
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
2340

2341
    TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
2342

2343 2344
    texture_impl = unsafe_impl_from_IDirect3DBaseTexture9(texture);

2345
    wined3d_mutex_lock();
2346
    hr = wined3d_device_set_texture(device->wined3d_device, stage,
2347
            texture_impl ? texture_impl->wined3d_texture : NULL);
2348 2349 2350 2351 2352 2353 2354
    if (SUCCEEDED(hr))
    {
        unsigned int i = stage >= D3DVERTEXTEXTURESAMPLER0 ? stage - D3DVERTEXTEXTURESAMPLER0 + 16 : stage;

        if (stage < ARRAY_SIZE(device->textures))
            device->textures[i] = texture_impl;
    }
2355 2356
    wined3d_mutex_unlock();

2357
    return hr;
2358 2359
}

2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394
static const enum wined3d_texture_stage_state tss_lookup[] =
{
    WINED3D_TSS_INVALID,                    /*  0, unused */
    WINED3D_TSS_COLOR_OP,                   /*  1, D3DTSS_COLOROP */
    WINED3D_TSS_COLOR_ARG1,                 /*  2, D3DTSS_COLORARG1 */
    WINED3D_TSS_COLOR_ARG2,                 /*  3, D3DTSS_COLORARG2 */
    WINED3D_TSS_ALPHA_OP,                   /*  4, D3DTSS_ALPHAOP */
    WINED3D_TSS_ALPHA_ARG1,                 /*  5, D3DTSS_ALPHAARG1 */
    WINED3D_TSS_ALPHA_ARG2,                 /*  6, D3DTSS_ALPHAARG2 */
    WINED3D_TSS_BUMPENV_MAT00,              /*  7, D3DTSS_BUMPENVMAT00 */
    WINED3D_TSS_BUMPENV_MAT01,              /*  8, D3DTSS_BUMPENVMAT01 */
    WINED3D_TSS_BUMPENV_MAT10,              /*  9, D3DTSS_BUMPENVMAT10 */
    WINED3D_TSS_BUMPENV_MAT11,              /* 10, D3DTSS_BUMPENVMAT11 */
    WINED3D_TSS_TEXCOORD_INDEX,             /* 11, D3DTSS_TEXCOORDINDEX */
    WINED3D_TSS_INVALID,                    /* 12, unused */
    WINED3D_TSS_INVALID,                    /* 13, unused */
    WINED3D_TSS_INVALID,                    /* 14, unused */
    WINED3D_TSS_INVALID,                    /* 15, unused */
    WINED3D_TSS_INVALID,                    /* 16, unused */
    WINED3D_TSS_INVALID,                    /* 17, unused */
    WINED3D_TSS_INVALID,                    /* 18, unused */
    WINED3D_TSS_INVALID,                    /* 19, unused */
    WINED3D_TSS_INVALID,                    /* 20, unused */
    WINED3D_TSS_INVALID,                    /* 21, unused */
    WINED3D_TSS_BUMPENV_LSCALE,             /* 22, D3DTSS_BUMPENVLSCALE */
    WINED3D_TSS_BUMPENV_LOFFSET,            /* 23, D3DTSS_BUMPENVLOFFSET */
    WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS,    /* 24, D3DTSS_TEXTURETRANSFORMFLAGS */
    WINED3D_TSS_INVALID,                    /* 25, unused */
    WINED3D_TSS_COLOR_ARG0,                 /* 26, D3DTSS_COLORARG0 */
    WINED3D_TSS_ALPHA_ARG0,                 /* 27, D3DTSS_ALPHAARG0 */
    WINED3D_TSS_RESULT_ARG,                 /* 28, D3DTSS_RESULTARG */
    WINED3D_TSS_INVALID,                    /* 29, unused */
    WINED3D_TSS_INVALID,                    /* 30, unused */
    WINED3D_TSS_INVALID,                    /* 31, unused */
    WINED3D_TSS_CONSTANT,                   /* 32, D3DTSS_CONSTANT */
2395 2396
};

2397 2398
static HRESULT WINAPI d3d9_device_GetTextureStageState(IDirect3DDevice9Ex *iface,
        DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD *value)
2399
{
2400
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
Henri Verbeet's avatar
Henri Verbeet committed
2401

2402
    TRACE("iface %p, stage %u, state %#x, value %p.\n", iface, stage, state, value);
2403

2404
    if (state >= ARRAY_SIZE(tss_lookup))
2405
    {
2406
        WARN("Invalid state %#x passed.\n", state);
2407 2408 2409
        return D3D_OK;
    }

2410
    wined3d_mutex_lock();
2411
    *value = wined3d_device_get_texture_stage_state(device->wined3d_device, stage, tss_lookup[state]);
2412 2413
    wined3d_mutex_unlock();

2414
    return D3D_OK;
2415 2416
}

2417 2418
static HRESULT WINAPI d3d9_device_SetTextureStageState(IDirect3DDevice9Ex *iface,
        DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD value)
2419
{
2420
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
Henri Verbeet's avatar
Henri Verbeet committed
2421

2422
    TRACE("iface %p, stage %u, state %#x, value %#x.\n", iface, stage, state, value);
2423

2424
    if (state >= ARRAY_SIZE(tss_lookup))
2425
    {
2426
        WARN("Invalid state %#x passed.\n", state);
2427 2428 2429
        return D3D_OK;
    }

2430
    wined3d_mutex_lock();
2431
    wined3d_device_set_texture_stage_state(device->wined3d_device, stage, tss_lookup[state], value);
2432 2433
    wined3d_mutex_unlock();

2434
    return D3D_OK;
2435 2436
}

2437 2438
static HRESULT WINAPI d3d9_device_GetSamplerState(IDirect3DDevice9Ex *iface,
        DWORD sampler, D3DSAMPLERSTATETYPE state, DWORD *value)
2439
{
2440
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
Henri Verbeet's avatar
Henri Verbeet committed
2441

2442
    TRACE("iface %p, sampler %u, state %#x, value %p.\n", iface, sampler, state, value);
2443

2444
    wined3d_mutex_lock();
2445
    *value = wined3d_device_get_sampler_state(device->wined3d_device, sampler, state);
2446 2447
    wined3d_mutex_unlock();

2448
    return D3D_OK;
2449 2450
}

2451 2452
static HRESULT WINAPI DECLSPEC_HOTPATCH d3d9_device_SetSamplerState(IDirect3DDevice9Ex *iface,
        DWORD sampler, D3DSAMPLERSTATETYPE state, DWORD value)
2453
{
2454
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
Henri Verbeet's avatar
Henri Verbeet committed
2455

2456
    TRACE("iface %p, sampler %u, state %#x, value %#x.\n", iface, sampler, state, value);
2457

2458
    wined3d_mutex_lock();
2459
    wined3d_device_set_sampler_state(device->wined3d_device, sampler, state, value);
2460 2461
    wined3d_mutex_unlock();

2462
    return D3D_OK;
2463 2464
}

2465
static HRESULT WINAPI d3d9_device_ValidateDevice(IDirect3DDevice9Ex *iface, DWORD *pass_count)
2466
{
2467
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2468
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
2469

2470
    TRACE("iface %p, pass_count %p.\n", iface, pass_count);
2471

2472
    wined3d_mutex_lock();
2473
    hr = wined3d_device_validate_device(device->wined3d_device, pass_count);
2474 2475
    wined3d_mutex_unlock();

2476
    return hr;
2477 2478
}

2479 2480
static HRESULT WINAPI d3d9_device_SetPaletteEntries(IDirect3DDevice9Ex *iface,
        UINT palette_idx, const PALETTEENTRY *entries)
2481
{
2482
    WARN("iface %p, palette_idx %u, entries %p unimplemented.\n", iface, palette_idx, entries);
Henri Verbeet's avatar
Henri Verbeet committed
2483

2484 2485 2486 2487 2488 2489
    /* The d3d9 palette API is non-functional on Windows. Getters and setters are implemented,
     * and some drivers allow the creation of P8 surfaces. These surfaces can be copied to
     * other P8 surfaces with StretchRect, but cannot be converted to (A)RGB.
     *
     * Some older(dx7) cards may have support for P8 textures, but games cannot rely on this. */
    return D3D_OK;
2490 2491
}

2492 2493
static HRESULT WINAPI d3d9_device_GetPaletteEntries(IDirect3DDevice9Ex *iface,
        UINT palette_idx, PALETTEENTRY *entries)
2494
{
2495
    FIXME("iface %p, palette_idx %u, entries %p unimplemented.\n", iface, palette_idx, entries);
Henri Verbeet's avatar
Henri Verbeet committed
2496

2497
    return D3DERR_INVALIDCALL;
2498 2499
}

2500
static HRESULT WINAPI d3d9_device_SetCurrentTexturePalette(IDirect3DDevice9Ex *iface, UINT palette_idx)
2501
{
2502
    WARN("iface %p, palette_idx %u unimplemented.\n", iface, palette_idx);
Henri Verbeet's avatar
Henri Verbeet committed
2503

2504
    return D3D_OK;
2505 2506
}

2507
static HRESULT WINAPI d3d9_device_GetCurrentTexturePalette(IDirect3DDevice9Ex *iface, UINT *palette_idx)
2508
{
2509
    FIXME("iface %p, palette_idx %p.\n", iface, palette_idx);
Henri Verbeet's avatar
Henri Verbeet committed
2510

2511
    return D3DERR_INVALIDCALL;
2512 2513
}

2514
static HRESULT WINAPI d3d9_device_SetScissorRect(IDirect3DDevice9Ex *iface, const RECT *rect)
2515
{
2516
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
Henri Verbeet's avatar
Henri Verbeet committed
2517

2518
    TRACE("iface %p, rect %p.\n", iface, rect);
2519

2520
    wined3d_mutex_lock();
2521
    wined3d_device_set_scissor_rect(device->wined3d_device, rect);
2522 2523
    wined3d_mutex_unlock();

2524
    return D3D_OK;
2525 2526
}

2527
static HRESULT WINAPI d3d9_device_GetScissorRect(IDirect3DDevice9Ex *iface, RECT *rect)
2528
{
2529
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
Henri Verbeet's avatar
Henri Verbeet committed
2530

2531
    TRACE("iface %p, rect %p.\n", iface, rect);
2532

2533
    wined3d_mutex_lock();
2534
    wined3d_device_get_scissor_rect(device->wined3d_device, rect);
2535 2536
    wined3d_mutex_unlock();

2537
    return D3D_OK;
2538 2539
}

2540
static HRESULT WINAPI d3d9_device_SetSoftwareVertexProcessing(IDirect3DDevice9Ex *iface, BOOL software)
2541
{
2542
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
Henri Verbeet's avatar
Henri Verbeet committed
2543

2544
    TRACE("iface %p, software %#x.\n", iface, software);
2545

2546
    wined3d_mutex_lock();
2547
    wined3d_device_set_software_vertex_processing(device->wined3d_device, software);
2548 2549
    wined3d_mutex_unlock();

2550
    return D3D_OK;
2551 2552
}

2553
static BOOL WINAPI d3d9_device_GetSoftwareVertexProcessing(IDirect3DDevice9Ex *iface)
2554
{
2555
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2556
    BOOL ret;
Henri Verbeet's avatar
Henri Verbeet committed
2557 2558

    TRACE("iface %p.\n", iface);
2559

2560
    wined3d_mutex_lock();
2561
    ret = wined3d_device_get_software_vertex_processing(device->wined3d_device);
2562 2563
    wined3d_mutex_unlock();

2564
    return ret;
2565 2566
}

2567
static HRESULT WINAPI d3d9_device_SetNPatchMode(IDirect3DDevice9Ex *iface, float segment_count)
2568
{
2569
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2570
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
2571

2572
    TRACE("iface %p, segment_count %.8e.\n", iface, segment_count);
2573

2574
    wined3d_mutex_lock();
2575
    hr = wined3d_device_set_npatch_mode(device->wined3d_device, segment_count);
2576 2577
    wined3d_mutex_unlock();

2578
    return hr;
2579 2580
}

2581
static float WINAPI d3d9_device_GetNPatchMode(IDirect3DDevice9Ex *iface)
2582
{
2583
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2584
    float ret;
Henri Verbeet's avatar
Henri Verbeet committed
2585 2586

    TRACE("iface %p.\n", iface);
2587

2588
    wined3d_mutex_lock();
2589
    ret = wined3d_device_get_npatch_mode(device->wined3d_device);
2590 2591
    wined3d_mutex_unlock();

2592
    return ret;
2593 2594
}

2595 2596 2597 2598 2599 2600 2601 2602 2603 2604
/* wined3d critical section must be taken by the caller. */
static void d3d9_generate_auto_mipmaps(struct d3d9_device *device)
{
    unsigned int i;

    for (i = 0; i < ARRAY_SIZE(device->textures); ++i)
        if (device->textures[i])
            d3d9_texture_gen_auto_mipmap(device->textures[i]);
}

2605 2606
static HRESULT WINAPI d3d9_device_DrawPrimitive(IDirect3DDevice9Ex *iface,
        D3DPRIMITIVETYPE primitive_type, UINT start_vertex, UINT primitive_count)
2607
{
2608
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2609
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
2610 2611

    TRACE("iface %p, primitive_type %#x, start_vertex %u, primitive_count %u.\n",
2612
            iface, primitive_type, start_vertex, primitive_count);
2613

2614
    wined3d_mutex_lock();
2615 2616 2617 2618 2619 2620
    if (!device->has_vertex_declaration)
    {
        wined3d_mutex_unlock();
        WARN("Called without a valid vertex declaration set.\n");
        return D3DERR_INVALIDCALL;
    }
2621
    d3d9_generate_auto_mipmaps(device);
2622
    wined3d_device_set_primitive_type(device->wined3d_device, primitive_type, 0);
2623 2624
    hr = wined3d_device_draw_primitive(device->wined3d_device, start_vertex,
            vertex_count_from_primitive_count(primitive_type, primitive_count));
2625 2626
    if (SUCCEEDED(hr))
        d3d9_rts_flag_auto_gen_mipmap(device);
2627 2628
    wined3d_mutex_unlock();

2629
    return hr;
2630 2631
}

2632 2633 2634
static HRESULT WINAPI d3d9_device_DrawIndexedPrimitive(IDirect3DDevice9Ex *iface,
        D3DPRIMITIVETYPE primitive_type, INT base_vertex_idx, UINT min_vertex_idx,
        UINT vertex_count, UINT start_idx, UINT primitive_count)
2635
{
2636
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2637
    HRESULT hr;
2638

2639
    TRACE("iface %p, primitive_type %#x, base_vertex_idx %u, min_vertex_idx %u, "
Henri Verbeet's avatar
Henri Verbeet committed
2640
            "vertex_count %u, start_idx %u, primitive_count %u.\n",
2641 2642
            iface, primitive_type, base_vertex_idx, min_vertex_idx,
            vertex_count, start_idx, primitive_count);
Henri Verbeet's avatar
Henri Verbeet committed
2643

2644
    wined3d_mutex_lock();
2645 2646 2647 2648 2649 2650
    if (!device->has_vertex_declaration)
    {
        wined3d_mutex_unlock();
        WARN("Called without a valid vertex declaration set.\n");
        return D3DERR_INVALIDCALL;
    }
2651
    d3d9_generate_auto_mipmaps(device);
2652
    wined3d_device_set_base_vertex_index(device->wined3d_device, base_vertex_idx);
2653
    wined3d_device_set_primitive_type(device->wined3d_device, primitive_type, 0);
2654 2655
    hr = wined3d_device_draw_indexed_primitive(device->wined3d_device, start_idx,
            vertex_count_from_primitive_count(primitive_type, primitive_count));
2656 2657
    if (SUCCEEDED(hr))
        d3d9_rts_flag_auto_gen_mipmap(device);
2658 2659
    wined3d_mutex_unlock();

2660
    return hr;
2661 2662
}

2663 2664 2665 2666 2667 2668 2669 2670
/* The caller is responsible for wined3d locking */
static HRESULT d3d9_device_prepare_vertex_buffer(struct d3d9_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);
2671
        struct wined3d_buffer_desc desc;
2672 2673
        struct wined3d_buffer *buffer;

2674
        TRACE("Growing vertex buffer to %u bytes.\n", size);
2675

2676 2677 2678
        desc.byte_width = size;
        desc.usage = WINED3DUSAGE_DYNAMIC | WINED3DUSAGE_WRITEONLY;
        desc.bind_flags = WINED3D_BIND_VERTEX_BUFFER;
2679
        desc.access = WINED3D_RESOURCE_ACCESS_GPU | WINED3D_RESOURCE_ACCESS_MAP_R | WINED3D_RESOURCE_ACCESS_MAP_W;
2680 2681 2682 2683 2684
        desc.misc_flags = 0;
        desc.structure_byte_stride = 0;

        if (FAILED(hr = wined3d_buffer_create(device->wined3d_device, &desc,
                NULL, NULL, &d3d9_null_wined3d_parent_ops, &buffer)))
2685
        {
2686
            ERR("Failed to create vertex buffer, hr %#x.\n", hr);
2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699
            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;
}

2700 2701
static HRESULT WINAPI d3d9_device_DrawPrimitiveUP(IDirect3DDevice9Ex *iface,
        D3DPRIMITIVETYPE primitive_type, UINT primitive_count, const void *data, UINT stride)
2702
{
2703
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2704
    HRESULT hr;
2705
    UINT vtx_count = vertex_count_from_primitive_count(primitive_type, primitive_count);
2706 2707
    struct wined3d_map_desc wined3d_map_desc;
    struct wined3d_box wined3d_box = {0};
2708
    UINT size = vtx_count * stride;
2709
    struct wined3d_resource *vb;
2710
    UINT vb_pos, align;
Henri Verbeet's avatar
Henri Verbeet committed
2711 2712

    TRACE("iface %p, primitive_type %#x, primitive_count %u, data %p, stride %u.\n",
2713
            iface, primitive_type, primitive_count, data, stride);
2714

2715 2716 2717 2718 2719 2720
    if (!primitive_count)
    {
        WARN("primitive_count is 0, returning D3D_OK\n");
        return D3D_OK;
    }

2721
    wined3d_mutex_lock();
2722

2723 2724 2725 2726 2727 2728 2729
    if (!device->has_vertex_declaration)
    {
        wined3d_mutex_unlock();
        WARN("Called without a valid vertex declaration set.\n");
        return D3DERR_INVALIDCALL;
    }

2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741
    hr = d3d9_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;

2742 2743 2744 2745
    wined3d_box.left = vb_pos;
    wined3d_box.right = vb_pos + size;
    vb = wined3d_buffer_get_resource(device->vertex_buffer);
    if (FAILED(hr = wined3d_resource_map(vb, 0, &wined3d_map_desc, &wined3d_box,
2746
            WINED3D_MAP_WRITE | (vb_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD))))
2747
        goto done;
2748 2749
    memcpy(wined3d_map_desc.data, data, size);
    wined3d_resource_unmap(vb, 0);
2750 2751 2752 2753 2754 2755
    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;

2756
    d3d9_generate_auto_mipmaps(device);
2757
    wined3d_device_set_primitive_type(device->wined3d_device, primitive_type, 0);
2758 2759
    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);
2760 2761
    if (SUCCEEDED(hr))
        d3d9_rts_flag_auto_gen_mipmap(device);
2762

2763 2764
done:
    wined3d_mutex_unlock();
2765
    return hr;
2766 2767
}

2768 2769 2770 2771 2772 2773 2774 2775
/* The caller is responsible for wined3d locking */
static HRESULT d3d9_device_prepare_index_buffer(struct d3d9_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);
2776
        struct wined3d_buffer_desc desc;
2777 2778
        struct wined3d_buffer *buffer;

2779
        TRACE("Growing index buffer to %u bytes.\n", size);
2780

2781 2782 2783
        desc.byte_width = size;
        desc.usage = WINED3DUSAGE_DYNAMIC | WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_STATICDECL;
        desc.bind_flags = WINED3D_BIND_INDEX_BUFFER;
2784
        desc.access = WINED3D_RESOURCE_ACCESS_GPU | WINED3D_RESOURCE_ACCESS_MAP_R | WINED3D_RESOURCE_ACCESS_MAP_W;
2785 2786 2787 2788 2789
        desc.misc_flags = 0;
        desc.structure_byte_stride = 0;

        if (FAILED(hr = wined3d_buffer_create(device->wined3d_device, &desc,
                NULL, NULL, &d3d9_null_wined3d_parent_ops, &buffer)))
2790
        {
2791
            ERR("Failed to create index buffer, hr %#x.\n", hr);
2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804
            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;
}

2805
static HRESULT WINAPI d3d9_device_DrawIndexedPrimitiveUP(IDirect3DDevice9Ex *iface,
2806
        D3DPRIMITIVETYPE primitive_type, UINT min_vertex_idx, UINT vertex_count,
2807 2808
        UINT primitive_count, const void *index_data, D3DFORMAT index_format,
        const void *vertex_data, UINT vertex_stride)
2809
{
2810
    UINT idx_count = vertex_count_from_primitive_count(primitive_type, primitive_count);
2811
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2812
    UINT idx_fmt_size = index_format == D3DFMT_INDEX16 ? 2 : 4;
2813
    UINT vtx_size = vertex_count * vertex_stride;
2814
    UINT idx_size = idx_count * idx_fmt_size;
2815 2816 2817
    struct wined3d_map_desc wined3d_map_desc;
    struct wined3d_box wined3d_box = {0};
    struct wined3d_resource *ib, *vb;
2818 2819
    UINT vb_pos, ib_pos, align;
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
2820

2821
    TRACE("iface %p, primitive_type %#x, min_vertex_idx %u, vertex_count %u, primitive_count %u, "
Henri Verbeet's avatar
Henri Verbeet committed
2822
            "index_data %p, index_format %#x, vertex_data %p, vertex_stride %u.\n",
2823
            iface, primitive_type, min_vertex_idx, vertex_count, primitive_count,
2824
            index_data, index_format, vertex_data, vertex_stride);
2825

2826 2827
    if (!primitive_count)
    {
2828
        WARN("primitive_count is 0, returning D3D_OK.\n");
2829 2830 2831
        return D3D_OK;
    }

2832
    wined3d_mutex_lock();
2833

2834 2835 2836 2837 2838 2839 2840
    if (!device->has_vertex_declaration)
    {
        wined3d_mutex_unlock();
        WARN("Called without a valid vertex declaration set.\n");
        return D3DERR_INVALIDCALL;
    }

2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852
    hr = d3d9_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;

2853 2854 2855 2856
    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,
2857
            WINED3D_MAP_WRITE | (vb_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD))))
2858
        goto done;
2859
    memcpy(wined3d_map_desc.data, (char *)vertex_data + min_vertex_idx * vertex_stride, vtx_size);
2860
    wined3d_resource_unmap(vb, 0);
2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874
    device->vertex_buffer_pos = vb_pos + vtx_size;

    hr = d3d9_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;

2875 2876 2877 2878
    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,
2879
            WINED3D_MAP_WRITE | (ib_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD))))
2880
        goto done;
2881 2882
    memcpy(wined3d_map_desc.data, index_data, idx_size);
    wined3d_resource_unmap(ib, 0);
2883 2884 2885 2886 2887 2888
    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;

2889
    d3d9_generate_auto_mipmaps(device);
2890
    wined3d_device_set_index_buffer(device->wined3d_device, device->index_buffer,
2891
            wined3dformat_from_d3dformat(index_format), 0);
2892
    wined3d_device_set_base_vertex_index(device->wined3d_device, vb_pos / vertex_stride - min_vertex_idx);
2893

2894
    wined3d_device_set_primitive_type(device->wined3d_device, primitive_type, 0);
2895 2896 2897
    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);
2898
    wined3d_device_set_index_buffer(device->wined3d_device, NULL, WINED3DFMT_UNKNOWN, 0);
2899
    wined3d_device_set_base_vertex_index(device->wined3d_device, 0);
2900

2901 2902 2903
    if (SUCCEEDED(hr))
        d3d9_rts_flag_auto_gen_mipmap(device);

2904 2905
done:
    wined3d_mutex_unlock();
2906
    return hr;
2907 2908
}

2909 2910 2911
static HRESULT WINAPI d3d9_device_ProcessVertices(IDirect3DDevice9Ex *iface,
        UINT src_start_idx, UINT dst_idx, UINT vertex_count, IDirect3DVertexBuffer9 *dst_buffer,
        IDirect3DVertexDeclaration9 *declaration, DWORD flags)
2912
{
2913
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2914
    struct d3d9_vertexbuffer *dst_impl = unsafe_impl_from_IDirect3DVertexBuffer9(dst_buffer);
2915
    struct d3d9_vertex_declaration *decl_impl = unsafe_impl_from_IDirect3DVertexDeclaration9(declaration);
2916
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
2917 2918

    TRACE("iface %p, src_start_idx %u, dst_idx %u, vertex_count %u, dst_buffer %p, declaration %p, flags %#x.\n",
2919
            iface, src_start_idx, dst_idx, vertex_count, dst_buffer, declaration, flags);
2920

2921
    wined3d_mutex_lock();
2922
    hr = wined3d_device_process_vertices(device->wined3d_device, src_start_idx, dst_idx, vertex_count,
2923
            dst_impl->wined3d_buffer, decl_impl ? decl_impl->wined3d_declaration : NULL,
2924
            flags, dst_impl->fvf);
2925 2926
    wined3d_mutex_unlock();

2927
    return hr;
2928 2929
}

2930
static HRESULT WINAPI d3d9_device_CreateVertexDeclaration(IDirect3DDevice9Ex *iface,
2931 2932
        const D3DVERTEXELEMENT9 *elements, IDirect3DVertexDeclaration9 **declaration)
{
2933
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2934
    struct d3d9_vertex_declaration *object;
2935 2936 2937 2938 2939 2940 2941 2942 2943 2944
    HRESULT hr;

    TRACE("iface %p, elements %p, declaration %p.\n", iface, elements, declaration);

    if (!declaration)
    {
        WARN("Caller passed a NULL declaration, returning D3DERR_INVALIDCALL.\n");
        return D3DERR_INVALIDCALL;
    }

2945
    if (SUCCEEDED(hr = d3d9_vertex_declaration_create(device, elements, &object)))
2946
        *declaration = &object->IDirect3DVertexDeclaration9_iface;
2947

2948
    return hr;
2949 2950
}

2951
static HRESULT WINAPI d3d9_device_SetVertexDeclaration(IDirect3DDevice9Ex *iface,
2952 2953
        IDirect3DVertexDeclaration9 *declaration)
{
2954
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2955
    struct d3d9_vertex_declaration *decl_impl = unsafe_impl_from_IDirect3DVertexDeclaration9(declaration);
2956 2957 2958 2959

    TRACE("iface %p, declaration %p.\n", iface, declaration);

    wined3d_mutex_lock();
2960
    wined3d_device_set_vertex_declaration(device->wined3d_device,
2961
            decl_impl ? decl_impl->wined3d_declaration : NULL);
2962
    device->has_vertex_declaration = !!decl_impl;
2963 2964
    wined3d_mutex_unlock();

2965
    return D3D_OK;
2966 2967
}

2968
static HRESULT WINAPI d3d9_device_GetVertexDeclaration(IDirect3DDevice9Ex *iface,
2969 2970
        IDirect3DVertexDeclaration9 **declaration)
{
2971
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2972
    struct wined3d_vertex_declaration *wined3d_declaration;
2973
    struct d3d9_vertex_declaration *declaration_impl;
2974 2975 2976 2977 2978 2979

    TRACE("iface %p, declaration %p.\n", iface, declaration);

    if (!declaration) return D3DERR_INVALIDCALL;

    wined3d_mutex_lock();
2980
    if ((wined3d_declaration = wined3d_device_get_vertex_declaration(device->wined3d_device)))
2981
    {
2982 2983
        declaration_impl = wined3d_vertex_declaration_get_parent(wined3d_declaration);
        *declaration = &declaration_impl->IDirect3DVertexDeclaration9_iface;
2984 2985 2986 2987 2988 2989 2990 2991 2992
        IDirect3DVertexDeclaration9_AddRef(*declaration);
    }
    else
    {
        *declaration = NULL;
    }
    wined3d_mutex_unlock();

    TRACE("Returning %p.\n", *declaration);
2993
    return D3D_OK;
2994 2995
}

2996
static struct wined3d_vertex_declaration *device_get_fvf_declaration(struct d3d9_device *device, DWORD fvf)
2997 2998 2999
{
    struct wined3d_vertex_declaration *wined3d_declaration;
    struct fvf_declaration *fvf_decls = device->fvf_decls;
3000
    struct d3d9_vertex_declaration *d3d9_declaration;
3001
    D3DVERTEXELEMENT9 *elements;
3002
    int p, low, high; /* deliberately signed */
3003
    HRESULT hr;
3004 3005 3006 3007

    TRACE("Searching for declaration for fvf %08x... ", fvf);

    low = 0;
3008 3009 3010
    high = device->fvf_decl_count - 1;
    while (low <= high)
    {
3011 3012
        p = (low + high) >> 1;
        TRACE("%d ", p);
3013 3014 3015 3016 3017 3018 3019 3020

        if (fvf_decls[p].fvf == fvf)
        {
            TRACE("found %p.\n", fvf_decls[p].decl);
            return fvf_decls[p].decl;
        }

        if (fvf_decls[p].fvf < fvf)
3021
            low = p + 1;
3022
        else
3023 3024 3025 3026
            high = p - 1;
    }
    TRACE("not found. Creating and inserting at position %d.\n", low);

3027 3028 3029 3030
    if (FAILED(hr = vdecl_convert_fvf(fvf, &elements)))
        return NULL;

    hr = d3d9_vertex_declaration_create(device, elements, &d3d9_declaration);
3031
    heap_free(elements);
3032 3033 3034 3035 3036 3037 3038
    if (FAILED(hr))
        return NULL;

    if (device->fvf_decl_size == device->fvf_decl_count)
    {
        UINT grow = max(device->fvf_decl_size / 2, 8);

3039
        if (!(fvf_decls = heap_realloc(fvf_decls, sizeof(*fvf_decls) * (device->fvf_decl_size + grow))))
3040
        {
3041
            IDirect3DVertexDeclaration9_Release(&d3d9_declaration->IDirect3DVertexDeclaration9_iface);
3042 3043
            return NULL;
        }
3044 3045
        device->fvf_decls = fvf_decls;
        device->fvf_decl_size += grow;
3046 3047
    }

3048 3049
    d3d9_declaration->fvf = fvf;
    wined3d_declaration = d3d9_declaration->wined3d_declaration;
3050
    wined3d_vertex_declaration_incref(wined3d_declaration);
3051
    IDirect3DVertexDeclaration9_Release(&d3d9_declaration->IDirect3DVertexDeclaration9_iface);
3052 3053 3054 3055 3056

    memmove(fvf_decls + low + 1, fvf_decls + low, sizeof(*fvf_decls) * (device->fvf_decl_count - low));
    fvf_decls[low].decl = wined3d_declaration;
    fvf_decls[low].fvf = fvf;
    ++device->fvf_decl_count;
3057

3058
    TRACE("Returning %p. %u declarations in array.\n", wined3d_declaration, device->fvf_decl_count);
3059

3060
    return wined3d_declaration;
3061 3062
}

3063
static HRESULT WINAPI d3d9_device_SetFVF(IDirect3DDevice9Ex *iface, DWORD fvf)
3064
{
3065
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3066
    struct wined3d_vertex_declaration *decl;
3067

3068
    TRACE("iface %p, fvf %#x.\n", iface, fvf);
3069

3070
    if (!fvf)
3071
    {
3072
        WARN("%#x is not a valid FVF.\n", fvf);
3073 3074
        return D3D_OK;
    }
3075

3076
    wined3d_mutex_lock();
3077
    if (!(decl = device_get_fvf_declaration(device, fvf)))
3078
    {
3079 3080 3081
        wined3d_mutex_unlock();
        ERR("Failed to create a vertex declaration for fvf %#x.\n", fvf);
        return D3DERR_DRIVERINTERNALERROR;
3082
    }
3083

3084
    wined3d_device_set_vertex_declaration(device->wined3d_device, decl);
3085
    device->has_vertex_declaration = TRUE;
3086
    wined3d_mutex_unlock();
3087

3088
    return D3D_OK;
3089 3090
}

3091
static HRESULT WINAPI d3d9_device_GetFVF(IDirect3DDevice9Ex *iface, DWORD *fvf)
Henri Verbeet's avatar
Henri Verbeet committed
3092
{
3093
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3094
    struct wined3d_vertex_declaration *wined3d_declaration;
3095
    struct d3d9_vertex_declaration *d3d9_declaration;
Henri Verbeet's avatar
Henri Verbeet committed
3096

3097
    TRACE("iface %p, fvf %p.\n", iface, fvf);
3098

3099
    wined3d_mutex_lock();
3100
    if ((wined3d_declaration = wined3d_device_get_vertex_declaration(device->wined3d_device)))
3101
    {
3102
        d3d9_declaration = wined3d_vertex_declaration_get_parent(wined3d_declaration);
3103
        *fvf = d3d9_declaration->fvf;
3104 3105 3106
    }
    else
    {
3107
        *fvf = 0;
3108
    }
3109
    wined3d_mutex_unlock();
3110

3111
    TRACE("Returning FVF %#x.\n", *fvf);
3112

3113
    return D3D_OK;
3114 3115
}

3116
static HRESULT WINAPI d3d9_device_CreateVertexShader(IDirect3DDevice9Ex *iface,
3117 3118
        const DWORD *byte_code, IDirect3DVertexShader9 **shader)
{
3119
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3120
    struct d3d9_vertexshader *object;
3121 3122 3123 3124
    HRESULT hr;

    TRACE("iface %p, byte_code %p, shader %p.\n", iface, byte_code, shader);

3125
    if (!(object = heap_alloc_zero(sizeof(*object))))
3126 3127
        return E_OUTOFMEMORY;

3128
    hr = vertexshader_init(object, device, byte_code);
3129 3130 3131
    if (FAILED(hr))
    {
        WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
3132
        heap_free(object);
3133 3134 3135 3136
        return hr;
    }

    TRACE("Created vertex shader %p.\n", object);
3137
    *shader = &object->IDirect3DVertexShader9_iface;
3138 3139 3140 3141

    return D3D_OK;
}

3142
static HRESULT WINAPI d3d9_device_SetVertexShader(IDirect3DDevice9Ex *iface, IDirect3DVertexShader9 *shader)
3143
{
3144
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3145
    struct d3d9_vertexshader *shader_obj = unsafe_impl_from_IDirect3DVertexShader9(shader);
3146 3147 3148 3149

    TRACE("iface %p, shader %p.\n", iface, shader);

    wined3d_mutex_lock();
3150
    wined3d_device_set_vertex_shader(device->wined3d_device,
3151
            shader_obj ? shader_obj->wined3d_shader : NULL);
3152 3153
    wined3d_mutex_unlock();

3154
    return D3D_OK;
3155 3156
}

3157
static HRESULT WINAPI d3d9_device_GetVertexShader(IDirect3DDevice9Ex *iface, IDirect3DVertexShader9 **shader)
3158
{
3159
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3160
    struct d3d9_vertexshader *shader_impl;
3161
    struct wined3d_shader *wined3d_shader;
3162 3163 3164 3165

    TRACE("iface %p, shader %p.\n", iface, shader);

    wined3d_mutex_lock();
3166
    if ((wined3d_shader = wined3d_device_get_vertex_shader(device->wined3d_device)))
3167
    {
3168 3169
        shader_impl = wined3d_shader_get_parent(wined3d_shader);
        *shader = &shader_impl->IDirect3DVertexShader9_iface;
3170
        IDirect3DVertexShader9_AddRef(*shader);
3171 3172 3173
    }
    else
    {
3174
        *shader = NULL;
3175 3176 3177 3178 3179
    }
    wined3d_mutex_unlock();

    TRACE("Returning %p.\n", *shader);

3180
    return D3D_OK;
3181 3182
}

3183
static HRESULT WINAPI d3d9_device_SetVertexShaderConstantF(IDirect3DDevice9Ex *iface,
3184 3185
        UINT reg_idx, const float *data, UINT count)
{
3186
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198
    HRESULT hr;

    TRACE("iface %p, reg_idx %u, data %p, count %u.\n", iface, reg_idx, data, count);

    if (reg_idx + count > D3D9_MAX_VERTEX_SHADER_CONSTANTF)
    {
        WARN("Trying to access %u constants, but d3d9 only supports %u\n",
             reg_idx + count, D3D9_MAX_VERTEX_SHADER_CONSTANTF);
        return D3DERR_INVALIDCALL;
    }

    wined3d_mutex_lock();
3199 3200
    hr = wined3d_device_set_vs_consts_f(device->wined3d_device,
            reg_idx, count, (const struct wined3d_vec4 *)data);
3201 3202 3203 3204 3205
    wined3d_mutex_unlock();

    return hr;
}

3206
static HRESULT WINAPI d3d9_device_GetVertexShaderConstantF(IDirect3DDevice9Ex *iface,
3207 3208
        UINT reg_idx, float *data, UINT count)
{
3209
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221
    HRESULT hr;

    TRACE("iface %p, reg_idx %u, data %p, count %u.\n", iface, reg_idx, data, count);

    if (reg_idx + count > D3D9_MAX_VERTEX_SHADER_CONSTANTF)
    {
        WARN("Trying to access %u constants, but d3d9 only supports %u\n",
             reg_idx + count, D3D9_MAX_VERTEX_SHADER_CONSTANTF);
        return D3DERR_INVALIDCALL;
    }

    wined3d_mutex_lock();
3222 3223
    hr = wined3d_device_get_vs_consts_f(device->wined3d_device,
            reg_idx, count, (struct wined3d_vec4 *)data);
3224 3225 3226 3227 3228
    wined3d_mutex_unlock();

    return hr;
}

3229
static HRESULT WINAPI d3d9_device_SetVertexShaderConstantI(IDirect3DDevice9Ex *iface,
3230 3231
        UINT reg_idx, const int *data, UINT count)
{
3232
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3233 3234 3235 3236 3237
    HRESULT hr;

    TRACE("iface %p, reg_idx %u, data %p, count %u.\n", iface, reg_idx, data, count);

    wined3d_mutex_lock();
3238 3239
    hr = wined3d_device_set_vs_consts_i(device->wined3d_device,
            reg_idx, count, (const struct wined3d_ivec4 *)data);
3240 3241 3242 3243 3244
    wined3d_mutex_unlock();

    return hr;
}

3245
static HRESULT WINAPI d3d9_device_GetVertexShaderConstantI(IDirect3DDevice9Ex *iface,
3246 3247
        UINT reg_idx, int *data, UINT count)
{
3248
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3249 3250 3251 3252 3253
    HRESULT hr;

    TRACE("iface %p, reg_idx %u, data %p, count %u.\n", iface, reg_idx, data, count);

    wined3d_mutex_lock();
3254 3255
    hr = wined3d_device_get_vs_consts_i(device->wined3d_device,
            reg_idx, count, (struct wined3d_ivec4 *)data);
3256 3257 3258 3259 3260
    wined3d_mutex_unlock();

    return hr;
}

3261
static HRESULT WINAPI d3d9_device_SetVertexShaderConstantB(IDirect3DDevice9Ex *iface,
3262 3263
        UINT reg_idx, const BOOL *data, UINT count)
{
3264
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3265 3266 3267 3268 3269
    HRESULT hr;

    TRACE("iface %p, reg_idx %u, data %p, count %u.\n", iface, reg_idx, data, count);

    wined3d_mutex_lock();
3270
    hr = wined3d_device_set_vs_consts_b(device->wined3d_device, reg_idx, count, data);
3271 3272 3273 3274 3275
    wined3d_mutex_unlock();

    return hr;
}

3276
static HRESULT WINAPI d3d9_device_GetVertexShaderConstantB(IDirect3DDevice9Ex *iface,
3277 3278
        UINT reg_idx, BOOL *data, UINT count)
{
3279
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3280 3281 3282 3283 3284
    HRESULT hr;

    TRACE("iface %p, reg_idx %u, data %p, count %u.\n", iface, reg_idx, data, count);

    wined3d_mutex_lock();
3285
    hr = wined3d_device_get_vs_consts_b(device->wined3d_device, reg_idx, count, data);
3286 3287 3288 3289 3290
    wined3d_mutex_unlock();

    return hr;
}

3291 3292
static HRESULT WINAPI d3d9_device_SetStreamSource(IDirect3DDevice9Ex *iface,
        UINT stream_idx, IDirect3DVertexBuffer9 *buffer, UINT offset, UINT stride)
3293
{
3294
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3295
    struct d3d9_vertexbuffer *buffer_impl = unsafe_impl_from_IDirect3DVertexBuffer9(buffer);
3296
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
3297 3298

    TRACE("iface %p, stream_idx %u, buffer %p, offset %u, stride %u.\n",
3299
            iface, stream_idx, buffer, offset, stride);
3300

3301
    wined3d_mutex_lock();
3302
    hr = wined3d_device_set_stream_source(device->wined3d_device, stream_idx,
3303
            buffer_impl ? buffer_impl->wined3d_buffer : NULL, offset, stride);
3304 3305
    wined3d_mutex_unlock();

3306
    return hr;
3307 3308
}

3309 3310
static HRESULT WINAPI d3d9_device_GetStreamSource(IDirect3DDevice9Ex *iface,
        UINT stream_idx, IDirect3DVertexBuffer9 **buffer, UINT *offset, UINT *stride)
3311
{
3312
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3313
    struct d3d9_vertexbuffer *buffer_impl;
3314
    struct wined3d_buffer *wined3d_buffer;
3315
    HRESULT hr;
3316

Henri Verbeet's avatar
Henri Verbeet committed
3317
    TRACE("iface %p, stream_idx %u, buffer %p, offset %p, stride %p.\n",
3318
            iface, stream_idx, buffer, offset, stride);
3319

3320
    if (!buffer)
3321 3322
        return D3DERR_INVALIDCALL;

3323
    wined3d_mutex_lock();
3324 3325
    hr = wined3d_device_get_stream_source(device->wined3d_device, stream_idx, &wined3d_buffer, offset, stride);
    if (SUCCEEDED(hr) && wined3d_buffer)
3326
    {
3327 3328 3329
        buffer_impl = wined3d_buffer_get_parent(wined3d_buffer);
        *buffer = &buffer_impl->IDirect3DVertexBuffer9_iface;
        IDirect3DVertexBuffer9_AddRef(*buffer);
3330 3331 3332 3333
    }
    else
    {
        if (FAILED(hr))
3334 3335
            FIXME("Call to GetStreamSource failed %p %p\n", offset, stride);
        *buffer = NULL;
3336
    }
3337
    wined3d_mutex_unlock();
3338

3339
    return hr;
3340 3341
}

3342
static HRESULT WINAPI d3d9_device_SetStreamSourceFreq(IDirect3DDevice9Ex *iface, UINT stream_idx, UINT freq)
3343
{
3344
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3345
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
3346

3347
    TRACE("iface %p, stream_idx %u, freq %u.\n", iface, stream_idx, freq);
3348

3349
    wined3d_mutex_lock();
3350
    hr = wined3d_device_set_stream_source_freq(device->wined3d_device, stream_idx, freq);
3351 3352
    wined3d_mutex_unlock();

3353
    return hr;
3354 3355
}

3356
static HRESULT WINAPI d3d9_device_GetStreamSourceFreq(IDirect3DDevice9Ex *iface, UINT stream_idx, UINT *freq)
3357
{
3358
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3359
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
3360

3361
    TRACE("iface %p, stream_idx %u, freq %p.\n", iface, stream_idx, freq);
3362

3363
    wined3d_mutex_lock();
3364
    hr = wined3d_device_get_stream_source_freq(device->wined3d_device, stream_idx, freq);
3365 3366
    wined3d_mutex_unlock();

3367
    return hr;
3368 3369
}

3370
static HRESULT WINAPI d3d9_device_SetIndices(IDirect3DDevice9Ex *iface, IDirect3DIndexBuffer9 *buffer)
3371
{
3372
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3373
    struct d3d9_indexbuffer *ib = unsafe_impl_from_IDirect3DIndexBuffer9(buffer);
Henri Verbeet's avatar
Henri Verbeet committed
3374

3375
    TRACE("iface %p, buffer %p.\n", iface, buffer);
3376

3377
    wined3d_mutex_lock();
3378
    wined3d_device_set_index_buffer(device->wined3d_device,
3379
            ib ? ib->wined3d_buffer : NULL, ib ? ib->format : WINED3DFMT_UNKNOWN, 0);
3380 3381
    wined3d_mutex_unlock();

3382
    return D3D_OK;
3383 3384
}

3385
static HRESULT WINAPI d3d9_device_GetIndices(IDirect3DDevice9Ex *iface, IDirect3DIndexBuffer9 **buffer)
3386
{
3387
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3388
    enum wined3d_format_id wined3d_format;
3389
    struct wined3d_buffer *wined3d_buffer;
3390
    struct d3d9_indexbuffer *buffer_impl;
3391

3392
    TRACE("iface %p, buffer %p.\n", iface, buffer);
3393

3394
    if (!buffer)
3395 3396
        return D3DERR_INVALIDCALL;

3397
    wined3d_mutex_lock();
3398
    if ((wined3d_buffer = wined3d_device_get_index_buffer(device->wined3d_device, &wined3d_format, NULL)))
3399
    {
3400
        buffer_impl = wined3d_buffer_get_parent(wined3d_buffer);
3401 3402
        *buffer = &buffer_impl->IDirect3DIndexBuffer9_iface;
        IDirect3DIndexBuffer9_AddRef(*buffer);
3403 3404 3405
    }
    else
    {
3406
        *buffer = NULL;
3407
    }
3408 3409
    wined3d_mutex_unlock();

3410
    return D3D_OK;
3411 3412
}

3413
static HRESULT WINAPI d3d9_device_CreatePixelShader(IDirect3DDevice9Ex *iface,
3414 3415
        const DWORD *byte_code, IDirect3DPixelShader9 **shader)
{
3416
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3417
    struct d3d9_pixelshader *object;
3418 3419 3420 3421
    HRESULT hr;

    TRACE("iface %p, byte_code %p, shader %p.\n", iface, byte_code, shader);

3422
    if (!(object = heap_alloc_zero(sizeof(*object))))
3423 3424 3425 3426 3427
    {
        FIXME("Failed to allocate pixel shader memory.\n");
        return E_OUTOFMEMORY;
    }

3428
    hr = pixelshader_init(object, device, byte_code);
3429 3430 3431
    if (FAILED(hr))
    {
        WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
3432
        heap_free(object);
3433 3434 3435 3436
        return hr;
    }

    TRACE("Created pixel shader %p.\n", object);
3437
    *shader = &object->IDirect3DPixelShader9_iface;
3438 3439 3440 3441

    return D3D_OK;
}

3442
static HRESULT WINAPI d3d9_device_SetPixelShader(IDirect3DDevice9Ex *iface, IDirect3DPixelShader9 *shader)
3443
{
3444
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3445
    struct d3d9_pixelshader *shader_obj = unsafe_impl_from_IDirect3DPixelShader9(shader);
3446 3447 3448 3449

    TRACE("iface %p, shader %p.\n", iface, shader);

    wined3d_mutex_lock();
3450
    wined3d_device_set_pixel_shader(device->wined3d_device,
3451
            shader_obj ? shader_obj->wined3d_shader : NULL);
3452 3453
    wined3d_mutex_unlock();

3454
    return D3D_OK;
3455 3456
}

3457
static HRESULT WINAPI d3d9_device_GetPixelShader(IDirect3DDevice9Ex *iface, IDirect3DPixelShader9 **shader)
3458
{
3459
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3460
    struct d3d9_pixelshader *shader_impl;
3461
    struct wined3d_shader *wined3d_shader;
3462 3463 3464 3465 3466 3467

    TRACE("iface %p, shader %p.\n", iface, shader);

    if (!shader) return D3DERR_INVALIDCALL;

    wined3d_mutex_lock();
3468
    if ((wined3d_shader = wined3d_device_get_pixel_shader(device->wined3d_device)))
3469
    {
3470 3471
        shader_impl = wined3d_shader_get_parent(wined3d_shader);
        *shader = &shader_impl->IDirect3DPixelShader9_iface;
3472
        IDirect3DPixelShader9_AddRef(*shader);
3473 3474 3475
    }
    else
    {
3476
        *shader = NULL;
3477 3478 3479 3480 3481
    }
    wined3d_mutex_unlock();

    TRACE("Returning %p.\n", *shader);

3482
    return D3D_OK;
3483 3484
}

3485
static HRESULT WINAPI d3d9_device_SetPixelShaderConstantF(IDirect3DDevice9Ex *iface,
3486 3487
        UINT reg_idx, const float *data, UINT count)
{
3488
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3489 3490 3491 3492 3493
    HRESULT hr;

    TRACE("iface %p, reg_idx %u, data %p, count %u.\n", iface, reg_idx, data, count);

    wined3d_mutex_lock();
3494 3495
    hr = wined3d_device_set_ps_consts_f(device->wined3d_device,
            reg_idx, count, (const struct wined3d_vec4 *)data);
3496 3497 3498 3499 3500
    wined3d_mutex_unlock();

    return hr;
}

3501
static HRESULT WINAPI d3d9_device_GetPixelShaderConstantF(IDirect3DDevice9Ex *iface,
3502 3503
        UINT reg_idx, float *data, UINT count)
{
3504
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3505 3506 3507 3508 3509
    HRESULT hr;

    TRACE("iface %p, reg_idx %u, data %p, count %u.\n", iface, reg_idx, data, count);

    wined3d_mutex_lock();
3510 3511
    hr = wined3d_device_get_ps_consts_f(device->wined3d_device,
            reg_idx, count, (struct wined3d_vec4 *)data);
3512 3513 3514 3515 3516
    wined3d_mutex_unlock();

    return hr;
}

3517
static HRESULT WINAPI d3d9_device_SetPixelShaderConstantI(IDirect3DDevice9Ex *iface,
3518 3519
        UINT reg_idx, const int *data, UINT count)
{
3520
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3521 3522 3523 3524 3525
    HRESULT hr;

    TRACE("iface %p, reg_idx %u, data %p, count %u.\n", iface, reg_idx, data, count);

    wined3d_mutex_lock();
3526 3527
    hr = wined3d_device_set_ps_consts_i(device->wined3d_device,
            reg_idx, count, (const struct wined3d_ivec4 *)data);
3528 3529 3530 3531 3532
    wined3d_mutex_unlock();

    return hr;
}

3533
static HRESULT WINAPI d3d9_device_GetPixelShaderConstantI(IDirect3DDevice9Ex *iface,
3534 3535
        UINT reg_idx, int *data, UINT count)
{
3536
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3537 3538 3539 3540 3541
    HRESULT hr;

    TRACE("iface %p, reg_idx %u, data %p, count %u.\n", iface, reg_idx, data, count);

    wined3d_mutex_lock();
3542 3543
    hr = wined3d_device_get_ps_consts_i(device->wined3d_device,
            reg_idx, count, (struct wined3d_ivec4 *)data);
3544 3545 3546 3547 3548
    wined3d_mutex_unlock();

    return hr;
}

3549
static HRESULT WINAPI d3d9_device_SetPixelShaderConstantB(IDirect3DDevice9Ex *iface,
3550 3551
        UINT reg_idx, const BOOL *data, UINT count)
{
3552
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3553 3554 3555 3556 3557
    HRESULT hr;

    TRACE("iface %p, reg_idx %u, data %p, count %u.\n", iface, reg_idx, data, count);

    wined3d_mutex_lock();
3558
    hr = wined3d_device_set_ps_consts_b(device->wined3d_device, reg_idx, count, data);
3559 3560 3561 3562 3563
    wined3d_mutex_unlock();

    return hr;
}

3564
static HRESULT WINAPI d3d9_device_GetPixelShaderConstantB(IDirect3DDevice9Ex *iface,
3565 3566
        UINT reg_idx, BOOL *data, UINT count)
{
3567
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3568 3569 3570 3571 3572
    HRESULT hr;

    TRACE("iface %p, reg_idx %u, data %p, count %u.\n", iface, reg_idx, data, count);

    wined3d_mutex_lock();
3573
    hr = wined3d_device_get_ps_consts_b(device->wined3d_device, reg_idx, count, data);
3574 3575 3576 3577 3578
    wined3d_mutex_unlock();

    return hr;
}

3579 3580
static HRESULT WINAPI d3d9_device_DrawRectPatch(IDirect3DDevice9Ex *iface, UINT handle,
        const float *segment_count, const D3DRECTPATCH_INFO *patch_info)
3581
{
3582
    FIXME("iface %p, handle %#x, segment_count %p, patch_info %p unimplemented.\n",
3583
            iface, handle, segment_count, patch_info);
3584
    return D3D_OK;
3585
}
3586

3587 3588
static HRESULT WINAPI d3d9_device_DrawTriPatch(IDirect3DDevice9Ex *iface, UINT handle,
        const float *segment_count, const D3DTRIPATCH_INFO *patch_info)
3589
{
3590
    FIXME("iface %p, handle %#x, segment_count %p, patch_info %p unimplemented.\n",
3591
            iface, handle, segment_count, patch_info);
3592
    return D3D_OK;
3593 3594
}

3595
static HRESULT WINAPI d3d9_device_DeletePatch(IDirect3DDevice9Ex *iface, UINT handle)
3596
{
3597 3598
    FIXME("iface %p, handle %#x unimplemented.\n", iface, handle);
    return D3DERR_INVALIDCALL;
3599 3600
}

3601
static HRESULT WINAPI d3d9_device_CreateQuery(IDirect3DDevice9Ex *iface, D3DQUERYTYPE type, IDirect3DQuery9 **query)
3602
{
3603
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3604
    struct d3d9_query *object;
3605 3606 3607 3608
    HRESULT hr;

    TRACE("iface %p, type %#x, query %p.\n", iface, type, query);

3609
    if (!(object = heap_alloc_zero(sizeof(*object))))
3610 3611
        return E_OUTOFMEMORY;

3612
    hr = query_init(object, device, type);
3613 3614 3615
    if (FAILED(hr))
    {
        WARN("Failed to initialize query, hr %#x.\n", hr);
3616
        heap_free(object);
3617 3618 3619 3620
        return hr;
    }

    TRACE("Created query %p.\n", object);
3621 3622
    if (query) *query = &object->IDirect3DQuery9_iface;
    else IDirect3DQuery9_Release(&object->IDirect3DQuery9_iface);
3623 3624 3625 3626

    return D3D_OK;
}

3627
static HRESULT WINAPI d3d9_device_SetConvolutionMonoKernel(IDirect3DDevice9Ex *iface,
Henri Verbeet's avatar
Henri Verbeet committed
3628 3629 3630 3631 3632
        UINT width, UINT height, float *rows, float *columns)
{
    FIXME("iface %p, width %u, height %u, rows %p, columns %p stub!\n",
            iface, width, height, rows, columns);

3633
    return E_NOTIMPL;
3634 3635
}

3636
static HRESULT WINAPI d3d9_device_ComposeRects(IDirect3DDevice9Ex *iface,
3637 3638 3639
        IDirect3DSurface9 *src_surface, IDirect3DSurface9 *dst_surface, IDirect3DVertexBuffer9 *src_descs,
        UINT rect_count, IDirect3DVertexBuffer9 *dst_descs, D3DCOMPOSERECTSOP operation, INT offset_x, INT offset_y)
{
3640
    FIXME("iface %p, src_surface %p, dst_surface %p, src_descs %p, rect_count %u, "
3641 3642 3643 3644
            "dst_descs %p, operation %#x, offset_x %u, offset_y %u stub!\n",
            iface, src_surface, dst_surface, src_descs, rect_count,
            dst_descs, operation, offset_x, offset_y);

3645
    return E_NOTIMPL;
3646 3647
}

3648
static HRESULT WINAPI DECLSPEC_HOTPATCH d3d9_device_PresentEx(IDirect3DDevice9Ex *iface,
Henri Verbeet's avatar
Henri Verbeet committed
3649 3650 3651
        const RECT *src_rect, const RECT *dst_rect, HWND dst_window_override,
        const RGNDATA *dirty_region, DWORD flags)
{
3652
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3653
    UINT i;
3654
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
3655

3656 3657 3658 3659
    TRACE("iface %p, src_rect %s, dst_rect %s, dst_window_override %p, dirty_region %p, flags %#x.\n",
            iface, wine_dbgstr_rect(src_rect), wine_dbgstr_rect(dst_rect),
            dst_window_override, dirty_region, flags);

3660 3661 3662
    if (device->device_state != D3D9_DEVICE_STATE_OK)
        return S_PRESENT_OCCLUDED;

3663 3664 3665
    if (dirty_region)
        FIXME("Ignoring dirty_region %p.\n", dirty_region);

3666
    wined3d_mutex_lock();
3667 3668
    for (i = 0; i < device->implicit_swapchain_count; ++i)
    {
3669 3670
        if (FAILED(hr = wined3d_swapchain_present(device->implicit_swapchains[i]->wined3d_swapchain,
                src_rect, dst_rect, dst_window_override, flags)))
3671 3672 3673 3674 3675
        {
            wined3d_mutex_unlock();
            return hr;
        }
    }
3676 3677
    wined3d_mutex_unlock();

3678
    return D3D_OK;
3679 3680
}

3681
static HRESULT WINAPI d3d9_device_GetGPUThreadPriority(IDirect3DDevice9Ex *iface, INT *priority)
Henri Verbeet's avatar
Henri Verbeet committed
3682 3683 3684
{
    FIXME("iface %p, priority %p stub!\n", iface, priority);

3685
    return E_NOTIMPL;
3686 3687
}

3688
static HRESULT WINAPI d3d9_device_SetGPUThreadPriority(IDirect3DDevice9Ex *iface, INT priority)
Henri Verbeet's avatar
Henri Verbeet committed
3689 3690 3691
{
    FIXME("iface %p, priority %d stub!\n", iface, priority);

3692
    return E_NOTIMPL;
3693 3694
}

3695
static HRESULT WINAPI d3d9_device_WaitForVBlank(IDirect3DDevice9Ex *iface, UINT swapchain_idx)
Henri Verbeet's avatar
Henri Verbeet committed
3696 3697 3698
{
    FIXME("iface %p, swapchain_idx %u stub!\n", iface, swapchain_idx);

3699
    return E_NOTIMPL;
3700 3701
}

3702
static HRESULT WINAPI d3d9_device_CheckResourceResidency(IDirect3DDevice9Ex *iface,
3703 3704 3705 3706 3707
        IDirect3DResource9 **resources, UINT32 resource_count)
{
    FIXME("iface %p, resources %p, resource_count %u stub!\n",
            iface, resources, resource_count);

3708
    return E_NOTIMPL;
3709 3710
}

3711
static HRESULT WINAPI d3d9_device_SetMaximumFrameLatency(IDirect3DDevice9Ex *iface, UINT max_latency)
Henri Verbeet's avatar
Henri Verbeet committed
3712
{
3713
    TRACE("iface %p, max_latency %u.\n", iface, max_latency);
Henri Verbeet's avatar
Henri Verbeet committed
3714

3715 3716 3717 3718
    if (max_latency)
        FIXME("Ignoring max_latency %u.\n", max_latency);

    return S_OK;
3719 3720
}

3721
static HRESULT WINAPI d3d9_device_GetMaximumFrameLatency(IDirect3DDevice9Ex *iface, UINT *max_latency)
Henri Verbeet's avatar
Henri Verbeet committed
3722 3723 3724 3725 3726
{
    FIXME("iface %p, max_latency %p stub!\n", iface, max_latency);

    *max_latency = 2;

3727
    return E_NOTIMPL;
3728 3729
}

3730
static HRESULT WINAPI d3d9_device_CheckDeviceState(IDirect3DDevice9Ex *iface, HWND dst_window)
3731
{
3732 3733 3734 3735 3736 3737
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
    struct wined3d_swapchain_desc swapchain_desc;

    TRACE("iface %p, dst_window %p.\n", iface, dst_window);

    wined3d_mutex_lock();
3738
    wined3d_swapchain_get_desc(device->implicit_swapchains[0]->wined3d_swapchain, &swapchain_desc);
3739
    wined3d_mutex_unlock();
3740

3741 3742
    if (swapchain_desc.windowed)
        return D3D_OK;
3743

3744 3745 3746 3747
    /* FIXME: This is actually supposed to check if any other device is in
     * fullscreen mode. */
    if (dst_window != swapchain_desc.device_window)
        return device->device_state == D3D9_DEVICE_STATE_OK ? S_PRESENT_OCCLUDED : D3D_OK;
3748

3749
    return device->device_state == D3D9_DEVICE_STATE_OK ? D3D_OK : S_PRESENT_OCCLUDED;
3750 3751
}

3752
static HRESULT WINAPI d3d9_device_CreateRenderTargetEx(IDirect3DDevice9Ex *iface,
Henri Verbeet's avatar
Henri Verbeet committed
3753 3754 3755
        UINT width, UINT height, D3DFORMAT format, D3DMULTISAMPLE_TYPE multisample_type, DWORD multisample_quality,
        BOOL lockable, IDirect3DSurface9 **surface, HANDLE *shared_handle, DWORD usage)
{
3756
    FIXME("iface %p, width %u, height %u, format %#x, multisample_type %#x, multisample_quality %u, "
Henri Verbeet's avatar
Henri Verbeet committed
3757 3758 3759 3760
            "lockable %#x, surface %p, shared_handle %p, usage %#x stub!\n",
            iface, width, height, format, multisample_type, multisample_quality,
            lockable, surface, shared_handle, usage);

3761
    *surface = NULL;
3762 3763 3764
    if (shared_handle)
        FIXME("Resource sharing not implemented, *shared_handle %p.\n", *shared_handle);

3765
    return E_NOTIMPL;
3766 3767
}

3768
static HRESULT WINAPI d3d9_device_CreateOffscreenPlainSurfaceEx(IDirect3DDevice9Ex *iface,
Henri Verbeet's avatar
Henri Verbeet committed
3769 3770 3771 3772 3773 3774
        UINT width, UINT height, D3DFORMAT format, D3DPOOL pool, IDirect3DSurface9 **surface,
        HANDLE *shared_handle, DWORD usage)
{
    FIXME("iface %p, width %u, height %u, format %#x, pool %#x, surface %p, shared_handle %p, usage %#x stub!\n",
            iface, width, height, format, pool, surface, shared_handle, usage);

3775
    return E_NOTIMPL;
3776 3777
}

3778
static HRESULT WINAPI d3d9_device_CreateDepthStencilSurfaceEx(IDirect3DDevice9Ex *iface,
3779 3780 3781
        UINT width, UINT height, D3DFORMAT format, D3DMULTISAMPLE_TYPE multisample_type, DWORD multisample_quality,
        BOOL discard, IDirect3DSurface9 **surface, HANDLE *shared_handle, DWORD usage)
{
3782
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3783
    DWORD flags = WINED3D_TEXTURE_CREATE_MAPPABLE;
3784 3785 3786

    TRACE("iface %p, width %u, height %u, format %#x, multisample_type %#x, multisample_quality %u, "
            "discard %#x, surface %p, shared_handle %p, usage %#x.\n",
3787 3788 3789
            iface, width, height, format, multisample_type, multisample_quality,
            discard, surface, shared_handle, usage);

3790 3791 3792 3793 3794 3795
    if (usage & D3DUSAGE_DEPTHSTENCIL)
    {
        WARN("Invalid usage %#x.\n", usage);
        return D3DERR_INVALIDCALL;
    }

3796 3797 3798
    if (shared_handle)
        FIXME("Resource sharing not implemented, *shared_handle %p.\n", *shared_handle);

3799
    if (discard)
3800
        flags |= WINED3D_TEXTURE_CREATE_DISCARD;
3801

3802
    *surface = NULL;
3803 3804
    return d3d9_device_create_surface(device, width, height, format, flags, surface,
            D3DUSAGE_DEPTHSTENCIL | usage, D3DPOOL_DEFAULT, multisample_type, multisample_quality, NULL);
3805 3806
}

3807
static HRESULT WINAPI DECLSPEC_HOTPATCH d3d9_device_ResetEx(IDirect3DDevice9Ex *iface,
Henri Verbeet's avatar
Henri Verbeet committed
3808 3809
        D3DPRESENT_PARAMETERS *present_parameters, D3DDISPLAYMODEEX *mode)
{
3810
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
Henri Verbeet's avatar
Henri Verbeet committed
3811

3812 3813
    TRACE("iface %p, present_parameters %p, mode %p.\n", iface, present_parameters, mode);

3814 3815 3816 3817 3818 3819
    if (!present_parameters->Windowed == !mode)
    {
        WARN("Mode can be passed if and only if Windowed is FALSE.\n");
        return D3DERR_INVALIDCALL;
    }

3820 3821 3822 3823 3824 3825 3826 3827 3828
    if (mode && (mode->Width != present_parameters->BackBufferWidth
            || mode->Height != present_parameters->BackBufferHeight))
    {
        WARN("Mode and back buffer mismatch (mode %ux%u, backbuffer %ux%u).\n",
                mode->Width, mode->Height,
                present_parameters->BackBufferWidth, present_parameters->BackBufferHeight);
        return D3DERR_INVALIDCALL;
    }

3829
    return d3d9_device_reset(device, present_parameters, mode);
3830 3831
}

3832
static HRESULT WINAPI d3d9_device_GetDisplayModeEx(IDirect3DDevice9Ex *iface,
Henri Verbeet's avatar
Henri Verbeet committed
3833 3834
        UINT swapchain_idx, D3DDISPLAYMODEEX *mode, D3DDISPLAYROTATION *rotation)
{
3835 3836 3837
    struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
    struct wined3d_display_mode wined3d_mode;
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
3838

3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859
    TRACE("iface %p, swapchain_idx %u, mode %p, rotation %p.\n",
            iface, swapchain_idx, mode, rotation);

    if (mode->Size != sizeof(*mode))
        return D3DERR_INVALIDCALL;

    wined3d_mutex_lock();
    hr = wined3d_device_get_display_mode(device->wined3d_device, swapchain_idx, &wined3d_mode,
            (enum wined3d_display_rotation *)rotation);
    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);
        mode->ScanLineOrdering = wined3d_mode.scanline_ordering;
    }

    return hr;
3860 3861
}

3862
static const struct IDirect3DDevice9ExVtbl d3d9_device_vtbl =
3863
{
3864
    /* IUnknown */
3865 3866 3867
    d3d9_device_QueryInterface,
    d3d9_device_AddRef,
    d3d9_device_Release,
3868
    /* IDirect3DDevice9 */
3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984
    d3d9_device_TestCooperativeLevel,
    d3d9_device_GetAvailableTextureMem,
    d3d9_device_EvictManagedResources,
    d3d9_device_GetDirect3D,
    d3d9_device_GetDeviceCaps,
    d3d9_device_GetDisplayMode,
    d3d9_device_GetCreationParameters,
    d3d9_device_SetCursorProperties,
    d3d9_device_SetCursorPosition,
    d3d9_device_ShowCursor,
    d3d9_device_CreateAdditionalSwapChain,
    d3d9_device_GetSwapChain,
    d3d9_device_GetNumberOfSwapChains,
    d3d9_device_Reset,
    d3d9_device_Present,
    d3d9_device_GetBackBuffer,
    d3d9_device_GetRasterStatus,
    d3d9_device_SetDialogBoxMode,
    d3d9_device_SetGammaRamp,
    d3d9_device_GetGammaRamp,
    d3d9_device_CreateTexture,
    d3d9_device_CreateVolumeTexture,
    d3d9_device_CreateCubeTexture,
    d3d9_device_CreateVertexBuffer,
    d3d9_device_CreateIndexBuffer,
    d3d9_device_CreateRenderTarget,
    d3d9_device_CreateDepthStencilSurface,
    d3d9_device_UpdateSurface,
    d3d9_device_UpdateTexture,
    d3d9_device_GetRenderTargetData,
    d3d9_device_GetFrontBufferData,
    d3d9_device_StretchRect,
    d3d9_device_ColorFill,
    d3d9_device_CreateOffscreenPlainSurface,
    d3d9_device_SetRenderTarget,
    d3d9_device_GetRenderTarget,
    d3d9_device_SetDepthStencilSurface,
    d3d9_device_GetDepthStencilSurface,
    d3d9_device_BeginScene,
    d3d9_device_EndScene,
    d3d9_device_Clear,
    d3d9_device_SetTransform,
    d3d9_device_GetTransform,
    d3d9_device_MultiplyTransform,
    d3d9_device_SetViewport,
    d3d9_device_GetViewport,
    d3d9_device_SetMaterial,
    d3d9_device_GetMaterial,
    d3d9_device_SetLight,
    d3d9_device_GetLight,
    d3d9_device_LightEnable,
    d3d9_device_GetLightEnable,
    d3d9_device_SetClipPlane,
    d3d9_device_GetClipPlane,
    d3d9_device_SetRenderState,
    d3d9_device_GetRenderState,
    d3d9_device_CreateStateBlock,
    d3d9_device_BeginStateBlock,
    d3d9_device_EndStateBlock,
    d3d9_device_SetClipStatus,
    d3d9_device_GetClipStatus,
    d3d9_device_GetTexture,
    d3d9_device_SetTexture,
    d3d9_device_GetTextureStageState,
    d3d9_device_SetTextureStageState,
    d3d9_device_GetSamplerState,
    d3d9_device_SetSamplerState,
    d3d9_device_ValidateDevice,
    d3d9_device_SetPaletteEntries,
    d3d9_device_GetPaletteEntries,
    d3d9_device_SetCurrentTexturePalette,
    d3d9_device_GetCurrentTexturePalette,
    d3d9_device_SetScissorRect,
    d3d9_device_GetScissorRect,
    d3d9_device_SetSoftwareVertexProcessing,
    d3d9_device_GetSoftwareVertexProcessing,
    d3d9_device_SetNPatchMode,
    d3d9_device_GetNPatchMode,
    d3d9_device_DrawPrimitive,
    d3d9_device_DrawIndexedPrimitive,
    d3d9_device_DrawPrimitiveUP,
    d3d9_device_DrawIndexedPrimitiveUP,
    d3d9_device_ProcessVertices,
    d3d9_device_CreateVertexDeclaration,
    d3d9_device_SetVertexDeclaration,
    d3d9_device_GetVertexDeclaration,
    d3d9_device_SetFVF,
    d3d9_device_GetFVF,
    d3d9_device_CreateVertexShader,
    d3d9_device_SetVertexShader,
    d3d9_device_GetVertexShader,
    d3d9_device_SetVertexShaderConstantF,
    d3d9_device_GetVertexShaderConstantF,
    d3d9_device_SetVertexShaderConstantI,
    d3d9_device_GetVertexShaderConstantI,
    d3d9_device_SetVertexShaderConstantB,
    d3d9_device_GetVertexShaderConstantB,
    d3d9_device_SetStreamSource,
    d3d9_device_GetStreamSource,
    d3d9_device_SetStreamSourceFreq,
    d3d9_device_GetStreamSourceFreq,
    d3d9_device_SetIndices,
    d3d9_device_GetIndices,
    d3d9_device_CreatePixelShader,
    d3d9_device_SetPixelShader,
    d3d9_device_GetPixelShader,
    d3d9_device_SetPixelShaderConstantF,
    d3d9_device_GetPixelShaderConstantF,
    d3d9_device_SetPixelShaderConstantI,
    d3d9_device_GetPixelShaderConstantI,
    d3d9_device_SetPixelShaderConstantB,
    d3d9_device_GetPixelShaderConstantB,
    d3d9_device_DrawRectPatch,
    d3d9_device_DrawTriPatch,
    d3d9_device_DeletePatch,
    d3d9_device_CreateQuery,
3985
    /* IDirect3DDevice9Ex */
3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000
    d3d9_device_SetConvolutionMonoKernel,
    d3d9_device_ComposeRects,
    d3d9_device_PresentEx,
    d3d9_device_GetGPUThreadPriority,
    d3d9_device_SetGPUThreadPriority,
    d3d9_device_WaitForVBlank,
    d3d9_device_CheckResourceResidency,
    d3d9_device_SetMaximumFrameLatency,
    d3d9_device_GetMaximumFrameLatency,
    d3d9_device_CheckDeviceState,
    d3d9_device_CreateRenderTargetEx,
    d3d9_device_CreateOffscreenPlainSurfaceEx,
    d3d9_device_CreateDepthStencilSurfaceEx,
    d3d9_device_ResetEx,
    d3d9_device_GetDisplayModeEx,
4001
};
4002

4003
static inline struct d3d9_device *device_from_device_parent(struct wined3d_device_parent *device_parent)
4004
{
4005
    return CONTAINING_RECORD(device_parent, struct d3d9_device, device_parent);
4006 4007
}

4008
static void CDECL device_parent_wined3d_device_created(struct wined3d_device_parent *device_parent,
4009
        struct wined3d_device *device)
4010
{
4011
    TRACE("device_parent %p, device %p.\n", device_parent, device);
4012 4013
}

4014 4015 4016 4017 4018
static void CDECL device_parent_mode_changed(struct wined3d_device_parent *device_parent)
{
    TRACE("device_parent %p.\n", device_parent);
}

4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035
static void CDECL device_parent_activate(struct wined3d_device_parent *device_parent, BOOL activate)
{
    struct d3d9_device *device = device_from_device_parent(device_parent);

    TRACE("device_parent %p, activate %#x.\n", device_parent, activate);

    if (!device->d3d_parent)
        return;

    if (!activate)
        InterlockedCompareExchange(&device->device_state, D3D9_DEVICE_STATE_LOST, D3D9_DEVICE_STATE_OK);
    else if (device->d3d_parent->extended)
        InterlockedCompareExchange(&device->device_state, D3D9_DEVICE_STATE_OK, D3D9_DEVICE_STATE_LOST);
    else
        InterlockedCompareExchange(&device->device_state, D3D9_DEVICE_STATE_NOT_RESET, D3D9_DEVICE_STATE_LOST);
}

4036
static HRESULT CDECL device_parent_surface_created(struct wined3d_device_parent *device_parent,
4037 4038
        struct wined3d_texture *wined3d_texture, unsigned int sub_resource_idx,
        void **parent, const struct wined3d_parent_ops **parent_ops)
4039
{
4040
    struct d3d9_surface *d3d_surface;
4041

4042 4043
    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);
4044

4045
    if (!(d3d_surface = heap_alloc_zero(sizeof(*d3d_surface))))
4046
        return E_OUTOFMEMORY;
4047

4048
    surface_init(d3d_surface, wined3d_texture, sub_resource_idx, parent_ops);
4049
    *parent = d3d_surface;
4050 4051
    TRACE("Created surface %p.\n", d3d_surface);

4052
    return D3D_OK;
4053 4054
}

4055
static HRESULT CDECL device_parent_volume_created(struct wined3d_device_parent *device_parent,
4056 4057
        struct wined3d_texture *wined3d_texture, unsigned int sub_resource_idx,
        void **parent, const struct wined3d_parent_ops **parent_ops)
4058 4059 4060
{
    struct d3d9_volume *d3d_volume;

4061 4062
    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);
4063

4064
    if (!(d3d_volume = heap_alloc_zero(sizeof(*d3d_volume))))
4065 4066
        return E_OUTOFMEMORY;

4067
    volume_init(d3d_volume, wined3d_texture, sub_resource_idx, parent_ops);
4068 4069 4070 4071 4072 4073
    *parent = d3d_volume;
    TRACE("Created volume %p.\n", d3d_volume);

    return D3D_OK;
}

4074
static HRESULT CDECL device_parent_create_swapchain_texture(struct wined3d_device_parent *device_parent,
4075 4076
        void *container_parent, const struct wined3d_resource_desc *desc, DWORD texture_flags,
        struct wined3d_texture **texture)
4077
{
4078
    struct d3d9_device *device = device_from_device_parent(device_parent);
4079
    struct d3d9_surface *d3d_surface;
4080 4081
    HRESULT hr;

4082 4083
    TRACE("device_parent %p, container_parent %p, desc %p, texture flags %#x, texture %p.\n",
            device_parent, container_parent, desc, texture_flags, texture);
4084

4085 4086 4087
    if (container_parent == device_parent)
        container_parent = &device->IDirect3DDevice9Ex_iface;

4088 4089 4090
    if (is_gdi_compat_wined3dformat(desc->format))
        texture_flags |= WINED3D_TEXTURE_CREATE_GET_DC;

4091
    if (FAILED(hr = wined3d_texture_create(device->wined3d_device, desc, 1, 1,
4092 4093
            texture_flags | WINED3D_TEXTURE_CREATE_MAPPABLE, NULL, container_parent,
            &d3d9_null_wined3d_parent_ops, texture)))
4094
    {
4095
        WARN("Failed to create texture, hr %#x.\n", hr);
4096 4097 4098
        return hr;
    }

4099
    d3d_surface = wined3d_texture_get_sub_resource_parent(*texture, 0);
4100
    d3d_surface->parent_device = &device->IDirect3DDevice9Ex_iface;
4101 4102 4103 4104

    return hr;
}

4105
static HRESULT CDECL device_parent_create_swapchain(struct wined3d_device_parent *device_parent,
4106
        struct wined3d_swapchain_desc *desc, struct wined3d_swapchain **swapchain)
4107
{
4108
    struct d3d9_device *device = device_from_device_parent(device_parent);
4109
    struct d3d9_swapchain *d3d_swapchain;
4110 4111
    HRESULT hr;

4112
    TRACE("device_parent %p, desc %p, swapchain %p\n", device_parent, desc, swapchain);
4113

4114
    hr = d3d9_swapchain_create(device, desc, &d3d_swapchain);
4115 4116
    if (FAILED(hr))
    {
4117
        WARN("Failed to create swapchain, hr %#x.\n", hr);
4118 4119 4120 4121
        *swapchain = NULL;
        return hr;
    }

4122
    *swapchain = d3d_swapchain->wined3d_swapchain;
4123
    wined3d_swapchain_incref(*swapchain);
4124
    IDirect3DSwapChain9Ex_Release(&d3d_swapchain->IDirect3DSwapChain9Ex_iface);
4125 4126 4127 4128

    return hr;
}

4129
static const struct wined3d_device_parent_ops d3d9_wined3d_device_parent_ops =
4130
{
4131
    device_parent_wined3d_device_created,
4132
    device_parent_mode_changed,
4133
    device_parent_activate,
4134
    device_parent_surface_created,
4135
    device_parent_volume_created,
4136
    device_parent_create_swapchain_texture,
4137
    device_parent_create_swapchain,
4138
};
4139

4140 4141 4142
static void setup_fpu(void)
{
#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
4143
    WORD cw;
4144 4145 4146
    __asm__ volatile ("fnstcw %0" : "=m" (cw));
    cw = (cw & ~0xf3f) | 0x3f;
    __asm__ volatile ("fldcw %0" : : "m" (cw));
4147 4148 4149 4150 4151
#elif defined(__i386__) && defined(_MSC_VER)
    WORD cw;
    __asm fnstcw cw;
    cw = (cw & ~0xf3f) | 0x3f;
    __asm fldcw cw;
4152 4153 4154 4155 4156
#else
    FIXME("FPU setup not implemented for this platform.\n");
#endif
}

4157
HRESULT device_init(struct d3d9_device *device, struct d3d9 *parent, struct wined3d *wined3d,
4158 4159
        UINT adapter, D3DDEVTYPE device_type, HWND focus_window, DWORD flags,
        D3DPRESENT_PARAMETERS *parameters, D3DDISPLAYMODEEX *mode)
4160
{
4161
    struct wined3d_swapchain_desc *swapchain_desc;
4162 4163
    unsigned i, count = 1;
    WINED3DCAPS caps;
4164 4165
    HRESULT hr;

4166 4167 4168
    if (mode)
        FIXME("Ignoring display mode.\n");

4169
    device->IDirect3DDevice9Ex_iface.lpVtbl = &d3d9_device_vtbl;
4170
    device->device_parent.ops = &d3d9_wined3d_device_parent_ops;
4171
    device->refcount = 1;
4172

4173 4174
    if (!(flags & D3DCREATE_FPU_PRESERVE)) setup_fpu();

4175
    wined3d_mutex_lock();
4176 4177
    if (FAILED(hr = wined3d_device_create(wined3d, adapter, device_type, focus_window, flags, 4,
            &device->device_parent, &device->wined3d_device)))
4178 4179 4180 4181 4182 4183
    {
        WARN("Failed to create wined3d device, hr %#x.\n", hr);
        wined3d_mutex_unlock();
        return hr;
    }

4184 4185
    wined3d_get_device_caps(wined3d, adapter, device_type, &caps);
    device->max_user_clip_planes = caps.MaxUserClipPlanes;
4186 4187 4188
    if (flags & D3DCREATE_ADAPTERGROUP_DEVICE)
        count = caps.NumberOfAdaptersInGroup;

4189 4190
    if (flags & D3DCREATE_MULTITHREADED)
        wined3d_device_set_multithreaded(device->wined3d_device);
4191

4192 4193
    if (!parameters->Windowed)
    {
4194 4195 4196
        if (!focus_window)
            focus_window = parameters->hDeviceWindow;
        if (FAILED(hr = wined3d_device_acquire_focus_window(device->wined3d_device, focus_window)))
4197 4198
        {
            ERR("Failed to acquire focus window, hr %#x.\n", hr);
4199
            wined3d_device_decref(device->wined3d_device);
4200 4201 4202 4203
            wined3d_mutex_unlock();
            return hr;
        }

4204 4205 4206
        for (i = 0; i < count; ++i)
        {
            HWND device_window = parameters[i].hDeviceWindow;
4207

4208
            if (!device_window) device_window = focus_window;
4209
            wined3d_device_setup_fullscreen_window(device->wined3d_device, device_window,
4210 4211 4212
                    parameters[i].BackBufferWidth,
                    parameters[i].BackBufferHeight);
        }
4213 4214
    }

4215
    if (!(swapchain_desc = heap_alloc(sizeof(*swapchain_desc) * count)))
4216 4217
    {
        ERR("Failed to allocate wined3d parameters.\n");
4218
        wined3d_device_release_focus_window(device->wined3d_device);
4219
        wined3d_device_decref(device->wined3d_device);
4220 4221 4222 4223 4224 4225
        wined3d_mutex_unlock();
        return E_OUTOFMEMORY;
    }

    for (i = 0; i < count; ++i)
    {
4226 4227 4228 4229 4230
        if (!wined3d_swapchain_desc_from_present_parameters(&swapchain_desc[i], &parameters[i],
                parent->extended))
        {
            wined3d_device_release_focus_window(device->wined3d_device);
            wined3d_device_decref(device->wined3d_device);
4231
            heap_free(swapchain_desc);
4232 4233 4234
            wined3d_mutex_unlock();
            return D3DERR_INVALIDCALL;
        }
4235 4236
    }

4237
    if (FAILED(hr = wined3d_device_init_3d(device->wined3d_device, swapchain_desc)))
4238 4239
    {
        WARN("Failed to initialize 3D, hr %#x.\n", hr);
4240
        wined3d_device_release_focus_window(device->wined3d_device);
4241
        heap_free(swapchain_desc);
4242
        wined3d_device_decref(device->wined3d_device);
4243 4244 4245 4246
        wined3d_mutex_unlock();
        return hr;
    }

4247 4248 4249
    wined3d_device_set_render_state(device->wined3d_device,
            WINED3D_RS_ZENABLE, !!swapchain_desc->enable_auto_depth_stencil);

4250 4251 4252 4253 4254 4255 4256 4257
    if (FAILED(hr = d3d9_device_get_swapchains(device)))
    {
        wined3d_device_uninit_3d(device->wined3d_device);
        wined3d_device_release_focus_window(device->wined3d_device);
        wined3d_device_decref(device->wined3d_device);
        wined3d_mutex_unlock();
        return E_OUTOFMEMORY;
    }
4258 4259 4260

    for (i = 0; i < count; ++i)
    {
4261
        present_parameters_from_wined3d_swapchain_desc(&parameters[i], &swapchain_desc[i]);
4262
    }
4263 4264 4265

    wined3d_mutex_unlock();

4266
    heap_free(swapchain_desc);
4267 4268 4269

    /* Initialize the converted declaration array. This creates a valid pointer
     * and when adding decls HeapReAlloc() can be used without further checking. */
4270
    if (!(device->fvf_decls = heap_alloc(0)))
4271 4272 4273
    {
        ERR("Failed to allocate FVF vertex declaration map memory.\n");
        wined3d_mutex_lock();
4274
        heap_free(device->implicit_swapchains);
4275 4276 4277
        wined3d_device_uninit_3d(device->wined3d_device);
        wined3d_device_release_focus_window(device->wined3d_device);
        wined3d_device_decref(device->wined3d_device);
4278 4279 4280 4281
        wined3d_mutex_unlock();
        return E_OUTOFMEMORY;
    }

4282 4283 4284 4285 4286 4287 4288 4289
    /* We could also simply ignore the initial rendertarget since it's known
     * not to be a texture (we currently use these only for automatic mipmap
     * generation). */
    wined3d_mutex_lock();
    device->render_targets[0] = wined3d_rendertarget_view_get_sub_resource_parent(
            wined3d_device_get_rendertarget_view(device->wined3d_device, 0));
    wined3d_mutex_unlock();

4290 4291
    IDirect3D9Ex_AddRef(&parent->IDirect3D9Ex_iface);
    device->d3d_parent = parent;
4292

4293 4294
    return D3D_OK;
}