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

#include "config.h"
#include "wined3d_private.h"

WINE_DEFAULT_DEBUG_CHANNEL(d3d);
27
#define GLINFO_LOCATION ((IWineD3DImpl *)(((IWineD3DDeviceImpl *)This->resource.wineD3DDevice)->wineD3D))->gl_info
28

29 30 31
#define VB_MAXDECLCHANGES     100     /* After that number we stop converting */
#define VB_RESETDECLCHANGE    1000    /* Reset the changecount after that number of draws */

32 33 34
/* *******************************************
   IWineD3DVertexBuffer IUnknown parts follow
   ******************************************* */
35
static HRESULT WINAPI IWineD3DVertexBufferImpl_QueryInterface(IWineD3DVertexBuffer *iface, REFIID riid, LPVOID *ppobj)
36 37
{
    IWineD3DVertexBufferImpl *This = (IWineD3DVertexBufferImpl *)iface;
38 39
    TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
    if (IsEqualGUID(riid, &IID_IUnknown)
40
        || IsEqualGUID(riid, &IID_IWineD3DBase)
41 42 43 44
        || IsEqualGUID(riid, &IID_IWineD3DResource)
        || IsEqualGUID(riid, &IID_IWineD3DVertexBuffer)){
        IUnknown_AddRef(iface);
        *ppobj = This;
45
        return S_OK;
46
    }
47
    *ppobj = NULL;
48 49 50
    return E_NOINTERFACE;
}

51
static ULONG WINAPI IWineD3DVertexBufferImpl_AddRef(IWineD3DVertexBuffer *iface) {
52
    IWineD3DVertexBufferImpl *This = (IWineD3DVertexBufferImpl *)iface;
53
    ULONG ref = InterlockedIncrement(&This->resource.ref);
54
    TRACE("(%p) : AddRef increasing from %d\n", This, ref - 1);
55
    return ref;
56 57
}

58
static ULONG WINAPI IWineD3DVertexBufferImpl_Release(IWineD3DVertexBuffer *iface) {
59
    IWineD3DVertexBufferImpl *This = (IWineD3DVertexBufferImpl *)iface;
60
    ULONG ref = InterlockedDecrement(&This->resource.ref);
61
    TRACE("(%p) : Releasing from %d\n", This, ref + 1);
62
    if (ref == 0) {
63 64 65 66 67 68 69 70

        if(This->vbo) {
            ENTER_GL();
            GL_EXTCALL(glDeleteBuffersARB(1, &This->vbo));
            checkGLcall("glDeleteBuffersARB");
            LEAVE_GL();
        }

71
        IWineD3DResourceImpl_CleanUp((IWineD3DResource *)iface);
72 73 74 75 76 77 78 79
        HeapFree(GetProcessHeap(), 0, This);
    }
    return ref;
}

/* ****************************************************
   IWineD3DVertexBuffer IWineD3DResource parts follow
   **************************************************** */
80
static HRESULT WINAPI IWineD3DVertexBufferImpl_GetDevice(IWineD3DVertexBuffer *iface, IWineD3DDevice** ppDevice) {
81
    return IWineD3DResourceImpl_GetDevice((IWineD3DResource *)iface, ppDevice);
82 83
}

