buffer.c 15.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/*
 * Copyright 2009 Henri Verbeet for CodeWeavers
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 *
 */

20
#include "d3d11_private.h"
21

22
WINE_DEFAULT_DEBUG_CHANNEL(d3d11);
23

24 25 26
/* ID3D11Buffer methods */

static inline struct d3d_buffer *impl_from_ID3D11Buffer(ID3D11Buffer *iface)
27
{
28
    return CONTAINING_RECORD(iface, struct d3d_buffer, ID3D11Buffer_iface);
29 30
}

31
static HRESULT STDMETHODCALLTYPE d3d11_buffer_QueryInterface(ID3D11Buffer *iface, REFIID riid, void **out)
32
{
33 34
    struct d3d_buffer *buffer = impl_from_ID3D11Buffer(iface);

35
    TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
36

37 38 39
    if (IsEqualGUID(riid, &IID_ID3D11Buffer)
            || IsEqualGUID(riid, &IID_ID3D11Resource)
            || IsEqualGUID(riid, &IID_ID3D11DeviceChild)
40 41
            || IsEqualGUID(riid, &IID_IUnknown))
    {
42
        ID3D11Buffer_AddRef(iface);
43
        *out = iface;
44 45 46
        return S_OK;
    }

47 48 49 50 51 52 53 54 55 56
    if (IsEqualGUID(riid, &IID_ID3D10Buffer)
            || IsEqualGUID(riid, &IID_ID3D10Resource)
            || IsEqualGUID(riid, &IID_ID3D10DeviceChild))
    {
        ID3D10Buffer_AddRef(&buffer->ID3D10Buffer_iface);
        *out = &buffer->ID3D10Buffer_iface;
        return S_OK;
    }

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

58
    *out = NULL;
59 60 61
    return E_NOINTERFACE;
}

62
static ULONG STDMETHODCALLTYPE d3d11_buffer_AddRef(ID3D11Buffer *iface)
63
{
64
    struct d3d_buffer *buffer = impl_from_ID3D11Buffer(iface);
65
    ULONG refcount = InterlockedIncrement(&buffer->refcount);
66

67
    TRACE("%p increasing refcount to %u.\n", buffer, refcount);
68

69
    if (refcount == 1)
70
    {
71
        ID3D11Device2_AddRef(buffer->device);
72
        wined3d_mutex_lock();
73
        wined3d_buffer_incref(buffer->wined3d_buffer);
74
        wined3d_mutex_unlock();
75
    }
76

77 78 79
    return refcount;
}

80
static ULONG STDMETHODCALLTYPE d3d11_buffer_Release(ID3D11Buffer *iface)
81
{
82
    struct d3d_buffer *buffer = impl_from_ID3D11Buffer(iface);
83
    ULONG refcount = InterlockedDecrement(&buffer->refcount);
84

85
    TRACE("%p decreasing refcount to %u.\n", buffer, refcount);
86 87

    if (!refcount)
88
    {
89
        ID3D11Device2 *device = buffer->device;
90

91
        wined3d_mutex_lock();
92
        wined3d_buffer_decref(buffer->wined3d_buffer);
93
        wined3d_mutex_unlock();
94 95
        /* Release the device last, it may cause the wined3d device to be
         * destroyed. */
96
        ID3D11Device2_Release(device);
97
    }
98 99 100 101

    return refcount;
}

102 103
static void STDMETHODCALLTYPE d3d11_buffer_GetDevice(ID3D11Buffer *iface, ID3D11Device **device)
{
104 105 106 107
    struct d3d_buffer *buffer = impl_from_ID3D11Buffer(iface);

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

108
    *device = (ID3D11Device *)buffer->device;
109
    ID3D11Device_AddRef(*device);
110 111 112 113 114
}

static HRESULT STDMETHODCALLTYPE d3d11_buffer_GetPrivateData(ID3D11Buffer *iface,
        REFGUID guid, UINT *data_size, void *data)
{
115 116 117
    struct d3d_buffer *buffer = impl_from_ID3D11Buffer(iface);

    TRACE("iface %p, guid %s, data_size %p, data %p.\n", iface, debugstr_guid(guid), data_size, data);
118

119
    return d3d_get_private_data(&buffer->private_store, guid, data_size, data);
120 121 122 123 124
}

