xref: /reactos/dll/directx/wine/ddraw/executebuffer.c (revision 3c774903)
1 /* Direct3D ExecuteBuffer
2  * Copyright (c) 1998-2004 Lionel ULMER
3  * Copyright (c) 2002-2004 Christian Costa
4  * Copyright (c) 2006      Stefan Dösinger
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 #include "config.h"
22 #include "wine/port.h"
23 
24 #include "ddraw_private.h"
25 
26 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
27 
28 /*****************************************************************************
29  * _dump_executedata
30  * _dump_D3DEXECUTEBUFFERDESC
31  *
32  * Debug functions which write the executebuffer data to the console
33  *
34  *****************************************************************************/
35 
36 static void _dump_executedata(const D3DEXECUTEDATA *lpData) {
37     TRACE("dwSize : %d\n", lpData->dwSize);
38     TRACE("Vertex      Offset : %d  Count  : %d\n", lpData->dwVertexOffset, lpData->dwVertexCount);
39     TRACE("Instruction Offset : %d  Length : %d\n", lpData->dwInstructionOffset, lpData->dwInstructionLength);
40     TRACE("HVertex     Offset : %d\n", lpData->dwHVertexOffset);
41 }
42 
43 static void _dump_D3DEXECUTEBUFFERDESC(const D3DEXECUTEBUFFERDESC *lpDesc) {
44     TRACE("dwSize       : %d\n", lpDesc->dwSize);
45     TRACE("dwFlags      : %x\n", lpDesc->dwFlags);
46     TRACE("dwCaps       : %x\n", lpDesc->dwCaps);
47     TRACE("dwBufferSize : %d\n", lpDesc->dwBufferSize);
48     TRACE("lpData       : %p\n", lpDesc->lpData);
49 }
50 
51 HRESULT d3d_execute_buffer_execute(struct d3d_execute_buffer *buffer,
52         struct d3d_device *device, struct d3d_viewport *viewport)
53 {
54     DWORD is = buffer->data.dwInstructionOffset;
55     char *instr = (char *)buffer->desc.lpData + is;
56     unsigned int i, primitive_size;
57     struct wined3d_map_desc map_desc;
58     struct wined3d_box box = {0};
59     HRESULT hr;
60 
61     if (viewport->active_device != device)
62     {
63         WARN("Viewport %p active device is %p.\n",
64                 viewport, viewport->active_device);
65         return DDERR_INVALIDPARAMS;
66     }
67 
68     /* Activate the viewport */
69     viewport_activate(viewport, FALSE);
70 
71     TRACE("ExecuteData :\n");
72     if (TRACE_ON(ddraw))
73         _dump_executedata(&(buffer->data));
74 
75     for (;;)
76     {
77         D3DINSTRUCTION *current = (D3DINSTRUCTION *)instr;
78         BYTE size;
79         WORD count;
80 
81         count = current->wCount;
82         size = current->bSize;
83         instr += sizeof(*current);
84         primitive_size = 0;
85 
86         switch (current->bOpcode)
87         {
88             case D3DOP_POINT:
89             {
90                 const D3DPOINT *p = (D3DPOINT *)instr;
91                 wined3d_device_set_primitive_type(device->wined3d_device, WINED3D_PT_POINTLIST, 0);
92                 wined3d_device_set_stream_source(device->wined3d_device, 0,
93                         buffer->dst_vertex_buffer, 0, sizeof(D3DTLVERTEX));
94                 wined3d_device_set_vertex_declaration(device->wined3d_device,
95                         ddraw_find_decl(device->ddraw, D3DFVF_TLVERTEX));
96 
97                 for (i = 0; i < count; ++i)
98                     wined3d_device_draw_primitive(device->wined3d_device, p[i].wFirst, p[i].wCount);
99 
100                 instr += sizeof(*p) * count;
101                 break;
102             }
103 
104             case D3DOP_LINE:
105                 primitive_size = 2;
106                 wined3d_device_set_primitive_type(device->wined3d_device, WINED3D_PT_LINELIST, 0);
107                 /* Drop through. */
108             case D3DOP_TRIANGLE:
109             {
110                 WORD *indices;
111                 unsigned int index_pos = buffer->index_pos, index_count;
112                 TRACE("TRIANGLE         (%d)\n", count);
113 
114                 if (!count)
115                     break;
116 
117                 if (!primitive_size)
118                 {
119                     wined3d_device_set_primitive_type(device->wined3d_device, WINED3D_PT_TRIANGLELIST, 0);
120                     primitive_size = 3;
121                 }
122 
123                 index_count = count * primitive_size;
124 
125                 if (buffer->index_size < index_count)
126                 {
127                     unsigned int new_size = max(buffer->index_size * 2, index_count);
128                     struct wined3d_buffer *new_buffer;
129                     struct wined3d_buffer_desc desc;
130 
131                     desc.byte_width = new_size * sizeof(*indices);
132                     desc.usage = WINED3DUSAGE_DYNAMIC | WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_STATICDECL;
133                     desc.bind_flags = WINED3D_BIND_INDEX_BUFFER;
134                     desc.access = WINED3D_RESOURCE_ACCESS_GPU
135                             | WINED3D_RESOURCE_ACCESS_MAP_R | WINED3D_RESOURCE_ACCESS_MAP_W;
136                     desc.misc_flags = 0;
137                     desc.structure_byte_stride = 0;
138 
139                     if (FAILED(hr = wined3d_buffer_create(device->wined3d_device, &desc,
140                             NULL, NULL, &ddraw_null_wined3d_parent_ops, &new_buffer)))
141                         return hr;
142 
143                     buffer->index_size = new_size;
144                     if (buffer->index_buffer)
145                         wined3d_buffer_decref(buffer->index_buffer);
146                     buffer->index_buffer = new_buffer;
147                     index_pos = 0;
148                 }
149                 else if (buffer->index_size - index_count < index_pos)
150                 {
151                     index_pos = 0;
152                 }
153 
154                 box.left = index_pos * sizeof(*indices);
155                 box.right = (index_pos + index_count) * sizeof(*indices);
156                 if (FAILED(hr = wined3d_resource_map(wined3d_buffer_get_resource(buffer->index_buffer), 0, &map_desc,
157                         &box, WINED3D_MAP_WRITE | (index_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD))))
158                     return hr;
159                 indices = map_desc.data;
160 
161                 for (i = 0; i < count; ++i)
162                 {
163                     D3DTRIANGLE *ci = (D3DTRIANGLE *)instr;
164                     TRACE("  v1: %d  v2: %d  v3: %d\n",ci->u1.v1, ci->u2.v2, ci->u3.v3);
165                     TRACE("  Flags : ");
166                     if (TRACE_ON(ddraw))
167                     {
168                         /* Wireframe */
169                         if (ci->wFlags & D3DTRIFLAG_EDGEENABLE1)
170                             TRACE("EDGEENABLE1 ");
171                         if (ci->wFlags & D3DTRIFLAG_EDGEENABLE2)
172                             TRACE("EDGEENABLE2 ");
173                         if (ci->wFlags & D3DTRIFLAG_EDGEENABLE1)
174                             TRACE("EDGEENABLE3 ");
175                         /* Strips / Fans */
176                         if (ci->wFlags == D3DTRIFLAG_EVEN)
177                             TRACE("EVEN ");
178                         if (ci->wFlags == D3DTRIFLAG_ODD)
179                             TRACE("ODD ");
180                         if (ci->wFlags == D3DTRIFLAG_START)
181                             TRACE("START ");
182                         if ((ci->wFlags > 0) && (ci->wFlags < 30))
183                             TRACE("STARTFLAT(%u) ", ci->wFlags);
184                         TRACE("\n");
185                     }
186 
187                     switch (primitive_size)
188                     {
189                         case 3:
190                             indices[(i * primitive_size) + 2] = ci->u3.v3;
191                             /* Drop through. */
192                         case 2:
193                             indices[(i * primitive_size) + 1] = ci->u2.v2;
194                             indices[(i * primitive_size)    ] = ci->u1.v1;
195                     }
196                     instr += size;
197                 }
198 
199                 wined3d_resource_unmap(wined3d_buffer_get_resource(buffer->index_buffer), 0);
200 
201                 wined3d_device_set_stream_source(device->wined3d_device, 0,
202                         buffer->dst_vertex_buffer, 0, sizeof(D3DTLVERTEX));
203                 wined3d_device_set_vertex_declaration(device->wined3d_device,
204                         ddraw_find_decl(device->ddraw, D3DFVF_TLVERTEX));
205                 wined3d_device_set_index_buffer(device->wined3d_device, buffer->index_buffer, WINED3DFMT_R16_UINT, 0);
206                 wined3d_device_draw_indexed_primitive(device->wined3d_device, index_pos, index_count);
207 
208                 buffer->index_pos = index_pos + index_count;
209                 break;
210             }
211 
212             case D3DOP_MATRIXLOAD:
213                 WARN("MATRIXLOAD-s     (%u)\n", count);
214                 instr += count * size;
215                 break;
216 
217             case D3DOP_MATRIXMULTIPLY:
218                 TRACE("MATRIXMULTIPLY   (%d)\n", count);
219                 for (i = 0; i < count; ++i)
220                 {
221                     D3DMATRIXMULTIPLY *ci = (D3DMATRIXMULTIPLY *)instr;
222                     D3DMATRIX *a, *b, *c;
223 
224                     a = ddraw_get_object(&device->handle_table, ci->hDestMatrix - 1, DDRAW_HANDLE_MATRIX);
225                     b = ddraw_get_object(&device->handle_table, ci->hSrcMatrix1 - 1, DDRAW_HANDLE_MATRIX);
226                     c = ddraw_get_object(&device->handle_table, ci->hSrcMatrix2 - 1, DDRAW_HANDLE_MATRIX);
227 
228                     if (!a || !b || !c)
229                     {
230                         ERR("Invalid matrix handle (a %#x -> %p, b %#x -> %p, c %#x -> %p).\n",
231                                 ci->hDestMatrix, a, ci->hSrcMatrix1, b, ci->hSrcMatrix2, c);
232                     }
233                     else
234                     {
235                         TRACE("dst %p, src1 %p, src2 %p.\n", a, b, c);
236                         multiply_matrix(a, c, b);
237                     }
238 
239                     instr += size;
240                 }
241                 break;
242 
243             case D3DOP_STATETRANSFORM:
244                 TRACE("STATETRANSFORM   (%d)\n", count);
245                 for (i = 0; i < count; ++i)
246                 {
247                     D3DSTATE *ci = (D3DSTATE *)instr;
248                     D3DMATRIX *m;
249 
250                     m = ddraw_get_object(&device->handle_table, ci->u2.dwArg[0] - 1, DDRAW_HANDLE_MATRIX);
251                     if (!m)
252                     {
253                         ERR("Invalid matrix handle %#x.\n", ci->u2.dwArg[0]);
254                     }
255                     else
256                     {
257                         if (ci->u1.dtstTransformStateType == D3DTRANSFORMSTATE_WORLD)
258                             device->world = ci->u2.dwArg[0];
259                         if (ci->u1.dtstTransformStateType == D3DTRANSFORMSTATE_VIEW)
260                             device->view = ci->u2.dwArg[0];
261                         if (ci->u1.dtstTransformStateType == D3DTRANSFORMSTATE_PROJECTION)
262                             device->proj = ci->u2.dwArg[0];
263                         IDirect3DDevice3_SetTransform(&device->IDirect3DDevice3_iface,
264                                 ci->u1.dtstTransformStateType, m);
265                     }
266 
267                     instr += size;
268                 }
269                 break;
270 
271             case D3DOP_STATELIGHT:
272                 TRACE("STATELIGHT       (%d)\n", count);
273                 for (i = 0; i < count; ++i)
274                 {
275                     D3DSTATE *ci = (D3DSTATE *)instr;
276 
277                     if (FAILED(IDirect3DDevice3_SetLightState(&device->IDirect3DDevice3_iface,
278                             ci->u1.dlstLightStateType, ci->u2.dwArg[0])))
279                         WARN("Failed to set light state.\n");
280 
281                     instr += size;
282                 }
283                 break;
284 
285             case D3DOP_STATERENDER:
286                 TRACE("STATERENDER      (%d)\n", count);
287                 for (i = 0; i < count; ++i)
288                 {
289                     D3DSTATE *ci = (D3DSTATE *)instr;
290 
291                     if (FAILED(IDirect3DDevice3_SetRenderState(&device->IDirect3DDevice3_iface,
292                             ci->u1.drstRenderStateType, ci->u2.dwArg[0])))
293                         WARN("Failed to set render state.\n");
294 
295                     instr += size;
296                 }
297                 break;
298 
299             case D3DOP_PROCESSVERTICES:
300                 TRACE("PROCESSVERTICES  (%d)\n", count);
301 
302                 for (i = 0; i < count; ++i)
303                 {
304                     D3DPROCESSVERTICES *ci = (D3DPROCESSVERTICES *)instr;
305                     DWORD op = ci->dwFlags & D3DPROCESSVERTICES_OPMASK;
306 
307                     TRACE("  start %u, dest %u, count %u, flags %#x.\n",
308                             ci->wStart, ci->wDest, ci->dwCount, ci->dwFlags);
309 
310                     if (ci->dwFlags & D3DPROCESSVERTICES_UPDATEEXTENTS)
311                     {
312                         static int once;
313                         if (!once++) FIXME("D3DPROCESSVERTICES_UPDATEEXTENTS not implemented.\n");
314                     }
315                     if (ci->dwFlags & D3DPROCESSVERTICES_NOCOLOR)
316                         FIXME("D3DPROCESSVERTICES_NOCOLOR not implemented.\n");
317 
318                     switch (op)
319                     {
320                         case D3DPROCESSVERTICES_TRANSFORMLIGHT:
321                         case D3DPROCESSVERTICES_TRANSFORM:
322                             wined3d_device_set_stream_source(device->wined3d_device, 0,
323                                     buffer->src_vertex_buffer, buffer->src_vertex_pos, sizeof(D3DVERTEX));
324                             if (op == D3DPROCESSVERTICES_TRANSFORMLIGHT)
325                             {
326                                 wined3d_device_set_vertex_declaration(device->wined3d_device,
327                                         ddraw_find_decl(device->ddraw, D3DFVF_VERTEX));
328                                 wined3d_device_set_render_state(device->wined3d_device,
329                                         WINED3D_RS_LIGHTING, TRUE);
330                             }
331                             else
332                             {
333                                 wined3d_device_set_vertex_declaration(device->wined3d_device,
334                                         ddraw_find_decl(device->ddraw, D3DFVF_LVERTEX));
335                                 wined3d_device_set_render_state(device->wined3d_device,
336                                         WINED3D_RS_LIGHTING, FALSE);
337                             }
338 
339                             wined3d_device_process_vertices(device->wined3d_device, ci->wStart, ci->wDest,
340                                     ci->dwCount, buffer->dst_vertex_buffer, NULL, 0, D3DFVF_TLVERTEX);
341                             break;
342 
343                         case D3DPROCESSVERTICES_COPY:
344                             box.left = (buffer->src_vertex_pos + ci->wStart) * sizeof(D3DTLVERTEX);
345                             box.right = box.left + ci->dwCount * sizeof(D3DTLVERTEX);
346                             box.top = box.front = 0;
347                             box.bottom = box.back = 1;
348                             wined3d_device_copy_sub_resource_region(device->wined3d_device,
349                                     wined3d_buffer_get_resource(buffer->dst_vertex_buffer), 0,
350                                     ci->wDest * sizeof(D3DTLVERTEX), 0, 0,
351                                     wined3d_buffer_get_resource(buffer->src_vertex_buffer), 0, &box);
352                             break;
353 
354                         default:
355                             FIXME("Unhandled vertex processing op %#x.\n", op);
356                             break;
357                     }
358 
359                     instr += size;
360                 }
361                 break;
362 
363             case D3DOP_TEXTURELOAD:
364                 TRACE("TEXTURELOAD    (%u)\n", count);
365 
366                 for (i = 0; i < count; ++i)
367                 {
368                     D3DTEXTURELOAD *ci = (D3DTEXTURELOAD *)instr;
369                     struct ddraw_surface *dst, *src;
370 
371                     instr += size;
372 
373                     if (!(dst = ddraw_get_object(&device->handle_table,
374                             ci->hDestTexture - 1, DDRAW_HANDLE_SURFACE)))
375                     {
376                         WARN("Invalid destination texture handle %#x.\n", ci->hDestTexture);
377                         continue;
378                     }
379                     if (!(src = ddraw_get_object(&device->handle_table,
380                             ci->hSrcTexture - 1, DDRAW_HANDLE_SURFACE)))
381                     {
382                         WARN("Invalid source texture handle %#x.\n", ci->hSrcTexture);
383                         continue;
384                     }
385 
386                     IDirect3DTexture2_Load(&dst->IDirect3DTexture2_iface, &src->IDirect3DTexture2_iface);
387                 }
388                 break;
389 
390             case D3DOP_EXIT:
391                 TRACE("EXIT             (%u)\n", count);
392                 instr += size;
393                 goto end_of_buffer;
394 
395             case D3DOP_BRANCHFORWARD:
396                 TRACE("BRANCHFORWARD    (%d)\n", count);
397                 for (i = 0; i < count; ++i)
398                 {
399                     D3DBRANCH *ci = (D3DBRANCH *)instr;
400 
401                     if ((buffer->data.dsStatus.dwStatus & ci->dwMask) == ci->dwValue)
402                     {
403                         if (!ci->bNegate)
404                         {
405                             TRACE(" Branch to %d\n", ci->dwOffset);
406                             if (ci->dwOffset) {
407                                 instr = (char*)current + ci->dwOffset;
408                                 break;
409                             }
410                         }
411                     }
412                     else
413                     {
414                         if (ci->bNegate)
415                         {
416                             TRACE(" Branch to %d\n", ci->dwOffset);
417                             if (ci->dwOffset) {
418                                 instr = (char*)current + ci->dwOffset;
419                                 break;
420                             }
421                         }
422                     }
423 
424                     instr += size;
425                 }
426                 break;
427 
428             case D3DOP_SPAN:
429                 WARN("SPAN-s           (%u)\n", count);
430                 instr += count * size;
431                 break;
432 
433             case D3DOP_SETSTATUS:
434                 TRACE("SETSTATUS        (%d)\n", count);
435                 for (i = 0; i < count; ++i)
436                 {
437                     buffer->data.dsStatus = *(D3DSTATUS *)instr;
438                     instr += size;
439                 }
440                 break;
441 
442             default:
443                 ERR("Unhandled OpCode %#x.\n",current->bOpcode);
444                 instr += count * size;
445                 break;
446         }
447     }
448 
449 end_of_buffer:
450     return D3D_OK;
451 }
452 
453 static inline struct d3d_execute_buffer *impl_from_IDirect3DExecuteBuffer(IDirect3DExecuteBuffer *iface)
454 {
455     return CONTAINING_RECORD(iface, struct d3d_execute_buffer, IDirect3DExecuteBuffer_iface);
456 }
457 
458 static HRESULT WINAPI d3d_execute_buffer_QueryInterface(IDirect3DExecuteBuffer *iface, REFIID iid, void **out)
459 {
460     TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
461 
462     if (IsEqualGUID(&IID_IDirect3DExecuteBuffer, iid)
463             || IsEqualGUID(&IID_IUnknown, iid))
464     {
465         IDirect3DExecuteBuffer_AddRef(iface);
466         *out = iface;
467         return S_OK;
468     }
469 
470     WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
471 
472     *out = NULL;
473     return E_NOINTERFACE;
474 }
475 
476 /*****************************************************************************
477  * IDirect3DExecuteBuffer::AddRef
478  *
479  * A normal AddRef method, nothing special
480  *
481  * Returns:
482  *  The new refcount
483  *
484  *****************************************************************************/
485 static ULONG WINAPI d3d_execute_buffer_AddRef(IDirect3DExecuteBuffer *iface)
486 {
487     struct d3d_execute_buffer *buffer = impl_from_IDirect3DExecuteBuffer(iface);
488     ULONG ref = InterlockedIncrement(&buffer->ref);
489 
490     TRACE("%p increasing refcount to %u.\n", buffer, ref);
491 
492     return ref;
493 }
494 
495 /*****************************************************************************
496  * IDirect3DExecuteBuffer::Release
497  *
498  * A normal Release method, nothing special
499  *
500  * Returns:
501  *  The new refcount
502  *
503  *****************************************************************************/
504 static ULONG WINAPI d3d_execute_buffer_Release(IDirect3DExecuteBuffer *iface)
505 {
506     struct d3d_execute_buffer *buffer = impl_from_IDirect3DExecuteBuffer(iface);
507     ULONG ref = InterlockedDecrement(&buffer->ref);
508 
509     TRACE("%p decreasing refcount to %u.\n", buffer, ref);
510 
511     if (!ref)
512     {
513         if (buffer->need_free)
514             heap_free(buffer->desc.lpData);
515         if (buffer->index_buffer)
516             wined3d_buffer_decref(buffer->index_buffer);
517         if (buffer->dst_vertex_buffer)
518         {
519             wined3d_buffer_decref(buffer->src_vertex_buffer);
520             wined3d_buffer_decref(buffer->dst_vertex_buffer);
521         }
522         heap_free(buffer);
523     }
524 
525     return ref;
526 }
527 
528 /*****************************************************************************
529  * IDirect3DExecuteBuffer::Initialize
530  *
531  * Initializes the Execute Buffer. This method exists for COM compliance
532  * Nothing to do here.
533  *
534  * Returns:
535  *  D3D_OK
536  *
537  *****************************************************************************/
538 static HRESULT WINAPI d3d_execute_buffer_Initialize(IDirect3DExecuteBuffer *iface,
539         IDirect3DDevice *device, D3DEXECUTEBUFFERDESC *desc)
540 {
541     TRACE("iface %p, device %p, desc %p.\n", iface, device, desc);
542 
543     return D3D_OK;
544 }
545 
546 /*****************************************************************************
547  * IDirect3DExecuteBuffer::Lock
548  *
549  * Locks the buffer, so the app can write into it.
550  *
551  * Params:
552  *  Desc: Pointer to return the buffer description. This Description contains
553  *        a pointer to the buffer data.
554  *
555  * Returns:
556  *  This implementation always returns D3D_OK
557  *
558  *****************************************************************************/
559 static HRESULT WINAPI d3d_execute_buffer_Lock(IDirect3DExecuteBuffer *iface, D3DEXECUTEBUFFERDESC *desc)
560 {
561     struct d3d_execute_buffer *buffer = impl_from_IDirect3DExecuteBuffer(iface);
562     DWORD dwSize;
563 
564     TRACE("iface %p, desc %p.\n", iface, desc);
565 
566     dwSize = desc->dwSize;
567     memcpy(desc, &buffer->desc, dwSize);
568 
569     if (TRACE_ON(ddraw))
570     {
571         TRACE("  Returning description :\n");
572         _dump_D3DEXECUTEBUFFERDESC(desc);
573     }
574     return D3D_OK;
575 }
576 
577 /*****************************************************************************
578  * IDirect3DExecuteBuffer::Unlock
579  *
580  * Unlocks the buffer. We don't have anything to do here
581  *
582  * Returns:
583  *  This implementation always returns D3D_OK
584  *
585  *****************************************************************************/
586 static HRESULT WINAPI d3d_execute_buffer_Unlock(IDirect3DExecuteBuffer *iface)
587 {
588     TRACE("iface %p.\n", iface);
589 
590     return D3D_OK;
591 }
592 
593 /*****************************************************************************
594  * IDirect3DExecuteBuffer::SetExecuteData
595  *
596  * Sets the execute data. This data is used to describe the buffer's content
597  *
598  * Params:
599  *  Data: Pointer to a D3DEXECUTEDATA structure containing the data to
600  *  assign
601  *
602  * Returns:
603  *  D3D_OK on success
604  *  DDERR_OUTOFMEMORY if the vertex buffer allocation failed
605  *
606  *****************************************************************************/
607 static HRESULT WINAPI d3d_execute_buffer_SetExecuteData(IDirect3DExecuteBuffer *iface, D3DEXECUTEDATA *data)
608 {
609     struct d3d_execute_buffer *buffer = impl_from_IDirect3DExecuteBuffer(iface);
610     struct wined3d_map_desc map_desc;
611     struct wined3d_box box = {0};
612     HRESULT hr;
613 
614     TRACE("iface %p, data %p.\n", iface, data);
615 
616     /* Skip past previous vertex data. */
617     buffer->src_vertex_pos += buffer->data.dwVertexCount;
618 
619     if (buffer->vertex_size < data->dwVertexCount)
620     {
621         unsigned int new_size = max(data->dwVertexCount, buffer->vertex_size * 2);
622         struct wined3d_buffer *src_buffer, *dst_buffer;
623         struct wined3d_buffer_desc desc;
624 
625         desc.byte_width = new_size * sizeof(D3DVERTEX);
626         desc.usage = 0;
627         desc.bind_flags = WINED3D_BIND_VERTEX_BUFFER;
628         desc.access = WINED3D_RESOURCE_ACCESS_CPU | WINED3D_RESOURCE_ACCESS_MAP_R | WINED3D_RESOURCE_ACCESS_MAP_W;
629         desc.misc_flags = 0;
630         desc.structure_byte_stride = 0;
631 
632         if (FAILED(hr = wined3d_buffer_create(buffer->d3ddev->wined3d_device, &desc,
633                 NULL, NULL, &ddraw_null_wined3d_parent_ops, &src_buffer)))
634             return hr;
635 
636         desc.byte_width = new_size * sizeof(D3DTLVERTEX);
637         desc.usage = WINED3DUSAGE_STATICDECL;
638         desc.access = WINED3D_RESOURCE_ACCESS_GPU | WINED3D_RESOURCE_ACCESS_MAP_R | WINED3D_RESOURCE_ACCESS_MAP_W;
639 
640         if (FAILED(hr = wined3d_buffer_create(buffer->d3ddev->wined3d_device, &desc,
641                 NULL, NULL, &ddraw_null_wined3d_parent_ops, &dst_buffer)))
642         {
643             wined3d_buffer_decref(src_buffer);
644             return hr;
645         }
646 
647         if (buffer->dst_vertex_buffer)
648         {
649             wined3d_buffer_decref(buffer->src_vertex_buffer);
650             wined3d_buffer_decref(buffer->dst_vertex_buffer);
651         }
652         buffer->src_vertex_buffer = src_buffer;
653         buffer->dst_vertex_buffer = dst_buffer;
654         buffer->vertex_size = new_size;
655         buffer->src_vertex_pos = 0;
656     }
657     else if (buffer->vertex_size - data->dwVertexCount < buffer->src_vertex_pos)
658     {
659         buffer->src_vertex_pos = 0;
660     }
661 
662     if (data->dwVertexCount)
663     {
664         box.left = buffer->src_vertex_pos * sizeof(D3DVERTEX);
665         box.right = box.left + data->dwVertexCount * sizeof(D3DVERTEX);
666         if (FAILED(hr = wined3d_resource_map(wined3d_buffer_get_resource(buffer->src_vertex_buffer),
667                 0, &map_desc, &box, WINED3D_MAP_WRITE)))
668             return hr;
669 
670         memcpy(map_desc.data, ((BYTE *)buffer->desc.lpData) + data->dwVertexOffset,
671                 data->dwVertexCount * sizeof(D3DVERTEX));
672 
673         wined3d_resource_unmap(wined3d_buffer_get_resource(buffer->src_vertex_buffer), 0);
674     }
675 
676     memcpy(&buffer->data, data, data->dwSize);
677 
678     if (TRACE_ON(ddraw))
679         _dump_executedata(data);
680 
681     return D3D_OK;
682 }
683 
684 /*****************************************************************************
685  * IDirect3DExecuteBuffer::GetExecuteData
686  *
687  * Returns the data in the execute buffer
688  *
689  * Params:
690  *  Data: Pointer to a D3DEXECUTEDATA structure used to return data
691  *
692  * Returns:
693  *  D3D_OK on success
694  *
695  *****************************************************************************/
696 static HRESULT WINAPI d3d_execute_buffer_GetExecuteData(IDirect3DExecuteBuffer *iface, D3DEXECUTEDATA *data)
697 {
698     struct d3d_execute_buffer *buffer = impl_from_IDirect3DExecuteBuffer(iface);
699     DWORD dwSize;
700 
701     TRACE("iface %p, data %p.\n", iface, data);
702 
703     dwSize = data->dwSize;
704     memcpy(data, &buffer->data, dwSize);
705 
706     if (TRACE_ON(ddraw))
707     {
708         TRACE("Returning data :\n");
709         _dump_executedata(data);
710     }
711 
712     return DD_OK;
713 }
714 
715 /*****************************************************************************
716  * IDirect3DExecuteBuffer::Validate
717  *
718  * DirectX 5 SDK: "The IDirect3DExecuteBuffer::Validate method is not
719  * currently implemented"
720  *
721  * Params:
722  *  ?
723  *
724  * Returns:
725  *  DDERR_UNSUPPORTED, because it's not implemented in Windows.
726  *
727  *****************************************************************************/
728 static HRESULT WINAPI d3d_execute_buffer_Validate(IDirect3DExecuteBuffer *iface,
729         DWORD *offset, LPD3DVALIDATECALLBACK callback, void *context, DWORD reserved)
730 {
731     TRACE("iface %p, offset %p, callback %p, context %p, reserved %#x.\n",
732             iface, offset, callback, context, reserved);
733 
734     WARN("Not implemented.\n");
735 
736     return DDERR_UNSUPPORTED; /* Unchecked */
737 }
738 
739 /*****************************************************************************
740  * IDirect3DExecuteBuffer::Optimize
741  *
742  * DirectX5 SDK: "The IDirect3DExecuteBuffer::Optimize method is not
743  * currently supported"
744  *
745  * Params:
746  *  Dummy: Seems to be an unused dummy ;)
747  *
748  * Returns:
749  *  DDERR_UNSUPPORTED, because it's not implemented in Windows.
750  *
751  *****************************************************************************/
752 static HRESULT WINAPI d3d_execute_buffer_Optimize(IDirect3DExecuteBuffer *iface, DWORD reserved)
753 {
754     TRACE("iface %p, reserved %#x.\n", iface, reserved);
755 
756     WARN("Not implemented.\n");
757 
758     return DDERR_UNSUPPORTED; /* Unchecked */
759 }
760 
761 static const struct IDirect3DExecuteBufferVtbl d3d_execute_buffer_vtbl =
762 {
763     d3d_execute_buffer_QueryInterface,
764     d3d_execute_buffer_AddRef,
765     d3d_execute_buffer_Release,
766     d3d_execute_buffer_Initialize,
767     d3d_execute_buffer_Lock,
768     d3d_execute_buffer_Unlock,
769     d3d_execute_buffer_SetExecuteData,
770     d3d_execute_buffer_GetExecuteData,
771     d3d_execute_buffer_Validate,
772     d3d_execute_buffer_Optimize,
773 };
774 
775 HRESULT d3d_execute_buffer_init(struct d3d_execute_buffer *execute_buffer,
776         struct d3d_device *device, D3DEXECUTEBUFFERDESC *desc)
777 {
778     execute_buffer->IDirect3DExecuteBuffer_iface.lpVtbl = &d3d_execute_buffer_vtbl;
779     execute_buffer->ref = 1;
780     execute_buffer->d3ddev = device;
781 
782     /* Initializes memory */
783     memcpy(&execute_buffer->desc, desc, desc->dwSize);
784 
785     /* No buffer given */
786     if (!(execute_buffer->desc.dwFlags & D3DDEB_LPDATA))
787         execute_buffer->desc.lpData = NULL;
788 
789     /* No buffer size given */
790     if (!(execute_buffer->desc.dwFlags & D3DDEB_BUFSIZE))
791         execute_buffer->desc.dwBufferSize = 0;
792 
793     /* Create buffer if asked */
794     if (!execute_buffer->desc.lpData && execute_buffer->desc.dwBufferSize)
795     {
796         execute_buffer->need_free = TRUE;
797         if (!(execute_buffer->desc.lpData = heap_alloc_zero(execute_buffer->desc.dwBufferSize)))
798         {
799             ERR("Failed to allocate execute buffer data.\n");
800             return DDERR_OUTOFMEMORY;
801         }
802     }
803 
804     execute_buffer->desc.dwFlags |= D3DDEB_LPDATA;
805 
806     return D3D_OK;
807 }
808 
809 struct d3d_execute_buffer *unsafe_impl_from_IDirect3DExecuteBuffer(IDirect3DExecuteBuffer *iface)
810 {
811     if (!iface)
812         return NULL;
813     assert(iface->lpVtbl == &d3d_execute_buffer_vtbl);
814 
815     return impl_from_IDirect3DExecuteBuffer(iface);
816 }
817