84
static HRESULT WINAPI IWineD3DVertexBufferImpl_SetPrivateData(IWineD3DVertexBuffer *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
85
    return IWineD3DResourceImpl_SetPrivateData((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags);
86 87
}

88
static HRESULT WINAPI IWineD3DVertexBufferImpl_GetPrivateData(IWineD3DVertexBuffer *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
89
    return IWineD3DResourceImpl_GetPrivateData((IWineD3DResource *)iface, refguid, pData, pSizeOfData);
90 91
}

92
static HRESULT WINAPI IWineD3DVertexBufferImpl_FreePrivateData(IWineD3DVertexBuffer *iface, REFGUID refguid) {
93
    return IWineD3DResourceImpl_FreePrivateData((IWineD3DResource *)iface, refguid);
94 95
}

96
static DWORD    WINAPI IWineD3DVertexBufferImpl_SetPriority(IWineD3DVertexBuffer *iface, DWORD PriorityNew) {
97
    return IWineD3DResourceImpl_SetPriority((IWineD3DResource *)iface, PriorityNew);
98 99
}

100
static DWORD    WINAPI IWineD3DVertexBufferImpl_GetPriority(IWineD3DVertexBuffer *iface) {
101
    return IWineD3DResourceImpl_GetPriority((IWineD3DResource *)iface);
102 103
}

104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
static void fixup_vertices(BYTE *src, BYTE *dst, int stride, int num, BYTE *pos, BOOL haspos, BYTE *diffuse, BOOL hasdiffuse, BYTE *specular, BOOL hasspecular) {
    int i;
    float x, y, z, w;

    for(i = num - 1; i >= 0; i--) {
        if(haspos) {
            float *p = (float *) (((int) src + (int) pos) + i * stride);

            /* rhw conversion like in drawStridedSlow */
            if(p[3] == 1.0 || ((p[3] < eps) && (p[3] > -eps))) {
                x = p[0];
                y = p[1];
                z = p[2];
                w = 1.0;
            } else {
                w = 1.0 / p[3];
                x = p[0] * w;
                y = p[1] * w;
                z = p[2] * w;
            }
            p = (float *) ((int) dst + i * stride + (int) pos);
            p[0] = x;
            p[1] = y;
            p[2] = z;
            p[3] = w;
        }
        if(hasdiffuse) {
            DWORD srcColor, *dstColor = (DWORD *) (dst + i * stride + (int) diffuse);
            srcColor = * (DWORD *) ( ((int) src + (int) diffuse) + i * stride);

            /* Color conversion like in drawStridedSlow. watch out for little endianity
            * If we want that stuff to work on big endian machines too we have to consider more things
            *
            * 0xff000000: Alpha mask
            * 0x00ff0000: Blue mask
            * 0x0000ff00: Green mask
            * 0x000000ff: Red mask
            */

            *dstColor = 0;
            *dstColor |= (srcColor & 0xff00ff00)      ;   /* Alpha Green */
            *dstColor |= (srcColor & 0x00ff0000) >> 16;   /* Red */
            *dstColor |= (srcColor & 0x000000ff) << 16;   /* Blue */
        }
        if(hasspecular) {
            DWORD srcColor, *dstColor = (DWORD *) (dst + i * stride + (int) specular);
            srcColor = * (DWORD *) ( ((int) src + (int) specular) + i * stride);

152
            /* Similar to diffuse
153 154 155 156 157 158 159 160 161 162
             * TODO: Write the alpha value out for fog coords
             */
            *dstColor = 0;
            *dstColor |= (srcColor & 0xff00ff00)      ;   /* Alpha Green */
            *dstColor |= (srcColor & 0x00ff0000) >> 16;   /* Red */
            *dstColor |= (srcColor & 0x000000ff) << 16;   /* Blue */
        }
    }
}

163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
inline BOOL WINAPI IWineD3DVertexBufferImpl_FindDecl(IWineD3DVertexBufferImpl *This)
{
    WineDirect3DVertexStridedData strided;
    IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
    BOOL ret;

    memset(&strided, 0, sizeof(strided));
    /* There are certain vertex data types that need to be fixed up. The Vertex Buffers FVF doesn't
     * help finding them, only the vertex declaration or the device FVF can determine that at drawPrim
     * time. Rules are as follows:
     *
     * -> No modification when Vertex Shaders are used
     * -> Fix up position1 and position 2 if they are XYZRHW
     * -> Fix up diffuse color
     * -> Fix up specular color
     *
     * The Declaration is only known at drawing time, and it can change from draw to draw. If any converted values
     * are changed, the whole buffer has to be reconverted and reloaded. (Converting is SLOW, so if this happens too
     * often PreLoad stops converting entirely and falls back to drawStridedSlow).
     *
     * Reconvert if:
     * -> New semantics that have to be converted appear
     * -> The position of semantics that have to be converted changes
     * -> The stride of the vertex changed AND there is stuff that needs conversion
187
     * -> (If a vertex shader is bound and in use assume that nothing that needs conversion is there)
188 189 190 191 192 193 194 195 196 197 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 234 235 236 237 238 239 240 241 242 243
     *
     * Return values:
     *  TRUE: Reload is needed
     *  FALSE: otherwise
     */

    if(device->stateBlock->vertexShader != NULL && wined3d_settings.vs_mode != VS_NONE 
       &&((IWineD3DVertexShaderImpl *)device->stateBlock->vertexShader)->baseShader.function != NULL
       && GL_SUPPORT(ARB_VERTEX_PROGRAM)) {
        /* Case 1: Vertex Shader: No conversion */
        TRACE("Vertex Shader, no conversion needed\n");
    } else if(device->stateBlock->vertexDecl || device->stateBlock->vertexShader) {
        /* Case 2: Vertex Declaration */
        TRACE("Using vertex declaration\n");

        This->Flags |= VBFLAG_LOAD;
        primitiveDeclarationConvertToStridedData((IWineD3DDevice *) device,
                FALSE,
                &strided,
                0,
                &ret /* buffer contains fixed data, ignored here */);
        This->Flags &= ~VBFLAG_LOAD;

    } else {
        /* Case 3: FVF */
        if(!(This->Flags & VBFLAG_STREAM) ) {
            TRACE("No vertex decl used and buffer is not bound to a stream\n");
            /* No reload needed */
            return FALSE;
        } else {
            This->Flags |= VBFLAG_LOAD;
            primitiveConvertFVFtoOffset(device->stateBlock->fvf,
                                        device->stateBlock->streamStride[This->stream],
                                        NULL,
                                        &strided,
                                        This->vbo);
            This->Flags &= ~VBFLAG_LOAD;
            /* Data can only come from this buffer */
        }
    }

    /* Filter out data that does not come from this VBO */
    if(strided.u.s.position.VBO != This->vbo)    memset(&strided.u.s.position, 0, sizeof(strided.u.s.position));
    if(strided.u.s.diffuse.VBO != This->vbo)     memset(&strided.u.s.diffuse, 0, sizeof(strided.u.s.diffuse));
    if(strided.u.s.specular.VBO != This->vbo)    memset(&strided.u.s.specular, 0, sizeof(strided.u.s.specular));
    if(strided.u.s.position2.VBO != This->vbo)   memset(&strided.u.s.position2, 0, sizeof(strided.u.s.position2));

    /* We have a declaration now in the buffer */
    This->Flags |= VBFLAG_HASDESC;

    /* Find out if reload is needed
     * Position of the semantic in the vertex and the stride must be equal to the stored type. Don't mind if only unconverted stuff changed.
     *
     * If some stuff does not exist in the buffer, then lpData, dwStride and dwType are memsetted to 0. So if the semantic didn't exist before
     * and does not exist now all 3 values will be equal(=0).
     *
244
     * Checking the lpData field alone is not enough, because data may appear at offset 0 in the buffer. This is the same location as nonexistent
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266
     * data uses, so we have to check the type and stride too. Colors can be at offset 0 too, because it is perfectly fine to render from 2 or more
     * buffers at the same time and get the position from one and the color from the other buffer.
     */
    if( /* Position transformed vs untransformed */
        ((This->strided.u.s.position_transformed || strided.u.s.position_transformed) &&
          This->strided.u.s.position.lpData != strided.u.s.position.lpData) ||
        /* Diffuse position and data type */
        This->strided.u.s.diffuse.lpData != strided.u.s.diffuse.lpData || This->strided.u.s.diffuse.dwStride != strided.u.s.diffuse.dwStride ||
         This->strided.u.s.diffuse.dwType != strided.u.s.diffuse.dwType ||
        /* Specular position and data type */
        This->strided.u.s.specular.lpData != strided.u.s.specular.lpData || This->strided.u.s.specular.dwStride != strided.u.s.specular.dwStride ||
         This->strided.u.s.specular.dwType != strided.u.s.specular.dwType) {

        TRACE("Declaration changed, reloading buffer\n");
        /* Set the new description */
        memcpy(&This->strided, &strided, sizeof(strided));
        return TRUE;
    }

    return FALSE;
}

267
static void     WINAPI IWineD3DVertexBufferImpl_PreLoad(IWineD3DVertexBuffer *iface) {
268
    IWineD3DVertexBufferImpl *This = (IWineD3DVertexBufferImpl *) iface;
269 270
    BYTE *data;
    UINT start = 0, end = 0, stride = 0;
271
    BOOL declChanged = FALSE;
272 273 274 275 276 277
    TRACE("(%p)->()\n", This);

    if(This->Flags & VBFLAG_LOAD) {
        return; /* Already doing that stuff */
    }

278 279 280
    if(!This->vbo) {
        /* TODO: Make converting independent from VBOs */
        return; /* Not doing any conversion */
281 282
    }

283
    declChanged = IWineD3DVertexBufferImpl_FindDecl(This);
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316

    /* If applications change the declaration over and over, reconverting all the time is a huge
     * performance hit. So count the declaration changes and release the VBO if there are too much
     * of them(and thus stop converting)
     */
    if(declChanged) {
        This->declChanges++;
        This->draws = 0;

        if(This->declChanges > VB_MAXDECLCHANGES) {
            if(This->resource.allocatedMemory) {
                FIXME("Too much declaration changes, stopping converting\n");
                ENTER_GL();
                GL_EXTCALL(glDeleteBuffersARB(1, &This->vbo));
                checkGLcall("glDeleteBuffersARB");
                LEAVE_GL();
                This->vbo = 0;
                return;
            }
            /* Otherwise do not bother to release the VBO. If we're doing direct locking now,
             * and the declarations changed the code below will fetch the VBO's contents, convert
             * and on the next decl change the data will be in sysmem too and we can just release the VBO
             */
        }
    } else {
        /* However, it is perfectly fine to change the declaration every now and then. We don't want a game that
         * changes it every minute drop the VBO after VB_MAX_DECL_CHANGES minutes. So count draws without
         * decl changes and reset the decl change count after a specific number of them
         */
        This->draws++;
        if(This->draws > VB_RESETDECLCHANGE) This->declChanges = 0;
    }

317 318 319 320 321 322 323 324 325 326 327 328 329
    if(declChanged) {
        /* The declaration changed, reload the whole buffer */
        WARN("Reloading buffer because of decl change\n");
        start = 0;
        end = This->resource.size;
    } else if(This->Flags & VBFLAG_DIRTY) {
        /* No decl change, but dirty data, reload the changed stuff */
        start = This->dirtystart;
        end = This->dirtyend;
    } else {
        /* Desc not changed, buffer not dirty, nothing to do :-) */
        return;
    }
330

331 332 333 334
    /* Mark the buffer clean */
    This->Flags &= ~VBFLAG_DIRTY;
    This->dirtystart = 0;
    This->dirtyend = 0;
335

336 337 338 339
    /* If there was no conversion done before, then resource.allocatedMemory does not exist
     * because locking was done directly into the VBO. In this case get the data out
     */
    if(declChanged && !This->resource.allocatedMemory) {
340

341 342 343
        This->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, This->resource.size);
        if(!This->resource.allocatedMemory) {
            ERR("Out of memory when allocating memory for a vertex buffer\n");
344 345
            return;
        }
346
        ERR("Was locking directly into the VBO, reading data back because conv is needed\n");
347

348 349 350 351 352 353 354 355
        ENTER_GL();
        GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, This->vbo));
        checkGLcall("glBindBufferARB");
        data = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_WRITE_ARB));
        if(!data) {
            ERR("glMapBuffer failed!\n");
            LEAVE_GL();
            return;
356
        }