static HRESULT STDMETHODCALLTYPE d3d11_buffer_SetPrivateData(ID3D11Buffer *iface,
        REFGUID guid, UINT data_size, const void *data)
{
125
    struct d3d_buffer *buffer = impl_from_ID3D11Buffer(iface);
126

127 128 129
    TRACE("iface %p, guid %s, data_size %u, data %p.\n", iface, debugstr_guid(guid), data_size, data);

    return d3d_set_private_data(&buffer->private_store, guid, data_size, data);
130 131 132 133 134
}

static HRESULT STDMETHODCALLTYPE d3d11_buffer_SetPrivateDataInterface(ID3D11Buffer *iface,
        REFGUID guid, const IUnknown *data)
{
135 136 137
    struct d3d_buffer *buffer = impl_from_ID3D11Buffer(iface);

    TRACE("iface %p, guid %s, data %p.\n", iface, debugstr_guid(guid), data);
138

139
    return d3d_set_private_data_interface(&buffer->private_store, guid, data);
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
}

static void STDMETHODCALLTYPE d3d11_buffer_GetType(ID3D11Buffer *iface,
        D3D11_RESOURCE_DIMENSION *resource_dimension)
{
    TRACE("iface %p, resource_dimension %p.\n", iface, resource_dimension);

    *resource_dimension = D3D11_RESOURCE_DIMENSION_BUFFER;
}

static void STDMETHODCALLTYPE d3d11_buffer_SetEvictionPriority(ID3D11Buffer *iface, UINT eviction_priority)
{
    FIXME("iface %p, eviction_priority %#x stub!\n", iface, eviction_priority);
}

static UINT STDMETHODCALLTYPE d3d11_buffer_GetEvictionPriority(ID3D11Buffer *iface)
{
    FIXME("iface %p stub!\n", iface);

    return 0;
}

static void STDMETHODCALLTYPE d3d11_buffer_GetDesc(ID3D11Buffer *iface, D3D11_BUFFER_DESC *desc)
{
164 165 166 167 168
    struct d3d_buffer *buffer = impl_from_ID3D11Buffer(iface);

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

    *desc = buffer->desc;
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
}

static const struct ID3D11BufferVtbl d3d11_buffer_vtbl =
{
    /* IUnknown methods */
    d3d11_buffer_QueryInterface,
    d3d11_buffer_AddRef,
    d3d11_buffer_Release,
    /* ID3D11DeviceChild methods */
    d3d11_buffer_GetDevice,
    d3d11_buffer_GetPrivateData,
    d3d11_buffer_SetPrivateData,
    d3d11_buffer_SetPrivateDataInterface,
    /* ID3D11Resource methods */
    d3d11_buffer_GetType,
    d3d11_buffer_SetEvictionPriority,
    d3d11_buffer_GetEvictionPriority,
    /* ID3D11Buffer methods */
    d3d11_buffer_GetDesc,
};

190 191 192 193 194 195 196 197
struct d3d_buffer *unsafe_impl_from_ID3D11Buffer(ID3D11Buffer *iface)
{
    if (!iface)
        return NULL;
    assert(iface->lpVtbl == &d3d11_buffer_vtbl);
    return CONTAINING_RECORD(iface, struct d3d_buffer, ID3D11Buffer_iface);
}

198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
/* ID3D10Buffer methods */

static inline struct d3d_buffer *impl_from_ID3D10Buffer(ID3D10Buffer *iface)
{
    return CONTAINING_RECORD(iface, struct d3d_buffer, ID3D10Buffer_iface);
}

/* IUnknown methods */

static HRESULT STDMETHODCALLTYPE d3d10_buffer_QueryInterface(ID3D10Buffer *iface, REFIID riid, void **out)
{
    struct d3d_buffer *buffer = impl_from_ID3D10Buffer(iface);

    TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);

    return d3d11_buffer_QueryInterface(&buffer->ID3D11Buffer_iface, riid, out);
}

