xref: /reactos/dll/directx/wine/d3d8/device.c (revision b819608e)
1 /*
2  * IDirect3DDevice8 implementation
3  *
4  * Copyright 2002-2004 Jason Edmeades
5  * Copyright 2004 Christian Costa
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21 
22 #include "d3d8_private.h"
23 
24 static void STDMETHODCALLTYPE d3d8_null_wined3d_object_destroyed(void *parent) {}
25 
26 static const struct wined3d_parent_ops d3d8_null_wined3d_parent_ops =
27 {
28     d3d8_null_wined3d_object_destroyed,
29 };
30 
31 D3DFORMAT d3dformat_from_wined3dformat(enum wined3d_format_id format)
32 {
33     BYTE *c = (BYTE *)&format;
34 
35     /* Don't translate FOURCC formats */
36     if (isprint(c[0]) && isprint(c[1]) && isprint(c[2]) && isprint(c[3])) return format;
37 
38     switch(format)
39     {
40         case WINED3DFMT_UNKNOWN: return D3DFMT_UNKNOWN;
41         case WINED3DFMT_B8G8R8_UNORM: return D3DFMT_R8G8B8;
42         case WINED3DFMT_B8G8R8A8_UNORM: return D3DFMT_A8R8G8B8;
43         case WINED3DFMT_B8G8R8X8_UNORM: return D3DFMT_X8R8G8B8;
44         case WINED3DFMT_B5G6R5_UNORM: return D3DFMT_R5G6B5;
45         case WINED3DFMT_B5G5R5X1_UNORM: return D3DFMT_X1R5G5B5;
46         case WINED3DFMT_B5G5R5A1_UNORM: return D3DFMT_A1R5G5B5;
47         case WINED3DFMT_B4G4R4A4_UNORM: return D3DFMT_A4R4G4B4;
48         case WINED3DFMT_B2G3R3_UNORM: return D3DFMT_R3G3B2;
49         case WINED3DFMT_A8_UNORM: return D3DFMT_A8;
50         case WINED3DFMT_B2G3R3A8_UNORM: return D3DFMT_A8R3G3B2;
51         case WINED3DFMT_B4G4R4X4_UNORM: return D3DFMT_X4R4G4B4;
52         case WINED3DFMT_R10G10B10A2_UNORM: return D3DFMT_A2B10G10R10;
53         case WINED3DFMT_R16G16_UNORM: return D3DFMT_G16R16;
54         case WINED3DFMT_P8_UINT_A8_UNORM: return D3DFMT_A8P8;
55         case WINED3DFMT_P8_UINT: return D3DFMT_P8;
56         case WINED3DFMT_L8_UNORM: return D3DFMT_L8;
57         case WINED3DFMT_L8A8_UNORM: return D3DFMT_A8L8;
58         case WINED3DFMT_L4A4_UNORM: return D3DFMT_A4L4;
59         case WINED3DFMT_R8G8_SNORM: return D3DFMT_V8U8;
60         case WINED3DFMT_R5G5_SNORM_L6_UNORM: return D3DFMT_L6V5U5;
61         case WINED3DFMT_R8G8_SNORM_L8X8_UNORM: return D3DFMT_X8L8V8U8;
62         case WINED3DFMT_R8G8B8A8_SNORM: return D3DFMT_Q8W8V8U8;
63         case WINED3DFMT_R16G16_SNORM: return D3DFMT_V16U16;
64         case WINED3DFMT_R10G11B11_SNORM: return D3DFMT_W11V11U10;
65         case WINED3DFMT_R10G10B10_SNORM_A2_UNORM: return D3DFMT_A2W10V10U10;
66         case WINED3DFMT_D16_LOCKABLE: return D3DFMT_D16_LOCKABLE;
67         case WINED3DFMT_D32_UNORM: return D3DFMT_D32;
68         case WINED3DFMT_S1_UINT_D15_UNORM: return D3DFMT_D15S1;
69         case WINED3DFMT_D24_UNORM_S8_UINT: return D3DFMT_D24S8;
70         case WINED3DFMT_X8D24_UNORM: return D3DFMT_D24X8;
71         case WINED3DFMT_S4X4_UINT_D24_UNORM: return D3DFMT_D24X4S4;
72         case WINED3DFMT_D16_UNORM: return D3DFMT_D16;
73         case WINED3DFMT_VERTEXDATA: return D3DFMT_VERTEXDATA;
74         case WINED3DFMT_R16_UINT: return D3DFMT_INDEX16;
75         case WINED3DFMT_R32_UINT: return D3DFMT_INDEX32;
76         default:
77             FIXME("Unhandled wined3d format %#x.\n", format);
78             return D3DFMT_UNKNOWN;
79     }
80 }
81 
82 enum wined3d_format_id wined3dformat_from_d3dformat(D3DFORMAT format)
83 {
84     BYTE *c = (BYTE *)&format;
85 
86     /* Don't translate FOURCC formats */
87     if (isprint(c[0]) && isprint(c[1]) && isprint(c[2]) && isprint(c[3])) return format;
88 
89     switch(format)
90     {
91         case D3DFMT_UNKNOWN: return WINED3DFMT_UNKNOWN;
92         case D3DFMT_R8G8B8: return WINED3DFMT_B8G8R8_UNORM;
93         case D3DFMT_A8R8G8B8: return WINED3DFMT_B8G8R8A8_UNORM;
94         case D3DFMT_X8R8G8B8: return WINED3DFMT_B8G8R8X8_UNORM;
95         case D3DFMT_R5G6B5: return WINED3DFMT_B5G6R5_UNORM;
96         case D3DFMT_X1R5G5B5: return WINED3DFMT_B5G5R5X1_UNORM;
97         case D3DFMT_A1R5G5B5: return WINED3DFMT_B5G5R5A1_UNORM;
98         case D3DFMT_A4R4G4B4: return WINED3DFMT_B4G4R4A4_UNORM;
99         case D3DFMT_R3G3B2: return WINED3DFMT_B2G3R3_UNORM;
100         case D3DFMT_A8: return WINED3DFMT_A8_UNORM;
101         case D3DFMT_A8R3G3B2: return WINED3DFMT_B2G3R3A8_UNORM;
102         case D3DFMT_X4R4G4B4: return WINED3DFMT_B4G4R4X4_UNORM;
103         case D3DFMT_A2B10G10R10: return WINED3DFMT_R10G10B10A2_UNORM;
104         case D3DFMT_G16R16: return WINED3DFMT_R16G16_UNORM;
105         case D3DFMT_A8P8: return WINED3DFMT_P8_UINT_A8_UNORM;
106         case D3DFMT_P8: return WINED3DFMT_P8_UINT;
107         case D3DFMT_L8: return WINED3DFMT_L8_UNORM;
108         case D3DFMT_A8L8: return WINED3DFMT_L8A8_UNORM;
109         case D3DFMT_A4L4: return WINED3DFMT_L4A4_UNORM;
110         case D3DFMT_V8U8: return WINED3DFMT_R8G8_SNORM;
111         case D3DFMT_L6V5U5: return WINED3DFMT_R5G5_SNORM_L6_UNORM;
112         case D3DFMT_X8L8V8U8: return WINED3DFMT_R8G8_SNORM_L8X8_UNORM;
113         case D3DFMT_Q8W8V8U8: return WINED3DFMT_R8G8B8A8_SNORM;
114         case D3DFMT_V16U16: return WINED3DFMT_R16G16_SNORM;
115         case D3DFMT_W11V11U10: return WINED3DFMT_R10G11B11_SNORM;
116         case D3DFMT_A2W10V10U10: return WINED3DFMT_R10G10B10_SNORM_A2_UNORM;
117         case D3DFMT_D16_LOCKABLE: return WINED3DFMT_D16_LOCKABLE;
118         case D3DFMT_D32: return WINED3DFMT_D32_UNORM;
119         case D3DFMT_D15S1: return WINED3DFMT_S1_UINT_D15_UNORM;
120         case D3DFMT_D24S8: return WINED3DFMT_D24_UNORM_S8_UINT;
121         case D3DFMT_D24X8: return WINED3DFMT_X8D24_UNORM;
122         case D3DFMT_D24X4S4: return WINED3DFMT_S4X4_UINT_D24_UNORM;
123         case D3DFMT_D16: return WINED3DFMT_D16_UNORM;
124         case D3DFMT_VERTEXDATA: return WINED3DFMT_VERTEXDATA;
125         case D3DFMT_INDEX16: return WINED3DFMT_R16_UINT;
126         case D3DFMT_INDEX32: return WINED3DFMT_R32_UINT;
127         default:
128             FIXME("Unhandled D3DFORMAT %#x\n", format);
129             return WINED3DFMT_UNKNOWN;
130     }
131 }
132 
133 static UINT vertex_count_from_primitive_count(D3DPRIMITIVETYPE primitive_type, UINT primitive_count)
134 {
135     switch(primitive_type)
136     {
137         case D3DPT_POINTLIST:
138             return primitive_count;
139 
140         case D3DPT_LINELIST:
141             return primitive_count * 2;
142 
143         case D3DPT_LINESTRIP:
144             return primitive_count + 1;
145 
146         case D3DPT_TRIANGLELIST:
147             return primitive_count * 3;
148 
149         case D3DPT_TRIANGLESTRIP:
150         case D3DPT_TRIANGLEFAN:
151             return primitive_count + 2;
152 
153         default:
154             FIXME("Unhandled primitive type %#x\n", primitive_type);
155             return 0;
156     }
157 }
158 
159 static void present_parameters_from_wined3d_swapchain_desc(D3DPRESENT_PARAMETERS *present_parameters,
160         const struct wined3d_swapchain_desc *swapchain_desc)
161 {
162     present_parameters->BackBufferWidth = swapchain_desc->backbuffer_width;
163     present_parameters->BackBufferHeight = swapchain_desc->backbuffer_height;
164     present_parameters->BackBufferFormat = d3dformat_from_wined3dformat(swapchain_desc->backbuffer_format);
165     present_parameters->BackBufferCount = swapchain_desc->backbuffer_count;
166     present_parameters->MultiSampleType = swapchain_desc->multisample_type;
167     present_parameters->SwapEffect = swapchain_desc->swap_effect;
168     present_parameters->hDeviceWindow = swapchain_desc->device_window;
169     present_parameters->Windowed = swapchain_desc->windowed;
170     present_parameters->EnableAutoDepthStencil = swapchain_desc->enable_auto_depth_stencil;
171     present_parameters->AutoDepthStencilFormat
172             = d3dformat_from_wined3dformat(swapchain_desc->auto_depth_stencil_format);
173     present_parameters->Flags = swapchain_desc->flags;
174     present_parameters->FullScreen_RefreshRateInHz = swapchain_desc->refresh_rate;
175     present_parameters->FullScreen_PresentationInterval = swapchain_desc->swap_interval;
176 }
177 
178 static void wined3d_swapchain_desc_from_present_parameters(struct wined3d_swapchain_desc *swapchain_desc,
179         const D3DPRESENT_PARAMETERS *present_parameters)
180 {
181     swapchain_desc->backbuffer_width = present_parameters->BackBufferWidth;
182     swapchain_desc->backbuffer_height = present_parameters->BackBufferHeight;
183     swapchain_desc->backbuffer_format = wined3dformat_from_d3dformat(present_parameters->BackBufferFormat);
184     swapchain_desc->backbuffer_count = max(1, present_parameters->BackBufferCount);
185     swapchain_desc->multisample_type = present_parameters->MultiSampleType;
186     swapchain_desc->multisample_quality = 0; /* d3d9 only */
187     swapchain_desc->swap_effect = present_parameters->SwapEffect;
188     swapchain_desc->device_window = present_parameters->hDeviceWindow;
189     swapchain_desc->windowed = present_parameters->Windowed;
190     swapchain_desc->enable_auto_depth_stencil = present_parameters->EnableAutoDepthStencil;
191     swapchain_desc->auto_depth_stencil_format
192             = wined3dformat_from_d3dformat(present_parameters->AutoDepthStencilFormat);
193     swapchain_desc->flags = present_parameters->Flags;
194     swapchain_desc->refresh_rate = present_parameters->FullScreen_RefreshRateInHz;
195     swapchain_desc->swap_interval = present_parameters->FullScreen_PresentationInterval;
196     swapchain_desc->auto_restore_display_mode = TRUE;
197 }
198 
199 /* Handle table functions */
200 static DWORD d3d8_allocate_handle(struct d3d8_handle_table *t, void *object, enum d3d8_handle_type type)
201 {
202     struct d3d8_handle_entry *entry;
203 
204     if (t->free_entries)
205     {
206         DWORD index = t->free_entries - t->entries;
207         /* Use a free handle */
208         entry = t->free_entries;
209         if (entry->type != D3D8_HANDLE_FREE)
210         {
211             ERR("Handle %u(%p) is in the free list, but has type %#x.\n", index, entry, entry->type);
212             return D3D8_INVALID_HANDLE;
213         }
214         t->free_entries = entry->object;
215         entry->object = object;
216         entry->type = type;
217 
218         return index;
219     }
220 
221     if (!(t->entry_count < t->table_size))
222     {
223         /* Grow the table */
224         UINT new_size = t->table_size + (t->table_size >> 1);
225         struct d3d8_handle_entry *new_entries = HeapReAlloc(GetProcessHeap(),
226                 0, t->entries, new_size * sizeof(*t->entries));
227         if (!new_entries)
228         {
229             ERR("Failed to grow the handle table.\n");
230             return D3D8_INVALID_HANDLE;
231         }
232         t->entries = new_entries;
233         t->table_size = new_size;
234     }
235 
236     entry = &t->entries[t->entry_count];
237     entry->object = object;
238     entry->type = type;
239 
240     return t->entry_count++;
241 }
242 
243 static void *d3d8_free_handle(struct d3d8_handle_table *t, DWORD handle, enum d3d8_handle_type type)
244 {
245     struct d3d8_handle_entry *entry;
246     void *object;
247 
248     if (handle == D3D8_INVALID_HANDLE || handle >= t->entry_count)
249     {
250         WARN("Invalid handle %u passed.\n", handle);
251         return NULL;
252     }
253 
254     entry = &t->entries[handle];
255     if (entry->type != type)
256     {
257         WARN("Handle %u(%p) is not of type %#x.\n", handle, entry, type);
258         return NULL;
259     }
260 
261     object = entry->object;
262     entry->object = t->free_entries;
263     entry->type = D3D8_HANDLE_FREE;
264     t->free_entries = entry;
265 
266     return object;
267 }
268 
269 static void *d3d8_get_object(struct d3d8_handle_table *t, DWORD handle, enum d3d8_handle_type type)
270 {
271     struct d3d8_handle_entry *entry;
272 
273     if (handle == D3D8_INVALID_HANDLE || handle >= t->entry_count)
274     {
275         WARN("Invalid handle %u passed.\n", handle);
276         return NULL;
277     }
278 
279     entry = &t->entries[handle];
280     if (entry->type != type)
281     {
282         WARN("Handle %u(%p) is not of type %#x.\n", handle, entry, type);
283         return NULL;
284     }
285 
286     return entry->object;
287 }
288 
289 static inline struct d3d8_device *impl_from_IDirect3DDevice8(IDirect3DDevice8 *iface)
290 {
291     return CONTAINING_RECORD(iface, struct d3d8_device, IDirect3DDevice8_iface);
292 }
293 
294 static HRESULT WINAPI d3d8_device_QueryInterface(IDirect3DDevice8 *iface, REFIID riid, void **out)
295 {
296     TRACE("iface %p, riid %s, out %p.\n",
297             iface, debugstr_guid(riid), out);
298 
299     if (IsEqualGUID(riid, &IID_IDirect3DDevice8)
300             || IsEqualGUID(riid, &IID_IUnknown))
301     {
302         IDirect3DDevice8_AddRef(iface);
303         *out = iface;
304         return S_OK;
305     }
306 
307     WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
308 
309     *out = NULL;
310     return E_NOINTERFACE;
311 }
312 
313 static ULONG WINAPI d3d8_device_AddRef(IDirect3DDevice8 *iface)
314 {
315     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
316     ULONG ref = InterlockedIncrement(&device->ref);
317 
318     TRACE("%p increasing refcount to %u.\n", iface, ref);
319 
320     return ref;
321 }
322 
323 static ULONG WINAPI d3d8_device_Release(IDirect3DDevice8 *iface)
324 {
325     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
326     ULONG ref;
327 
328     if (device->inDestruction)
329         return 0;
330 
331     ref = InterlockedDecrement(&device->ref);
332 
333     TRACE("%p decreasing refcount to %u.\n", iface, ref);
334 
335     if (!ref)
336     {
337         IDirect3D8 *parent = device->d3d_parent;
338         unsigned i;
339 
340         TRACE("Releasing wined3d device %p.\n", device->wined3d_device);
341 
342         wined3d_mutex_lock();
343 
344         device->inDestruction = TRUE;
345 
346         for (i = 0; i < device->numConvertedDecls; ++i)
347         {
348             d3d8_vertex_declaration_destroy(device->decls[i].declaration);
349         }
350         HeapFree(GetProcessHeap(), 0, device->decls);
351 
352         if (device->vertex_buffer)
353             wined3d_buffer_decref(device->vertex_buffer);
354         if (device->index_buffer)
355             wined3d_buffer_decref(device->index_buffer);
356 
357         wined3d_device_uninit_3d(device->wined3d_device);
358         wined3d_device_release_focus_window(device->wined3d_device);
359         wined3d_device_decref(device->wined3d_device);
360         HeapFree(GetProcessHeap(), 0, device->handle_table.entries);
361         HeapFree(GetProcessHeap(), 0, device);
362 
363         wined3d_mutex_unlock();
364 
365         IDirect3D8_Release(parent);
366     }
367     return ref;
368 }
369 
370 static HRESULT WINAPI d3d8_device_TestCooperativeLevel(IDirect3DDevice8 *iface)
371 {
372     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
373 
374     TRACE("iface %p.\n", iface);
375 
376     if (device->lost)
377     {
378         TRACE("Device is lost.\n");
379         return D3DERR_DEVICENOTRESET;
380     }
381 
382     return D3D_OK;
383 }
384 
385 static UINT WINAPI d3d8_device_GetAvailableTextureMem(IDirect3DDevice8 *iface)
386 {
387     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
388     HRESULT hr;
389 
390     TRACE("iface %p.\n", iface);
391 
392     wined3d_mutex_lock();
393     hr = wined3d_device_get_available_texture_mem(device->wined3d_device);
394     wined3d_mutex_unlock();
395 
396     return hr;
397 }
398 
399 static HRESULT WINAPI d3d8_device_ResourceManagerDiscardBytes(IDirect3DDevice8 *iface, DWORD byte_count)
400 {
401     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
402 
403     TRACE("iface %p, byte_count %u.\n", iface, byte_count);
404 
405     if (byte_count)
406         FIXME("Byte count ignored.\n");
407 
408     wined3d_mutex_lock();
409     wined3d_device_evict_managed_resources(device->wined3d_device);
410     wined3d_mutex_unlock();
411 
412     return D3D_OK;
413 }
414 
415 static HRESULT WINAPI d3d8_device_GetDirect3D(IDirect3DDevice8 *iface, IDirect3D8 **d3d8)
416 {
417     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
418 
419     TRACE("iface %p, d3d8 %p.\n", iface, d3d8);
420 
421     if (!d3d8)
422         return D3DERR_INVALIDCALL;
423 
424     return IDirect3D8_QueryInterface(device->d3d_parent, &IID_IDirect3D8, (void **)d3d8);
425 }
426 
427 static HRESULT WINAPI d3d8_device_GetDeviceCaps(IDirect3DDevice8 *iface, D3DCAPS8 *caps)
428 {
429     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
430     WINED3DCAPS *wined3d_caps;
431     HRESULT hr;
432 
433     TRACE("iface %p, caps %p.\n", iface, caps);
434 
435     if (!caps)
436         return D3DERR_INVALIDCALL;
437 
438     if (!(wined3d_caps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wined3d_caps))))
439         return D3DERR_INVALIDCALL; /* well this is what MSDN says to return */
440 
441     wined3d_mutex_lock();
442     hr = wined3d_device_get_device_caps(device->wined3d_device, wined3d_caps);
443     wined3d_mutex_unlock();
444 
445     fixup_caps(wined3d_caps);
446     WINECAPSTOD3D8CAPS(caps, wined3d_caps)
447     HeapFree(GetProcessHeap(), 0, wined3d_caps);
448 
449     return hr;
450 }
451 
452 static HRESULT WINAPI d3d8_device_GetDisplayMode(IDirect3DDevice8 *iface, D3DDISPLAYMODE *mode)
453 {
454     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
455     struct wined3d_display_mode wined3d_mode;
456     HRESULT hr;
457 
458     TRACE("iface %p, mode %p.\n", iface, mode);
459 
460     wined3d_mutex_lock();
461     hr = wined3d_device_get_display_mode(device->wined3d_device, 0, &wined3d_mode, NULL);
462     wined3d_mutex_unlock();
463 
464     if (SUCCEEDED(hr))
465     {
466         mode->Width = wined3d_mode.width;
467         mode->Height = wined3d_mode.height;
468         mode->RefreshRate = wined3d_mode.refresh_rate;
469         mode->Format = d3dformat_from_wined3dformat(wined3d_mode.format_id);
470     }
471 
472     return hr;
473 }
474 
475 static HRESULT WINAPI d3d8_device_GetCreationParameters(IDirect3DDevice8 *iface,
476         D3DDEVICE_CREATION_PARAMETERS *parameters)
477 {
478     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
479 
480     TRACE("iface %p, parameters %p.\n", iface, parameters);
481 
482     wined3d_mutex_lock();
483     wined3d_device_get_creation_parameters(device->wined3d_device,
484             (struct wined3d_device_creation_parameters *)parameters);
485     wined3d_mutex_unlock();
486 
487     return D3D_OK;
488 }
489 
490 static HRESULT WINAPI d3d8_device_SetCursorProperties(IDirect3DDevice8 *iface,
491         UINT hotspot_x, UINT hotspot_y, IDirect3DSurface8 *bitmap)
492 {
493     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
494     struct d3d8_surface *bitmap_impl = unsafe_impl_from_IDirect3DSurface8(bitmap);
495     HRESULT hr;
496 
497     TRACE("iface %p, hotspot_x %u, hotspot_y %u, bitmap %p.\n",
498             iface, hotspot_x, hotspot_y, bitmap);
499 
500     if (!bitmap)
501     {
502         WARN("No cursor bitmap, returning D3DERR_INVALIDCALL.\n");
503         return D3DERR_INVALIDCALL;
504     }
505 
506     wined3d_mutex_lock();
507     hr = wined3d_device_set_cursor_properties(device->wined3d_device,
508             hotspot_x, hotspot_y, bitmap_impl->wined3d_surface);
509     wined3d_mutex_unlock();
510 
511     return hr;
512 }
513 
514 static void WINAPI d3d8_device_SetCursorPosition(IDirect3DDevice8 *iface, UINT x, UINT y, DWORD flags)
515 {
516     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
517 
518     TRACE("iface %p, x %u, y %u, flags %#x.\n", iface, x, y, flags);
519 
520     wined3d_mutex_lock();
521     wined3d_device_set_cursor_position(device->wined3d_device, x, y, flags);
522     wined3d_mutex_unlock();
523 }
524 
525 static BOOL WINAPI d3d8_device_ShowCursor(IDirect3DDevice8 *iface, BOOL show)
526 {
527     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
528     BOOL ret;
529 
530     TRACE("iface %p, show %#x.\n", iface, show);
531 
532     wined3d_mutex_lock();
533     ret = wined3d_device_show_cursor(device->wined3d_device, show);
534     wined3d_mutex_unlock();
535 
536     return ret;
537 }
538 
539 static HRESULT WINAPI d3d8_device_CreateAdditionalSwapChain(IDirect3DDevice8 *iface,
540         D3DPRESENT_PARAMETERS *present_parameters, IDirect3DSwapChain8 **swapchain)
541 {
542     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
543     struct wined3d_swapchain_desc desc;
544     struct d3d8_swapchain *object;
545 
546     TRACE("iface %p, present_parameters %p, swapchain %p.\n",
547             iface, present_parameters, swapchain);
548 
549     wined3d_swapchain_desc_from_present_parameters(&desc, present_parameters);
550     if (SUCCEEDED(d3d8_swapchain_create(device, &desc, &object)))
551         *swapchain = &object->IDirect3DSwapChain8_iface;
552     present_parameters_from_wined3d_swapchain_desc(present_parameters, &desc);
553 
554     return D3D_OK;
555 }
556 
557 static HRESULT CDECL reset_enum_callback(struct wined3d_resource *resource)
558 {
559     struct wined3d_resource_desc desc;
560 
561     wined3d_resource_get_desc(resource, &desc);
562     if (desc.pool == WINED3D_POOL_DEFAULT)
563     {
564         struct d3d8_surface *surface;
565 
566         if (desc.resource_type == WINED3D_RTYPE_TEXTURE)
567         {
568             IUnknown *parent = wined3d_resource_get_parent(resource);
569             IDirect3DBaseTexture8 *texture;
570 
571             if (SUCCEEDED(IUnknown_QueryInterface(parent, &IID_IDirect3DBaseTexture8, (void **)&texture)))
572             {
573                 IDirect3DBaseTexture8_Release(texture);
574                 WARN("Texture %p (resource %p) in pool D3DPOOL_DEFAULT blocks the Reset call.\n", texture, resource);
575                 return D3DERR_DEVICELOST;
576             }
577 
578             return D3D_OK;
579         }
580 
581         if (desc.resource_type != WINED3D_RTYPE_SURFACE)
582         {
583             WARN("Resource %p in pool D3DPOOL_DEFAULT blocks the Reset call.\n", resource);
584             return D3DERR_DEVICELOST;
585         }
586 
587         surface = wined3d_resource_get_parent(resource);
588         if (surface->resource.refcount)
589         {
590             WARN("Surface %p (resource %p) in pool D3DPOOL_DEFAULT blocks the Reset call.\n", surface, resource);
591             return D3DERR_DEVICELOST;
592         }
593 
594         WARN("Surface %p (resource %p) is an implicit resource with ref 0.\n", surface, resource);
595     }
596 
597     return D3D_OK;
598 }
599 
600 static HRESULT WINAPI d3d8_device_Reset(IDirect3DDevice8 *iface,
601         D3DPRESENT_PARAMETERS *present_parameters)
602 {
603     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
604     struct wined3d_swapchain_desc swapchain_desc;
605     HRESULT hr;
606 
607     TRACE("iface %p, present_parameters %p.\n", iface, present_parameters);
608 
609     wined3d_mutex_lock();
610 
611     if (device->vertex_buffer)
612     {
613         wined3d_buffer_decref(device->vertex_buffer);
614         device->vertex_buffer = NULL;
615         device->vertex_buffer_size = 0;
616     }
617     if (device->index_buffer)
618     {
619         wined3d_buffer_decref(device->index_buffer);
620         device->index_buffer = NULL;
621         device->index_buffer_size = 0;
622     }
623 
624     wined3d_swapchain_desc_from_present_parameters(&swapchain_desc, present_parameters);
625     if (SUCCEEDED(hr = wined3d_device_reset(device->wined3d_device, &swapchain_desc,
626             NULL, reset_enum_callback, TRUE)))
627     {
628         wined3d_device_set_render_state(device->wined3d_device, WINED3D_RS_POINTSIZE_MIN, 0);
629         device->lost = FALSE;
630     }
631     else
632     {
633         device->lost = TRUE;
634     }
635     wined3d_mutex_unlock();
636 
637     return hr;
638 }
639 
640 static HRESULT WINAPI d3d8_device_Present(IDirect3DDevice8 *iface, const RECT *src_rect,
641         const RECT *dst_rect, HWND dst_window_override, const RGNDATA *dirty_region)
642 {
643     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
644     HRESULT hr;
645 
646     TRACE("iface %p, src_rect %s, dst_rect %s, dst_window_override %p, dirty_region %p.\n",
647             iface, wine_dbgstr_rect(src_rect), wine_dbgstr_rect(dst_rect), dst_window_override, dirty_region);
648 
649     wined3d_mutex_lock();
650     hr = wined3d_device_present(device->wined3d_device, src_rect, dst_rect,
651             dst_window_override, dirty_region, 0);
652     wined3d_mutex_unlock();
653 
654     return hr;
655 }
656 
657 static HRESULT WINAPI d3d8_device_GetBackBuffer(IDirect3DDevice8 *iface,
658         UINT backbuffer_idx, D3DBACKBUFFER_TYPE backbuffer_type, IDirect3DSurface8 **backbuffer)
659 {
660     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
661     struct wined3d_surface *wined3d_surface = NULL;
662     struct d3d8_surface *surface_impl;
663     HRESULT hr;
664 
665     TRACE("iface %p, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
666             iface, backbuffer_idx, backbuffer_type, backbuffer);
667 
668     wined3d_mutex_lock();
669     hr = wined3d_device_get_back_buffer(device->wined3d_device, 0, backbuffer_idx,
670             (enum wined3d_backbuffer_type)backbuffer_type, &wined3d_surface);
671     if (SUCCEEDED(hr) && wined3d_surface && backbuffer)
672     {
673         surface_impl = wined3d_surface_get_parent(wined3d_surface);
674         *backbuffer = &surface_impl->IDirect3DSurface8_iface;
675         IDirect3DSurface8_AddRef(*backbuffer);
676     }
677     wined3d_mutex_unlock();
678 
679     return hr;
680 }
681 
682 static HRESULT WINAPI d3d8_device_GetRasterStatus(IDirect3DDevice8 *iface, D3DRASTER_STATUS *raster_status)
683 {
684     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
685     HRESULT hr;
686 
687     TRACE("iface %p, raster_status %p.\n", iface, raster_status);
688 
689     wined3d_mutex_lock();
690     hr = wined3d_device_get_raster_status(device->wined3d_device, 0, (struct wined3d_raster_status *)raster_status);
691     wined3d_mutex_unlock();
692 
693     return hr;
694 }
695 
696 static void WINAPI d3d8_device_SetGammaRamp(IDirect3DDevice8 *iface, DWORD flags, const D3DGAMMARAMP *ramp)
697 {
698     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
699 
700     TRACE("iface %p, flags %#x, ramp %p.\n", iface, flags, ramp);
701 
702     /* Note: D3DGAMMARAMP is compatible with struct wined3d_gamma_ramp. */
703     wined3d_mutex_lock();
704     wined3d_device_set_gamma_ramp(device->wined3d_device, 0, flags, (const struct wined3d_gamma_ramp *)ramp);
705     wined3d_mutex_unlock();
706 }
707 
708 static void WINAPI d3d8_device_GetGammaRamp(IDirect3DDevice8 *iface, D3DGAMMARAMP *ramp)
709 {
710     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
711 
712     TRACE("iface %p, ramp %p.\n", iface, ramp);
713 
714     /* Note: D3DGAMMARAMP is compatible with struct wined3d_gamma_ramp. */
715     wined3d_mutex_lock();
716     wined3d_device_get_gamma_ramp(device->wined3d_device, 0, (struct wined3d_gamma_ramp *)ramp);
717     wined3d_mutex_unlock();
718 }
719 
720 static HRESULT WINAPI d3d8_device_CreateTexture(IDirect3DDevice8 *iface,
721         UINT width, UINT height, UINT levels, DWORD usage, D3DFORMAT format,
722         D3DPOOL pool, IDirect3DTexture8 **texture)
723 {
724     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
725     struct d3d8_texture *object;
726     HRESULT hr;
727 
728     TRACE("iface %p, width %u, height %u, levels %u, usage %#x, format %#x, pool %#x, texture %p.\n",
729             iface, width, height, levels, usage, format, pool, texture);
730 
731     *texture = NULL;
732     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
733     if (!object)
734         return D3DERR_OUTOFVIDEOMEMORY;
735 
736     hr = texture_init(object, device, width, height, levels, usage, format, pool);
737     if (FAILED(hr))
738     {
739         WARN("Failed to initialize texture, hr %#x.\n", hr);
740         HeapFree(GetProcessHeap(), 0, object);
741         return hr;
742     }
743 
744     TRACE("Created texture %p.\n", object);
745     *texture = (IDirect3DTexture8 *)&object->IDirect3DBaseTexture8_iface;
746 
747     return D3D_OK;
748 }
749 
750 static HRESULT WINAPI d3d8_device_CreateVolumeTexture(IDirect3DDevice8 *iface,
751         UINT width, UINT height, UINT depth, UINT levels, DWORD usage, D3DFORMAT format,
752         D3DPOOL pool, IDirect3DVolumeTexture8 **texture)
753 {
754     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
755     struct d3d8_texture *object;
756     HRESULT hr;
757 
758     TRACE("iface %p, width %u, height %u, depth %u, levels %u, usage %#x, format %#x, pool %#x, texture %p.\n",
759             iface, width, height, depth, levels, usage, format, pool, texture);
760 
761     *texture = NULL;
762     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
763     if (!object)
764         return D3DERR_OUTOFVIDEOMEMORY;
765 
766     hr = volumetexture_init(object, device, width, height, depth, levels, usage, format, pool);
767     if (FAILED(hr))
768     {
769         WARN("Failed to initialize volume texture, hr %#x.\n", hr);
770         HeapFree(GetProcessHeap(), 0, object);
771         return hr;
772     }
773 
774     TRACE("Created volume texture %p.\n", object);
775     *texture = (IDirect3DVolumeTexture8 *)&object->IDirect3DBaseTexture8_iface;
776 
777     return D3D_OK;
778 }
779 
780 static HRESULT WINAPI d3d8_device_CreateCubeTexture(IDirect3DDevice8 *iface, UINT edge_length,
781         UINT levels, DWORD usage, D3DFORMAT format, D3DPOOL pool, IDirect3DCubeTexture8 **texture)
782 {
783     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
784     struct d3d8_texture *object;
785     HRESULT hr;
786 
787     TRACE("iface %p, edge_length %u, levels %u, usage %#x, format %#x, pool %#x, texture %p.\n",
788             iface, edge_length, levels, usage, format, pool, texture);
789 
790     *texture = NULL;
791     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
792     if (!object)
793         return D3DERR_OUTOFVIDEOMEMORY;
794 
795     hr = cubetexture_init(object, device, edge_length, levels, usage, format, pool);
796     if (FAILED(hr))
797     {
798         WARN("Failed to initialize cube texture, hr %#x.\n", hr);
799         HeapFree(GetProcessHeap(), 0, object);
800         return hr;
801     }
802 
803     TRACE("Created cube texture %p.\n", object);
804     *texture = (IDirect3DCubeTexture8 *)&object->IDirect3DBaseTexture8_iface;
805 
806     return hr;
807 }
808 
809 static HRESULT WINAPI d3d8_device_CreateVertexBuffer(IDirect3DDevice8 *iface, UINT size,
810         DWORD usage, DWORD fvf, D3DPOOL pool, IDirect3DVertexBuffer8 **buffer)
811 {
812     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
813     struct d3d8_vertexbuffer *object;
814     HRESULT hr;
815 
816     TRACE("iface %p, size %u, usage %#x, fvf %#x, pool %#x, buffer %p.\n",
817             iface, size, usage, fvf, pool, buffer);
818 
819     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
820     if (!object)
821         return D3DERR_OUTOFVIDEOMEMORY;
822 
823     hr = vertexbuffer_init(object, device, size, usage, fvf, pool);
824     if (FAILED(hr))
825     {
826         WARN("Failed to initialize vertex buffer, hr %#x.\n", hr);
827         HeapFree(GetProcessHeap(), 0, object);
828         return hr;
829     }
830 
831     TRACE("Created vertex buffer %p.\n", object);
832     *buffer = &object->IDirect3DVertexBuffer8_iface;
833 
834     return D3D_OK;
835 }
836 
837 static HRESULT WINAPI d3d8_device_CreateIndexBuffer(IDirect3DDevice8 *iface, UINT size,
838         DWORD usage, D3DFORMAT format, D3DPOOL pool, IDirect3DIndexBuffer8 **buffer)
839 {
840     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
841     struct d3d8_indexbuffer *object;
842     HRESULT hr;
843 
844     TRACE("iface %p, size %u, usage %#x, format %#x, pool %#x, buffer %p.\n",
845             iface, size, usage, format, pool, buffer);
846 
847     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
848     if (!object)
849         return D3DERR_OUTOFVIDEOMEMORY;
850 
851     hr = indexbuffer_init(object, device, size, usage, format, pool);
852     if (FAILED(hr))
853     {
854         WARN("Failed to initialize index buffer, hr %#x.\n", hr);
855         HeapFree(GetProcessHeap(), 0, object);
856         return hr;
857     }
858 
859     TRACE("Created index buffer %p.\n", object);
860     *buffer = &object->IDirect3DIndexBuffer8_iface;
861 
862     return D3D_OK;
863 }
864 
865 static HRESULT d3d8_device_create_surface(struct d3d8_device *device, UINT width, UINT height,
866         D3DFORMAT format, DWORD flags, IDirect3DSurface8 **surface, UINT usage, D3DPOOL pool,
867         D3DMULTISAMPLE_TYPE multisample_type, DWORD multisample_quality)
868 {
869     struct wined3d_resource *sub_resource;
870     struct wined3d_resource_desc desc;
871     struct d3d8_surface *surface_impl;
872     struct wined3d_texture *texture;
873     HRESULT hr;
874 
875     TRACE("device %p, width %u, height %u, format %#x, flags %#x, surface %p,\n"
876             "\tusage %#x, pool %#x, multisample_type %#x, multisample_quality %u.\n",
877             device, width, height, format, flags, surface,
878             usage, pool, multisample_type, multisample_quality);
879 
880     desc.resource_type = WINED3D_RTYPE_TEXTURE;
881     desc.format = wined3dformat_from_d3dformat(format);
882     desc.multisample_type = multisample_type;
883     desc.multisample_quality = multisample_quality;
884     desc.usage = usage & WINED3DUSAGE_MASK;
885     desc.pool = pool;
886     desc.width = width;
887     desc.height = height;
888     desc.depth = 1;
889     desc.size = 0;
890 
891     wined3d_mutex_lock();
892 
893     if (FAILED(hr = wined3d_texture_create(device->wined3d_device, &desc,
894             1, flags, NULL, &d3d8_null_wined3d_parent_ops, &texture)))
895     {
896         wined3d_mutex_unlock();
897         WARN("Failed to create texture, hr %#x.\n", hr);
898         return hr;
899     }
900 
901     sub_resource = wined3d_texture_get_sub_resource(texture, 0);
902     surface_impl = wined3d_resource_get_parent(sub_resource);
903     surface_impl->forwardReference = NULL;
904     surface_impl->parent_device = &device->IDirect3DDevice8_iface;
905     *surface = &surface_impl->IDirect3DSurface8_iface;
906     IDirect3DSurface8_AddRef(*surface);
907     wined3d_texture_decref(texture);
908 
909     wined3d_mutex_unlock();
910 
911     return D3D_OK;
912 }
913 
914 static HRESULT WINAPI d3d8_device_CreateRenderTarget(IDirect3DDevice8 *iface, UINT width,
915         UINT height, D3DFORMAT format, D3DMULTISAMPLE_TYPE multisample_type, BOOL lockable,
916         IDirect3DSurface8 **surface)
917 {
918     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
919     DWORD flags = 0;
920 
921     TRACE("iface %p, width %u, height %u, format %#x, multisample_type %#x, lockable %#x, surface %p.\n",
922             iface, width, height, format, multisample_type, lockable, surface);
923 
924     *surface = NULL;
925     if (lockable)
926         flags |= WINED3D_SURFACE_MAPPABLE;
927 
928     return d3d8_device_create_surface(device, width, height, format, flags, surface,
929             D3DUSAGE_RENDERTARGET, D3DPOOL_DEFAULT, multisample_type, 0);
930 }
931 
932 static HRESULT WINAPI d3d8_device_CreateDepthStencilSurface(IDirect3DDevice8 *iface,
933         UINT width, UINT height, D3DFORMAT format, D3DMULTISAMPLE_TYPE multisample_type,
934         IDirect3DSurface8 **surface)
935 {
936     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
937 
938     TRACE("iface %p, width %u, height %u, format %#x, multisample_type %#x, surface %p.\n",
939             iface, width, height, format, multisample_type, surface);
940 
941     *surface = NULL;
942 
943     /* TODO: Verify that Discard is false */
944     return d3d8_device_create_surface(device, width, height, format, WINED3D_SURFACE_MAPPABLE,
945             surface, D3DUSAGE_DEPTHSTENCIL, D3DPOOL_DEFAULT, multisample_type, 0);
946 }
947 
948 /*  IDirect3DDevice8Impl::CreateImageSurface returns surface with pool type SYSTEMMEM */
949 static HRESULT WINAPI d3d8_device_CreateImageSurface(IDirect3DDevice8 *iface, UINT width,
950         UINT height, D3DFORMAT format, IDirect3DSurface8 **surface)
951 {
952     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
953 
954     TRACE("iface %p, width %u, height %u, format %#x, surface %p.\n",
955             iface, width, height, format, surface);
956 
957     *surface = NULL;
958 
959     return d3d8_device_create_surface(device, width, height, format, WINED3D_SURFACE_MAPPABLE,
960             surface, 0, D3DPOOL_SYSTEMMEM, D3DMULTISAMPLE_NONE, 0);
961 }
962 
963 static HRESULT WINAPI d3d8_device_CopyRects(IDirect3DDevice8 *iface,
964         IDirect3DSurface8 *src_surface, const RECT *src_rects, UINT rect_count,
965         IDirect3DSurface8 *dst_surface, const POINT *dst_points)
966 {
967     struct d3d8_surface *src = unsafe_impl_from_IDirect3DSurface8(src_surface);
968     struct d3d8_surface *dst = unsafe_impl_from_IDirect3DSurface8(dst_surface);
969     enum wined3d_format_id src_format, dst_format;
970     struct wined3d_resource_desc wined3d_desc;
971     struct wined3d_resource *wined3d_resource;
972     UINT src_w, src_h;
973     HRESULT hr;
974 
975     TRACE("iface %p, src_surface %p, src_rects %p, rect_count %u, dst_surface %p, dst_points %p.\n",
976             iface, src_surface, src_rects, rect_count, dst_surface, dst_points);
977 
978     /* Check that the source texture is in WINED3D_POOL_SYSTEM_MEM and the
979      * destination texture is in WINED3D_POOL_DEFAULT. */
980 
981     wined3d_mutex_lock();
982     wined3d_resource = wined3d_surface_get_resource(src->wined3d_surface);
983     wined3d_resource_get_desc(wined3d_resource, &wined3d_desc);
984     if (wined3d_desc.usage & WINED3DUSAGE_DEPTHSTENCIL)
985     {
986         WARN("Source %p is a depth stencil surface, returning D3DERR_INVALIDCALL.\n", src_surface);
987         wined3d_mutex_unlock();
988         return D3DERR_INVALIDCALL;
989     }
990     src_format = wined3d_desc.format;
991     src_w = wined3d_desc.width;
992     src_h = wined3d_desc.height;
993 
994     wined3d_resource = wined3d_surface_get_resource(dst->wined3d_surface);
995     wined3d_resource_get_desc(wined3d_resource, &wined3d_desc);
996     if (wined3d_desc.usage & WINED3DUSAGE_DEPTHSTENCIL)
997     {
998         WARN("Destination %p is a depth stencil surface, returning D3DERR_INVALIDCALL.\n", dst_surface);
999         wined3d_mutex_unlock();
1000         return D3DERR_INVALIDCALL;
1001     }
1002     dst_format = wined3d_desc.format;
1003 
1004     /* Check that the source and destination formats match */
1005     if (src_format != dst_format && WINED3DFMT_UNKNOWN != dst_format)
1006     {
1007         WARN("Source %p format must match the destination %p format, returning D3DERR_INVALIDCALL.\n",
1008                 src_surface, dst_surface);
1009         wined3d_mutex_unlock();
1010         return D3DERR_INVALIDCALL;
1011     }
1012     else if (WINED3DFMT_UNKNOWN == dst_format)
1013     {
1014         TRACE("Converting destination surface from WINED3DFMT_UNKNOWN to the source format.\n");
1015         if (FAILED(hr = wined3d_surface_update_desc(dst->wined3d_surface, wined3d_desc.width, wined3d_desc.height,
1016                 src_format, wined3d_desc.multisample_type, wined3d_desc.multisample_quality, NULL, 0)))
1017         {
1018             WARN("Failed to update surface desc, hr %#x.\n", hr);
1019             wined3d_mutex_unlock();
1020             return hr;
1021         }
1022     }
1023 
1024     /* Quick if complete copy ... */
1025     if (!rect_count && !src_rects && !dst_points)
1026     {
1027         RECT rect = {0, 0, src_w, src_h};
1028         wined3d_surface_blt(dst->wined3d_surface, &rect,
1029                 src->wined3d_surface, &rect, 0, NULL, WINED3D_TEXF_POINT);
1030     }
1031     else
1032     {
1033         unsigned int i;
1034         /* Copy rect by rect */
1035         if (src_rects && dst_points)
1036         {
1037             for (i = 0; i < rect_count; ++i)
1038             {
1039                 UINT w = src_rects[i].right - src_rects[i].left;
1040                 UINT h = src_rects[i].bottom - src_rects[i].top;
1041                 RECT dst_rect = {dst_points[i].x, dst_points[i].y,
1042                         dst_points[i].x + w, dst_points[i].y + h};
1043 
1044                 wined3d_surface_blt(dst->wined3d_surface, &dst_rect,
1045                         src->wined3d_surface, &src_rects[i], 0, NULL, WINED3D_TEXF_POINT);
1046             }
1047         }
1048         else
1049         {
1050             for (i = 0; i < rect_count; ++i)
1051             {
1052                 UINT w = src_rects[i].right - src_rects[i].left;
1053                 UINT h = src_rects[i].bottom - src_rects[i].top;
1054                 RECT dst_rect = {0, 0, w, h};
1055 
1056                 wined3d_surface_blt(dst->wined3d_surface, &dst_rect,
1057                         src->wined3d_surface, &src_rects[i], 0, NULL, WINED3D_TEXF_POINT);
1058             }
1059         }
1060     }
1061     wined3d_mutex_unlock();
1062 
1063     return WINED3D_OK;
1064 }
1065 
1066 static HRESULT WINAPI d3d8_device_UpdateTexture(IDirect3DDevice8 *iface,
1067         IDirect3DBaseTexture8 *src_texture, IDirect3DBaseTexture8 *dst_texture)
1068 {
1069     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1070     struct d3d8_texture *src_impl, *dst_impl;
1071     HRESULT hr;
1072 
1073     TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
1074 
1075     src_impl = unsafe_impl_from_IDirect3DBaseTexture8(src_texture);
1076     dst_impl = unsafe_impl_from_IDirect3DBaseTexture8(dst_texture);
1077 
1078     wined3d_mutex_lock();
1079     hr = wined3d_device_update_texture(device->wined3d_device,
1080             src_impl->wined3d_texture, dst_impl->wined3d_texture);
1081     wined3d_mutex_unlock();
1082 
1083     return hr;
1084 }
1085 
1086 static HRESULT WINAPI d3d8_device_GetFrontBuffer(IDirect3DDevice8 *iface, IDirect3DSurface8 *dst_surface)
1087 {
1088     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1089     struct d3d8_surface *dst_impl = unsafe_impl_from_IDirect3DSurface8(dst_surface);
1090     HRESULT hr;
1091 
1092     TRACE("iface %p, dst_surface %p.\n", iface, dst_surface);
1093 
1094     if (!dst_surface)
1095     {
1096         WARN("Invalid destination surface passed.\n");
1097         return D3DERR_INVALIDCALL;
1098     }
1099 
1100     wined3d_mutex_lock();
1101     hr = wined3d_device_get_front_buffer_data(device->wined3d_device, 0, dst_impl->wined3d_surface);
1102     wined3d_mutex_unlock();
1103 
1104     return hr;
1105 }
1106 
1107 static HRESULT WINAPI d3d8_device_SetRenderTarget(IDirect3DDevice8 *iface,
1108         IDirect3DSurface8 *render_target, IDirect3DSurface8 *depth_stencil)
1109 {
1110     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1111     struct d3d8_surface *rt_impl = unsafe_impl_from_IDirect3DSurface8(render_target);
1112     struct d3d8_surface *ds_impl = unsafe_impl_from_IDirect3DSurface8(depth_stencil);
1113     struct wined3d_surface *original_ds = NULL;
1114     HRESULT hr = D3D_OK;
1115 
1116     TRACE("iface %p, render_target %p, depth_stencil %p.\n", iface, render_target, depth_stencil);
1117 
1118     wined3d_mutex_lock();
1119 
1120     if (ds_impl)
1121     {
1122         struct wined3d_resource_desc ds_desc, rt_desc;
1123         struct wined3d_resource *wined3d_resource;
1124         struct wined3d_surface *original_rt = NULL;
1125 
1126         /* If no render target is passed in check the size against the current RT */
1127         if (!render_target)
1128         {
1129             if (!(original_rt = wined3d_device_get_render_target(device->wined3d_device, 0)))
1130             {
1131                 wined3d_mutex_unlock();
1132                 return D3DERR_NOTFOUND;
1133             }
1134             wined3d_resource = wined3d_surface_get_resource(original_rt);
1135         }
1136         else
1137             wined3d_resource = wined3d_surface_get_resource(rt_impl->wined3d_surface);
1138         wined3d_resource_get_desc(wined3d_resource, &rt_desc);
1139 
1140         wined3d_resource = wined3d_surface_get_resource(ds_impl->wined3d_surface);
1141         wined3d_resource_get_desc(wined3d_resource, &ds_desc);
1142 
1143         if (ds_desc.width < rt_desc.width || ds_desc.height < rt_desc.height)
1144         {
1145             WARN("Depth stencil is smaller than the render target, returning D3DERR_INVALIDCALL\n");
1146             wined3d_mutex_unlock();
1147             return D3DERR_INVALIDCALL;
1148         }
1149     }
1150 
1151     original_ds = wined3d_device_get_depth_stencil(device->wined3d_device);
1152     wined3d_device_set_depth_stencil(device->wined3d_device, ds_impl ? ds_impl->wined3d_surface : NULL);
1153     if (render_target)
1154     {
1155         hr = wined3d_device_set_render_target(device->wined3d_device, 0, rt_impl->wined3d_surface, TRUE);
1156         if (FAILED(hr))
1157             wined3d_device_set_depth_stencil(device->wined3d_device, original_ds);
1158     }
1159 
1160     wined3d_mutex_unlock();
1161 
1162     return hr;
1163 }
1164 
1165 static HRESULT WINAPI d3d8_device_GetRenderTarget(IDirect3DDevice8 *iface, IDirect3DSurface8 **render_target)
1166 {
1167     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1168     struct wined3d_surface *wined3d_surface;
1169     struct d3d8_surface *surface_impl;
1170     HRESULT hr;
1171 
1172     TRACE("iface %p, render_target %p.\n", iface, render_target);
1173 
1174     if (!render_target)
1175         return D3DERR_INVALIDCALL;
1176 
1177     wined3d_mutex_lock();
1178     if ((wined3d_surface = wined3d_device_get_render_target(device->wined3d_device, 0)))
1179     {
1180         surface_impl = wined3d_surface_get_parent(wined3d_surface);
1181         *render_target = &surface_impl->IDirect3DSurface8_iface;
1182         IDirect3DSurface8_AddRef(*render_target);
1183         hr = D3D_OK;
1184     }
1185     else
1186     {
1187         ERR("Failed to get wined3d render target.\n");
1188         *render_target = NULL;
1189         hr = D3DERR_NOTFOUND;
1190     }
1191     wined3d_mutex_unlock();
1192 
1193     return hr;
1194 }
1195 
1196 static HRESULT WINAPI d3d8_device_GetDepthStencilSurface(IDirect3DDevice8 *iface, IDirect3DSurface8 **depth_stencil)
1197 {
1198     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1199     struct wined3d_surface *wined3d_surface;
1200     struct d3d8_surface *surface_impl;
1201     HRESULT hr = D3D_OK;
1202 
1203     TRACE("iface %p, depth_stencil %p.\n", iface, depth_stencil);
1204 
1205     if (!depth_stencil)
1206         return D3DERR_INVALIDCALL;
1207 
1208     wined3d_mutex_lock();
1209     if ((wined3d_surface = wined3d_device_get_depth_stencil(device->wined3d_device)))
1210     {
1211         surface_impl = wined3d_surface_get_parent(wined3d_surface);
1212         *depth_stencil = &surface_impl->IDirect3DSurface8_iface;
1213         IDirect3DSurface8_AddRef(*depth_stencil);
1214     }
1215     else
1216     {
1217         hr = WINED3DERR_NOTFOUND;
1218         *depth_stencil = NULL;
1219     }
1220     wined3d_mutex_unlock();
1221 
1222     return hr;
1223 }
1224 
1225 static HRESULT WINAPI d3d8_device_BeginScene(IDirect3DDevice8 *iface)
1226 {
1227     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1228     HRESULT hr;
1229 
1230     TRACE("iface %p.\n", iface);
1231 
1232     wined3d_mutex_lock();
1233     hr = wined3d_device_begin_scene(device->wined3d_device);
1234     wined3d_mutex_unlock();
1235 
1236     return hr;
1237 }
1238 
1239 static HRESULT WINAPI DECLSPEC_HOTPATCH d3d8_device_EndScene(IDirect3DDevice8 *iface)
1240 {
1241     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1242     HRESULT hr;
1243 
1244     TRACE("iface %p.\n", iface);
1245 
1246     wined3d_mutex_lock();
1247     hr = wined3d_device_end_scene(device->wined3d_device);
1248     wined3d_mutex_unlock();
1249 
1250     return hr;
1251 }
1252 
1253 static HRESULT WINAPI d3d8_device_Clear(IDirect3DDevice8 *iface, DWORD rect_count,
1254         const D3DRECT *rects, DWORD flags, D3DCOLOR color, float z, DWORD stencil)
1255 {
1256     const struct wined3d_color c =
1257     {
1258         ((color >> 16) & 0xff) / 255.0f,
1259         ((color >>  8) & 0xff) / 255.0f,
1260         (color & 0xff) / 255.0f,
1261         ((color >> 24) & 0xff) / 255.0f,
1262     };
1263     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1264     HRESULT hr;
1265 
1266     TRACE("iface %p, rect_count %u, rects %p, flags %#x, color 0x%08x, z %.8e, stencil %u.\n",
1267             iface, rect_count, rects, flags, color, z, stencil);
1268 
1269     wined3d_mutex_lock();
1270     hr = wined3d_device_clear(device->wined3d_device, rect_count, (const RECT *)rects, flags, &c, z, stencil);
1271     wined3d_mutex_unlock();
1272 
1273     return hr;
1274 }
1275 
1276 static HRESULT WINAPI d3d8_device_SetTransform(IDirect3DDevice8 *iface,
1277         D3DTRANSFORMSTATETYPE state, const D3DMATRIX *matrix)
1278 {
1279     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1280 
1281     TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
1282 
1283     /* Note: D3DMATRIX is compatible with struct wined3d_matrix. */
1284     wined3d_mutex_lock();
1285     wined3d_device_set_transform(device->wined3d_device, state, (const struct wined3d_matrix *)matrix);
1286     wined3d_mutex_unlock();
1287 
1288     return D3D_OK;
1289 }
1290 
1291 static HRESULT WINAPI d3d8_device_GetTransform(IDirect3DDevice8 *iface,
1292         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
1293 {
1294     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1295 
1296     TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
1297 
1298     /* Note: D3DMATRIX is compatible with struct wined3d_matrix. */
1299     wined3d_mutex_lock();
1300     wined3d_device_get_transform(device->wined3d_device, state, (struct wined3d_matrix *)matrix);
1301     wined3d_mutex_unlock();
1302 
1303     return D3D_OK;
1304 }
1305 
1306 static HRESULT WINAPI d3d8_device_MultiplyTransform(IDirect3DDevice8 *iface,
1307         D3DTRANSFORMSTATETYPE state, const D3DMATRIX *matrix)
1308 {
1309     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1310 
1311     TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
1312 
1313     /* Note: D3DMATRIX is compatible with struct wined3d_matrix. */
1314     wined3d_mutex_lock();
1315     wined3d_device_multiply_transform(device->wined3d_device, state, (const struct wined3d_matrix *)matrix);
1316     wined3d_mutex_unlock();
1317 
1318     return D3D_OK;
1319 }
1320 
1321 static HRESULT WINAPI d3d8_device_SetViewport(IDirect3DDevice8 *iface, const D3DVIEWPORT8 *viewport)
1322 {
1323     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1324 
1325     TRACE("iface %p, viewport %p.\n", iface, viewport);
1326 
1327     /* Note: D3DVIEWPORT8 is compatible with struct wined3d_viewport. */
1328     wined3d_mutex_lock();
1329     wined3d_device_set_viewport(device->wined3d_device, (const struct wined3d_viewport *)viewport);
1330     wined3d_mutex_unlock();
1331 
1332     return D3D_OK;
1333 }
1334 
1335 static HRESULT WINAPI d3d8_device_GetViewport(IDirect3DDevice8 *iface, D3DVIEWPORT8 *viewport)
1336 {
1337     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1338 
1339     TRACE("iface %p, viewport %p.\n", iface, viewport);
1340 
1341     /* Note: D3DVIEWPORT8 is compatible with struct wined3d_viewport. */
1342     wined3d_mutex_lock();
1343     wined3d_device_get_viewport(device->wined3d_device, (struct wined3d_viewport *)viewport);
1344     wined3d_mutex_unlock();
1345 
1346     return D3D_OK;
1347 }
1348 
1349 static HRESULT WINAPI d3d8_device_SetMaterial(IDirect3DDevice8 *iface, const D3DMATERIAL8 *material)
1350 {
1351     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1352 
1353     TRACE("iface %p, material %p.\n", iface, material);
1354 
1355     /* Note: D3DMATERIAL8 is compatible with struct wined3d_material. */
1356     wined3d_mutex_lock();
1357     wined3d_device_set_material(device->wined3d_device, (const struct wined3d_material *)material);
1358     wined3d_mutex_unlock();
1359 
1360     return D3D_OK;
1361 }
1362 
1363 static HRESULT WINAPI d3d8_device_GetMaterial(IDirect3DDevice8 *iface, D3DMATERIAL8 *material)
1364 {
1365     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1366 
1367     TRACE("iface %p, material %p.\n", iface, material);
1368 
1369     /* Note: D3DMATERIAL8 is compatible with struct wined3d_material. */
1370     wined3d_mutex_lock();
1371     wined3d_device_get_material(device->wined3d_device, (struct wined3d_material *)material);
1372     wined3d_mutex_unlock();
1373 
1374     return D3D_OK;
1375 }
1376 
1377 static HRESULT WINAPI d3d8_device_SetLight(IDirect3DDevice8 *iface, DWORD index, const D3DLIGHT8 *light)
1378 {
1379     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1380     HRESULT hr;
1381 
1382     TRACE("iface %p, index %u, light %p.\n", iface, index, light);
1383 
1384     /* Note: D3DLIGHT8 is compatible with struct wined3d_light. */
1385     wined3d_mutex_lock();
1386     hr = wined3d_device_set_light(device->wined3d_device, index, (const struct wined3d_light *)light);
1387     wined3d_mutex_unlock();
1388 
1389     return hr;
1390 }
1391 
1392 static HRESULT WINAPI d3d8_device_GetLight(IDirect3DDevice8 *iface, DWORD index, D3DLIGHT8 *light)
1393 {
1394     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1395     HRESULT hr;
1396 
1397     TRACE("iface %p, index %u, light %p.\n", iface, index, light);
1398 
1399     /* Note: D3DLIGHT8 is compatible with struct wined3d_light. */
1400     wined3d_mutex_lock();
1401     hr = wined3d_device_get_light(device->wined3d_device, index, (struct wined3d_light *)light);
1402     wined3d_mutex_unlock();
1403 
1404     return hr;
1405 }
1406 
1407 static HRESULT WINAPI d3d8_device_LightEnable(IDirect3DDevice8 *iface, DWORD index, BOOL enable)
1408 {
1409     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1410     HRESULT hr;
1411 
1412     TRACE("iface %p, index %u, enable %#x.\n", iface, index, enable);
1413 
1414     wined3d_mutex_lock();
1415     hr = wined3d_device_set_light_enable(device->wined3d_device, index, enable);
1416     wined3d_mutex_unlock();
1417 
1418     return hr;
1419 }
1420 
1421 static HRESULT WINAPI d3d8_device_GetLightEnable(IDirect3DDevice8 *iface, DWORD index, BOOL *enable)
1422 {
1423     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1424     HRESULT hr;
1425 
1426     TRACE("iface %p, index %u, enable %p.\n", iface, index, enable);
1427 
1428     wined3d_mutex_lock();
1429     hr = wined3d_device_get_light_enable(device->wined3d_device, index, enable);
1430     wined3d_mutex_unlock();
1431 
1432     return hr;
1433 }
1434 
1435 static HRESULT WINAPI d3d8_device_SetClipPlane(IDirect3DDevice8 *iface, DWORD index, const float *plane)
1436 {
1437     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1438     HRESULT hr;
1439 
1440     TRACE("iface %p, index %u, plane %p.\n", iface, index, plane);
1441 
1442     wined3d_mutex_lock();
1443     hr = wined3d_device_set_clip_plane(device->wined3d_device, index, (const struct wined3d_vec4 *)plane);
1444     wined3d_mutex_unlock();
1445 
1446     return hr;
1447 }
1448 
1449 static HRESULT WINAPI d3d8_device_GetClipPlane(IDirect3DDevice8 *iface, DWORD index, float *plane)
1450 {
1451     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1452     HRESULT hr;
1453 
1454     TRACE("iface %p, index %u, plane %p.\n", iface, index, plane);
1455 
1456     wined3d_mutex_lock();
1457     hr = wined3d_device_get_clip_plane(device->wined3d_device, index, (struct wined3d_vec4 *)plane);
1458     wined3d_mutex_unlock();
1459 
1460     return hr;
1461 }
1462 
1463 static HRESULT WINAPI d3d8_device_SetRenderState(IDirect3DDevice8 *iface,
1464         D3DRENDERSTATETYPE state, DWORD value)
1465 {
1466     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1467 
1468     TRACE("iface %p, state %#x, value %#x.\n", iface, state, value);
1469 
1470     wined3d_mutex_lock();
1471     switch (state)
1472     {
1473         case D3DRS_ZBIAS:
1474             wined3d_device_set_render_state(device->wined3d_device, WINED3D_RS_DEPTHBIAS, value);
1475             break;
1476 
1477         default:
1478             wined3d_device_set_render_state(device->wined3d_device, state, value);
1479     }
1480     wined3d_mutex_unlock();
1481 
1482     return D3D_OK;
1483 }
1484 
1485 static HRESULT WINAPI d3d8_device_GetRenderState(IDirect3DDevice8 *iface,
1486         D3DRENDERSTATETYPE state, DWORD *value)
1487 {
1488     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1489 
1490     TRACE("iface %p, state %#x, value %p.\n", iface, state, value);
1491 
1492     wined3d_mutex_lock();
1493     switch (state)
1494     {
1495         case D3DRS_ZBIAS:
1496             *value = wined3d_device_get_render_state(device->wined3d_device, WINED3D_RS_DEPTHBIAS);
1497             break;
1498 
1499         default:
1500             *value = wined3d_device_get_render_state(device->wined3d_device, state);
1501     }
1502     wined3d_mutex_unlock();
1503 
1504     return D3D_OK;
1505 }
1506 
1507 static HRESULT WINAPI d3d8_device_BeginStateBlock(IDirect3DDevice8 *iface)
1508 {
1509     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1510     HRESULT hr;
1511 
1512     TRACE("iface %p.\n", iface);
1513 
1514     wined3d_mutex_lock();
1515     hr = wined3d_device_begin_stateblock(device->wined3d_device);
1516     wined3d_mutex_unlock();
1517 
1518     return hr;
1519 }
1520 
1521 static HRESULT WINAPI d3d8_device_EndStateBlock(IDirect3DDevice8 *iface, DWORD *token)
1522 {
1523     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1524     struct wined3d_stateblock *stateblock;
1525     HRESULT hr;
1526 
1527     TRACE("iface %p, token %p.\n", iface, token);
1528 
1529     /* Tell wineD3D to endstateblock before anything else (in case we run out
1530      * of memory later and cause locking problems)
1531      */
1532     wined3d_mutex_lock();
1533     hr = wined3d_device_end_stateblock(device->wined3d_device, &stateblock);
1534     if (FAILED(hr))
1535     {
1536         WARN("IWineD3DDevice_EndStateBlock returned an error\n");
1537         wined3d_mutex_unlock();
1538         return hr;
1539     }
1540 
1541     *token = d3d8_allocate_handle(&device->handle_table, stateblock, D3D8_HANDLE_SB);
1542     wined3d_mutex_unlock();
1543 
1544     if (*token == D3D8_INVALID_HANDLE)
1545     {
1546         ERR("Failed to create a handle\n");
1547         wined3d_mutex_lock();
1548         wined3d_stateblock_decref(stateblock);
1549         wined3d_mutex_unlock();
1550         return E_FAIL;
1551     }
1552     ++*token;
1553 
1554     TRACE("Returning %#x (%p).\n", *token, stateblock);
1555 
1556     return hr;
1557 }
1558 
1559 static HRESULT WINAPI d3d8_device_ApplyStateBlock(IDirect3DDevice8 *iface, DWORD token)
1560 {
1561     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1562     struct wined3d_stateblock *stateblock;
1563 
1564     TRACE("iface %p, token %#x.\n", iface, token);
1565 
1566     if (!token)
1567         return D3D_OK;
1568 
1569     wined3d_mutex_lock();
1570     stateblock = d3d8_get_object(&device->handle_table, token - 1, D3D8_HANDLE_SB);
1571     if (!stateblock)
1572     {
1573         WARN("Invalid handle (%#x) passed.\n", token);
1574         wined3d_mutex_unlock();
1575         return D3DERR_INVALIDCALL;
1576     }
1577     wined3d_stateblock_apply(stateblock);
1578     wined3d_mutex_unlock();
1579 
1580     return D3D_OK;
1581 }
1582 
1583 static HRESULT WINAPI d3d8_device_CaptureStateBlock(IDirect3DDevice8 *iface, DWORD token)
1584 {
1585     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1586     struct wined3d_stateblock *stateblock;
1587 
1588     TRACE("iface %p, token %#x.\n", iface, token);
1589 
1590     wined3d_mutex_lock();
1591     stateblock = d3d8_get_object(&device->handle_table, token - 1, D3D8_HANDLE_SB);
1592     if (!stateblock)
1593     {
1594         WARN("Invalid handle (%#x) passed.\n", token);
1595         wined3d_mutex_unlock();
1596         return D3DERR_INVALIDCALL;
1597     }
1598     wined3d_stateblock_capture(stateblock);
1599     wined3d_mutex_unlock();
1600 
1601     return D3D_OK;
1602 }
1603 
1604 static HRESULT WINAPI d3d8_device_DeleteStateBlock(IDirect3DDevice8 *iface, DWORD token)
1605 {
1606     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1607     struct wined3d_stateblock *stateblock;
1608 
1609     TRACE("iface %p, token %#x.\n", iface, token);
1610 
1611     wined3d_mutex_lock();
1612     stateblock = d3d8_free_handle(&device->handle_table, token - 1, D3D8_HANDLE_SB);
1613 
1614     if (!stateblock)
1615     {
1616         WARN("Invalid handle (%#x) passed.\n", token);
1617         wined3d_mutex_unlock();
1618         return D3DERR_INVALIDCALL;
1619     }
1620 
1621     if (wined3d_stateblock_decref(stateblock))
1622     {
1623         ERR("Stateblock %p has references left, this shouldn't happen.\n", stateblock);
1624     }
1625     wined3d_mutex_unlock();
1626 
1627     return D3D_OK;
1628 }
1629 
1630 static HRESULT WINAPI d3d8_device_CreateStateBlock(IDirect3DDevice8 *iface,
1631         D3DSTATEBLOCKTYPE type, DWORD *handle)
1632 {
1633     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1634     struct wined3d_stateblock *stateblock;
1635     HRESULT hr;
1636 
1637     TRACE("iface %p, type %#x, handle %p.\n", iface, type, handle);
1638 
1639     if (type != D3DSBT_ALL
1640             && type != D3DSBT_PIXELSTATE
1641             && type != D3DSBT_VERTEXSTATE)
1642     {
1643         WARN("Unexpected stateblock type, returning D3DERR_INVALIDCALL\n");
1644         return D3DERR_INVALIDCALL;
1645     }
1646 
1647     wined3d_mutex_lock();
1648     hr = wined3d_stateblock_create(device->wined3d_device, (enum wined3d_stateblock_type)type, &stateblock);
1649     if (FAILED(hr))
1650     {
1651         wined3d_mutex_unlock();
1652         ERR("IWineD3DDevice_CreateStateBlock failed, hr %#x\n", hr);
1653         return hr;
1654     }
1655 
1656     *handle = d3d8_allocate_handle(&device->handle_table, stateblock, D3D8_HANDLE_SB);
1657     wined3d_mutex_unlock();
1658 
1659     if (*handle == D3D8_INVALID_HANDLE)
1660     {
1661         ERR("Failed to allocate a handle.\n");
1662         wined3d_mutex_lock();
1663         wined3d_stateblock_decref(stateblock);
1664         wined3d_mutex_unlock();
1665         return E_FAIL;
1666     }
1667     ++*handle;
1668 
1669     TRACE("Returning %#x (%p).\n", *handle, stateblock);
1670 
1671     return hr;
1672 }
1673 
1674 static HRESULT WINAPI d3d8_device_SetClipStatus(IDirect3DDevice8 *iface, const D3DCLIPSTATUS8 *clip_status)
1675 {
1676     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1677     HRESULT hr;
1678 
1679     TRACE("iface %p, clip_status %p.\n", iface, clip_status);
1680     /* FIXME: Verify that D3DCLIPSTATUS8 ~= struct wined3d_clip_status. */
1681 
1682     wined3d_mutex_lock();
1683     hr = wined3d_device_set_clip_status(device->wined3d_device, (const struct wined3d_clip_status *)clip_status);
1684     wined3d_mutex_unlock();
1685 
1686     return hr;
1687 }
1688 
1689 static HRESULT WINAPI d3d8_device_GetClipStatus(IDirect3DDevice8 *iface, D3DCLIPSTATUS8 *clip_status)
1690 {
1691     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1692     HRESULT hr;
1693 
1694     TRACE("iface %p, clip_status %p.\n", iface, clip_status);
1695 
1696     wined3d_mutex_lock();
1697     hr = wined3d_device_get_clip_status(device->wined3d_device, (struct wined3d_clip_status *)clip_status);
1698     wined3d_mutex_unlock();
1699 
1700     return hr;
1701 }
1702 
1703 static HRESULT WINAPI d3d8_device_GetTexture(IDirect3DDevice8 *iface, DWORD stage, IDirect3DBaseTexture8 **texture)
1704 {
1705     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1706     struct wined3d_texture *wined3d_texture;
1707     struct d3d8_texture *texture_impl;
1708 
1709     TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
1710 
1711     if (!texture)
1712         return D3DERR_INVALIDCALL;
1713 
1714     wined3d_mutex_lock();
1715     if ((wined3d_texture = wined3d_device_get_texture(device->wined3d_device, stage)))
1716     {
1717         texture_impl = wined3d_texture_get_parent(wined3d_texture);
1718         *texture = &texture_impl->IDirect3DBaseTexture8_iface;
1719         IDirect3DBaseTexture8_AddRef(*texture);
1720     }
1721     else
1722     {
1723         *texture = NULL;
1724     }
1725     wined3d_mutex_unlock();
1726 
1727     return D3D_OK;
1728 }
1729 
1730 static HRESULT WINAPI d3d8_device_SetTexture(IDirect3DDevice8 *iface, DWORD stage, IDirect3DBaseTexture8 *texture)
1731 {
1732     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1733     struct d3d8_texture *texture_impl;
1734     HRESULT hr;
1735 
1736     TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
1737 
1738     texture_impl = unsafe_impl_from_IDirect3DBaseTexture8(texture);
1739 
1740     wined3d_mutex_lock();
1741     hr = wined3d_device_set_texture(device->wined3d_device, stage,
1742             texture_impl ? texture_impl->wined3d_texture : NULL);
1743     wined3d_mutex_unlock();
1744 
1745     return hr;
1746 }
1747 
1748 static const struct tss_lookup
1749 {
1750     BOOL sampler_state;
1751     enum wined3d_texture_stage_state state;
1752 }
1753 tss_lookup[] =
1754 {
1755     {FALSE, WINED3D_TSS_INVALID},                   /*  0, unused */
1756     {FALSE, WINED3D_TSS_COLOR_OP},                  /*  1, D3DTSS_COLOROP */
1757     {FALSE, WINED3D_TSS_COLOR_ARG1},                /*  2, D3DTSS_COLORARG1 */
1758     {FALSE, WINED3D_TSS_COLOR_ARG2},                /*  3, D3DTSS_COLORARG2 */
1759     {FALSE, WINED3D_TSS_ALPHA_OP},                  /*  4, D3DTSS_ALPHAOP */
1760     {FALSE, WINED3D_TSS_ALPHA_ARG1},                /*  5, D3DTSS_ALPHAARG1 */
1761     {FALSE, WINED3D_TSS_ALPHA_ARG2},                /*  6, D3DTSS_ALPHAARG2 */
1762     {FALSE, WINED3D_TSS_BUMPENV_MAT00},             /*  7, D3DTSS_BUMPENVMAT00 */
1763     {FALSE, WINED3D_TSS_BUMPENV_MAT01},             /*  8, D3DTSS_BUMPENVMAT01 */
1764     {FALSE, WINED3D_TSS_BUMPENV_MAT10},             /*  9, D3DTSS_BUMPENVMAT10 */
1765     {FALSE, WINED3D_TSS_BUMPENV_MAT11},             /* 10, D3DTSS_BUMPENVMAT11 */
1766     {FALSE, WINED3D_TSS_TEXCOORD_INDEX},            /* 11, D3DTSS_TEXCOORDINDEX */
1767     {FALSE, WINED3D_TSS_INVALID},                   /* 12, unused */
1768     {TRUE,  WINED3D_SAMP_ADDRESS_U},                /* 13, D3DTSS_ADDRESSU */
1769     {TRUE,  WINED3D_SAMP_ADDRESS_V},                /* 14, D3DTSS_ADDRESSV */
1770     {TRUE,  WINED3D_SAMP_BORDER_COLOR},             /* 15, D3DTSS_BORDERCOLOR */
1771     {TRUE,  WINED3D_SAMP_MAG_FILTER},               /* 16, D3DTSS_MAGFILTER */
1772     {TRUE,  WINED3D_SAMP_MIN_FILTER},               /* 17, D3DTSS_MINFILTER */
1773     {TRUE,  WINED3D_SAMP_MIP_FILTER},               /* 18, D3DTSS_MIPFILTER */
1774     {TRUE,  WINED3D_SAMP_MIPMAP_LOD_BIAS},          /* 19, D3DTSS_MIPMAPLODBIAS */
1775     {TRUE,  WINED3D_SAMP_MAX_MIP_LEVEL},            /* 20, D3DTSS_MAXMIPLEVEL */
1776     {TRUE,  WINED3D_SAMP_MAX_ANISOTROPY},           /* 21, D3DTSS_MAXANISOTROPY */
1777     {FALSE, WINED3D_TSS_BUMPENV_LSCALE},            /* 22, D3DTSS_BUMPENVLSCALE */
1778     {FALSE, WINED3D_TSS_BUMPENV_LOFFSET},           /* 23, D3DTSS_BUMPENVLOFFSET */
1779     {FALSE, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS},   /* 24, D3DTSS_TEXTURETRANSFORMFLAGS */
1780     {TRUE,  WINED3D_SAMP_ADDRESS_W},                /* 25, D3DTSS_ADDRESSW */
1781     {FALSE, WINED3D_TSS_COLOR_ARG0},                /* 26, D3DTSS_COLORARG0 */
1782     {FALSE, WINED3D_TSS_ALPHA_ARG0},                /* 27, D3DTSS_ALPHAARG0 */
1783     {FALSE, WINED3D_TSS_RESULT_ARG},                /* 28, D3DTSS_RESULTARG */
1784 };
1785 
1786 static HRESULT WINAPI d3d8_device_GetTextureStageState(IDirect3DDevice8 *iface,
1787         DWORD stage, D3DTEXTURESTAGESTATETYPE Type, DWORD *value)
1788 {
1789     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1790     const struct tss_lookup *l;
1791 
1792     TRACE("iface %p, stage %u, state %#x, value %p.\n", iface, stage, Type, value);
1793 
1794     if (Type >= sizeof(tss_lookup) / sizeof(*tss_lookup))
1795     {
1796         WARN("Invalid Type %#x passed.\n", Type);
1797         return D3D_OK;
1798     }
1799 
1800     l = &tss_lookup[Type];
1801 
1802     wined3d_mutex_lock();
1803     if (l->sampler_state)
1804         *value = wined3d_device_get_sampler_state(device->wined3d_device, stage, l->state);
1805     else
1806         *value = wined3d_device_get_texture_stage_state(device->wined3d_device, stage, l->state);
1807     wined3d_mutex_unlock();
1808 
1809     return D3D_OK;
1810 }
1811 
1812 static HRESULT WINAPI d3d8_device_SetTextureStageState(IDirect3DDevice8 *iface,
1813         DWORD stage, D3DTEXTURESTAGESTATETYPE type, DWORD value)
1814 {
1815     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1816     const struct tss_lookup *l;
1817 
1818     TRACE("iface %p, stage %u, state %#x, value %#x.\n", iface, stage, type, value);
1819 
1820     if (type >= sizeof(tss_lookup) / sizeof(*tss_lookup))
1821     {
1822         WARN("Invalid type %#x passed.\n", type);
1823         return D3D_OK;
1824     }
1825 
1826     l = &tss_lookup[type];
1827 
1828     wined3d_mutex_lock();
1829     if (l->sampler_state)
1830         wined3d_device_set_sampler_state(device->wined3d_device, stage, l->state, value);
1831     else
1832         wined3d_device_set_texture_stage_state(device->wined3d_device, stage, l->state, value);
1833     wined3d_mutex_unlock();
1834 
1835     return D3D_OK;
1836 }
1837 
1838 static HRESULT WINAPI d3d8_device_ValidateDevice(IDirect3DDevice8 *iface, DWORD *pass_count)
1839 {
1840     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1841     HRESULT hr;
1842 
1843     TRACE("iface %p, pass_count %p.\n", iface, pass_count);
1844 
1845     wined3d_mutex_lock();
1846     hr = wined3d_device_validate_device(device->wined3d_device, pass_count);
1847     wined3d_mutex_unlock();
1848 
1849     return hr;
1850 }
1851 
1852 static HRESULT WINAPI d3d8_device_GetInfo(IDirect3DDevice8 *iface,
1853         DWORD info_id, void *info, DWORD info_size)
1854 {
1855     FIXME("iface %p, info_id %#x, info %p, info_size %u stub!\n", iface, info_id, info, info_size);
1856 
1857     return D3D_OK;
1858 }
1859 
1860 static HRESULT WINAPI d3d8_device_SetPaletteEntries(IDirect3DDevice8 *iface,
1861         UINT palette_idx, const PALETTEENTRY *entries)
1862 {
1863     WARN("iface %p, palette_idx %u, entries %p unimplemented\n", iface, palette_idx, entries);
1864 
1865     /* GPUs stopped supporting palettized textures with the Shader Model 1 generation. Wined3d
1866      * does not have a d3d8/9-style palette API */
1867 
1868     return D3D_OK;
1869 }
1870 
1871 static HRESULT WINAPI d3d8_device_GetPaletteEntries(IDirect3DDevice8 *iface,
1872         UINT palette_idx, PALETTEENTRY *entries)
1873 {
1874     FIXME("iface %p, palette_idx %u, entries %p unimplemented.\n", iface, palette_idx, entries);
1875 
1876     return D3DERR_INVALIDCALL;
1877 }
1878 
1879 static HRESULT WINAPI d3d8_device_SetCurrentTexturePalette(IDirect3DDevice8 *iface, UINT palette_idx)
1880 {
1881     WARN("iface %p, palette_idx %u unimplemented.\n", iface, palette_idx);
1882 
1883     return D3D_OK;
1884 }
1885 
1886 static HRESULT WINAPI d3d8_device_GetCurrentTexturePalette(IDirect3DDevice8 *iface, UINT *palette_idx)
1887 {
1888     FIXME("iface %p, palette_idx %p unimplemented.\n", iface, palette_idx);
1889 
1890     return D3DERR_INVALIDCALL;
1891 }
1892 
1893 static HRESULT WINAPI d3d8_device_DrawPrimitive(IDirect3DDevice8 *iface,
1894         D3DPRIMITIVETYPE primitive_type, UINT start_vertex, UINT primitive_count)
1895 {
1896     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1897     HRESULT hr;
1898 
1899     TRACE("iface %p, primitive_type %#x, start_vertex %u, primitive_count %u.\n",
1900             iface, primitive_type, start_vertex, primitive_count);
1901 
1902     wined3d_mutex_lock();
1903     wined3d_device_set_primitive_type(device->wined3d_device, primitive_type);
1904     hr = wined3d_device_draw_primitive(device->wined3d_device, start_vertex,
1905             vertex_count_from_primitive_count(primitive_type, primitive_count));
1906     wined3d_mutex_unlock();
1907 
1908     return hr;
1909 }
1910 
1911 static HRESULT WINAPI d3d8_device_DrawIndexedPrimitive(IDirect3DDevice8 *iface,
1912         D3DPRIMITIVETYPE primitive_type, UINT min_vertex_idx, UINT vertex_count,
1913         UINT start_idx, UINT primitive_count)
1914 {
1915     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1916     HRESULT hr;
1917 
1918     TRACE("iface %p, primitive_type %#x, min_vertex_idx %u, vertex_count %u, start_idx %u, primitive_count %u.\n",
1919             iface, primitive_type, min_vertex_idx, vertex_count, start_idx, primitive_count);
1920 
1921     wined3d_mutex_lock();
1922     wined3d_device_set_primitive_type(device->wined3d_device, primitive_type);
1923     hr = wined3d_device_draw_indexed_primitive(device->wined3d_device, start_idx,
1924             vertex_count_from_primitive_count(primitive_type, primitive_count));
1925     wined3d_mutex_unlock();
1926 
1927     return hr;
1928 }
1929 
1930 /* The caller is responsible for wined3d locking */
1931 static HRESULT d3d8_device_prepare_vertex_buffer(struct d3d8_device *device, UINT min_size)
1932 {
1933     HRESULT hr;
1934 
1935     if (device->vertex_buffer_size < min_size || !device->vertex_buffer)
1936     {
1937         UINT size = max(device->vertex_buffer_size * 2, min_size);
1938         struct wined3d_buffer *buffer;
1939 
1940         TRACE("Growing vertex buffer to %u bytes\n", size);
1941 
1942         hr = wined3d_buffer_create_vb(device->wined3d_device, size, WINED3DUSAGE_DYNAMIC | WINED3DUSAGE_WRITEONLY,
1943                 WINED3D_POOL_DEFAULT, NULL, &d3d8_null_wined3d_parent_ops, &buffer);
1944         if (FAILED(hr))
1945         {
1946             ERR("(%p) wined3d_buffer_create_vb failed with hr = %08x\n", device, hr);
1947             return hr;
1948         }
1949 
1950         if (device->vertex_buffer)
1951             wined3d_buffer_decref(device->vertex_buffer);
1952 
1953         device->vertex_buffer = buffer;
1954         device->vertex_buffer_size = size;
1955         device->vertex_buffer_pos = 0;
1956     }
1957     return D3D_OK;
1958 }
1959 
1960 static HRESULT WINAPI d3d8_device_DrawPrimitiveUP(IDirect3DDevice8 *iface,
1961         D3DPRIMITIVETYPE primitive_type, UINT primitive_count, const void *data,
1962         UINT stride)
1963 {
1964     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1965     HRESULT hr;
1966     UINT vtx_count = vertex_count_from_primitive_count(primitive_type, primitive_count);
1967     UINT size = vtx_count * stride;
1968     UINT vb_pos, align;
1969     BYTE *buffer_data;
1970 
1971     TRACE("iface %p, primitive_type %#x, primitive_count %u, data %p, stride %u.\n",
1972             iface, primitive_type, primitive_count, data, stride);
1973 
1974     if (!primitive_count)
1975     {
1976         WARN("primitive_count is 0, returning D3D_OK\n");
1977         return D3D_OK;
1978     }
1979 
1980     wined3d_mutex_lock();
1981     hr = d3d8_device_prepare_vertex_buffer(device, size);
1982     if (FAILED(hr))
1983         goto done;
1984 
1985     vb_pos = device->vertex_buffer_pos;
1986     align = vb_pos % stride;
1987     if (align) align = stride - align;
1988     if (vb_pos + size + align > device->vertex_buffer_size)
1989         vb_pos = 0;
1990     else
1991         vb_pos += align;
1992 
1993     hr = wined3d_buffer_map(device->vertex_buffer, vb_pos, size, &buffer_data,
1994             vb_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD);
1995     if (FAILED(hr))
1996         goto done;
1997     memcpy(buffer_data, data, size);
1998     wined3d_buffer_unmap(device->vertex_buffer);
1999     device->vertex_buffer_pos = vb_pos + size;
2000 
2001     hr = wined3d_device_set_stream_source(device->wined3d_device, 0, device->vertex_buffer, 0, stride);
2002     if (FAILED(hr))
2003         goto done;
2004 
2005     wined3d_device_set_primitive_type(device->wined3d_device, primitive_type);
2006     hr = wined3d_device_draw_primitive(device->wined3d_device, vb_pos / stride, vtx_count);
2007     wined3d_device_set_stream_source(device->wined3d_device, 0, NULL, 0, 0);
2008 
2009 done:
2010     wined3d_mutex_unlock();
2011     return hr;
2012 }
2013 
2014 /* The caller is responsible for wined3d locking */
2015 static HRESULT d3d8_device_prepare_index_buffer(struct d3d8_device *device, UINT min_size)
2016 {
2017     HRESULT hr;
2018 
2019     if (device->index_buffer_size < min_size || !device->index_buffer)
2020     {
2021         UINT size = max(device->index_buffer_size * 2, min_size);
2022         struct wined3d_buffer *buffer;
2023 
2024         TRACE("Growing index buffer to %u bytes\n", size);
2025 
2026         hr = wined3d_buffer_create_ib(device->wined3d_device, size, WINED3DUSAGE_DYNAMIC | WINED3DUSAGE_WRITEONLY,
2027                 WINED3D_POOL_DEFAULT, NULL, &d3d8_null_wined3d_parent_ops, &buffer);
2028         if (FAILED(hr))
2029         {
2030             ERR("(%p) wined3d_buffer_create_ib failed with hr = %08x\n", device, hr);
2031             return hr;
2032         }
2033 
2034         if (device->index_buffer)
2035             wined3d_buffer_decref(device->index_buffer);
2036 
2037         device->index_buffer = buffer;
2038         device->index_buffer_size = size;
2039         device->index_buffer_pos = 0;
2040     }
2041     return D3D_OK;
2042 }
2043 
2044 static HRESULT WINAPI d3d8_device_DrawIndexedPrimitiveUP(IDirect3DDevice8 *iface,
2045         D3DPRIMITIVETYPE primitive_type, UINT min_vertex_idx, UINT vertex_count,
2046         UINT primitive_count, const void *index_data, D3DFORMAT index_format,
2047         const void *vertex_data, UINT vertex_stride)
2048 {
2049     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2050     HRESULT hr;
2051     BYTE *buffer_data;
2052 
2053     UINT idx_count = vertex_count_from_primitive_count(primitive_type, primitive_count);
2054     UINT idx_fmt_size = index_format == D3DFMT_INDEX16 ? 2 : 4;
2055     UINT idx_size = idx_count * idx_fmt_size;
2056     UINT ib_pos;
2057 
2058     UINT vtx_size = vertex_count * vertex_stride;
2059     UINT vb_pos, align;
2060 
2061     TRACE("iface %p, primitive_type %#x, min_vertex_idx %u, vertex_count %u, primitive_count %u,\n"
2062             "index_data %p, index_format %#x, vertex_data %p, vertex_stride %u.\n",
2063             iface, primitive_type, min_vertex_idx, vertex_count, primitive_count,
2064             index_data, index_format, vertex_data, vertex_stride);
2065 
2066     if (!primitive_count)
2067     {
2068         WARN("primitive_count is 0, returning D3D_OK\n");
2069         return D3D_OK;
2070     }
2071 
2072     wined3d_mutex_lock();
2073 
2074     hr = d3d8_device_prepare_vertex_buffer(device, vtx_size);
2075     if (FAILED(hr))
2076         goto done;
2077 
2078     vb_pos = device->vertex_buffer_pos;
2079     align = vb_pos % vertex_stride;
2080     if (align) align = vertex_stride - align;
2081     if (vb_pos + vtx_size + align > device->vertex_buffer_size)
2082         vb_pos = 0;
2083     else
2084         vb_pos += align;
2085 
2086     hr = wined3d_buffer_map(device->vertex_buffer, vb_pos, vtx_size, &buffer_data,
2087             vb_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD);
2088     if (FAILED(hr))
2089         goto done;
2090     memcpy(buffer_data, vertex_data, vtx_size);
2091     wined3d_buffer_unmap(device->vertex_buffer);
2092     device->vertex_buffer_pos = vb_pos + vtx_size;
2093 
2094     hr = d3d8_device_prepare_index_buffer(device, idx_size);
2095     if (FAILED(hr))
2096         goto done;
2097 
2098     ib_pos = device->index_buffer_pos;
2099     align = ib_pos % idx_fmt_size;
2100     if (align) align = idx_fmt_size - align;
2101     if (ib_pos + idx_size + align > device->index_buffer_size)
2102         ib_pos = 0;
2103     else
2104         ib_pos += align;
2105 
2106     hr = wined3d_buffer_map(device->index_buffer, ib_pos, idx_size, &buffer_data,
2107             ib_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD);
2108     if (FAILED(hr))
2109         goto done;
2110     memcpy(buffer_data, index_data, idx_size);
2111     wined3d_buffer_unmap(device->index_buffer);
2112     device->index_buffer_pos = ib_pos + idx_size;
2113 
2114     hr = wined3d_device_set_stream_source(device->wined3d_device, 0, device->vertex_buffer, 0, vertex_stride);
2115     if (FAILED(hr))
2116         goto done;
2117 
2118     wined3d_device_set_index_buffer(device->wined3d_device, device->index_buffer,
2119             wined3dformat_from_d3dformat(index_format));
2120     wined3d_device_set_base_vertex_index(device->wined3d_device, vb_pos / vertex_stride);
2121 
2122     wined3d_device_set_primitive_type(device->wined3d_device, primitive_type);
2123     hr = wined3d_device_draw_indexed_primitive(device->wined3d_device, ib_pos / idx_fmt_size, idx_count);
2124 
2125     wined3d_device_set_stream_source(device->wined3d_device, 0, NULL, 0, 0);
2126     wined3d_device_set_index_buffer(device->wined3d_device, NULL, WINED3DFMT_UNKNOWN);
2127     wined3d_device_set_base_vertex_index(device->wined3d_device, 0);
2128 
2129 done:
2130     wined3d_mutex_unlock();
2131     return hr;
2132 }
2133 
2134 static HRESULT WINAPI d3d8_device_ProcessVertices(IDirect3DDevice8 *iface, UINT src_start_idx,
2135         UINT dst_idx, UINT vertex_count, IDirect3DVertexBuffer8 *dst_buffer, DWORD flags)
2136 {
2137     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2138     struct d3d8_vertexbuffer *dst = unsafe_impl_from_IDirect3DVertexBuffer8(dst_buffer);
2139     HRESULT hr;
2140 
2141     TRACE("iface %p, src_start_idx %u, dst_idx %u, vertex_count %u, dst_buffer %p, flags %#x.\n",
2142             iface, src_start_idx, dst_idx, vertex_count, dst_buffer, flags);
2143 
2144     wined3d_mutex_lock();
2145     hr = wined3d_device_process_vertices(device->wined3d_device, src_start_idx, dst_idx,
2146             vertex_count, dst->wined3d_buffer, NULL, flags, dst->fvf);
2147     wined3d_mutex_unlock();
2148 
2149     return hr;
2150 }
2151 
2152 static HRESULT WINAPI d3d8_device_CreateVertexShader(IDirect3DDevice8 *iface,
2153         const DWORD *declaration, const DWORD *byte_code, DWORD *shader, DWORD usage)
2154 {
2155     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2156     struct d3d8_vertex_shader *object;
2157     DWORD shader_handle;
2158     DWORD handle;
2159     HRESULT hr;
2160 
2161     TRACE("iface %p, declaration %p, byte_code %p, shader %p, usage %#x.\n",
2162             iface, declaration, byte_code, shader, usage);
2163 
2164     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2165     if (!object)
2166     {
2167         *shader = 0;
2168         return E_OUTOFMEMORY;
2169     }
2170 
2171     wined3d_mutex_lock();
2172     handle = d3d8_allocate_handle(&device->handle_table, object, D3D8_HANDLE_VS);
2173     wined3d_mutex_unlock();
2174     if (handle == D3D8_INVALID_HANDLE)
2175     {
2176         ERR("Failed to allocate vertex shader handle.\n");
2177         HeapFree(GetProcessHeap(), 0, object);
2178         *shader = 0;
2179         return E_OUTOFMEMORY;
2180     }
2181 
2182     shader_handle = handle + VS_HIGHESTFIXEDFXF + 1;
2183 
2184     hr = d3d8_vertex_shader_init(object, device, declaration, byte_code, shader_handle, usage);
2185     if (FAILED(hr))
2186     {
2187         WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
2188         wined3d_mutex_lock();
2189         d3d8_free_handle(&device->handle_table, handle, D3D8_HANDLE_VS);
2190         wined3d_mutex_unlock();
2191         HeapFree(GetProcessHeap(), 0, object);
2192         *shader = 0;
2193         return hr;
2194     }
2195 
2196     TRACE("Created vertex shader %p (handle %#x).\n", object, shader_handle);
2197     *shader = shader_handle;
2198 
2199     return D3D_OK;
2200 }
2201 
2202 static struct d3d8_vertex_declaration *d3d8_device_get_fvf_declaration(struct d3d8_device *device, DWORD fvf)
2203 {
2204     struct d3d8_vertex_declaration *d3d8_declaration;
2205     struct FvfToDecl *convertedDecls = device->decls;
2206     int p, low, high; /* deliberately signed */
2207     HRESULT hr;
2208 
2209     TRACE("Searching for declaration for fvf %08x... ", fvf);
2210 
2211     low = 0;
2212     high = device->numConvertedDecls - 1;
2213     while (low <= high)
2214     {
2215         p = (low + high) >> 1;
2216         TRACE("%d ", p);
2217 
2218         if (convertedDecls[p].fvf == fvf)
2219         {
2220             TRACE("found %p\n", convertedDecls[p].declaration);
2221             return convertedDecls[p].declaration;
2222         }
2223 
2224         if (convertedDecls[p].fvf < fvf)
2225             low = p + 1;
2226         else
2227             high = p - 1;
2228     }
2229     TRACE("not found. Creating and inserting at position %d.\n", low);
2230 
2231     if (!(d3d8_declaration = HeapAlloc(GetProcessHeap(), 0, sizeof(*d3d8_declaration))))
2232         return NULL;
2233 
2234     if (FAILED(hr = d3d8_vertex_declaration_init_fvf(d3d8_declaration, device, fvf)))
2235     {
2236         WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
2237         HeapFree(GetProcessHeap(), 0, d3d8_declaration);
2238         return NULL;
2239     }
2240 
2241     if (device->declArraySize == device->numConvertedDecls)
2242     {
2243         UINT grow = device->declArraySize / 2;
2244 
2245         convertedDecls = HeapReAlloc(GetProcessHeap(), 0, convertedDecls,
2246                 sizeof(*convertedDecls) * (device->numConvertedDecls + grow));
2247         if (!convertedDecls)
2248         {
2249             d3d8_vertex_declaration_destroy(d3d8_declaration);
2250             return NULL;
2251         }
2252         device->decls = convertedDecls;
2253         device->declArraySize += grow;
2254     }
2255 
2256     memmove(convertedDecls + low + 1, convertedDecls + low,
2257             sizeof(*convertedDecls) * (device->numConvertedDecls - low));
2258     convertedDecls[low].declaration = d3d8_declaration;
2259     convertedDecls[low].fvf = fvf;
2260     ++device->numConvertedDecls;
2261 
2262     TRACE("Returning %p. %u decls in array.\n", d3d8_declaration, device->numConvertedDecls);
2263 
2264     return d3d8_declaration;
2265 }
2266 
2267 static HRESULT WINAPI d3d8_device_SetVertexShader(IDirect3DDevice8 *iface, DWORD shader)
2268 {
2269     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2270     struct d3d8_vertex_shader *shader_impl;
2271 
2272     TRACE("iface %p, shader %#x.\n", iface, shader);
2273 
2274     if (VS_HIGHESTFIXEDFXF >= shader)
2275     {
2276         TRACE("Setting FVF, %#x\n", shader);
2277 
2278         wined3d_mutex_lock();
2279         wined3d_device_set_vertex_declaration(device->wined3d_device,
2280                 d3d8_device_get_fvf_declaration(device, shader)->wined3d_vertex_declaration);
2281         wined3d_device_set_vertex_shader(device->wined3d_device, NULL);
2282         wined3d_mutex_unlock();
2283 
2284         return D3D_OK;
2285     }
2286 
2287     TRACE("Setting shader\n");
2288 
2289     wined3d_mutex_lock();
2290     if (!(shader_impl = d3d8_get_object(&device->handle_table, shader - (VS_HIGHESTFIXEDFXF + 1), D3D8_HANDLE_VS)))
2291     {
2292         WARN("Invalid handle (%#x) passed.\n", shader);
2293         wined3d_mutex_unlock();
2294 
2295         return D3DERR_INVALIDCALL;
2296     }
2297 
2298     wined3d_device_set_vertex_declaration(device->wined3d_device,
2299             shader_impl->vertex_declaration->wined3d_vertex_declaration);
2300     wined3d_device_set_vertex_shader(device->wined3d_device, shader_impl->wined3d_shader);
2301     wined3d_mutex_unlock();
2302 
2303     return D3D_OK;
2304 }
2305 
2306 static HRESULT WINAPI d3d8_device_GetVertexShader(IDirect3DDevice8 *iface, DWORD *shader)
2307 {
2308     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2309     struct wined3d_vertex_declaration *wined3d_declaration;
2310     struct d3d8_vertex_declaration *d3d8_declaration;
2311 
2312     TRACE("iface %p, shader %p.\n", iface, shader);
2313 
2314     wined3d_mutex_lock();
2315     if ((wined3d_declaration = wined3d_device_get_vertex_declaration(device->wined3d_device)))
2316     {
2317         d3d8_declaration = wined3d_vertex_declaration_get_parent(wined3d_declaration);
2318         *shader = d3d8_declaration->shader_handle;
2319     }
2320     else
2321     {
2322         *shader = 0;
2323     }
2324     wined3d_mutex_unlock();
2325 
2326     TRACE("Returning %#x.\n", *shader);
2327 
2328     return D3D_OK;
2329 }
2330 
2331 static HRESULT WINAPI d3d8_device_DeleteVertexShader(IDirect3DDevice8 *iface, DWORD shader)
2332 {
2333     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2334     struct d3d8_vertex_shader *shader_impl;
2335 
2336     TRACE("iface %p, shader %#x.\n", iface, shader);
2337 
2338     wined3d_mutex_lock();
2339     if (!(shader_impl = d3d8_free_handle(&device->handle_table, shader - (VS_HIGHESTFIXEDFXF + 1), D3D8_HANDLE_VS)))
2340     {
2341         WARN("Invalid handle (%#x) passed.\n", shader);
2342         wined3d_mutex_unlock();
2343 
2344         return D3DERR_INVALIDCALL;
2345     }
2346 
2347     if (shader_impl->wined3d_shader
2348             && wined3d_device_get_vertex_shader(device->wined3d_device) == shader_impl->wined3d_shader)
2349         IDirect3DDevice8_SetVertexShader(iface, 0);
2350 
2351     wined3d_mutex_unlock();
2352 
2353     d3d8_vertex_shader_destroy(shader_impl);
2354 
2355     return D3D_OK;
2356 }
2357 
2358 static HRESULT WINAPI d3d8_device_SetVertexShaderConstant(IDirect3DDevice8 *iface,
2359         DWORD start_register, const void *data, DWORD count)
2360 {
2361     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2362     HRESULT hr;
2363 
2364     TRACE("iface %p, start_register %u, data %p, count %u.\n",
2365             iface, start_register, data, count);
2366 
2367     if (start_register + count > D3D8_MAX_VERTEX_SHADER_CONSTANTF)
2368     {
2369         WARN("Trying to access %u constants, but d3d8 only supports %u\n",
2370              start_register + count, D3D8_MAX_VERTEX_SHADER_CONSTANTF);
2371         return D3DERR_INVALIDCALL;
2372     }
2373 
2374     wined3d_mutex_lock();
2375     hr = wined3d_device_set_vs_consts_f(device->wined3d_device, start_register, data, count);
2376     wined3d_mutex_unlock();
2377 
2378     return hr;
2379 }
2380 
2381 static HRESULT WINAPI d3d8_device_GetVertexShaderConstant(IDirect3DDevice8 *iface,
2382         DWORD start_register, void *data, DWORD count)
2383 {
2384     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2385     HRESULT hr;
2386 
2387     TRACE("iface %p, start_register %u, data %p, count %u.\n",
2388             iface, start_register, data, count);
2389 
2390     if (start_register + count > D3D8_MAX_VERTEX_SHADER_CONSTANTF)
2391     {
2392         WARN("Trying to access %u constants, but d3d8 only supports %u\n",
2393              start_register + count, D3D8_MAX_VERTEX_SHADER_CONSTANTF);
2394         return D3DERR_INVALIDCALL;
2395     }
2396 
2397     wined3d_mutex_lock();
2398     hr = wined3d_device_get_vs_consts_f(device->wined3d_device, start_register, data, count);
2399     wined3d_mutex_unlock();
2400 
2401     return hr;
2402 }
2403 
2404 static HRESULT WINAPI d3d8_device_GetVertexShaderDeclaration(IDirect3DDevice8 *iface,
2405         DWORD shader, void *data, DWORD *data_size)
2406 {
2407     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2408     struct d3d8_vertex_declaration *declaration;
2409     struct d3d8_vertex_shader *shader_impl;
2410 
2411     TRACE("iface %p, shader %#x, data %p, data_size %p.\n",
2412             iface, shader, data, data_size);
2413 
2414     wined3d_mutex_lock();
2415     shader_impl = d3d8_get_object(&device->handle_table, shader - (VS_HIGHESTFIXEDFXF + 1), D3D8_HANDLE_VS);
2416     wined3d_mutex_unlock();
2417 
2418     if (!shader_impl)
2419     {
2420         WARN("Invalid handle (%#x) passed.\n", shader);
2421         return D3DERR_INVALIDCALL;
2422     }
2423     declaration = shader_impl->vertex_declaration;
2424 
2425     if (!data)
2426     {
2427         *data_size = declaration->elements_size;
2428         return D3D_OK;
2429     }
2430 
2431     /* MSDN claims that if *data_size is smaller than the required size
2432      * we should write the required size and return D3DERR_MOREDATA.
2433      * That's not actually true. */
2434     if (*data_size < declaration->elements_size)
2435         return D3DERR_INVALIDCALL;
2436 
2437     memcpy(data, declaration->elements, declaration->elements_size);
2438 
2439     return D3D_OK;
2440 }
2441 
2442 static HRESULT WINAPI d3d8_device_GetVertexShaderFunction(IDirect3DDevice8 *iface,
2443         DWORD shader, void *data, DWORD *data_size)
2444 {
2445     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2446     struct d3d8_vertex_shader *shader_impl = NULL;
2447     HRESULT hr;
2448 
2449     TRACE("iface %p, shader %#x, data %p, data_size %p.\n",
2450             iface, shader, data, data_size);
2451 
2452     wined3d_mutex_lock();
2453     if (!(shader_impl = d3d8_get_object(&device->handle_table, shader - (VS_HIGHESTFIXEDFXF + 1), D3D8_HANDLE_VS)))
2454     {
2455         WARN("Invalid handle (%#x) passed.\n", shader);
2456         wined3d_mutex_unlock();
2457 
2458         return D3DERR_INVALIDCALL;
2459     }
2460 
2461     if (!shader_impl->wined3d_shader)
2462     {
2463         wined3d_mutex_unlock();
2464         *data_size = 0;
2465         return D3D_OK;
2466     }
2467 
2468     hr = wined3d_shader_get_byte_code(shader_impl->wined3d_shader, data, data_size);
2469     wined3d_mutex_unlock();
2470 
2471     return hr;
2472 }
2473 
2474 static HRESULT WINAPI d3d8_device_SetIndices(IDirect3DDevice8 *iface,
2475         IDirect3DIndexBuffer8 *buffer, UINT base_vertex_idx)
2476 {
2477     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2478     struct d3d8_indexbuffer *ib = unsafe_impl_from_IDirect3DIndexBuffer8(buffer);
2479 
2480     TRACE("iface %p, buffer %p, base_vertex_idx %u.\n", iface, buffer, base_vertex_idx);
2481 
2482     /* WineD3D takes an INT(due to d3d9), but d3d8 uses UINTs. Do I have to add a check here that
2483      * the UINT doesn't cause an overflow in the INT? It seems rather unlikely because such large
2484      * vertex buffers can't be created to address them with an index that requires the 32nd bit
2485      * (4 Byte minimum vertex size * 2^31-1 -> 8 gb buffer. The index sign would be the least
2486      * problem)
2487      */
2488     wined3d_mutex_lock();
2489     wined3d_device_set_base_vertex_index(device->wined3d_device, base_vertex_idx);
2490     wined3d_device_set_index_buffer(device->wined3d_device,
2491             ib ? ib->wined3d_buffer : NULL,
2492             ib ? ib->format : WINED3DFMT_UNKNOWN);
2493     wined3d_mutex_unlock();
2494 
2495     return D3D_OK;
2496 }
2497 
2498 static HRESULT WINAPI d3d8_device_GetIndices(IDirect3DDevice8 *iface,
2499         IDirect3DIndexBuffer8 **buffer, UINT *base_vertex_index)
2500 {
2501     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2502     enum wined3d_format_id wined3d_format;
2503     struct wined3d_buffer *wined3d_buffer;
2504     struct d3d8_indexbuffer *buffer_impl;
2505 
2506     TRACE("iface %p, buffer %p, base_vertex_index %p.\n", iface, buffer, base_vertex_index);
2507 
2508     if (!buffer)
2509         return D3DERR_INVALIDCALL;
2510 
2511     /* The case from UINT to INT is safe because d3d8 will never set negative values */
2512     wined3d_mutex_lock();
2513     *base_vertex_index = wined3d_device_get_base_vertex_index(device->wined3d_device);
2514     if ((wined3d_buffer = wined3d_device_get_index_buffer(device->wined3d_device, &wined3d_format)))
2515     {
2516         buffer_impl = wined3d_buffer_get_parent(wined3d_buffer);
2517         *buffer = &buffer_impl->IDirect3DIndexBuffer8_iface;
2518         IDirect3DIndexBuffer8_AddRef(*buffer);
2519     }
2520     else
2521     {
2522         *buffer = NULL;
2523     }
2524     wined3d_mutex_unlock();
2525 
2526     return D3D_OK;
2527 }
2528 
2529 static HRESULT WINAPI d3d8_device_CreatePixelShader(IDirect3DDevice8 *iface,
2530         const DWORD *byte_code, DWORD *shader)
2531 {
2532     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2533     struct d3d8_pixel_shader *object;
2534     DWORD shader_handle;
2535     DWORD handle;
2536     HRESULT hr;
2537 
2538     TRACE("iface %p, byte_code %p, shader %p.\n", iface, byte_code, shader);
2539 
2540     if (!shader)
2541         return D3DERR_INVALIDCALL;
2542 
2543     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2544     if (!object)
2545         return E_OUTOFMEMORY;
2546 
2547     wined3d_mutex_lock();
2548     handle = d3d8_allocate_handle(&device->handle_table, object, D3D8_HANDLE_PS);
2549     wined3d_mutex_unlock();
2550     if (handle == D3D8_INVALID_HANDLE)
2551     {
2552         ERR("Failed to allocate pixel shader handle.\n");
2553         HeapFree(GetProcessHeap(), 0, object);
2554         return E_OUTOFMEMORY;
2555     }
2556 
2557     shader_handle = handle + VS_HIGHESTFIXEDFXF + 1;
2558 
2559     hr = d3d8_pixel_shader_init(object, device, byte_code, shader_handle);
2560     if (FAILED(hr))
2561     {
2562         WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
2563         wined3d_mutex_lock();
2564         d3d8_free_handle(&device->handle_table, handle, D3D8_HANDLE_PS);
2565         wined3d_mutex_unlock();
2566         HeapFree(GetProcessHeap(), 0, object);
2567         *shader = 0;
2568         return hr;
2569     }
2570 
2571     TRACE("Created pixel shader %p (handle %#x).\n", object, shader_handle);
2572     *shader = shader_handle;
2573 
2574     return D3D_OK;
2575 }
2576 
2577 static HRESULT WINAPI d3d8_device_SetPixelShader(IDirect3DDevice8 *iface, DWORD shader)
2578 {
2579     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2580     struct d3d8_pixel_shader *shader_impl;
2581 
2582     TRACE("iface %p, shader %#x.\n", iface, shader);
2583 
2584     wined3d_mutex_lock();
2585 
2586     if (!shader)
2587     {
2588         wined3d_device_set_pixel_shader(device->wined3d_device, NULL);
2589         wined3d_mutex_unlock();
2590         return D3D_OK;
2591     }
2592 
2593     if (!(shader_impl = d3d8_get_object(&device->handle_table, shader - (VS_HIGHESTFIXEDFXF + 1), D3D8_HANDLE_PS)))
2594     {
2595         WARN("Invalid handle (%#x) passed.\n", shader);
2596         wined3d_mutex_unlock();
2597         return D3DERR_INVALIDCALL;
2598     }
2599 
2600     TRACE("Setting shader %p.\n", shader_impl);
2601     wined3d_device_set_pixel_shader(device->wined3d_device, shader_impl->wined3d_shader);
2602     wined3d_mutex_unlock();
2603 
2604     return D3D_OK;
2605 }
2606 
2607 static HRESULT WINAPI d3d8_device_GetPixelShader(IDirect3DDevice8 *iface, DWORD *shader)
2608 {
2609     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2610     struct wined3d_shader *object;
2611 
2612     TRACE("iface %p, shader %p.\n", iface, shader);
2613 
2614     if (!shader)
2615         return D3DERR_INVALIDCALL;
2616 
2617     wined3d_mutex_lock();
2618     if ((object = wined3d_device_get_pixel_shader(device->wined3d_device)))
2619     {
2620         struct d3d8_pixel_shader *d3d8_shader;
2621         d3d8_shader = wined3d_shader_get_parent(object);
2622         *shader = d3d8_shader->handle;
2623     }
2624     else
2625     {
2626         *shader = 0;
2627     }
2628     wined3d_mutex_unlock();
2629 
2630     TRACE("Returning %#x.\n", *shader);
2631 
2632     return D3D_OK;
2633 }
2634 
2635 static HRESULT WINAPI d3d8_device_DeletePixelShader(IDirect3DDevice8 *iface, DWORD shader)
2636 {
2637     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2638     struct d3d8_pixel_shader *shader_impl;
2639 
2640     TRACE("iface %p, shader %#x.\n", iface, shader);
2641 
2642     wined3d_mutex_lock();
2643 
2644     if (!(shader_impl = d3d8_free_handle(&device->handle_table, shader - (VS_HIGHESTFIXEDFXF + 1), D3D8_HANDLE_PS)))
2645     {
2646         WARN("Invalid handle (%#x) passed.\n", shader);
2647         wined3d_mutex_unlock();
2648         return D3DERR_INVALIDCALL;
2649     }
2650 
2651     if (wined3d_device_get_pixel_shader(device->wined3d_device) == shader_impl->wined3d_shader)
2652         IDirect3DDevice8_SetPixelShader(iface, 0);
2653 
2654     wined3d_mutex_unlock();
2655 
2656     d3d8_pixel_shader_destroy(shader_impl);
2657 
2658     return D3D_OK;
2659 }
2660 
2661 static HRESULT WINAPI d3d8_device_SetPixelShaderConstant(IDirect3DDevice8 *iface,
2662         DWORD start_register, const void *data, DWORD count)
2663 {
2664     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2665     HRESULT hr;
2666 
2667     TRACE("iface %p, start_register %u, data %p, count %u.\n",
2668             iface, start_register, data, count);
2669 
2670     wined3d_mutex_lock();
2671     hr = wined3d_device_set_ps_consts_f(device->wined3d_device, start_register, data, count);
2672     wined3d_mutex_unlock();
2673 
2674     return hr;
2675 }
2676 
2677 static HRESULT WINAPI d3d8_device_GetPixelShaderConstant(IDirect3DDevice8 *iface,
2678         DWORD start_register, void *data, DWORD count)
2679 {
2680     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2681     HRESULT hr;
2682 
2683     TRACE("iface %p, start_register %u, data %p, count %u.\n",
2684             iface, start_register, data, count);
2685 
2686     wined3d_mutex_lock();
2687     hr = wined3d_device_get_ps_consts_f(device->wined3d_device, start_register, data, count);
2688     wined3d_mutex_unlock();
2689 
2690     return hr;
2691 }
2692 
2693 static HRESULT WINAPI d3d8_device_GetPixelShaderFunction(IDirect3DDevice8 *iface,
2694         DWORD shader, void *data, DWORD *data_size)
2695 {
2696     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2697     struct d3d8_pixel_shader *shader_impl = NULL;
2698     HRESULT hr;
2699 
2700     TRACE("iface %p, shader %#x, data %p, data_size %p.\n",
2701             iface, shader, data, data_size);
2702 
2703     wined3d_mutex_lock();
2704     if (!(shader_impl = d3d8_get_object(&device->handle_table, shader - (VS_HIGHESTFIXEDFXF + 1), D3D8_HANDLE_PS)))
2705     {
2706         WARN("Invalid handle (%#x) passed.\n", shader);
2707         wined3d_mutex_unlock();
2708 
2709         return D3DERR_INVALIDCALL;
2710     }
2711 
2712     hr = wined3d_shader_get_byte_code(shader_impl->wined3d_shader, data, data_size);
2713     wined3d_mutex_unlock();
2714 
2715     return hr;
2716 }
2717 
2718 static HRESULT WINAPI d3d8_device_DrawRectPatch(IDirect3DDevice8 *iface, UINT handle,
2719         const float *segment_count, const D3DRECTPATCH_INFO *patch_info)
2720 {
2721     FIXME("iface %p, handle %#x, segment_count %p, patch_info %p unimplemented.\n",
2722             iface, handle, segment_count, patch_info);
2723     return D3D_OK;
2724 }
2725 
2726 static HRESULT WINAPI d3d8_device_DrawTriPatch(IDirect3DDevice8 *iface, UINT handle,
2727         const float *segment_count, const D3DTRIPATCH_INFO *patch_info)
2728 {
2729     FIXME("iface %p, handle %#x, segment_count %p, patch_info %p unimplemented.\n",
2730             iface, handle, segment_count, patch_info);
2731     return D3D_OK;
2732 }
2733 
2734 static HRESULT WINAPI d3d8_device_DeletePatch(IDirect3DDevice8 *iface, UINT handle)
2735 {
2736     FIXME("iface %p, handle %#x unimplemented.\n", iface, handle);
2737     return D3DERR_INVALIDCALL;
2738 }
2739 
2740 static HRESULT WINAPI d3d8_device_SetStreamSource(IDirect3DDevice8 *iface,
2741         UINT stream_idx, IDirect3DVertexBuffer8 *buffer, UINT stride)
2742 {
2743     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2744     struct d3d8_vertexbuffer *buffer_impl = unsafe_impl_from_IDirect3DVertexBuffer8(buffer);
2745     HRESULT hr;
2746 
2747     TRACE("iface %p, stream_idx %u, buffer %p, stride %u.\n",
2748             iface, stream_idx, buffer, stride);
2749 
2750     wined3d_mutex_lock();
2751     hr = wined3d_device_set_stream_source(device->wined3d_device, stream_idx,
2752             buffer_impl ? buffer_impl->wined3d_buffer : NULL, 0, stride);
2753     wined3d_mutex_unlock();
2754 
2755     return hr;
2756 }
2757 
2758 static HRESULT WINAPI d3d8_device_GetStreamSource(IDirect3DDevice8 *iface,
2759         UINT stream_idx, IDirect3DVertexBuffer8 **buffer, UINT *stride)
2760 {
2761     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2762     struct d3d8_vertexbuffer *buffer_impl;
2763     struct wined3d_buffer *wined3d_buffer = NULL;
2764     HRESULT hr;
2765 
2766     TRACE("iface %p, stream_idx %u, buffer %p, stride %p.\n",
2767             iface, stream_idx, buffer, stride);
2768 
2769     if (!buffer)
2770         return D3DERR_INVALIDCALL;
2771 
2772     wined3d_mutex_lock();
2773     hr = wined3d_device_get_stream_source(device->wined3d_device, stream_idx, &wined3d_buffer, 0, stride);
2774     if (SUCCEEDED(hr) && wined3d_buffer)
2775     {
2776         buffer_impl = wined3d_buffer_get_parent(wined3d_buffer);
2777         *buffer = &buffer_impl->IDirect3DVertexBuffer8_iface;
2778         IDirect3DVertexBuffer8_AddRef(*buffer);
2779         wined3d_buffer_decref(wined3d_buffer);
2780     }
2781     else
2782     {
2783         if (FAILED(hr))
2784             ERR("Failed to get wined3d stream source, hr %#x.\n", hr);
2785         *buffer = NULL;
2786     }
2787     wined3d_mutex_unlock();
2788 
2789     return hr;
2790 }
2791 
2792 static const struct IDirect3DDevice8Vtbl d3d8_device_vtbl =
2793 {
2794     d3d8_device_QueryInterface,
2795     d3d8_device_AddRef,
2796     d3d8_device_Release,
2797     d3d8_device_TestCooperativeLevel,
2798     d3d8_device_GetAvailableTextureMem,
2799     d3d8_device_ResourceManagerDiscardBytes,
2800     d3d8_device_GetDirect3D,
2801     d3d8_device_GetDeviceCaps,
2802     d3d8_device_GetDisplayMode,
2803     d3d8_device_GetCreationParameters,
2804     d3d8_device_SetCursorProperties,
2805     d3d8_device_SetCursorPosition,
2806     d3d8_device_ShowCursor,
2807     d3d8_device_CreateAdditionalSwapChain,
2808     d3d8_device_Reset,
2809     d3d8_device_Present,
2810     d3d8_device_GetBackBuffer,
2811     d3d8_device_GetRasterStatus,
2812     d3d8_device_SetGammaRamp,
2813     d3d8_device_GetGammaRamp,
2814     d3d8_device_CreateTexture,
2815     d3d8_device_CreateVolumeTexture,
2816     d3d8_device_CreateCubeTexture,
2817     d3d8_device_CreateVertexBuffer,
2818     d3d8_device_CreateIndexBuffer,
2819     d3d8_device_CreateRenderTarget,
2820     d3d8_device_CreateDepthStencilSurface,
2821     d3d8_device_CreateImageSurface,
2822     d3d8_device_CopyRects,
2823     d3d8_device_UpdateTexture,
2824     d3d8_device_GetFrontBuffer,
2825     d3d8_device_SetRenderTarget,
2826     d3d8_device_GetRenderTarget,
2827     d3d8_device_GetDepthStencilSurface,
2828     d3d8_device_BeginScene,
2829     d3d8_device_EndScene,
2830     d3d8_device_Clear,
2831     d3d8_device_SetTransform,
2832     d3d8_device_GetTransform,
2833     d3d8_device_MultiplyTransform,
2834     d3d8_device_SetViewport,
2835     d3d8_device_GetViewport,
2836     d3d8_device_SetMaterial,
2837     d3d8_device_GetMaterial,
2838     d3d8_device_SetLight,
2839     d3d8_device_GetLight,
2840     d3d8_device_LightEnable,
2841     d3d8_device_GetLightEnable,
2842     d3d8_device_SetClipPlane,
2843     d3d8_device_GetClipPlane,
2844     d3d8_device_SetRenderState,
2845     d3d8_device_GetRenderState,
2846     d3d8_device_BeginStateBlock,
2847     d3d8_device_EndStateBlock,
2848     d3d8_device_ApplyStateBlock,
2849     d3d8_device_CaptureStateBlock,
2850     d3d8_device_DeleteStateBlock,
2851     d3d8_device_CreateStateBlock,
2852     d3d8_device_SetClipStatus,
2853     d3d8_device_GetClipStatus,
2854     d3d8_device_GetTexture,
2855     d3d8_device_SetTexture,
2856     d3d8_device_GetTextureStageState,
2857     d3d8_device_SetTextureStageState,
2858     d3d8_device_ValidateDevice,
2859     d3d8_device_GetInfo,
2860     d3d8_device_SetPaletteEntries,
2861     d3d8_device_GetPaletteEntries,
2862     d3d8_device_SetCurrentTexturePalette,
2863     d3d8_device_GetCurrentTexturePalette,
2864     d3d8_device_DrawPrimitive,
2865     d3d8_device_DrawIndexedPrimitive,
2866     d3d8_device_DrawPrimitiveUP,
2867     d3d8_device_DrawIndexedPrimitiveUP,
2868     d3d8_device_ProcessVertices,
2869     d3d8_device_CreateVertexShader,
2870     d3d8_device_SetVertexShader,
2871     d3d8_device_GetVertexShader,
2872     d3d8_device_DeleteVertexShader,
2873     d3d8_device_SetVertexShaderConstant,
2874     d3d8_device_GetVertexShaderConstant,
2875     d3d8_device_GetVertexShaderDeclaration,
2876     d3d8_device_GetVertexShaderFunction,
2877     d3d8_device_SetStreamSource,
2878     d3d8_device_GetStreamSource,
2879     d3d8_device_SetIndices,
2880     d3d8_device_GetIndices,
2881     d3d8_device_CreatePixelShader,
2882     d3d8_device_SetPixelShader,
2883     d3d8_device_GetPixelShader,
2884     d3d8_device_DeletePixelShader,
2885     d3d8_device_SetPixelShaderConstant,
2886     d3d8_device_GetPixelShaderConstant,
2887     d3d8_device_GetPixelShaderFunction,
2888     d3d8_device_DrawRectPatch,
2889     d3d8_device_DrawTriPatch,
2890     d3d8_device_DeletePatch,
2891 };
2892 
2893 static inline struct d3d8_device *device_from_device_parent(struct wined3d_device_parent *device_parent)
2894 {
2895     return CONTAINING_RECORD(device_parent, struct d3d8_device, device_parent);
2896 }
2897 
2898 static void CDECL device_parent_wined3d_device_created(struct wined3d_device_parent *device_parent,
2899         struct wined3d_device *device)
2900 {
2901     TRACE("device_parent %p, device %p\n", device_parent, device);
2902 }
2903 
2904 static void CDECL device_parent_mode_changed(struct wined3d_device_parent *device_parent)
2905 {
2906     TRACE("device_parent %p.\n", device_parent);
2907 }
2908 
2909 static HRESULT CDECL device_parent_surface_created(struct wined3d_device_parent *device_parent,
2910         void *container_parent, struct wined3d_surface *surface, void **parent,
2911         const struct wined3d_parent_ops **parent_ops)
2912 {
2913     struct d3d8_device *device = device_from_device_parent(device_parent);
2914     struct d3d8_surface *d3d_surface;
2915 
2916     TRACE("device_parent %p, container_parent %p, surface %p, parent %p, parent_ops %p.\n",
2917             device_parent, container_parent, surface, parent, parent_ops);
2918 
2919     if (!(d3d_surface = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*d3d_surface))))
2920     {
2921         FIXME("Failed to allocate surface memory.\n");
2922         return D3DERR_OUTOFVIDEOMEMORY;
2923     }
2924 
2925     surface_init(d3d_surface, surface, device, parent_ops);
2926     *parent = d3d_surface;
2927     TRACE("Created surface %p.\n", d3d_surface);
2928 
2929     d3d_surface->container = container_parent;
2930     IDirect3DDevice8_Release(d3d_surface->parent_device);
2931     d3d_surface->parent_device = NULL;
2932 
2933     IDirect3DSurface8_Release(&d3d_surface->IDirect3DSurface8_iface);
2934     d3d_surface->forwardReference = container_parent;
2935 
2936     return D3D_OK;
2937 }
2938 
2939 static HRESULT CDECL device_parent_volume_created(struct wined3d_device_parent *device_parent,
2940         void *container_parent, struct wined3d_volume *volume, void **parent,
2941         const struct wined3d_parent_ops **parent_ops)
2942 {
2943     struct d3d8_volume *d3d_volume;
2944 
2945     TRACE("device_parent %p, container_parent %p, volume %p, parent %p, parent_ops %p.\n",
2946             device_parent, container_parent, volume, parent, parent_ops);
2947 
2948     if (!(d3d_volume = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*d3d_volume))))
2949         return E_OUTOFMEMORY;
2950 
2951     volume_init(d3d_volume, volume, parent_ops);
2952     *parent = d3d_volume;
2953     TRACE("Created volume %p.\n", d3d_volume);
2954 
2955     d3d_volume->container = container_parent;
2956 
2957     IDirect3DVolume8_Release(&d3d_volume->IDirect3DVolume8_iface);
2958     d3d_volume->forwardReference = container_parent;
2959 
2960     return D3D_OK;
2961 }
2962 
2963 static HRESULT CDECL device_parent_create_swapchain_surface(struct wined3d_device_parent *device_parent,
2964         void *container_parent, const struct wined3d_resource_desc *desc, struct wined3d_surface **surface)
2965 {
2966     struct d3d8_device *device = device_from_device_parent(device_parent);
2967     struct wined3d_resource_desc texture_desc;
2968     struct d3d8_surface *d3d_surface;
2969     struct wined3d_texture *texture;
2970     HRESULT hr;
2971 
2972     TRACE("device_parent %p, container_parent %p, desc %p, surface %p.\n",
2973             device_parent, container_parent, desc, surface);
2974 
2975     texture_desc = *desc;
2976     texture_desc.resource_type = WINED3D_RTYPE_TEXTURE;
2977     if (FAILED(hr = wined3d_texture_create(device->wined3d_device, &texture_desc, 1,
2978             WINED3D_SURFACE_MAPPABLE, &device->IDirect3DDevice8_iface, &d3d8_null_wined3d_parent_ops, &texture)))
2979     {
2980         WARN("Failed to create texture, hr %#x.\n", hr);
2981         return hr;
2982     }
2983 
2984     *surface = wined3d_surface_from_resource(wined3d_texture_get_sub_resource(texture, 0));
2985     wined3d_surface_incref(*surface);
2986     wined3d_texture_decref(texture);
2987 
2988     d3d_surface = wined3d_surface_get_parent(*surface);
2989     d3d_surface->forwardReference = NULL;
2990     d3d_surface->parent_device = &device->IDirect3DDevice8_iface;
2991 
2992     return hr;
2993 }
2994 
2995 static HRESULT CDECL device_parent_create_swapchain(struct wined3d_device_parent *device_parent,
2996         struct wined3d_swapchain_desc *desc, struct wined3d_swapchain **swapchain)
2997 {
2998     struct d3d8_device *device = device_from_device_parent(device_parent);
2999     struct d3d8_swapchain *d3d_swapchain;
3000     HRESULT hr;
3001 
3002     TRACE("device_parent %p, desc %p, swapchain %p.\n", device_parent, desc, swapchain);
3003 
3004     if (FAILED(hr = d3d8_swapchain_create(device, desc, &d3d_swapchain)))
3005     {
3006         WARN("Failed to create swapchain, hr %#x.\n", hr);
3007         *swapchain = NULL;
3008         return hr;
3009     }
3010 
3011     *swapchain = d3d_swapchain->wined3d_swapchain;
3012     wined3d_swapchain_incref(*swapchain);
3013     IDirect3DSwapChain8_Release(&d3d_swapchain->IDirect3DSwapChain8_iface);
3014 
3015     return hr;
3016 }
3017 
3018 static const struct wined3d_device_parent_ops d3d8_wined3d_device_parent_ops =
3019 {
3020     device_parent_wined3d_device_created,
3021     device_parent_mode_changed,
3022     device_parent_surface_created,
3023     device_parent_volume_created,
3024     device_parent_create_swapchain_surface,
3025     device_parent_create_swapchain,
3026 };
3027 
3028 static void setup_fpu(void)
3029 {
3030 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
3031     WORD cw;
3032     __asm__ volatile ("fnstcw %0" : "=m" (cw));
3033     cw = (cw & ~0xf3f) | 0x3f;
3034     __asm__ volatile ("fldcw %0" : : "m" (cw));
3035 #elif defined(__i386__) && defined(_MSC_VER)
3036     WORD cw;
3037     __asm fnstcw cw;
3038     cw = (cw & ~0xf3f) | 0x3f;
3039     __asm fldcw cw;
3040 #else
3041     FIXME("FPU setup not implemented for this platform.\n");
3042 #endif
3043 }
3044 
3045 HRESULT device_init(struct d3d8_device *device, struct d3d8 *parent, struct wined3d *wined3d, UINT adapter,
3046         D3DDEVTYPE device_type, HWND focus_window, DWORD flags, D3DPRESENT_PARAMETERS *parameters)
3047 {
3048     struct wined3d_swapchain_desc swapchain_desc;
3049     HRESULT hr;
3050 
3051     device->IDirect3DDevice8_iface.lpVtbl = &d3d8_device_vtbl;
3052     device->device_parent.ops = &d3d8_wined3d_device_parent_ops;
3053     device->ref = 1;
3054     device->handle_table.entries = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3055             D3D8_INITIAL_HANDLE_TABLE_SIZE * sizeof(*device->handle_table.entries));
3056     if (!device->handle_table.entries)
3057     {
3058         ERR("Failed to allocate handle table memory.\n");
3059         return E_OUTOFMEMORY;
3060     }
3061     device->handle_table.table_size = D3D8_INITIAL_HANDLE_TABLE_SIZE;
3062 
3063     if (!(flags & D3DCREATE_FPU_PRESERVE)) setup_fpu();
3064 
3065     wined3d_mutex_lock();
3066     hr = wined3d_device_create(wined3d, adapter, device_type, focus_window, flags, 4,
3067             &device->device_parent, &device->wined3d_device);
3068     if (FAILED(hr))
3069     {
3070         WARN("Failed to create wined3d device, hr %#x.\n", hr);
3071         wined3d_mutex_unlock();
3072         HeapFree(GetProcessHeap(), 0, device->handle_table.entries);
3073         return hr;
3074     }
3075 
3076     if (!parameters->Windowed)
3077     {
3078         HWND device_window = parameters->hDeviceWindow;
3079 
3080         if (!focus_window)
3081             focus_window = device_window;
3082         if (FAILED(hr = wined3d_device_acquire_focus_window(device->wined3d_device, focus_window)))
3083         {
3084             ERR("Failed to acquire focus window, hr %#x.\n", hr);
3085             wined3d_device_decref(device->wined3d_device);
3086             wined3d_mutex_unlock();
3087             HeapFree(GetProcessHeap(), 0, device->handle_table.entries);
3088             return hr;
3089         }
3090 
3091         if (!device_window)
3092             device_window = focus_window;
3093         wined3d_device_setup_fullscreen_window(device->wined3d_device, device_window,
3094                 parameters->BackBufferWidth,
3095                 parameters->BackBufferHeight);
3096     }
3097 
3098     if (flags & D3DCREATE_MULTITHREADED)
3099         wined3d_device_set_multithreaded(device->wined3d_device);
3100 
3101     wined3d_swapchain_desc_from_present_parameters(&swapchain_desc, parameters);
3102 
3103     hr = wined3d_device_init_3d(device->wined3d_device, &swapchain_desc);
3104     if (FAILED(hr))
3105     {
3106         WARN("Failed to initialize 3D, hr %#x.\n", hr);
3107         wined3d_device_release_focus_window(device->wined3d_device);
3108         wined3d_device_decref(device->wined3d_device);
3109         wined3d_mutex_unlock();
3110         HeapFree(GetProcessHeap(), 0, device->handle_table.entries);
3111         return hr;
3112     }
3113 
3114     wined3d_device_set_render_state(device->wined3d_device, WINED3D_RS_POINTSIZE_MIN, 0);
3115     wined3d_mutex_unlock();
3116 
3117     present_parameters_from_wined3d_swapchain_desc(parameters, &swapchain_desc);
3118 
3119     device->declArraySize = 16;
3120     device->decls = HeapAlloc(GetProcessHeap(), 0, device->declArraySize * sizeof(*device->decls));
3121     if (!device->decls)
3122     {
3123         ERR("Failed to allocate FVF vertex declaration map memory.\n");
3124         hr = E_OUTOFMEMORY;
3125         goto err;
3126     }
3127 
3128     device->d3d_parent = &parent->IDirect3D8_iface;
3129     IDirect3D8_AddRef(device->d3d_parent);
3130 
3131     return D3D_OK;
3132 
3133 err:
3134     wined3d_mutex_lock();
3135     wined3d_device_uninit_3d(device->wined3d_device);
3136     wined3d_device_release_focus_window(device->wined3d_device);
3137     wined3d_device_decref(device->wined3d_device);
3138     wined3d_mutex_unlock();
3139     HeapFree(GetProcessHeap(), 0, device->handle_table.entries);
3140     return hr;
3141 }
3142