357 358 359 360 361 362 363 364 365 366 367 368 369 370
        memcpy(This->resource.allocatedMemory, data, This->resource.size);
        GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
        checkGLcall("glUnmapBufferARB");
        LEAVE_GL();
    }

    if     (This->strided.u.s.position.dwStride) stride = This->strided.u.s.position.dwStride;
    else if(This->strided.u.s.specular.dwStride) stride = This->strided.u.s.specular.dwStride;
    else if(This->strided.u.s.diffuse.dwStride)  stride = This->strided.u.s.diffuse.dwStride;
    else {
        /* That means that there is nothing to fixup. Upload everything into the VBO and
         * free This->resource.allocatedMemory
         */
        TRACE("No conversion needed, locking directly into the VBO in future\n");
371 372

        ENTER_GL();
373
        GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, This->vbo));
374
        checkGLcall("glBindBufferARB");
375
        GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, This->resource.size, This->resource.allocatedMemory));
376 377
        checkGLcall("glBufferSubDataARB");
        LEAVE_GL();
378 379
        return;
    }
380

381 382 383 384 385 386 387
    /* OK, we have the original data from the app, the description of the buffer and the dirty area.
     * so convert the stuff
     */
    data = HeapAlloc(GetProcessHeap(), 0, end-start);
    if(!data) {
        ERR("Out of memory\n");
        return;
388
    }