static ULONG STDMETHODCALLTYPE d3d10_buffer_AddRef(ID3D10Buffer *iface)
{
    struct d3d_buffer *buffer = impl_from_ID3D10Buffer(iface);

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

    return d3d11_buffer_AddRef(&buffer->ID3D11Buffer_iface);
}

static ULONG STDMETHODCALLTYPE d3d10_buffer_Release(ID3D10Buffer *iface)
{
    struct d3d_buffer *buffer = impl_from_ID3D10Buffer(iface);

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

    return d3d11_buffer_Release(&buffer->ID3D11Buffer_iface);
}

234 235 236 237
/* ID3D10DeviceChild methods */

static void STDMETHODCALLTYPE d3d10_buffer_GetDevice(ID3D10Buffer *iface, ID3D10Device **device)
{
238
    struct d3d_buffer *buffer = impl_from_ID3D10Buffer(iface);
239 240 241

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

242
    ID3D11Device2_QueryInterface(buffer->device, &IID_ID3D10Device, (void **)device);
243 244 245 246 247
}

static HRESULT STDMETHODCALLTYPE d3d10_buffer_GetPrivateData(ID3D10Buffer *iface,
        REFGUID guid, UINT *data_size, void *data)
{
248
    struct d3d_buffer *buffer = impl_from_ID3D10Buffer(iface);
249 250

    TRACE("iface %p, guid %s, data_size %p, data %p.\n",
251 252
            iface, debugstr_guid(guid), data_size, data);

253
    return d3d_get_private_data(&buffer->private_store, guid, data_size, data);
254 255 256 257 258
}

static HRESULT STDMETHODCALLTYPE d3d10_buffer_SetPrivateData(ID3D10Buffer *iface,
        REFGUID guid, UINT data_size, const void *data)
{
259
    struct d3d_buffer *buffer = impl_from_ID3D10Buffer(iface);
260 261

    TRACE("iface %p, guid %s, data_size %u, data %p.\n",
262 263
            iface, debugstr_guid(guid), data_size, data);

264
    return d3d_set_private_data(&buffer->private_store, guid, data_size, data);
265 266 267 268 269
}

static HRESULT STDMETHODCALLTYPE d3d10_buffer_SetPrivateDataInterface(ID3D10Buffer *iface,
        REFGUID guid, const IUnknown *data)
{
270
    struct d3d_buffer *buffer = impl_from_ID3D10Buffer(iface);
271

272 273
    TRACE("iface %p, guid %s, data %p.\n", iface, debugstr_guid(guid), data);

274
    return d3d_set_private_data_interface(&buffer->private_store, guid, data);
275 276 277 278 279 280
}

/* ID3D10Resource methods */

static void STDMETHODCALLTYPE d3d10_buffer_GetType(ID3D10Buffer *iface, D3D10_RESOURCE_DIMENSION *resource_dimension)
{
281 282 283
    TRACE("iface %p, resource_dimension %p\n", iface, resource_dimension);

    *resource_dimension = D3D10_RESOURCE_DIMENSION_BUFFER;
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301
}

static void STDMETHODCALLTYPE d3d10_buffer_SetEvictionPriority(ID3D10Buffer *iface, UINT eviction_priority)
{
    FIXME("iface %p, eviction_priority %u stub!\n", iface, eviction_priority);
}

static UINT STDMETHODCALLTYPE d3d10_buffer_GetEvictionPriority(ID3D10Buffer *iface)
{
    FIXME("iface %p stub!\n", iface);

    return 0;
}

/* ID3D10Buffer methods */

static HRESULT STDMETHODCALLTYPE d3d10_buffer_Map(ID3D10Buffer *iface, D3D10_MAP map_type, UINT map_flags, void **data)
{
302
    struct d3d_buffer *buffer = impl_from_ID3D10Buffer(iface);
303
    struct wined3d_map_desc wined3d_map_desc;
304
    HRESULT hr;
305

306 307 308 309 310
    TRACE("iface %p, map_type %u, map_flags %#x, data %p.\n", iface, map_type, map_flags, data);

    if (map_flags)
        FIXME("Ignoring map_flags %#x.\n", map_flags);

311
    wined3d_mutex_lock();
312 313 314
    hr = wined3d_resource_map(wined3d_buffer_get_resource(buffer->wined3d_buffer), 0,
            &wined3d_map_desc, NULL, wined3d_map_flags_from_d3d11_map_type(map_type));
    *data = wined3d_map_desc.data;
315 316 317
    wined3d_mutex_unlock();

    return hr;
318 319 320 321
}

