2 * IWineD3DVertexBuffer Implementation
4 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2004 Christian Costa
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * 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
24 #include "wined3d_private.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(d3d
);
27 #define GLINFO_LOCATION This->resource.wineD3DDevice->adapter->gl_info
29 #define VB_MAXDECLCHANGES 100 /* After that number we stop converting */
30 #define VB_RESETDECLCHANGE 1000 /* Reset the changecount after that number of draws */
32 /* *******************************************
33 IWineD3DVertexBuffer IUnknown parts follow
34 ******************************************* */
35 static HRESULT WINAPI
IWineD3DVertexBufferImpl_QueryInterface(IWineD3DVertexBuffer
*iface
, REFIID riid
, LPVOID
*ppobj
)
37 IWineD3DVertexBufferImpl
*This
= (IWineD3DVertexBufferImpl
*)iface
;
38 TRACE("(%p)->(%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
39 if (IsEqualGUID(riid
, &IID_IUnknown
)
40 || IsEqualGUID(riid
, &IID_IWineD3DBase
)
41 || IsEqualGUID(riid
, &IID_IWineD3DResource
)
42 || IsEqualGUID(riid
, &IID_IWineD3DVertexBuffer
)){
43 IUnknown_AddRef(iface
);
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);
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);
65 IWineD3DDeviceImpl
*device
= This
->resource
.wineD3DDevice
;
67 ActivateContext(device
, device
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
69 GL_EXTCALL(glDeleteBuffersARB(1, &This
->vbo
));
70 checkGLcall("glDeleteBuffersARB");
74 IWineD3DResourceImpl_CleanUp((IWineD3DResource
*)iface
);
75 HeapFree(GetProcessHeap(), 0, This
);
80 /* ****************************************************
81 IWineD3DVertexBuffer IWineD3DResource parts follow
82 **************************************************** */
83 static HRESULT WINAPI
IWineD3DVertexBufferImpl_GetDevice(IWineD3DVertexBuffer
*iface
, IWineD3DDevice
** ppDevice
) {
84 return IWineD3DResourceImpl_GetDevice((IWineD3DResource
*)iface
, ppDevice
);
87 static HRESULT WINAPI
IWineD3DVertexBufferImpl_SetPrivateData(IWineD3DVertexBuffer
*iface
, REFGUID refguid
, CONST
void* pData
, DWORD SizeOfData
, DWORD Flags
) {
88 return IWineD3DResourceImpl_SetPrivateData((IWineD3DResource
*)iface
, refguid
, pData
, SizeOfData
, Flags
);
91 static HRESULT WINAPI
IWineD3DVertexBufferImpl_GetPrivateData(IWineD3DVertexBuffer
*iface
, REFGUID refguid
, void* pData
, DWORD
* pSizeOfData
) {
92 return IWineD3DResourceImpl_GetPrivateData((IWineD3DResource
*)iface
, refguid
, pData
, pSizeOfData
);
95 static HRESULT WINAPI
IWineD3DVertexBufferImpl_FreePrivateData(IWineD3DVertexBuffer
*iface
, REFGUID refguid
) {
96 return IWineD3DResourceImpl_FreePrivateData((IWineD3DResource
*)iface
, refguid
);
99 static DWORD WINAPI
IWineD3DVertexBufferImpl_SetPriority(IWineD3DVertexBuffer
*iface
, DWORD PriorityNew
) {
100 return IWineD3DResourceImpl_SetPriority((IWineD3DResource
*)iface
, PriorityNew
);
103 static DWORD WINAPI
IWineD3DVertexBufferImpl_GetPriority(IWineD3DVertexBuffer
*iface
) {
104 return IWineD3DResourceImpl_GetPriority((IWineD3DResource
*)iface
);
107 static inline void fixup_d3dcolor(DWORD
*pos
) {
108 DWORD srcColor
= *pos
;
110 /* Color conversion like in drawStridedSlow. watch out for little endianity
111 * If we want that stuff to work on big endian machines too we have to consider more things
113 * 0xff000000: Alpha mask
114 * 0x00ff0000: Blue mask
115 * 0x0000ff00: Green mask
116 * 0x000000ff: Red mask
119 *pos
|= (srcColor
& 0xff00ff00) ; /* Alpha Green */
120 *pos
|= (srcColor
& 0x00ff0000) >> 16; /* Red */
121 *pos
|= (srcColor
& 0x000000ff) << 16; /* Blue */
124 static inline void fixup_transformed_pos(float *p
) {
127 /* rhw conversion like in drawStridedSlow */
128 if(p
[3] == 1.0 || ((p
[3] < eps
) && (p
[3] > -eps
))) {
145 DWORD
*find_conversion_shift(IWineD3DVertexBufferImpl
*This
, WineDirect3DVertexStridedData
*strided
, DWORD stride
) {
146 DWORD
*ret
, i
, shift
, j
, type
;
147 DWORD orig_type_size
;
154 This
->conv_stride
= stride
;
155 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(DWORD
) * stride
);
156 for(i
= 0; i
< MAX_ATTRIBS
; i
++) {
157 type
= strided
->u
.input
[i
].dwType
;
158 if(type
== WINED3DDECLTYPE_FLOAT16_2
) {
160 } else if(type
== WINED3DDECLTYPE_FLOAT16_4
) {
165 This
->conv_stride
+= shift
;
168 orig_type_size
= WINED3D_ATR_TYPESIZE(type
) * WINED3D_ATR_SIZE(type
);
169 for(j
= (DWORD_PTR
) strided
->u
.input
[i
].lpData
+ orig_type_size
; j
< stride
; j
++) {
176 TRACE("Dumping conversion shift:\n");
177 for(i
= 0; i
< stride
; i
++) {
178 TRACE("[%d]", ret
[i
]);
185 inline BOOL WINAPI
IWineD3DVertexBufferImpl_FindDecl(IWineD3DVertexBufferImpl
*This
)
187 WineDirect3DVertexStridedData strided
;
188 IWineD3DDeviceImpl
*device
= This
->resource
.wineD3DDevice
;
190 DWORD type_old
, type_new
, stride
;
193 /* In d3d7 the vertex buffer declaration NEVER changes because it is stored in the d3d7 vertex buffer.
194 * Once we have our declaration there is no need to look it up again.
196 if(((IWineD3DImpl
*)device
->wineD3D
)->dxVersion
== 7 && This
->Flags
& VBFLAG_HASDESC
) {
200 /* There are certain vertex data types that need to be fixed up. The Vertex Buffers FVF doesn't
201 * help finding them, only the vertex declaration or the device FVF can determine that at drawPrim
202 * time. Rules are as follows:
204 * -> Fix up position1 and position 2 if they are XYZRHW
205 * -> Fix up types that are D3DDECLTYPE_D3DCOLOR if no shader is used
206 * -> TODO: Convert FLOAT16 to FLOAT32 if not supported natively by gl
208 * The Declaration is only known at drawing time, and it can change from draw to draw. If any converted values
209 * are changed, the whole buffer has to be reconverted and reloaded. (Converting is SLOW, so if this happens too
210 * often PreLoad stops converting entirely and falls back to drawStridedSlow).
213 * -> New semantics that have to be converted appear
214 * -> The position of semantics that have to be converted changes
215 * -> The stride of the vertex changed AND there is stuff that needs conversion
216 * -> (If a vertex shader is bound and in use assume that nothing that needs conversion is there)
219 * TRUE: Reload is needed
223 if (use_vs(device
)) {
224 if(!This
->last_was_vshader
&& This
->last_was_converted
) {
225 /* Reload if we're switching from converted fixed function to vertex shaders.
226 * This isn't strictly needed, e.g. a FLOAT16 attribute could stay at the same
227 * place. It is always needed for the FLOAT4 and D3DCOLOR conversions however, and
228 * it is unlikely that any game uses FLOAT16s with fixed function vertex processing.
230 TRACE("Reconverting because switching from converted fixed function drawing to shaders\n");
233 This
->last_was_vshader
= TRUE
;
235 /* The vertex declaration is so nice to carry a flag for this. It takes the gl info into account,
236 * but check that separately to avoid the memcmp over the structure
238 if(GL_SUPPORT(NV_HALF_FLOAT
)) {
239 memset(&strided
, 0, sizeof(strided
));
241 } else if(((IWineD3DVertexDeclarationImpl
*)device
->stateBlock
->vertexDecl
)->half_float_conv_needed
) {
242 memcpy(&strided
, &device
->strided_streams
, sizeof(strided
));
245 for(i
= 0; i
< MAX_ATTRIBS
; i
++) {
246 if(strided
.u
.input
[i
].VBO
!= This
->vbo
) {
247 /* Ignore attributes from a different vbo */
248 memset(&strided
.u
.input
[i
], 0, sizeof(strided
.u
.input
[i
]));
252 type_old
= This
->strided
.u
.input
[i
].dwType
;
253 type_new
= strided
.u
.input
[i
].dwType
;
254 if(type_old
!= type_new
) {
255 if(type_old
== WINED3DDECLTYPE_FLOAT16_2
|| type_new
== WINED3DDECLTYPE_FLOAT16_2
||
256 type_old
== WINED3DDECLTYPE_FLOAT16_4
|| type_new
== WINED3DDECLTYPE_FLOAT16_4
) {
257 TRACE("Reloading because attribute %i was %s before and is %s now\n", i
,
258 debug_d3ddecltype(type_old
), debug_d3ddecltype(type_new
));
259 stride
= strided
.u
.input
[i
].dwStride
;
262 } else if(type_new
== WINED3DDECLTYPE_FLOAT16_2
|| type_new
== WINED3DDECLTYPE_FLOAT16_4
) {
263 if(This
->strided
.u
.input
[i
].lpData
!= strided
.u
.input
[i
].lpData
) {
264 TRACE("Reconverting buffer because attribute %d has type %s and moved from offset %p to %p\n",
265 i
, debug_d3ddecltype(type_new
), This
->strided
.u
.s
.position
.lpData
, strided
.u
.s
.position
.lpData
);
266 memcpy(&This
->strided
, &strided
, sizeof(strided
));
268 stride
= strided
.u
.input
[i
].dwStride
;
272 if(!(type_new
== WINED3DDECLTYPE_FLOAT16_2
|| type_new
== WINED3DDECLTYPE_FLOAT16_4
)) {
273 /* Nuke unconverted attributes */
274 memset(&strided
.u
.input
[i
], 0, sizeof(strided
.u
.input
[i
]));
278 memcpy(&This
->strided
, &strided
, sizeof(strided
));
279 HeapFree(GetProcessHeap(), 0, This
->conv_shift
);
280 This
->conv_shift
= find_conversion_shift(This
, &This
->strided
, stride
);
284 memset(&strided
, 0, sizeof(strided
));
285 ret
= (memcmp(&strided
, &This
->strided
, sizeof(strided
)) != 0);
287 HeapFree(GetProcessHeap(), 0, This
->conv_shift
);
288 This
->conv_shift
= NULL
;
292 /* This will need modifications of the loading code as well - not handled right now */
293 if(((IWineD3DVertexDeclarationImpl
*)device
->stateBlock
->vertexDecl
)->half_float_conv_needed
) {
294 FIXME("Implement half float fixup with fixed function vertex processing\n");
297 /* we need a copy because we modify some params */
298 memcpy(&strided
, &device
->strided_streams
, sizeof(strided
));
300 /* Kill things that does not exist in our fixed function pipeline implementation */
301 memset(&strided
.u
.s
.blendWeights
, 0, sizeof(strided
.u
.s
.blendWeights
));
302 memset(&strided
.u
.s
.blendMatrixIndices
, 0, sizeof(strided
.u
.s
.blendMatrixIndices
));
303 memset(&strided
.u
.s
.pSize
, 0, sizeof(strided
.u
.s
.pSize
));
304 memset(&strided
.u
.s
.position2
, 0, sizeof(strided
.u
.s
.position2
));
305 memset(&strided
.u
.s
.normal2
, 0, sizeof(strided
.u
.s
.normal2
));
306 memset(&strided
.u
.s
.tangent
, 0, sizeof(strided
.u
.s
.tangent
));
307 memset(&strided
.u
.s
.binormal
, 0, sizeof(strided
.u
.s
.binormal
));
308 memset(&strided
.u
.s
.tessFactor
, 0, sizeof(strided
.u
.s
.tessFactor
));
309 memset(&strided
.u
.s
.fog
, 0, sizeof(strided
.u
.s
.fog
));
310 memset(&strided
.u
.s
.depth
, 0, sizeof(strided
.u
.s
.depth
));
311 memset(&strided
.u
.s
.sample
, 0, sizeof(strided
.u
.s
.sample
));
313 /* Filter out data that does not come from this VBO. No need to repeat that on
314 * the attributes filtered above.
316 #define FILTER_OTHER_VBO(name) if(strided.u.s.name.VBO != This->vbo) {memset(&strided.u.s.name, 0, sizeof(strided.u.s.name));}
317 FILTER_OTHER_VBO(position
);
318 /*FILTER_OTHER_VBO(blendWeights);*/
319 /*FILTER_OTHER_VBO(blendMatrixIndices);*/
320 FILTER_OTHER_VBO(normal
);
321 /*FILTER_OTHER_VBO(pSize);*/
322 FILTER_OTHER_VBO(diffuse
);
323 FILTER_OTHER_VBO(specular
);
324 FILTER_OTHER_VBO(texCoords
[0]);
325 FILTER_OTHER_VBO(texCoords
[1]);
326 FILTER_OTHER_VBO(texCoords
[2]);
327 FILTER_OTHER_VBO(texCoords
[3]);
328 FILTER_OTHER_VBO(texCoords
[4]);
329 FILTER_OTHER_VBO(texCoords
[5]);
330 FILTER_OTHER_VBO(texCoords
[6]);
331 FILTER_OTHER_VBO(texCoords
[7]);
332 /*FILTER_OTHER_VBO(position2);*/
333 /*FILTER_OTHER_VBO(normal2);*/
334 /*FILTER_OTHER_VBO(tangent);*/
335 /*FILTER_OTHER_VBO(binormal);*/
336 /*FILTER_OTHER_VBO(tessFactor);*/
337 /*FILTER_OTHER_VBO(fog);*/
338 /*FILTER_OTHER_VBO(depth);*/
339 /*FILTER_OTHER_VBO(sample);*/
340 #undef FILTER_OTHER_VBO
342 /* Now find out if anything has changed. compared to the last run. Keep a few things in mind:
344 * 1) We do not mind if types change that do not need conversion
346 * 2) If some data exists cannot be found out by the data field alone. Data can appear at offset 0,
347 * so the main identification is the type. Note that D3DDECLTYPE_FLOAT1 is defined to 0, watch out
348 * for this if any semantic needs conversion if it is declared with that
350 * 3) If the type is the same, and it needs conversion, make sure it stayed at the same place. Moving
351 * converted bytes requires a reconversion of the whole buffer
353 * 4) The stride is not a reliable indicator for existance, as it can be 0 if an attribute stays static
355 * 5) If we used a vertex buffer before, and we aren't using one now(wouldn't be in this codepath
356 * otherwise) then we cannot compare the strided structures. Vertex shaders use numbered attributes,
357 * fixed function pipeline uses named once. For example, a vertex shader could have used converted
358 * tessFactor data which the code below ignores entirely. So if we used a vertex shader before, and
359 * used conversion before, assume a decl change
361 if(This
->last_was_vshader
&& This
->last_was_converted
) {
362 TRACE("Reconverting because a vertex shader with conversion was used before\n");
364 /* Still have to run through the code below to find the fixed function attribs that need
369 /* Position: We have to convert FLOAT4 data because opengl divides the vertex by 1 / w, or
370 * of course if the position has type D3DCOLOR
372 type_old
= This
->strided
.u
.s
.position
.dwType
;
373 type_new
= strided
.u
.s
.position
.dwType
;
374 if(type_old
!= type_new
) {
375 if(type_old
== WINED3DDECLTYPE_FLOAT4
|| type_new
== WINED3DDECLTYPE_FLOAT4
||
376 type_old
== WINED3DDECLTYPE_D3DCOLOR
|| type_new
== WINED3DDECLTYPE_D3DCOLOR
) {
377 TRACE("Reconverting buffer because POSITION type changed from %s to %s\n",
378 debug_d3ddecltype(type_old
), debug_d3ddecltype(type_new
));
379 memcpy(&This
->strided
, &strided
, sizeof(strided
));
383 } else if(type_new
== WINED3DDECLTYPE_D3DCOLOR
|| type_new
== WINED3DDECLTYPE_FLOAT4
) {
384 if(This
->strided
.u
.s
.position
.lpData
!= strided
.u
.s
.position
.lpData
) {
385 TRACE("Reconverting buffer because POSITION has type %s and moved from offset %p to %p\n",
386 debug_d3ddecltype(type_new
), This
->strided
.u
.s
.position
.lpData
, strided
.u
.s
.position
.lpData
);
387 memcpy(&This
->strided
, &strided
, sizeof(strided
));
393 /* Others: D3DCOLOR needs conversion */
394 #define CHECK_D3DCOLOR_CONV(name) \
395 type_old = This->strided.u.s.name.dwType; \
396 type_new = strided.u.s.name.dwType; \
397 if(type_old != type_new) { \
398 if(type_old == WINED3DDECLTYPE_D3DCOLOR || type_new == WINED3DDECLTYPE_D3DCOLOR) { \
399 TRACE("Reconverting buffer because %s type changed from %s to %s\n", \
400 #name, debug_d3ddecltype(type_old), debug_d3ddecltype(type_new)); \
401 memcpy(&This->strided, &strided, sizeof(strided)); \
405 } else if(type_new == WINED3DDECLTYPE_D3DCOLOR) { \
406 if(This->strided.u.s.name.lpData != strided.u.s.name.lpData) { \
407 TRACE("Reconverting buffer because DIFFUSE has type %s and moved from offset %p to %p\n", \
408 debug_d3ddecltype(type_new), This->strided.u.s.name.lpData, strided.u.s.name.lpData); \
409 memcpy(&This->strided, &strided, sizeof(strided)); \
414 CHECK_D3DCOLOR_CONV(normal
);
415 CHECK_D3DCOLOR_CONV(diffuse
);
416 CHECK_D3DCOLOR_CONV(specular
);
417 CHECK_D3DCOLOR_CONV(texCoords
[0]);
418 CHECK_D3DCOLOR_CONV(texCoords
[1]);
419 CHECK_D3DCOLOR_CONV(texCoords
[2]);
420 CHECK_D3DCOLOR_CONV(texCoords
[3]);
421 CHECK_D3DCOLOR_CONV(texCoords
[4]);
422 CHECK_D3DCOLOR_CONV(texCoords
[5]);
423 CHECK_D3DCOLOR_CONV(texCoords
[6]);
424 CHECK_D3DCOLOR_CONV(texCoords
[7]);
425 #undef CHECK_D3DCOLOR_CONV
429 This
->last_was_vshader
= FALSE
;
431 /* We have a declaration now in the buffer */
432 This
->Flags
|= VBFLAG_HASDESC
;
437 static void WINAPI
IWineD3DVertexBufferImpl_PreLoad(IWineD3DVertexBuffer
*iface
) {
438 IWineD3DVertexBufferImpl
*This
= (IWineD3DVertexBufferImpl
*) iface
;
439 IWineD3DDeviceImpl
*device
= This
->resource
.wineD3DDevice
;
441 UINT start
= 0, end
= 0, stride
= 0, vertices
;
442 BOOL declChanged
= FALSE
;
444 TRACE("(%p)->()\n", This
);
446 if(This
->Flags
& VBFLAG_LOAD
) {
447 return; /* Already doing that stuff */
451 /* TODO: Make converting independent from VBOs */
452 return; /* Not doing any conversion */
455 /* Reading the declaration makes only sense if the stateblock is finalized and the buffer bound to a stream */
456 if(device
->isInDraw
&& This
->bindCount
> 0) {
457 declChanged
= IWineD3DVertexBufferImpl_FindDecl(This
);
458 } else if(This
->Flags
& VBFLAG_HASDESC
) {
459 /* Reuse the declaration stored in the buffer. It will most likely not change, and if it does
460 * the stream source state handler will call PreLoad again and the change will be cought
463 /* Cannot get a declaration, and no declaration is stored in the buffer. It is pointless to preload
464 * now. When the buffer is used, PreLoad will be called by the stream source state handler and a valid
465 * declaration for the buffer can be found
470 /* If applications change the declaration over and over, reconverting all the time is a huge
471 * performance hit. So count the declaration changes and release the VBO if there are too much
472 * of them(and thus stop converting)
475 WineDirect3DVertexStridedData zero
;
479 memset(&zero
, 0, sizeof(zero
));
480 zero
.u
.s
.position_transformed
= This
->strided
.u
.s
.position_transformed
;
481 if(memcmp(&zero
, &This
->strided
, sizeof(zero
)) == 0) {
482 This
->last_was_converted
= FALSE
;
484 This
->last_was_converted
= TRUE
;
487 if(This
->declChanges
> VB_MAXDECLCHANGES
) {
488 FIXME("Too much declaration changes, stopping converting\n");
489 ActivateContext(device
, device
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
491 GL_EXTCALL(glDeleteBuffersARB(1, &This
->vbo
));
492 checkGLcall("glDeleteBuffersARB");
495 HeapFree(GetProcessHeap(), 0, This
->conv_shift
);
497 /* The stream source state handler might have read the memory of the vertex buffer already
498 * and got the memory in the vbo which is not valid any longer. Dirtify the stream source
499 * to force a reload. This happens only once per changed vertexbuffer and should occur rather
502 IWineD3DDeviceImpl_MarkStateDirty(device
, STATE_STREAMSRC
);
507 /* However, it is perfectly fine to change the declaration every now and then. We don't want a game that
508 * changes it every minute drop the VBO after VB_MAX_DECL_CHANGES minutes. So count draws without
509 * decl changes and reset the decl change count after a specific number of them
512 if(This
->draws
> VB_RESETDECLCHANGE
) This
->declChanges
= 0;
516 /* The declaration changed, reload the whole buffer */
517 WARN("Reloading buffer because of decl change\n");
519 end
= This
->resource
.size
;
520 } else if(This
->Flags
& VBFLAG_DIRTY
) {
521 /* No decl change, but dirty data, reload the changed stuff */
522 start
= This
->dirtystart
;
523 end
= This
->dirtyend
;
525 /* Desc not changed, buffer not dirty, nothing to do :-) */
529 /* Mark the buffer clean */
530 This
->Flags
&= ~VBFLAG_DIRTY
;
531 This
->dirtystart
= 0;
534 if(!This
->last_was_converted
) {
535 /* That means that there is nothing to fixup. Just upload from This->resource.allocatedMemory
536 * directly into the vbo. Do not free the system memory copy because drawPrimitive may need it if
537 * the stride is 0, for instancing emulation, vertex blending emulation or shader emulation.
539 TRACE("No conversion needed\n");
541 if(!device
->isInDraw
) {
542 ActivateContext(device
, device
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
545 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, This
->vbo
));
546 checkGLcall("glBindBufferARB");
547 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB
, start
, end
-start
, This
->resource
.allocatedMemory
+ start
));
548 checkGLcall("glBufferSubDataARB");
553 /* OK, we have the original data from the app, the description of the buffer and the dirty area.
554 * so convert the stuff
556 if(This
->last_was_vshader
) {
557 TRACE("vertex-shadered conversion\n");
558 /* TODO: Improve that */
559 for(i
= 0; i
< MAX_ATTRIBS
; i
++) {
560 if(This
->strided
.u
.input
[i
].dwStride
) {
561 stride
= This
->strided
.u
.input
[i
].dwStride
;
564 TRACE("Found input stride %d, output stride %d\n", stride
, This
->conv_stride
);
565 /* For now reconvert the entire buffer */
567 end
= This
->resource
.size
;
569 vertices
= This
->resource
.size
/ stride
;
570 TRACE("%d vertices in buffer\n", vertices
);
571 if(This
->vbo_size
!= vertices
* This
->conv_stride
) {
572 TRACE("Old size %d, creating new size %d\n", This
->vbo_size
, vertices
* This
->conv_stride
);
574 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, This
->vbo
));
575 checkGLcall("glBindBufferARB");
576 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB
, vertices
* This
->conv_stride
, NULL
, This
->vbo_usage
));
577 This
->vbo_size
= vertices
* This
->conv_stride
;
578 checkGLcall("glBufferDataARB");
581 data
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, vertices
* This
->conv_stride
);
583 ERR("Out of memory\n");
587 /* Now for each vertex in the buffer */
588 for(i
= 0; i
< vertices
; i
++) {
589 /* Copy the vertex over, taking the shifts into account */
590 for(j
= 0; j
< stride
; j
++) {
591 data
[This
->conv_stride
* i
+ j
+ This
->conv_shift
[j
]] = This
->resource
.allocatedMemory
[i
* stride
+ j
];
593 /* And convert FLOAT16s */
594 for(j
= 0; j
< MAX_ATTRIBS
; j
++) {
595 DWORD_PTR offset
= (DWORD_PTR
) This
->strided
.u
.input
[j
].lpData
;
596 float *dest
= (float *) (&data
[This
->conv_stride
* i
+ offset
+ This
->conv_shift
[offset
]]);
597 WORD
*in
= (WORD
*) (&This
->resource
.allocatedMemory
[i
* stride
+ offset
]);
599 switch(This
->strided
.u
.input
[j
].dwType
) {
600 case WINED3DDECLTYPE_FLOAT16_4
:
601 dest
[3] = float_16_to_32(in
+ 3);
602 dest
[2] = float_16_to_32(in
+ 2);
604 case WINED3DDECLTYPE_FLOAT16_2
:
605 dest
[1] = float_16_to_32(in
+ 1);
606 dest
[0] = float_16_to_32(in
+ 0);
613 if(!device
->isInDraw
) {
614 ActivateContext(device
, device
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
617 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, This
->vbo
));
618 checkGLcall("glBindBufferARB");
619 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB
, 0, This
->vbo_size
, data
));
620 checkGLcall("glBufferSubDataARB");
623 data
= HeapAlloc(GetProcessHeap(), 0, end
-start
);
625 ERR("Out of memory\n");
628 memcpy(data
, This
->resource
.allocatedMemory
+ start
, end
- start
);
630 if (This
->strided
.u
.s
.position
.dwStride
) stride
= This
->strided
.u
.s
.position
.dwStride
;
631 else if(This
->strided
.u
.s
.specular
.dwStride
) stride
= This
->strided
.u
.s
.specular
.dwStride
;
632 else if(This
->strided
.u
.s
.diffuse
.dwStride
) stride
= This
->strided
.u
.s
.diffuse
.dwStride
;
633 else if(This
->strided
.u
.s
.normal
.dwStride
) stride
= This
->strided
.u
.s
.normal
.dwStride
;
634 else if(This
->strided
.u
.s
.texCoords
[0].dwStride
) stride
= This
->strided
.u
.s
.texCoords
[0].dwStride
;
635 else if(This
->strided
.u
.s
.texCoords
[1].dwStride
) stride
= This
->strided
.u
.s
.texCoords
[1].dwStride
;
636 else if(This
->strided
.u
.s
.texCoords
[2].dwStride
) stride
= This
->strided
.u
.s
.texCoords
[2].dwStride
;
637 else if(This
->strided
.u
.s
.texCoords
[3].dwStride
) stride
= This
->strided
.u
.s
.texCoords
[3].dwStride
;
638 else if(This
->strided
.u
.s
.texCoords
[4].dwStride
) stride
= This
->strided
.u
.s
.texCoords
[4].dwStride
;
639 else if(This
->strided
.u
.s
.texCoords
[5].dwStride
) stride
= This
->strided
.u
.s
.texCoords
[5].dwStride
;
640 else if(This
->strided
.u
.s
.texCoords
[6].dwStride
) stride
= This
->strided
.u
.s
.texCoords
[6].dwStride
;
641 else if(This
->strided
.u
.s
.texCoords
[7].dwStride
) stride
= This
->strided
.u
.s
.texCoords
[7].dwStride
;
643 for(i
= (( end
- start
) / stride
) - 1; i
>= 0; i
--) {
644 if(This
->strided
.u
.s
.position
.dwType
== WINED3DDECLTYPE_FLOAT4
) {
645 fixup_transformed_pos((float *)((DWORD_PTR
) data
+ ((DWORD_PTR
) This
->strided
.u
.s
.position
.lpData
) + i
* stride
));
646 } else if(This
->strided
.u
.s
.position
.dwType
== WINED3DDECLTYPE_D3DCOLOR
) {
647 FIXME("Write a test for D3DCOLOR position\n");
649 #define CONVERT_D3DCOLOR_ATTRIB(name) \
650 if(This->strided.u.s.name.dwType == WINED3DDECLTYPE_D3DCOLOR) { \
651 fixup_d3dcolor((DWORD *)((DWORD_PTR) data + ((DWORD_PTR) This->strided.u.s.name.lpData) + i * stride)); \
653 CONVERT_D3DCOLOR_ATTRIB(position
);
654 CONVERT_D3DCOLOR_ATTRIB(specular
);
655 CONVERT_D3DCOLOR_ATTRIB(diffuse
);
656 CONVERT_D3DCOLOR_ATTRIB(normal
);
657 CONVERT_D3DCOLOR_ATTRIB(texCoords
[0]);
658 CONVERT_D3DCOLOR_ATTRIB(texCoords
[1]);
659 CONVERT_D3DCOLOR_ATTRIB(texCoords
[2]);
660 CONVERT_D3DCOLOR_ATTRIB(texCoords
[3]);
661 CONVERT_D3DCOLOR_ATTRIB(texCoords
[4]);
662 CONVERT_D3DCOLOR_ATTRIB(texCoords
[5]);
663 CONVERT_D3DCOLOR_ATTRIB(texCoords
[6]);
664 CONVERT_D3DCOLOR_ATTRIB(texCoords
[7]);
665 #undef CONVERT_D3DCOLOR_ATTRIB
667 if(!device
->isInDraw
) {
668 ActivateContext(device
, device
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
671 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, This
->vbo
));
672 checkGLcall("glBindBufferARB");
673 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB
, start
, end
- start
, data
));
674 checkGLcall("glBufferSubDataARB");
678 HeapFree(GetProcessHeap(), 0, data
);
681 static WINED3DRESOURCETYPE WINAPI
IWineD3DVertexBufferImpl_GetType(IWineD3DVertexBuffer
*iface
) {
682 return IWineD3DResourceImpl_GetType((IWineD3DResource
*)iface
);
685 static HRESULT WINAPI
IWineD3DVertexBufferImpl_GetParent(IWineD3DVertexBuffer
*iface
, IUnknown
**pParent
) {
686 return IWineD3DResourceImpl_GetParent((IWineD3DResource
*)iface
, pParent
);
689 /* ******************************************************
690 IWineD3DVertexBuffer IWineD3DVertexBuffer parts follow
691 ****************************************************** */
692 static HRESULT WINAPI
IWineD3DVertexBufferImpl_Lock(IWineD3DVertexBuffer
*iface
, UINT OffsetToLock
, UINT SizeToLock
, BYTE
** ppbData
, DWORD Flags
) {
693 IWineD3DVertexBufferImpl
*This
= (IWineD3DVertexBufferImpl
*)iface
;
695 TRACE("(%p)->%d, %d, %p, %08x\n", This
, OffsetToLock
, SizeToLock
, ppbData
, Flags
);
697 InterlockedIncrement(&This
->lockcount
);
699 if(This
->Flags
& VBFLAG_DIRTY
) {
700 if(This
->dirtystart
> OffsetToLock
) This
->dirtystart
= OffsetToLock
;
702 if(This
->dirtyend
< OffsetToLock
+ SizeToLock
) This
->dirtyend
= OffsetToLock
+ SizeToLock
;
704 This
->dirtyend
= This
->resource
.size
;
707 This
->dirtystart
= OffsetToLock
;
709 This
->dirtyend
= OffsetToLock
+ SizeToLock
;
711 This
->dirtyend
= This
->resource
.size
;
714 data
= This
->resource
.allocatedMemory
;
715 This
->Flags
|= VBFLAG_DIRTY
;
716 *ppbData
= data
+ OffsetToLock
;
718 TRACE("(%p) : returning memory of %p (base:%p,offset:%u)\n", This
, data
+ OffsetToLock
, data
, OffsetToLock
);
719 /* TODO: check Flags compatibility with This->currentDesc.Usage (see MSDN) */
722 HRESULT WINAPI
IWineD3DVertexBufferImpl_Unlock(IWineD3DVertexBuffer
*iface
) {
723 IWineD3DVertexBufferImpl
*This
= (IWineD3DVertexBufferImpl
*) iface
;
725 TRACE("(%p)\n", This
);
727 lockcount
= InterlockedDecrement(&This
->lockcount
);
729 /* Delay loading the buffer until everything is unlocked */
730 TRACE("Ignoring the unlock\n");
734 if(This
->Flags
& VBFLAG_HASDESC
) {
735 IWineD3DVertexBufferImpl_PreLoad(iface
);
739 static HRESULT WINAPI
IWineD3DVertexBufferImpl_GetDesc(IWineD3DVertexBuffer
*iface
, WINED3DVERTEXBUFFER_DESC
*pDesc
) {
740 IWineD3DVertexBufferImpl
*This
= (IWineD3DVertexBufferImpl
*)iface
;
742 TRACE("(%p)\n", This
);
743 pDesc
->Format
= This
->resource
.format
;
744 pDesc
->Type
= This
->resource
.resourceType
;
745 pDesc
->Usage
= This
->resource
.usage
;
746 pDesc
->Pool
= This
->resource
.pool
;
747 pDesc
->Size
= This
->resource
.size
;
748 pDesc
->FVF
= This
->fvf
;
752 const IWineD3DVertexBufferVtbl IWineD3DVertexBuffer_Vtbl
=
755 IWineD3DVertexBufferImpl_QueryInterface
,
756 IWineD3DVertexBufferImpl_AddRef
,
757 IWineD3DVertexBufferImpl_Release
,
758 /* IWineD3DResource */
759 IWineD3DVertexBufferImpl_GetParent
,
760 IWineD3DVertexBufferImpl_GetDevice
,
761 IWineD3DVertexBufferImpl_SetPrivateData
,
762 IWineD3DVertexBufferImpl_GetPrivateData
,
763 IWineD3DVertexBufferImpl_FreePrivateData
,
764 IWineD3DVertexBufferImpl_SetPriority
,
765 IWineD3DVertexBufferImpl_GetPriority
,
766 IWineD3DVertexBufferImpl_PreLoad
,
767 IWineD3DVertexBufferImpl_GetType
,
768 /* IWineD3DVertexBuffer */
769 IWineD3DVertexBufferImpl_Lock
,
770 IWineD3DVertexBufferImpl_Unlock
,
771 IWineD3DVertexBufferImpl_GetDesc
774 BYTE
* WINAPI
IWineD3DVertexBufferImpl_GetMemory(IWineD3DVertexBuffer
* iface
, DWORD iOffset
, GLint
*vbo
) {
775 IWineD3DVertexBufferImpl
*This
= (IWineD3DVertexBufferImpl
*)iface
;
779 return This
->resource
.allocatedMemory
+ iOffset
;
781 return (BYTE
*) iOffset
;
785 HRESULT WINAPI
IWineD3DVertexBufferImpl_ReleaseMemory(IWineD3DVertexBuffer
* iface
) {