389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409
    memcpy(data, This->resource.allocatedMemory + start, end - start);

    fixup_vertices(data, data, stride, ( end - start) / stride,
                   /* Position */
                   This->strided.u.s.position.lpData, /* Data location */
                   This->strided.u.s.position_transformed, /* Do convert? */
                   /* Diffuse color */
                   This->strided.u.s.diffuse.lpData, /* Location */
                   This->strided.u.s.diffuse.dwType == WINED3DDECLTYPE_SHORT4 || This->strided.u.s.diffuse.dwType == WINED3DDECLTYPE_D3DCOLOR, /* Convert? */
                   /* specular color */
                   This->strided.u.s.specular.lpData, /* location */
                   This->strided.u.s.specular.dwType == WINED3DDECLTYPE_SHORT4 || This->strided.u.s.specular.dwType == WINED3DDECLTYPE_D3DCOLOR);

    ENTER_GL();
    GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, This->vbo));
    checkGLcall("glBindBufferARB");
    GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, start, end - start, data));
    checkGLcall("glBufferSubDataARB");
    LEAVE_GL();

    HeapFree(GetProcessHeap(), 0, data);
410 411
}

412
static WINED3DRESOURCETYPE WINAPI IWineD3DVertexBufferImpl_GetType(IWineD3DVertexBuffer *iface) {
413
    return IWineD3DResourceImpl_GetType((IWineD3DResource *)iface);
414 415
}