static void STDMETHODCALLTYPE d3d10_buffer_Unmap(ID3D10Buffer *iface)
{
322
    struct d3d_buffer *buffer = impl_from_ID3D10Buffer(iface);
323

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

326
    wined3d_mutex_lock();
327
    wined3d_resource_unmap(wined3d_buffer_get_resource(buffer->wined3d_buffer), 0);
328
    wined3d_mutex_unlock();
329 330 331 332
}

static void STDMETHODCALLTYPE d3d10_buffer_GetDesc(ID3D10Buffer *iface, D3D10_BUFFER_DESC *desc)
{
333 334 335 336 337 338 339 340 341 342
    struct d3d_buffer *buffer = impl_from_ID3D10Buffer(iface);
    const D3D11_BUFFER_DESC *d3d11_desc = &buffer->desc;

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

    desc->ByteWidth = d3d11_desc->ByteWidth;
    desc->Usage = d3d10_usage_from_d3d11_usage(d3d11_desc->Usage);
    desc->BindFlags = d3d10_bind_flags_from_d3d11_bind_flags(d3d11_desc->BindFlags);
    desc->CPUAccessFlags = d3d10_cpu_access_flags_from_d3d11_cpu_access_flags(d3d11_desc->CPUAccessFlags);
    desc->MiscFlags = d3d10_resource_misc_flags_from_d3d11_resource_misc_flags(d3d11_desc->MiscFlags);
343 344
}

345
static const struct ID3D10BufferVtbl d3d10_buffer_vtbl =
346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364
{
    /* IUnknown methods */
    d3d10_buffer_QueryInterface,
    d3d10_buffer_AddRef,
    d3d10_buffer_Release,
    /* ID3D10DeviceChild methods */
    d3d10_buffer_GetDevice,
    d3d10_buffer_GetPrivateData,
    d3d10_buffer_SetPrivateData,
    d3d10_buffer_SetPrivateDataInterface,
    /* ID3D10Resource methods */
    d3d10_buffer_GetType,
    d3d10_buffer_SetEvictionPriority,
    d3d10_buffer_GetEvictionPriority,
    /* ID3D10Buffer methods */
    d3d10_buffer_Map,
    d3d10_buffer_Unmap,
    d3d10_buffer_GetDesc,
};
365

366
struct d3d_buffer *unsafe_impl_from_ID3D10Buffer(ID3D10Buffer *iface)
367 368 369 370
{
    if (!iface)
        return NULL;
    assert(iface->lpVtbl == &d3d10_buffer_vtbl);
371
    return CONTAINING_RECORD(iface, struct d3d_buffer, ID3D10Buffer_iface);
372 373
}

374
static void STDMETHODCALLTYPE d3d_buffer_wined3d_object_released(void *parent)
375
{
376
    struct d3d_buffer *buffer = parent;
377 378

    wined3d_private_store_cleanup(&buffer->private_store);
379
    heap_free(parent);
380 381
}

382
static const struct wined3d_parent_ops d3d_buffer_wined3d_parent_ops =
383
{
384
    d3d_buffer_wined3d_object_released,
385 386
};

