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, 0); 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 DWORD buf_size = buffer->desc.dwBufferSize, copy_size; 614 615 TRACE("iface %p, data %p.\n", iface, data); 616 617 if (data->dwSize != sizeof(*data)) 618 { 619 WARN("data->dwSize is %u, returning DDERR_INVALIDPARAMS.\n", data->dwSize); 620 return DDERR_INVALIDPARAMS; 621 } 622 623 /* Skip past previous vertex data. */ 624 buffer->src_vertex_pos += buffer->data.dwVertexCount; 625 626 if (buffer->vertex_size < data->dwVertexCount) 627 { 628 unsigned int new_size = max(data->dwVertexCount, buffer->vertex_size * 2); 629 struct wined3d_buffer *src_buffer, *dst_buffer; 630 struct wined3d_buffer_desc desc; 631 632 desc.byte_width = new_size * sizeof(D3DVERTEX); 633 desc.usage = 0; 634 desc.bind_flags = WINED3D_BIND_VERTEX_BUFFER; 635 desc.access = WINED3D_RESOURCE_ACCESS_CPU | WINED3D_RESOURCE_ACCESS_MAP_R | WINED3D_RESOURCE_ACCESS_MAP_W; 636 desc.misc_flags = 0; 637 desc.structure_byte_stride = 0; 638 639 if (FAILED(hr = wined3d_buffer_create(buffer->d3ddev->wined3d_device, &desc, 640 NULL, NULL, &ddraw_null_wined3d_parent_ops, &src_buffer))) 641 return hr; 642 643 desc.byte_width = new_size * sizeof(D3DTLVERTEX); 644 desc.usage = WINED3DUSAGE_STATICDECL; 645 desc.access = WINED3D_RESOURCE_ACCESS_GPU | WINED3D_RESOURCE_ACCESS_MAP_R | WINED3D_RESOURCE_ACCESS_MAP_W; 646 647 if (FAILED(hr = wined3d_buffer_create(buffer->d3ddev->wined3d_device, &desc, 648 NULL, NULL, &ddraw_null_wined3d_parent_ops, &dst_buffer))) 649 { 650 wined3d_buffer_decref(src_buffer); 651 return hr; 652 } 653 654 if (buffer->dst_vertex_buffer) 655 { 656 wined3d_buffer_decref(buffer->src_vertex_buffer); 657 wined3d_buffer_decref(buffer->dst_vertex_buffer); 658 } 659 buffer->src_vertex_buffer = src_buffer; 660 buffer->dst_vertex_buffer = dst_buffer; 661 buffer->vertex_size = new_size; 662 buffer->src_vertex_pos = 0; 663 } 664 else if (buffer->vertex_size - data->dwVertexCount < buffer->src_vertex_pos) 665 { 666 buffer->src_vertex_pos = 0; 667 } 668 669 if (data->dwVertexCount && (!buf_size || data->dwVertexOffset < buf_size)) 670 { 671 box.left = buffer->src_vertex_pos * sizeof(D3DVERTEX); 672 box.right = box.left + data->dwVertexCount * sizeof(D3DVERTEX); 673 if (FAILED(hr = wined3d_resource_map(wined3d_buffer_get_resource(buffer->src_vertex_buffer), 674 0, &map_desc, &box, WINED3D_MAP_WRITE))) 675 return hr; 676 677 copy_size = data->dwVertexCount * sizeof(D3DVERTEX); 678 if (buf_size) 679 copy_size = min(copy_size, buf_size - data->dwVertexOffset); 680 681 memcpy(map_desc.data, ((BYTE *)buffer->desc.lpData) + data->dwVertexOffset, copy_size); 682 683 wined3d_resource_unmap(wined3d_buffer_get_resource(buffer->src_vertex_buffer), 0); 684 } 685 686 memcpy(&buffer->data, data, data->dwSize); 687 688 if (TRACE_ON(ddraw)) 689 _dump_executedata(data); 690 691 return D3D_OK; 692 } 693 694 /***************************************************************************** 695 * IDirect3DExecuteBuffer::GetExecuteData 696 * 697 * Returns the data in the execute buffer 698 * 699 * Params: 700 * Data: Pointer to a D3DEXECUTEDATA structure used to return data 701 * 702 * Returns: 703 * D3D_OK on success 704 * 705 *****************************************************************************/ 706 static HRESULT WINAPI d3d_execute_buffer_GetExecuteData(IDirect3DExecuteBuffer *iface, D3DEXECUTEDATA *data) 707 { 708 struct d3d_execute_buffer *buffer = impl_from_IDirect3DExecuteBuffer(iface); 709 710 TRACE("iface %p, data %p.\n", iface, data); 711 712 /* Tests show that dwSize is ignored. */ 713 memcpy(data, &buffer->data, sizeof(*data)); 714 715 if (TRACE_ON(ddraw)) 716 { 717 TRACE("Returning data :\n"); 718 _dump_executedata(data); 719 } 720 721 return DD_OK; 722 } 723 724 /***************************************************************************** 725 * IDirect3DExecuteBuffer::Validate 726 * 727 * DirectX 5 SDK: "The IDirect3DExecuteBuffer::Validate method is not 728 * currently implemented" 729 * 730 * Params: 731 * ? 732 * 733 * Returns: 734 * DDERR_UNSUPPORTED, because it's not implemented in Windows. 735 * 736 *****************************************************************************/ 737 static HRESULT WINAPI d3d_execute_buffer_Validate(IDirect3DExecuteBuffer *iface, 738 DWORD *offset, LPD3DVALIDATECALLBACK callback, void *context, DWORD reserved) 739 { 740 TRACE("iface %p, offset %p, callback %p, context %p, reserved %#x.\n", 741 iface, offset, callback, context, reserved); 742 743 WARN("Not implemented.\n"); 744 745 return DDERR_UNSUPPORTED; /* Unchecked */ 746 } 747 748 /***************************************************************************** 749 * IDirect3DExecuteBuffer::Optimize 750 * 751 * DirectX5 SDK: "The IDirect3DExecuteBuffer::Optimize method is not 752 * currently supported" 753 * 754 * Params: 755 * Dummy: Seems to be an unused dummy ;) 756 * 757 * Returns: 758 * DDERR_UNSUPPORTED, because it's not implemented in Windows. 759 * 760 *****************************************************************************/ 761 static HRESULT WINAPI d3d_execute_buffer_Optimize(IDirect3DExecuteBuffer *iface, DWORD reserved) 762 { 763 TRACE("iface %p, reserved %#x.\n", iface, reserved); 764 765 WARN("Not implemented.\n"); 766 767 return DDERR_UNSUPPORTED; /* Unchecked */ 768 } 769 770 static const struct IDirect3DExecuteBufferVtbl d3d_execute_buffer_vtbl = 771 { 772 d3d_execute_buffer_QueryInterface, 773 d3d_execute_buffer_AddRef, 774 d3d_execute_buffer_Release, 775 d3d_execute_buffer_Initialize, 776 d3d_execute_buffer_Lock, 777 d3d_execute_buffer_Unlock, 778 d3d_execute_buffer_SetExecuteData, 779 d3d_execute_buffer_GetExecuteData, 780 d3d_execute_buffer_Validate, 781 d3d_execute_buffer_Optimize, 782 }; 783 784 HRESULT d3d_execute_buffer_init(struct d3d_execute_buffer *execute_buffer, 785 struct d3d_device *device, D3DEXECUTEBUFFERDESC *desc) 786 { 787 execute_buffer->IDirect3DExecuteBuffer_iface.lpVtbl = &d3d_execute_buffer_vtbl; 788 execute_buffer->ref = 1; 789 execute_buffer->d3ddev = device; 790 791 /* Initializes memory */ 792 memcpy(&execute_buffer->desc, desc, desc->dwSize); 793 794 /* No buffer given */ 795 if (!(execute_buffer->desc.dwFlags & D3DDEB_LPDATA)) 796 execute_buffer->desc.lpData = NULL; 797 798 /* No buffer size given */ 799 if (!(execute_buffer->desc.dwFlags & D3DDEB_BUFSIZE)) 800 execute_buffer->desc.dwBufferSize = 0; 801 802 /* Create buffer if asked */ 803 if (!execute_buffer->desc.lpData && execute_buffer->desc.dwBufferSize) 804 { 805 execute_buffer->need_free = TRUE; 806 if (!(execute_buffer->desc.lpData = heap_alloc_zero(execute_buffer->desc.dwBufferSize))) 807 { 808 ERR("Failed to allocate execute buffer data.\n"); 809 return DDERR_OUTOFMEMORY; 810 } 811 } 812 813 execute_buffer->desc.dwFlags |= D3DDEB_LPDATA; 814 815 return D3D_OK; 816 } 817 818 struct d3d_execute_buffer *unsafe_impl_from_IDirect3DExecuteBuffer(IDirect3DExecuteBuffer *iface) 819 { 820 if (!iface) 821 return NULL; 822 assert(iface->lpVtbl == &d3d_execute_buffer_vtbl); 823 824 return impl_from_IDirect3DExecuteBuffer(iface); 825 } 826