416
static HRESULT WINAPI IWineD3DVertexBufferImpl_GetParent(IWineD3DVertexBuffer *iface, IUnknown **pParent) {
417
    return IWineD3DResourceImpl_GetParent((IWineD3DResource *)iface, pParent);
418
}
419 420 421 422

/* ******************************************************
   IWineD3DVertexBuffer IWineD3DVertexBuffer parts follow
   ****************************************************** */
423
static HRESULT  WINAPI IWineD3DVertexBufferImpl_Lock(IWineD3DVertexBuffer *iface, UINT OffsetToLock, UINT SizeToLock, BYTE** ppbData, DWORD Flags) {
424
    IWineD3DVertexBufferImpl *This = (IWineD3DVertexBufferImpl *)iface;
425
    BYTE *data;
426
    TRACE("(%p)->%d, %d, %p, %08x\n", This, OffsetToLock, SizeToLock, ppbData, Flags);
427

428 429
    InterlockedIncrement(&This->lockcount);

430 431
    if(This->Flags & VBFLAG_DIRTY) {
        if(This->dirtystart > OffsetToLock) This->dirtystart = OffsetToLock;
432 433 434 435 436
        if(SizeToLock) {
            if(This->dirtyend < OffsetToLock + SizeToLock) This->dirtyend = OffsetToLock + SizeToLock;
        } else {
            This->dirtyend = This->resource.size;
        }
437 438
    } else {
        This->dirtystart = OffsetToLock;
439 440 441 442
        if(SizeToLock)
            This->dirtyend = OffsetToLock + SizeToLock;
        else
            This->dirtyend = OffsetToLock + This->resource.size;
443 444 445 446 447 448
    }

    if(This->resource.allocatedMemory) {
          data = This->resource.allocatedMemory;
          This->Flags |= VBFLAG_DIRTY;
    } else {
449
        GLenum mode = GL_READ_WRITE_ARB;
450 451 452 453
        /* Return data to the VBO */

        TRACE("Locking directly into the buffer\n");

454
        if((This->resource.usage & WINED3DUSAGE_WRITEONLY) || ( Flags & WINED3DLOCK_DISCARD) ) {
455
            mode = GL_WRITE_ONLY_ARB;
456
        } else if( Flags & (WINED3DLOCK_READONLY | WINED3DLOCK_NO_DIRTY_UPDATE) ) {
457
            mode = GL_READ_ONLY_ARB;
458 459 460
        }

        ENTER_GL();
461
        GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, This->vbo));
462
        checkGLcall("glBindBufferARB");
