wined3d: Pass a wined3d_device_context to wined3d_cs_emit_blt_sub_resource().
[wine/zf.git] / dlls / ddraw / vertexbuffer.c
blob584d9d162b959ee62d25a7d5d54fc68e307fb6c6
1 /* Direct3D Vertex Buffer
2 * Copyright (c) 2002 Lionel ULMER
3 * Copyright (c) 2006 Stefan DÖSINGER
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include "ddraw_private.h"
22 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
24 static inline struct d3d_vertex_buffer *impl_from_IDirect3DVertexBuffer7(IDirect3DVertexBuffer7 *iface)
26 return CONTAINING_RECORD(iface, struct d3d_vertex_buffer, IDirect3DVertexBuffer7_iface);
29 /*****************************************************************************
30 * IUnknown Methods
31 *****************************************************************************/
33 static HRESULT WINAPI d3d_vertex_buffer7_QueryInterface(IDirect3DVertexBuffer7 *iface, REFIID riid, void **obj)
35 struct d3d_vertex_buffer *buffer = impl_from_IDirect3DVertexBuffer7(iface);
37 TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), obj);
39 *obj = NULL;
41 if (IsEqualGUID(&IID_IUnknown, riid))
43 IDirect3DVertexBuffer7_AddRef(iface);
44 *obj = iface;
45 return S_OK;
47 if (IsEqualGUID(&IID_IDirect3DVertexBuffer7, riid) && buffer->version == 7)
49 IDirect3DVertexBuffer7_AddRef(iface);
50 *obj = iface;
51 return S_OK;
53 if (IsEqualGUID(&IID_IDirect3DVertexBuffer, riid) && buffer->version == 3)
55 IDirect3DVertexBuffer7_AddRef(iface);
56 *obj = iface;
57 return S_OK;
60 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
61 return E_NOINTERFACE;
64 static ULONG WINAPI d3d_vertex_buffer7_AddRef(IDirect3DVertexBuffer7 *iface)
66 struct d3d_vertex_buffer *buffer = impl_from_IDirect3DVertexBuffer7(iface);
67 ULONG ref = InterlockedIncrement(&buffer->ref);
69 TRACE("%p increasing refcount to %u.\n", buffer, ref);
71 return ref;
74 static ULONG WINAPI d3d_vertex_buffer7_Release(IDirect3DVertexBuffer7 *iface)
76 struct d3d_vertex_buffer *buffer = impl_from_IDirect3DVertexBuffer7(iface);
77 ULONG ref = InterlockedDecrement(&buffer->ref);
79 TRACE("%p decreasing refcount to %u.\n", buffer, ref);
81 if (!ref)
83 /* D3D7 vertex buffers don't stay bound in the device, they are passed
84 * as a parameter to DrawPrimitiveVB. DrawPrimitiveVB sets them as the
85 * stream source in wined3d and they should get unset there before
86 * they are destroyed. */
87 wined3d_mutex_lock();
88 if (buffer->ddraw->stateblock_state->streams[0].buffer == buffer->wined3d_buffer)
89 wined3d_stateblock_set_stream_source(buffer->ddraw->state, 0, NULL, 0, 0);
91 wined3d_vertex_declaration_decref(buffer->wined3d_declaration);
92 wined3d_buffer_decref(buffer->wined3d_buffer);
93 wined3d_mutex_unlock();
95 if (buffer->version == 7)
96 IDirectDraw7_Release(&buffer->ddraw->IDirectDraw7_iface);
98 heap_free(buffer);
101 return ref;
104 /*****************************************************************************
105 * IDirect3DVertexBuffer Methods
106 *****************************************************************************/
108 static HRESULT d3d_vertex_buffer_create_wined3d_buffer(struct d3d_vertex_buffer *buffer, BOOL dynamic,
109 struct wined3d_buffer **wined3d_buffer)
111 struct wined3d_buffer_desc desc;
113 desc.byte_width = buffer->size;
114 desc.usage = WINED3DUSAGE_STATICDECL;
115 if (dynamic)
116 desc.usage |= WINED3DUSAGE_DYNAMIC;
117 desc.bind_flags = WINED3D_BIND_VERTEX_BUFFER;
118 if (buffer->Caps & D3DVBCAPS_SYSTEMMEMORY)
119 desc.access = WINED3D_RESOURCE_ACCESS_CPU | WINED3D_RESOURCE_ACCESS_MAP_R | WINED3D_RESOURCE_ACCESS_MAP_W;
120 else
121 desc.access = WINED3D_RESOURCE_ACCESS_GPU | WINED3D_RESOURCE_ACCESS_MAP_R | WINED3D_RESOURCE_ACCESS_MAP_W;
122 desc.misc_flags = 0;
123 desc.structure_byte_stride = 0;
125 return wined3d_buffer_create(buffer->ddraw->wined3d_device, &desc,
126 NULL, buffer, &ddraw_null_wined3d_parent_ops, wined3d_buffer);
129 /*****************************************************************************
130 * IDirect3DVertexBuffer7::Lock
132 * Locks the vertex buffer and returns a pointer to the vertex data
133 * Locking vertex buffers is similar to locking surfaces, because Windows
134 * uses surfaces to store vertex data internally (According to the DX sdk)
136 * Params:
137 * Flags: Locking flags. Relevant here are DDLOCK_READONLY, DDLOCK_WRITEONLY,
138 * DDLOCK_DISCARDCONTENTS and DDLOCK_NOOVERWRITE.
139 * Data: Returns a pointer to the vertex data
140 * Size: Returns the size of the buffer if not NULL
142 * Returns:
143 * D3D_OK on success
144 * DDERR_INVALIDPARAMS if Data is NULL
145 * D3DERR_VERTEXBUFFEROPTIMIZED if called on an optimized buffer(WineD3D)
147 *****************************************************************************/
148 static HRESULT WINAPI d3d_vertex_buffer7_Lock(IDirect3DVertexBuffer7 *iface,
149 DWORD flags, void **data, DWORD *data_size)
151 struct d3d_vertex_buffer *buffer = impl_from_IDirect3DVertexBuffer7(iface);
152 struct wined3d_resource_desc wined3d_desc;
153 struct wined3d_resource *wined3d_resource;
154 struct wined3d_map_desc wined3d_map_desc;
155 HRESULT hr;
157 TRACE("iface %p, flags %#x, data %p, data_size %p.\n", iface, flags, data, data_size);
159 if (buffer->version != 7)
160 flags &= ~(DDLOCK_NOOVERWRITE | DDLOCK_DISCARDCONTENTS);
162 if (!(flags & DDLOCK_WAIT))
163 flags |= DDLOCK_DONOTWAIT;
164 if (flags & DDLOCK_DISCARDCONTENTS)
166 if (!buffer->dynamic)
168 struct wined3d_buffer *new_buffer;
169 wined3d_mutex_lock();
170 hr = d3d_vertex_buffer_create_wined3d_buffer(buffer, TRUE, &new_buffer);
171 if (SUCCEEDED(hr))
173 buffer->dynamic = TRUE;
174 wined3d_buffer_decref(buffer->wined3d_buffer);
175 buffer->wined3d_buffer = new_buffer;
177 else
179 WARN("Failed to create a dynamic buffer\n");
181 wined3d_mutex_unlock();
185 wined3d_mutex_lock();
186 if (data_size)
188 /* Get the size, for returning it, and for locking */
189 wined3d_resource = wined3d_buffer_get_resource(buffer->wined3d_buffer);
190 wined3d_resource_get_desc(wined3d_resource, &wined3d_desc);
191 *data_size = wined3d_desc.size;
194 hr = wined3d_resource_map(wined3d_buffer_get_resource(buffer->wined3d_buffer),
195 0, &wined3d_map_desc, NULL, wined3dmapflags_from_ddrawmapflags(flags));
196 *data = wined3d_map_desc.data;
198 wined3d_mutex_unlock();
200 return hr;
203 /*****************************************************************************
204 * IDirect3DVertexBuffer7::Unlock
206 * Unlocks a vertex Buffer
208 * Returns:
209 * D3D_OK on success
211 *****************************************************************************/
212 static HRESULT WINAPI d3d_vertex_buffer7_Unlock(IDirect3DVertexBuffer7 *iface)
214 struct d3d_vertex_buffer *buffer = impl_from_IDirect3DVertexBuffer7(iface);
216 TRACE("iface %p.\n", iface);
218 wined3d_mutex_lock();
219 wined3d_resource_unmap(wined3d_buffer_get_resource(buffer->wined3d_buffer), 0);
220 wined3d_mutex_unlock();
222 return D3D_OK;
225 /*****************************************************************************
226 * IDirect3DVertexBuffer7::ProcessVertices
228 * Processes untransformed Vertices into a transformed or optimized vertex
229 * buffer. It can also perform other operations, such as lighting or clipping
231 * Params
232 * VertexOp: Operation(s) to perform: D3DVOP_CLIP, _EXTENTS, _LIGHT, _TRANSFORM
233 * DestIndex: Index in the destination buffer(This), where the vertices are
234 * placed
235 * Count: Number of Vertices in the Source buffer to process
236 * SrcBuffer: Source vertex buffer
237 * SrcIndex: Index of the first vertex in the src buffer to process
238 * D3DDevice: Device to use for transformation
239 * Flags: 0 for default, D3DPV_DONOTCOPYDATA to prevent copying
240 * unchanged vertices
242 * Returns:
243 * D3D_OK on success
244 * DDERR_INVALIDPARAMS If D3DVOP_TRANSFORM wasn't passed
246 *****************************************************************************/
247 static HRESULT WINAPI d3d_vertex_buffer7_ProcessVertices(IDirect3DVertexBuffer7 *iface,
248 DWORD vertex_op, DWORD dst_idx, DWORD count, IDirect3DVertexBuffer7 *src_buffer,
249 DWORD src_idx, IDirect3DDevice7 *device, DWORD flags)
251 struct d3d_vertex_buffer *dst_buffer_impl = impl_from_IDirect3DVertexBuffer7(iface);
252 struct d3d_vertex_buffer *src_buffer_impl = unsafe_impl_from_IDirect3DVertexBuffer7(src_buffer);
253 struct d3d_device *device_impl = dst_buffer_impl->version == 7
254 ? unsafe_impl_from_IDirect3DDevice7(device)
255 : unsafe_impl_from_IDirect3DDevice3((IDirect3DDevice3 *)device);
256 BOOL old_clip, do_clip, old_lighting, do_lighting;
257 const struct wined3d_stateblock_state *state;
258 HRESULT hr;
260 TRACE("iface %p, vertex_op %#x, dst_idx %u, count %u, src_buffer %p, src_idx %u, device %p, flags %#x.\n",
261 iface, vertex_op, dst_idx, count, src_buffer, src_idx, device, flags);
263 /* Vertex operations:
264 * D3DVOP_CLIP: Clips vertices outside the viewing frustrum. Needs clipping information
265 * in the vertex buffer (Buffer may not be created with D3DVBCAPS_DONOTCLIP)
266 * D3DVOP_EXTENTS: Causes the screen extents to be updated when rendering the vertices
267 * D3DVOP_LIGHT: Lights the vertices
268 * D3DVOP_TRANSFORM: Transform the vertices. This flag is necessary
270 * WineD3D only transforms and clips the vertices by now, so EXTENTS and LIGHT
271 * are not implemented. Clipping is disabled ATM, because of unsure conditions.
273 if (!(vertex_op & D3DVOP_TRANSFORM))
274 return DDERR_INVALIDPARAMS;
276 wined3d_mutex_lock();
278 state = device_impl->stateblock_state;
280 /* WineD3D doesn't know d3d7 vertex operation, it uses
281 * render states instead. Set the render states according to
282 * the vertex ops
284 do_clip = !!(vertex_op & D3DVOP_CLIP);
285 old_clip = !!state->rs[WINED3D_RS_CLIPPING];
286 if (do_clip != old_clip)
287 wined3d_stateblock_set_render_state(device_impl->state, WINED3D_RS_CLIPPING, do_clip);
289 old_lighting = !!state->rs[WINED3D_RS_LIGHTING];
290 if (dst_buffer_impl->version == 3)
291 do_lighting = device_impl->material && (src_buffer_impl->fvf & D3DFVF_NORMAL)
292 && (vertex_op & D3DVOP_LIGHT);
293 else
294 do_lighting = old_lighting && (vertex_op & D3DVOP_LIGHT);
296 if (do_lighting != old_lighting)
297 wined3d_stateblock_set_render_state(device_impl->state, WINED3D_RS_LIGHTING, do_lighting);
299 wined3d_stateblock_set_stream_source(device_impl->state,
300 0, src_buffer_impl->wined3d_buffer, 0, get_flexible_vertex_size(src_buffer_impl->fvf));
301 wined3d_stateblock_set_vertex_declaration(device_impl->state, src_buffer_impl->wined3d_declaration);
302 wined3d_device_apply_stateblock(device_impl->wined3d_device, device_impl->state);
303 hr = wined3d_device_process_vertices(device_impl->wined3d_device, src_idx, dst_idx,
304 count, dst_buffer_impl->wined3d_buffer, NULL, flags, dst_buffer_impl->fvf);
306 /* Restore the states if needed */
307 if (do_clip != old_clip)
308 wined3d_stateblock_set_render_state(device_impl->state, WINED3D_RS_CLIPPING, old_clip);
309 if (do_lighting != old_lighting)
310 wined3d_stateblock_set_render_state(device_impl->state, WINED3D_RS_LIGHTING, old_lighting);
312 wined3d_mutex_unlock();
314 return hr;
317 /*****************************************************************************
318 * IDirect3DVertexBuffer7::GetVertexBufferDesc
320 * Returns the description of a vertex buffer
322 * Params:
323 * Desc: Address to write the description to
325 * Returns
326 * DDERR_INVALIDPARAMS if Desc is NULL
327 * D3D_OK on success
329 *****************************************************************************/
330 static HRESULT WINAPI d3d_vertex_buffer7_GetVertexBufferDesc(IDirect3DVertexBuffer7 *iface, D3DVERTEXBUFFERDESC *desc)
332 struct d3d_vertex_buffer *buffer = impl_from_IDirect3DVertexBuffer7(iface);
333 struct wined3d_resource_desc wined3d_desc;
334 struct wined3d_resource *wined3d_resource;
336 TRACE("iface %p, desc %p.\n", iface, desc);
338 if (!desc) return DDERR_INVALIDPARAMS;
340 wined3d_mutex_lock();
341 wined3d_resource = wined3d_buffer_get_resource(buffer->wined3d_buffer);
342 wined3d_resource_get_desc(wined3d_resource, &wined3d_desc);
343 wined3d_mutex_unlock();
345 /* Now fill the desc structure */
346 desc->dwCaps = buffer->Caps;
347 desc->dwFVF = buffer->fvf;
348 desc->dwNumVertices = wined3d_desc.size / get_flexible_vertex_size(buffer->fvf);
350 return D3D_OK;
353 /*****************************************************************************
354 * IDirect3DVertexBuffer7::Optimize
356 * Converts an unoptimized vertex buffer into an optimized buffer
358 * Params:
359 * D3DDevice: Device for which this buffer is optimized
360 * Flags: Not used, should be set to 0
362 * Returns
363 * D3D_OK, because it's a stub
365 *****************************************************************************/
366 static HRESULT WINAPI d3d_vertex_buffer7_Optimize(IDirect3DVertexBuffer7 *iface,
367 IDirect3DDevice7 *device, DWORD flags)
369 struct d3d_vertex_buffer *buffer = impl_from_IDirect3DVertexBuffer7(iface);
370 static BOOL hide = FALSE;
372 TRACE("iface %p, device %p, flags %#x.\n", iface, device, flags);
374 if (!hide)
376 FIXME("iface %p, device %p, flags %#x stub!\n", iface, device, flags);
377 hide = TRUE;
380 /* We could forward this call to WineD3D and take advantage
381 * of it once we use OpenGL vertex buffers
383 wined3d_mutex_lock();
384 buffer->Caps |= D3DVBCAPS_OPTIMIZED;
385 wined3d_mutex_unlock();
387 return DD_OK;
390 /*****************************************************************************
391 * IDirect3DVertexBuffer7::ProcessVerticesStrided
393 * This method processes untransformed strided vertices into a processed
394 * or optimized vertex buffer.
396 * For more details on the parameters, see
397 * IDirect3DVertexBuffer7::ProcessVertices
399 * Params:
400 * VertexOp: Operations to perform
401 * DestIndex: Destination index to write the vertices to
402 * Count: Number of input vertices
403 * StrideData: Array containing the input vertices
404 * VertexTypeDesc: Vertex Description or source index?????????
405 * D3DDevice: IDirect3DDevice7 to use for processing
406 * Flags: Can be D3DPV_DONOTCOPYDATA to avoid copying unmodified vertices
408 * Returns
409 * D3D_OK on success, or DDERR_*
411 *****************************************************************************/
412 static HRESULT WINAPI d3d_vertex_buffer7_ProcessVerticesStrided(IDirect3DVertexBuffer7 *iface,
413 DWORD vertex_op, DWORD dst_idx, DWORD count, D3DDRAWPRIMITIVESTRIDEDDATA *data,
414 DWORD fvf, IDirect3DDevice7 *device, DWORD flags)
416 FIXME("iface %p, vertex_op %#x, dst_idx %u, count %u, data %p, fvf %#x, device %p, flags %#x stub!\n",
417 iface, vertex_op, dst_idx, count, data, fvf, device, flags);
419 return DD_OK;
422 /*****************************************************************************
423 * The VTables
424 *****************************************************************************/
426 static const struct IDirect3DVertexBuffer7Vtbl d3d_vertex_buffer7_vtbl =
428 d3d_vertex_buffer7_QueryInterface,
429 d3d_vertex_buffer7_AddRef,
430 d3d_vertex_buffer7_Release,
431 d3d_vertex_buffer7_Lock,
432 d3d_vertex_buffer7_Unlock,
433 d3d_vertex_buffer7_ProcessVertices,
434 d3d_vertex_buffer7_GetVertexBufferDesc,
435 d3d_vertex_buffer7_Optimize,
436 d3d_vertex_buffer7_ProcessVerticesStrided,
439 HRESULT d3d_vertex_buffer_create(struct d3d_vertex_buffer **vertex_buf,
440 struct ddraw *ddraw, D3DVERTEXBUFFERDESC *desc)
442 struct d3d_vertex_buffer *buffer;
443 HRESULT hr = D3D_OK;
445 TRACE("Vertex buffer description:\n");
446 TRACE(" dwSize %u\n", desc->dwSize);
447 TRACE(" dwCaps %#x\n", desc->dwCaps);
448 TRACE(" FVF %#x\n", desc->dwFVF);
449 TRACE(" dwNumVertices %u\n", desc->dwNumVertices);
451 if (!(buffer = heap_alloc_zero(sizeof(*buffer))))
452 return DDERR_OUTOFMEMORY;
454 buffer->IDirect3DVertexBuffer7_iface.lpVtbl = &d3d_vertex_buffer7_vtbl;
455 buffer->ref = 1;
456 buffer->version = ddraw->d3dversion;
457 if (buffer->version == 7)
458 IDirectDraw7_AddRef(&ddraw->IDirectDraw7_iface);
459 buffer->ddraw = ddraw;
460 buffer->Caps = desc->dwCaps;
461 buffer->fvf = desc->dwFVF;
462 buffer->size = get_flexible_vertex_size(desc->dwFVF) * desc->dwNumVertices;
464 wined3d_mutex_lock();
466 if (FAILED(hr = d3d_vertex_buffer_create_wined3d_buffer(buffer, FALSE, &buffer->wined3d_buffer)))
468 WARN("Failed to create wined3d vertex buffer, hr %#x.\n", hr);
469 if (hr == WINED3DERR_INVALIDCALL)
470 hr = DDERR_INVALIDPARAMS;
471 goto end;
474 if (!(buffer->wined3d_declaration = ddraw_find_decl(ddraw, desc->dwFVF)))
476 ERR("Failed to find vertex declaration for fvf %#x.\n", desc->dwFVF);
477 wined3d_buffer_decref(buffer->wined3d_buffer);
478 hr = DDERR_INVALIDPARAMS;
479 goto end;
481 wined3d_vertex_declaration_incref(buffer->wined3d_declaration);
483 end:
484 wined3d_mutex_unlock();
485 if (hr == D3D_OK)
486 *vertex_buf = buffer;
487 else
488 heap_free(buffer);
490 return hr;
493 struct d3d_vertex_buffer *unsafe_impl_from_IDirect3DVertexBuffer7(IDirect3DVertexBuffer7 *iface)
495 if (!iface)
496 return NULL;
497 assert(iface->lpVtbl == &d3d_vertex_buffer7_vtbl);
499 return impl_from_IDirect3DVertexBuffer7(iface);