387
static BOOL validate_buffer_desc(D3D11_BUFFER_DESC *desc, D3D_FEATURE_LEVEL feature_level)
388
{
389 390 391 392
    if (!validate_d3d11_resource_access_flags(D3D11_RESOURCE_DIMENSION_BUFFER,
            desc->Usage, desc->BindFlags, desc->CPUAccessFlags, feature_level))
        return FALSE;

393
    if (desc->MiscFlags & D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS)
394
    {
395
        if (desc->MiscFlags & D3D11_RESOURCE_MISC_BUFFER_STRUCTURED)
396 397
        {
            WARN("Raw and structure buffers are mutually exclusive.\n");
398
            return FALSE;
399
        }
400
        if (!(desc->BindFlags & (D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS)))
401
        {
402 403
            WARN("Invalid bind flags %#x for raw buffer.\n", desc->BindFlags);
            return FALSE;
404 405 406
        }
    }

407
    if (desc->MiscFlags & D3D11_RESOURCE_MISC_BUFFER_STRUCTURED)
408
    {
409
        if (!desc->StructureByteStride || desc->StructureByteStride % 4)
410
        {
411 412
            WARN("Invalid structure byte stride %u.\n", desc->StructureByteStride);
            return FALSE;
413
        }
414
        if (desc->ByteWidth % desc->StructureByteStride)
415 416
        {
            WARN("Byte width %u is not divisible by structure byte stride %u.\n",
417 418
                    desc->ByteWidth, desc->StructureByteStride);
            return FALSE;
419 420 421 422
        }
    }
    else
    {
423
        desc->StructureByteStride = 0;
424 425
    }

426 427 428 429 430 431
    if (desc->MiscFlags & D3D11_RESOURCE_MISC_GENERATE_MIPS)
    {
        WARN("Buffer with the D3D11_RESOURCE_MISC_GENERATE_MIPS flag.\n");
        return FALSE;
    }

432 433 434 435 436 437 438 439 440 441 442 443 444 445
    return TRUE;
}

static HRESULT d3d_buffer_init(struct d3d_buffer *buffer, struct d3d_device *device,
        const D3D11_BUFFER_DESC *desc, const D3D11_SUBRESOURCE_DATA *data)
{
    struct wined3d_buffer_desc wined3d_desc;
    HRESULT hr;

    buffer->ID3D11Buffer_iface.lpVtbl = &d3d11_buffer_vtbl;
    buffer->ID3D10Buffer_iface.lpVtbl = &d3d10_buffer_vtbl;
    buffer->refcount = 1;
    buffer->desc = *desc;

446
    if (!validate_buffer_desc(&buffer->desc, device->feature_level))
447 448
        return E_INVALIDARG;

449
    wined3d_desc.byte_width = buffer->desc.ByteWidth;
450
    wined3d_desc.usage = wined3d_usage_from_d3d11(buffer->desc.Usage);
451
    wined3d_desc.bind_flags = wined3d_bind_flags_from_d3d11(buffer->desc.BindFlags, buffer->desc.MiscFlags);
452
    wined3d_desc.access = wined3d_access_from_d3d11(buffer->desc.Usage, buffer->desc.CPUAccessFlags);
453
    wined3d_desc.misc_flags = buffer->desc.MiscFlags;
454
    wined3d_desc.structure_byte_stride = buffer->desc.StructureByteStride;
455

456 457 458
    wined3d_mutex_lock();
    wined3d_private_store_init(&buffer->private_store);

459 460
    if (FAILED(hr = wined3d_buffer_create(device->wined3d_device, &wined3d_desc,
            (const struct wined3d_sub_resource_data *)data, buffer,
461
            &d3d_buffer_wined3d_parent_ops, &buffer->wined3d_buffer)))
462 463
    {
        WARN("Failed to create wined3d buffer, hr %#x.\n", hr);
464
        wined3d_private_store_cleanup(&buffer->private_store);
465
        wined3d_mutex_unlock();
466 467
        return hr;
    }
468
    wined3d_mutex_unlock();
469

470
    ID3D11Device2_AddRef(buffer->device = &device->ID3D11Device2_iface);
471

472 473
    return S_OK;
}
474 475 476 477 478 479 480

HRESULT d3d_buffer_create(struct d3d_device *device, const D3D11_BUFFER_DESC *desc,
        const D3D11_SUBRESOURCE_DATA *data, struct d3d_buffer **buffer)
{
    struct d3d_buffer *object;
    HRESULT hr;

481
    if (!(object = heap_alloc_zero(sizeof(*object))))
482 483 484 485 486
        return E_OUTOFMEMORY;

    if (FAILED(hr = d3d_buffer_init(object, device, desc, data)))
    {
        WARN("Failed to initialize buffer, hr %#x.\n", hr);
487
        heap_free(object);
488 489 490 491 492 493 494 495
        return hr;
    }

    TRACE("Created buffer %p.\n", object);
    *buffer = object;

    return S_OK;
}