463
        data = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, mode));
464 465 466 467 468 469 470 471 472
        LEAVE_GL();
        if(!data) {
            ERR("glMapBuffer failed\n");
            return WINED3DERR_INVALIDCALL;
        }
    }
    *ppbData = data + OffsetToLock;

    TRACE("(%p) : returning memory of %p (base:%p,offset:%u)\n", This, data + OffsetToLock, data, OffsetToLock);
473
    /* TODO: check Flags compatibility with This->currentDesc.Usage (see MSDN) */
474
    return WINED3D_OK;
475
}
476 477
HRESULT  WINAPI IWineD3DVertexBufferImpl_Unlock(IWineD3DVertexBuffer *iface) {
    IWineD3DVertexBufferImpl *This = (IWineD3DVertexBufferImpl *) iface;
478
    LONG lockcount;
479
    TRACE("(%p)\n", This);
480 481 482 483 484 485 486 487

    lockcount = InterlockedDecrement(&This->lockcount);
    if(lockcount > 0) {
        /* Delay loading the buffer until everything is unlocked */
        TRACE("Ignoring the unlock\n");
        return D3D_OK;
    }

488 489
    if(!This->resource.allocatedMemory) {
        ENTER_GL();
490
        GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, This->vbo));
491
        checkGLcall("glBindBufferARB");
492
        GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
493 494
        checkGLcall("glUnmapBufferARB");
        LEAVE_GL();
495
    } else if(This->Flags & VBFLAG_HASDESC){
496 497
        IWineD3DVertexBufferImpl_PreLoad(iface);
    }
498
    return WINED3D_OK;
499
}
500
static HRESULT  WINAPI IWineD3DVertexBufferImpl_GetDesc(IWineD3DVertexBuffer *iface, WINED3DVERTEXBUFFER_DESC *pDesc) {
501 502 503
    IWineD3DVertexBufferImpl *This = (IWineD3DVertexBufferImpl *)iface;

    TRACE("(%p)\n", This);
504
    pDesc->Format = This->resource.format;
505
    pDesc->Type   = This->resource.resourceType;
506 507 508
    pDesc->Usage  = This->resource.usage;
    pDesc->Pool   = This->resource.pool;
    pDesc->Size   = This->resource.size;
509
    pDesc->FVF    = This->fvf;
510
    return WINED3D_OK;
511 512
}

513
const IWineD3DVertexBufferVtbl IWineD3DVertexBuffer_Vtbl =
514
{
515
    /* IUnknown */
516 517 518
    IWineD3DVertexBufferImpl_QueryInterface,
    IWineD3DVertexBufferImpl_AddRef,
    IWineD3DVertexBufferImpl_Release,
519
    /* IWineD3DResource */
520
    IWineD3DVertexBufferImpl_GetParent,
521 522 523 524 525 526 527 528
    IWineD3DVertexBufferImpl_GetDevice,
    IWineD3DVertexBufferImpl_SetPrivateData,
    IWineD3DVertexBufferImpl_GetPrivateData,
    IWineD3DVertexBufferImpl_FreePrivateData,
    IWineD3DVertexBufferImpl_SetPriority,
    IWineD3DVertexBufferImpl_GetPriority,
    IWineD3DVertexBufferImpl_PreLoad,
    IWineD3DVertexBufferImpl_GetType,
529
    /* IWineD3DVertexBuffer */
530 531 532 533
    IWineD3DVertexBufferImpl_Lock,
    IWineD3DVertexBufferImpl_Unlock,
    IWineD3DVertexBufferImpl_GetDesc
};
534

535
BYTE* WINAPI IWineD3DVertexBufferImpl_GetMemory(IWineD3DVertexBuffer* iface, DWORD iOffset, GLint *vbo) {
536 537
    IWineD3DVertexBufferImpl *This = (IWineD3DVertexBufferImpl *)iface;

538 539 540 541 542 543
    *vbo = This->vbo;
    if(This->vbo == 0) {
        return This->resource.allocatedMemory + iOffset;
    } else {
        return (BYTE *) iOffset;
    }
544 545 546
}

HRESULT WINAPI IWineD3DVertexBufferImpl_ReleaseMemory(IWineD3DVertexBuffer* iface) {
547
  return WINED3D_OK;
548
}