- Merge from trunk up to r45543
[reactos.git] / dll / directx / wine / wined3d / device.c
1 /*
2 * IWineD3DDevice implementation
3 *
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2008 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
12 * Copyright 2009 Henri Verbeet for CodeWeavers
13 *
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
18 *
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
23 *
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 */
28
29 #include "config.h"
30 #include <stdio.h>
31 #ifdef HAVE_FLOAT_H
32 # include <float.h>
33 #endif
34 #include "wined3d_private.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
37 #define GLINFO_LOCATION This->adapter->gl_info
38
39 /* Define the default light parameters as specified by MSDN */
40 const WINED3DLIGHT WINED3D_default_light = {
41
42 WINED3DLIGHT_DIRECTIONAL, /* Type */
43 { 1.0f, 1.0f, 1.0f, 0.0f }, /* Diffuse r,g,b,a */
44 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Specular r,g,b,a */
45 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Ambient r,g,b,a, */
46 { 0.0f, 0.0f, 0.0f }, /* Position x,y,z */
47 { 0.0f, 0.0f, 1.0f }, /* Direction x,y,z */
48 0.0f, /* Range */
49 0.0f, /* Falloff */
50 0.0f, 0.0f, 0.0f, /* Attenuation 0,1,2 */
51 0.0f, /* Theta */
52 0.0f /* Phi */
53 };
54
55 /**********************************************************
56 * Global variable / Constants follow
57 **********************************************************/
58 const float identity[] =
59 {
60 1.0f, 0.0f, 0.0f, 0.0f,
61 0.0f, 1.0f, 0.0f, 0.0f,
62 0.0f, 0.0f, 1.0f, 0.0f,
63 0.0f, 0.0f, 0.0f, 1.0f,
64 }; /* When needed for comparisons */
65
66 /* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these
67 * actually have the same values in GL and D3D. */
68 static GLenum gl_primitive_type_from_d3d(WINED3DPRIMITIVETYPE primitive_type)
69 {
70 switch(primitive_type)
71 {
72 case WINED3DPT_POINTLIST:
73 return GL_POINTS;
74
75 case WINED3DPT_LINELIST:
76 return GL_LINES;
77
78 case WINED3DPT_LINESTRIP:
79 return GL_LINE_STRIP;
80
81 case WINED3DPT_TRIANGLELIST:
82 return GL_TRIANGLES;
83
84 case WINED3DPT_TRIANGLESTRIP:
85 return GL_TRIANGLE_STRIP;
86
87 case WINED3DPT_TRIANGLEFAN:
88 return GL_TRIANGLE_FAN;
89
90 case WINED3DPT_LINELIST_ADJ:
91 return GL_LINES_ADJACENCY_ARB;
92
93 case WINED3DPT_LINESTRIP_ADJ:
94 return GL_LINE_STRIP_ADJACENCY_ARB;
95
96 case WINED3DPT_TRIANGLELIST_ADJ:
97 return GL_TRIANGLES_ADJACENCY_ARB;
98
99 case WINED3DPT_TRIANGLESTRIP_ADJ:
100 return GL_TRIANGLE_STRIP_ADJACENCY_ARB;
101
102 default:
103 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
104 return GL_NONE;
105 }
106 }
107
108 static WINED3DPRIMITIVETYPE d3d_primitive_type_from_gl(GLenum primitive_type)
109 {
110 switch(primitive_type)
111 {
112 case GL_POINTS:
113 return WINED3DPT_POINTLIST;
114
115 case GL_LINES:
116 return WINED3DPT_LINELIST;
117
118 case GL_LINE_STRIP:
119 return WINED3DPT_LINESTRIP;
120
121 case GL_TRIANGLES:
122 return WINED3DPT_TRIANGLELIST;
123
124 case GL_TRIANGLE_STRIP:
125 return WINED3DPT_TRIANGLESTRIP;
126
127 case GL_TRIANGLE_FAN:
128 return WINED3DPT_TRIANGLEFAN;
129
130 case GL_LINES_ADJACENCY_ARB:
131 return WINED3DPT_LINELIST_ADJ;
132
133 case GL_LINE_STRIP_ADJACENCY_ARB:
134 return WINED3DPT_LINESTRIP_ADJ;
135
136 case GL_TRIANGLES_ADJACENCY_ARB:
137 return WINED3DPT_TRIANGLELIST_ADJ;
138
139 case GL_TRIANGLE_STRIP_ADJACENCY_ARB:
140 return WINED3DPT_TRIANGLESTRIP_ADJ;
141
142 default:
143 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
144 return WINED3DPT_UNDEFINED;
145 }
146 }
147
148 static BOOL fixed_get_input(BYTE usage, BYTE usage_idx, unsigned int *regnum)
149 {
150 if ((usage == WINED3DDECLUSAGE_POSITION || usage == WINED3DDECLUSAGE_POSITIONT) && usage_idx == 0)
151 *regnum = WINED3D_FFP_POSITION;
152 else if (usage == WINED3DDECLUSAGE_BLENDWEIGHT && usage_idx == 0)
153 *regnum = WINED3D_FFP_BLENDWEIGHT;
154 else if (usage == WINED3DDECLUSAGE_BLENDINDICES && usage_idx == 0)
155 *regnum = WINED3D_FFP_BLENDINDICES;
156 else if (usage == WINED3DDECLUSAGE_NORMAL && usage_idx == 0)
157 *regnum = WINED3D_FFP_NORMAL;
158 else if (usage == WINED3DDECLUSAGE_PSIZE && usage_idx == 0)
159 *regnum = WINED3D_FFP_PSIZE;
160 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 0)
161 *regnum = WINED3D_FFP_DIFFUSE;
162 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 1)
163 *regnum = WINED3D_FFP_SPECULAR;
164 else if (usage == WINED3DDECLUSAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
165 *regnum = WINED3D_FFP_TEXCOORD0 + usage_idx;
166 else
167 {
168 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage), usage_idx);
169 *regnum = ~0U;
170 return FALSE;
171 }
172
173 return TRUE;
174 }
175
176 /* Context activation is done by the caller. */
177 void device_stream_info_from_declaration(IWineD3DDeviceImpl *This,
178 BOOL use_vshader, struct wined3d_stream_info *stream_info, BOOL *fixup)
179 {
180 /* We need to deal with frequency data! */
181 IWineD3DVertexDeclarationImpl *declaration = (IWineD3DVertexDeclarationImpl *)This->stateBlock->vertexDecl;
182 UINT stream_count = This->stateBlock->streamIsUP ? 0 : declaration->num_streams;
183 const DWORD *streams = declaration->streams;
184 unsigned int i;
185
186 stream_info->use_map = 0;
187 stream_info->swizzle_map = 0;
188
189 /* Check for transformed vertices, disable vertex shader if present. */
190 stream_info->position_transformed = declaration->position_transformed;
191 if (declaration->position_transformed) use_vshader = FALSE;
192
193 /* Translate the declaration into strided data. */
194 for (i = 0; i < declaration->element_count; ++i)
195 {
196 const struct wined3d_vertex_declaration_element *element = &declaration->elements[i];
197 GLuint buffer_object = 0;
198 const BYTE *data = NULL;
199 BOOL stride_used;
200 unsigned int idx;
201 DWORD stride;
202
203 TRACE("%p Element %p (%u of %u)\n", declaration->elements,
204 element, i + 1, declaration->element_count);
205
206 if (!This->stateBlock->streamSource[element->input_slot]) continue;
207
208 stride = This->stateBlock->streamStride[element->input_slot];
209 if (This->stateBlock->streamIsUP)
210 {
211 TRACE("Stream %u is UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
212 buffer_object = 0;
213 data = (BYTE *)This->stateBlock->streamSource[element->input_slot];
214 }
215 else
216 {
217 TRACE("Stream %u isn't UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
218 data = buffer_get_memory(This->stateBlock->streamSource[element->input_slot], 0, &buffer_object);
219
220 /* Can't use vbo's if the base vertex index is negative. OpenGL doesn't accept negative offsets
221 * (or rather offsets bigger than the vbo, because the pointer is unsigned), so use system memory
222 * sources. In most sane cases the pointer - offset will still be > 0, otherwise it will wrap
223 * around to some big value. Hope that with the indices, the driver wraps it back internally. If
224 * not, drawStridedSlow is needed, including a vertex buffer path. */
225 if (This->stateBlock->loadBaseVertexIndex < 0)
226 {
227 WARN("loadBaseVertexIndex is < 0 (%d), not using vbos\n", This->stateBlock->loadBaseVertexIndex);
228 buffer_object = 0;
229 data = buffer_get_sysmem((struct wined3d_buffer *)This->stateBlock->streamSource[element->input_slot]);
230 if ((UINT_PTR)data < -This->stateBlock->loadBaseVertexIndex * stride)
231 {
232 FIXME("System memory vertex data load offset is negative!\n");
233 }
234 }
235
236 if (fixup)
237 {
238 if (buffer_object) *fixup = TRUE;
239 else if (*fixup && !use_vshader
240 && (element->usage == WINED3DDECLUSAGE_COLOR
241 || element->usage == WINED3DDECLUSAGE_POSITIONT))
242 {
243 static BOOL warned = FALSE;
244 if (!warned)
245 {
246 /* This may be bad with the fixed function pipeline. */
247 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
248 warned = TRUE;
249 }
250 }
251 }
252 }
253 data += element->offset;
254
255 TRACE("offset %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx);
256
257 if (use_vshader)
258 {
259 if (element->output_slot == ~0U)
260 {
261 /* TODO: Assuming vertexdeclarations are usually used with the
262 * same or a similar shader, it might be worth it to store the
263 * last used output slot and try that one first. */
264 stride_used = vshader_get_input(This->stateBlock->vertexShader,
265 element->usage, element->usage_idx, &idx);
266 }
267 else
268 {
269 idx = element->output_slot;
270 stride_used = TRUE;
271 }
272 }
273 else
274 {
275 if (!element->ffp_valid)
276 {
277 WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
278 debug_d3dformat(element->format_desc->format), debug_d3ddeclusage(element->usage));
279 stride_used = FALSE;
280 }
281 else
282 {
283 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
284 }
285 }
286
287 if (stride_used)
288 {
289 TRACE("Load %s array %u [usage %s, usage_idx %u, "
290 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
291 use_vshader ? "shader": "fixed function", idx,
292 debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot,
293 element->offset, stride, debug_d3dformat(element->format_desc->format), buffer_object);
294
295 stream_info->elements[idx].format_desc = element->format_desc;
296 stream_info->elements[idx].stride = stride;
297 stream_info->elements[idx].data = data;
298 stream_info->elements[idx].stream_idx = element->input_slot;
299 stream_info->elements[idx].buffer_object = buffer_object;
300
301 if (!This->adapter->gl_info.supported[EXT_VERTEX_ARRAY_BGRA]
302 && element->format_desc->format == WINED3DFMT_B8G8R8A8_UNORM)
303 {
304 stream_info->swizzle_map |= 1 << idx;
305 }
306 stream_info->use_map |= 1 << idx;
307 }
308 }
309
310 /* Now call PreLoad on all the vertex buffers. In the very rare case
311 * that the buffers stopps converting PreLoad will dirtify the VDECL again.
312 * The vertex buffer can now use the strided structure in the device instead of finding its
313 * own again.
314 *
315 * NULL streams won't be recorded in the array, UP streams won't be either. A stream is only
316 * once in there. */
317 for (i = 0; i < stream_count; ++i)
318 {
319 IWineD3DBuffer *vb = This->stateBlock->streamSource[streams[i]];
320 if (vb) IWineD3DBuffer_PreLoad(vb);
321 }
322 }
323
324 static void stream_info_element_from_strided(const struct wined3d_gl_info *gl_info,
325 const struct WineDirect3DStridedData *strided, struct wined3d_stream_info_element *e)
326 {
327 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(strided->format, gl_info);
328 e->format_desc = format_desc;
329 e->stride = strided->dwStride;
330 e->data = strided->lpData;
331 e->stream_idx = 0;
332 e->buffer_object = 0;
333 }
334
335 void device_stream_info_from_strided(const struct wined3d_gl_info *gl_info,
336 const struct WineDirect3DVertexStridedData *strided, struct wined3d_stream_info *stream_info)
337 {
338 unsigned int i;
339
340 memset(stream_info, 0, sizeof(*stream_info));
341
342 if (strided->position.lpData)
343 stream_info_element_from_strided(gl_info, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
344 if (strided->normal.lpData)
345 stream_info_element_from_strided(gl_info, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
346 if (strided->diffuse.lpData)
347 stream_info_element_from_strided(gl_info, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
348 if (strided->specular.lpData)
349 stream_info_element_from_strided(gl_info, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);
350
351 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
352 {
353 if (strided->texCoords[i].lpData)
354 stream_info_element_from_strided(gl_info, &strided->texCoords[i],
355 &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
356 }
357
358 stream_info->position_transformed = strided->position_transformed;
359
360 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
361 {
362 if (!stream_info->elements[i].format_desc) continue;
363
364 if (!gl_info->supported[EXT_VERTEX_ARRAY_BGRA]
365 && stream_info->elements[i].format_desc->format == WINED3DFMT_B8G8R8A8_UNORM)
366 {
367 stream_info->swizzle_map |= 1 << i;
368 }
369 stream_info->use_map |= 1 << i;
370 }
371 }
372
373 /**********************************************************
374 * IUnknown parts follows
375 **********************************************************/
376
377 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
378 {
379 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
380
381 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
382 if (IsEqualGUID(riid, &IID_IUnknown)
383 || IsEqualGUID(riid, &IID_IWineD3DBase)
384 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
385 IUnknown_AddRef(iface);
386 *ppobj = This;
387 return S_OK;
388 }
389 *ppobj = NULL;
390 return E_NOINTERFACE;
391 }
392
393 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
395 ULONG refCount = InterlockedIncrement(&This->ref);
396
397 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
398 return refCount;
399 }
400
401 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
402 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
403 ULONG refCount = InterlockedDecrement(&This->ref);
404
405 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
406
407 if (!refCount) {
408 UINT i;
409
410 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
411 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
412 This->multistate_funcs[i] = NULL;
413 }
414
415 /* TODO: Clean up all the surfaces and textures! */
416 /* NOTE: You must release the parent if the object was created via a callback
417 ** ***************************/
418
419 if (!list_empty(&This->resources)) {
420 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
421 dumpResources(&This->resources);
422 }
423
424 if(This->contexts) ERR("Context array not freed!\n");
425 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
426 This->haveHardwareCursor = FALSE;
427
428 IWineD3D_Release(This->wined3d);
429 This->wined3d = NULL;
430 HeapFree(GetProcessHeap(), 0, This);
431 TRACE("Freed device %p\n", This);
432 This = NULL;
433 }
434 return refCount;
435 }
436
437 /**********************************************************
438 * IWineD3DDevice implementation follows
439 **********************************************************/
440 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
441 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
442 *pParent = This->parent;
443 IUnknown_AddRef(This->parent);
444 return WINED3D_OK;
445 }
446
447 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
448 const void *data, IUnknown *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **buffer)
449 {
450 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
451 struct wined3d_buffer *object;
452 HRESULT hr;
453
454 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
455
456 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
457 if (!object)
458 {
459 ERR("Failed to allocate memory\n");
460 return E_OUTOFMEMORY;
461 }
462
463 FIXME("Ignoring access flags (pool)\n");
464
465 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
466 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
467 if (FAILED(hr))
468 {
469 WARN("Failed to initialize buffer, hr %#x.\n", hr);
470 HeapFree(GetProcessHeap(), 0, object);
471 return hr;
472 }
473 object->desc = *desc;
474
475 TRACE("Created buffer %p.\n", object);
476
477 *buffer = (IWineD3DBuffer *)object;
478
479 return WINED3D_OK;
480 }
481
482 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface,
483 UINT Size, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppVertexBuffer,
484 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
485 {
486 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
487 struct wined3d_buffer *object;
488 HRESULT hr;
489
490 TRACE("iface %p, size %u, usage %#x, pool %#x, buffer %p, parent %p, parent_ops %p.\n",
491 iface, Size, Usage, Pool, ppVertexBuffer, parent, parent_ops);
492
493 if (Pool == WINED3DPOOL_SCRATCH)
494 {
495 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
496 * anyway, SCRATCH vertex buffers aren't usable anywhere
497 */
498 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
499 *ppVertexBuffer = NULL;
500 return WINED3DERR_INVALIDCALL;
501 }
502
503 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
504 if (!object)
505 {
506 ERR("Out of memory\n");
507 *ppVertexBuffer = NULL;
508 return WINED3DERR_OUTOFVIDEOMEMORY;
509 }
510
511 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
512 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
513 if (FAILED(hr))
514 {
515 WARN("Failed to initialize buffer, hr %#x.\n", hr);
516 HeapFree(GetProcessHeap(), 0, object);
517 return hr;
518 }
519
520 TRACE("Created buffer %p.\n", object);
521 *ppVertexBuffer = (IWineD3DBuffer *)object;
522
523 return WINED3D_OK;
524 }
525
526 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
527 UINT Length, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppIndexBuffer,
528 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
529 {
530 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
531 struct wined3d_buffer *object;
532 HRESULT hr;
533
534 TRACE("(%p) Creating index buffer\n", This);
535
536 /* Allocate the storage for the device */
537 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
538 if (!object)
539 {
540 ERR("Out of memory\n");
541 *ppIndexBuffer = NULL;
542 return WINED3DERR_OUTOFVIDEOMEMORY;
543 }
544
545 hr = buffer_init(object, This, Length, Usage | WINED3DUSAGE_STATICDECL,
546 WINED3DFMT_UNKNOWN, Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL,
547 parent, parent_ops);
548 if (FAILED(hr))
549 {
550 WARN("Failed to initialize buffer, hr %#x\n", hr);
551 HeapFree(GetProcessHeap(), 0, object);
552 return hr;
553 }
554
555 TRACE("Created buffer %p.\n", object);
556
557 *ppIndexBuffer = (IWineD3DBuffer *) object;
558
559 return WINED3D_OK;
560 }
561
562 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
563 WINED3DSTATEBLOCKTYPE type, IWineD3DStateBlock **stateblock, IUnknown *parent)
564 {
565 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
566 IWineD3DStateBlockImpl *object;
567 HRESULT hr;
568
569 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
570 if(!object)
571 {
572 ERR("Failed to allocate stateblock memory.\n");
573 return E_OUTOFMEMORY;
574 }
575
576 hr = stateblock_init(object, This, type);
577 if (FAILED(hr))
578 {
579 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
580 HeapFree(GetProcessHeap(), 0, object);
581 return hr;
582 }
583
584 TRACE("Created stateblock %p.\n", object);
585 *stateblock = (IWineD3DStateBlock *)object;
586
587 return WINED3D_OK;
588 }
589
590 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
591 WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,
592 DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality,
593 WINED3DSURFTYPE Impl, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
594 {
595 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
596 IWineD3DSurfaceImpl *object;
597 HRESULT hr;
598
599 TRACE("(%p) Create surface\n",This);
600
601 if (Impl == SURFACE_OPENGL && !This->adapter)
602 {
603 ERR("OpenGL surfaces are not available without OpenGL.\n");
604 return WINED3DERR_NOTAVAILABLE;
605 }
606
607 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
608 if (!object)
609 {
610 ERR("Failed to allocate surface memory.\n");
611 return WINED3DERR_OUTOFVIDEOMEMORY;
612 }
613
614 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
615 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
616 if (FAILED(hr))
617 {
618 WARN("Failed to initialize surface, returning %#x.\n", hr);
619 HeapFree(GetProcessHeap(), 0, object);
620 return hr;
621 }
622
623 TRACE("(%p) : Created surface %p\n", This, object);
624
625 *ppSurface = (IWineD3DSurface *)object;
626
627 return hr;
628 }
629
630 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
631 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
632 {
633 struct wined3d_rendertarget_view *object;
634
635 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
636 if (!object)
637 {
638 ERR("Failed to allocate memory\n");
639 return E_OUTOFMEMORY;
640 }
641
642 object->vtbl = &wined3d_rendertarget_view_vtbl;
643 object->refcount = 1;
644 IWineD3DResource_AddRef(resource);
645 object->resource = resource;
646 object->parent = parent;
647
648 *rendertarget_view = (IWineD3DRendertargetView *)object;
649
650 return WINED3D_OK;
651 }
652
653 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
654 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
655 IWineD3DTexture **ppTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
656 {
657 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
658 IWineD3DTextureImpl *object;
659 HRESULT hr;
660
661 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
662 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
663 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
664
665 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
666 if (!object)
667 {
668 ERR("Out of memory\n");
669 *ppTexture = NULL;
670 return WINED3DERR_OUTOFVIDEOMEMORY;
671 }
672
673 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
674 if (FAILED(hr))
675 {
676 WARN("Failed to initialize texture, returning %#x\n", hr);
677 HeapFree(GetProcessHeap(), 0, object);
678 *ppTexture = NULL;
679 return hr;
680 }
681
682 *ppTexture = (IWineD3DTexture *)object;
683
684 TRACE("(%p) : Created texture %p\n", This, object);
685
686 return WINED3D_OK;
687 }
688
689 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
690 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
691 IWineD3DVolumeTexture **ppVolumeTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
692 {
693 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
694 IWineD3DVolumeTextureImpl *object;
695 HRESULT hr;
696
697 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
698 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
699
700 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
701 if (!object)
702 {
703 ERR("Out of memory\n");
704 *ppVolumeTexture = NULL;
705 return WINED3DERR_OUTOFVIDEOMEMORY;
706 }
707
708 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
709 if (FAILED(hr))
710 {
711 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
712 HeapFree(GetProcessHeap(), 0, object);
713 *ppVolumeTexture = NULL;
714 return hr;
715 }
716
717 TRACE("(%p) : Created volume texture %p.\n", This, object);
718 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
719
720 return WINED3D_OK;
721 }
722
723 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
724 UINT Depth, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DVolume **ppVolume,
725 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
726 {
727 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
728 IWineD3DVolumeImpl *object;
729 HRESULT hr;
730
731 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
732 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
733
734 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
735 if (!object)
736 {
737 ERR("Out of memory\n");
738 *ppVolume = NULL;
739 return WINED3DERR_OUTOFVIDEOMEMORY;
740 }
741
742 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
743 if (FAILED(hr))
744 {
745 WARN("Failed to initialize volume, returning %#x.\n", hr);
746 HeapFree(GetProcessHeap(), 0, object);
747 return hr;
748 }
749
750 TRACE("(%p) : Created volume %p.\n", This, object);
751 *ppVolume = (IWineD3DVolume *)object;
752
753 return WINED3D_OK;
754 }
755
756 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
757 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture,
758 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
759 {
760 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
761 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
762 HRESULT hr;
763
764 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
765 if (!object)
766 {
767 ERR("Out of memory\n");
768 *ppCubeTexture = NULL;
769 return WINED3DERR_OUTOFVIDEOMEMORY;
770 }
771
772 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
773 if (FAILED(hr))
774 {
775 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
776 HeapFree(GetProcessHeap(), 0, object);
777 *ppCubeTexture = NULL;
778 return hr;
779 }
780
781 TRACE("(%p) : Created Cube Texture %p\n", This, object);
782 *ppCubeTexture = (IWineD3DCubeTexture *)object;
783
784 return WINED3D_OK;
785 }
786
787 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
788 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
789 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
790 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
791 HRESULT hr = WINED3DERR_NOTAVAILABLE;
792 const IWineD3DQueryVtbl *vtable;
793
794 /* Just a check to see if we support this type of query */
795 switch(Type) {
796 case WINED3DQUERYTYPE_OCCLUSION:
797 TRACE("(%p) occlusion query\n", This);
798 if (gl_info->supported[ARB_OCCLUSION_QUERY])
799 hr = WINED3D_OK;
800 else
801 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
802
803 vtable = &IWineD3DOcclusionQuery_Vtbl;
804 break;
805
806 case WINED3DQUERYTYPE_EVENT:
807 if (!gl_info->supported[NV_FENCE] && !gl_info->supported[APPLE_FENCE])
808 {
809 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
810 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
811 */
812 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
813 }
814 vtable = &IWineD3DEventQuery_Vtbl;
815 hr = WINED3D_OK;
816 break;
817
818 case WINED3DQUERYTYPE_VCACHE:
819 case WINED3DQUERYTYPE_RESOURCEMANAGER:
820 case WINED3DQUERYTYPE_VERTEXSTATS:
821 case WINED3DQUERYTYPE_TIMESTAMP:
822 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
823 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
824 case WINED3DQUERYTYPE_PIPELINETIMINGS:
825 case WINED3DQUERYTYPE_INTERFACETIMINGS:
826 case WINED3DQUERYTYPE_VERTEXTIMINGS:
827 case WINED3DQUERYTYPE_PIXELTIMINGS:
828 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
829 case WINED3DQUERYTYPE_CACHEUTILIZATION:
830 default:
831 /* Use the base Query vtable until we have a special one for each query */
832 vtable = &IWineD3DQuery_Vtbl;
833 FIXME("(%p) Unhandled query type %d\n", This, Type);
834 }
835 if(NULL == ppQuery || hr != WINED3D_OK) {
836 return hr;
837 }
838
839 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
840 if(!object)
841 {
842 ERR("Out of memory\n");
843 *ppQuery = NULL;
844 return WINED3DERR_OUTOFVIDEOMEMORY;
845 }
846
847 object->lpVtbl = vtable;
848 object->type = Type;
849 object->state = QUERY_CREATED;
850 object->device = This;
851 object->parent = parent;
852 object->ref = 1;
853
854 *ppQuery = (IWineD3DQuery *)object;
855
856 /* allocated the 'extended' data based on the type of query requested */
857 switch(Type){
858 case WINED3DQUERYTYPE_OCCLUSION:
859 object->extendedData = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_occlusion_query));
860 ((struct wined3d_occlusion_query *)object->extendedData)->context = NULL;
861 break;
862
863 case WINED3DQUERYTYPE_EVENT:
864 object->extendedData = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_event_query));
865 ((struct wined3d_event_query *)object->extendedData)->context = NULL;
866 break;
867
868 case WINED3DQUERYTYPE_VCACHE:
869 case WINED3DQUERYTYPE_RESOURCEMANAGER:
870 case WINED3DQUERYTYPE_VERTEXSTATS:
871 case WINED3DQUERYTYPE_TIMESTAMP:
872 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
873 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
874 case WINED3DQUERYTYPE_PIPELINETIMINGS:
875 case WINED3DQUERYTYPE_INTERFACETIMINGS:
876 case WINED3DQUERYTYPE_VERTEXTIMINGS:
877 case WINED3DQUERYTYPE_PIXELTIMINGS:
878 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
879 case WINED3DQUERYTYPE_CACHEUTILIZATION:
880 default:
881 object->extendedData = 0;
882 FIXME("(%p) Unhandled query type %d\n",This , Type);
883 }
884 TRACE("(%p) : Created Query %p\n", This, object);
885 return WINED3D_OK;
886 }
887
888 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
889 WINED3DPRESENT_PARAMETERS *present_parameters, IWineD3DSwapChain **swapchain,
890 IUnknown *parent, WINED3DSURFTYPE surface_type)
891 {
892 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
893 IWineD3DSwapChainImpl *object;
894 HRESULT hr;
895
896 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
897 iface, present_parameters, swapchain, parent, surface_type);
898
899 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
900 if (!object)
901 {
902 ERR("Failed to allocate swapchain memory.\n");
903 return E_OUTOFMEMORY;
904 }
905
906 hr = swapchain_init(object, surface_type, This, present_parameters, parent);
907 if (FAILED(hr))
908 {
909 WARN("Failed to initialize swapchain, hr %#x.\n", hr);
910 HeapFree(GetProcessHeap(), 0, object);
911 return hr;
912 }
913
914 TRACE("Created swapchain %p.\n", object);
915 *swapchain = (IWineD3DSwapChain *)object;
916
917 return WINED3D_OK;
918 }
919
920 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
921 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
922 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
923 TRACE("(%p)\n", This);
924
925 return This->NumberOfSwapChains;
926 }
927
928 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
929 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
930 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
931
932 if(iSwapChain < This->NumberOfSwapChains) {
933 *pSwapChain = This->swapchains[iSwapChain];
934 IWineD3DSwapChain_AddRef(*pSwapChain);
935 TRACE("(%p) returning %p\n", This, *pSwapChain);
936 return WINED3D_OK;
937 } else {
938 TRACE("Swapchain out of range\n");
939 *pSwapChain = NULL;
940 return WINED3DERR_INVALIDCALL;
941 }
942 }
943
944 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
945 IWineD3DVertexDeclaration **declaration, IUnknown *parent, const struct wined3d_parent_ops *parent_ops,
946 const WINED3DVERTEXELEMENT *elements, UINT element_count)
947 {
948 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
949 IWineD3DVertexDeclarationImpl *object = NULL;
950 HRESULT hr;
951
952 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
953 iface, declaration, parent, elements, element_count);
954
955 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
956 if(!object)
957 {
958 ERR("Failed to allocate vertex declaration memory.\n");
959 return E_OUTOFMEMORY;
960 }
961
962 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
963 if (FAILED(hr))
964 {
965 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
966 HeapFree(GetProcessHeap(), 0, object);
967 return hr;
968 }
969
970 TRACE("Created vertex declaration %p.\n", object);
971 *declaration = (IWineD3DVertexDeclaration *)object;
972
973 return WINED3D_OK;
974 }
975
976 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
977 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
978
979 unsigned int idx, idx2;
980 unsigned int offset;
981 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
982 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
983 BOOL has_blend_idx = has_blend &&
984 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
985 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
986 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
987 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
988 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
989 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
990 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
991
992 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
993 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
994 WINED3DVERTEXELEMENT *elements = NULL;
995
996 unsigned int size;
997 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
998 if (has_blend_idx) num_blends--;
999
1000 /* Compute declaration size */
1001 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1002 has_psize + has_diffuse + has_specular + num_textures;
1003
1004 /* convert the declaration */
1005 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1006 if (!elements) return ~0U;
1007
1008 idx = 0;
1009 if (has_pos) {
1010 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1011 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1012 elements[idx].usage = WINED3DDECLUSAGE_POSITIONT;
1013 }
1014 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
1015 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1016 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1017 }
1018 else {
1019 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1020 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1021 }
1022 elements[idx].usage_idx = 0;
1023 idx++;
1024 }
1025 if (has_blend && (num_blends > 0)) {
1026 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1027 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1028 else {
1029 switch(num_blends) {
1030 case 1: elements[idx].format = WINED3DFMT_R32_FLOAT; break;
1031 case 2: elements[idx].format = WINED3DFMT_R32G32_FLOAT; break;
1032 case 3: elements[idx].format = WINED3DFMT_R32G32B32_FLOAT; break;
1033 case 4: elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
1034 default:
1035 ERR("Unexpected amount of blend values: %u\n", num_blends);
1036 }
1037 }
1038 elements[idx].usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1039 elements[idx].usage_idx = 0;
1040 idx++;
1041 }
1042 if (has_blend_idx) {
1043 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1044 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1045 elements[idx].format = WINED3DFMT_R8G8B8A8_UINT;
1046 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1047 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1048 else
1049 elements[idx].format = WINED3DFMT_R32_FLOAT;
1050 elements[idx].usage = WINED3DDECLUSAGE_BLENDINDICES;
1051 elements[idx].usage_idx = 0;
1052 idx++;
1053 }
1054 if (has_normal) {
1055 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1056 elements[idx].usage = WINED3DDECLUSAGE_NORMAL;
1057 elements[idx].usage_idx = 0;
1058 idx++;
1059 }
1060 if (has_psize) {
1061 elements[idx].format = WINED3DFMT_R32_FLOAT;
1062 elements[idx].usage = WINED3DDECLUSAGE_PSIZE;
1063 elements[idx].usage_idx = 0;
1064 idx++;
1065 }
1066 if (has_diffuse) {
1067 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1068 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1069 elements[idx].usage_idx = 0;
1070 idx++;
1071 }
1072 if (has_specular) {
1073 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1074 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1075 elements[idx].usage_idx = 1;
1076 idx++;
1077 }
1078 for (idx2 = 0; idx2 < num_textures; idx2++) {
1079 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1080 switch (numcoords) {
1081 case WINED3DFVF_TEXTUREFORMAT1:
1082 elements[idx].format = WINED3DFMT_R32_FLOAT;
1083 break;
1084 case WINED3DFVF_TEXTUREFORMAT2:
1085 elements[idx].format = WINED3DFMT_R32G32_FLOAT;
1086 break;
1087 case WINED3DFVF_TEXTUREFORMAT3:
1088 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1089 break;
1090 case WINED3DFVF_TEXTUREFORMAT4:
1091 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1092 break;
1093 }
1094 elements[idx].usage = WINED3DDECLUSAGE_TEXCOORD;
1095 elements[idx].usage_idx = idx2;
1096 idx++;
1097 }
1098
1099 /* Now compute offsets, and initialize the rest of the fields */
1100 for (idx = 0, offset = 0; idx < size; ++idx)
1101 {
1102 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(elements[idx].format, &This->adapter->gl_info);
1103 elements[idx].input_slot = 0;
1104 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1105 elements[idx].offset = offset;
1106 offset += format_desc->component_count * format_desc->component_size;
1107 }
1108
1109 *ppVertexElements = elements;
1110 return size;
1111 }
1112
1113 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1114 IWineD3DVertexDeclaration **declaration, IUnknown *parent,
1115 const struct wined3d_parent_ops *parent_ops, DWORD fvf)
1116 {
1117 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1118 WINED3DVERTEXELEMENT *elements;
1119 unsigned int size;
1120 DWORD hr;
1121
1122 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1123
1124 size = ConvertFvfToDeclaration(This, fvf, &elements);
1125 if (size == ~0U) return E_OUTOFMEMORY;
1126
1127 hr = IWineD3DDevice_CreateVertexDeclaration(iface, declaration, parent, parent_ops, elements, size);
1128 HeapFree(GetProcessHeap(), 0, elements);
1129 return hr;
1130 }
1131
1132 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1133 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1134 IWineD3DVertexShader **ppVertexShader, IUnknown *parent,
1135 const struct wined3d_parent_ops *parent_ops)
1136 {
1137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1138 IWineD3DVertexShaderImpl *object;
1139 HRESULT hr;
1140
1141 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1142 if (!object)
1143 {
1144 ERR("Failed to allocate shader memory.\n");
1145 return E_OUTOFMEMORY;
1146 }
1147
1148 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1149 if (FAILED(hr))
1150 {
1151 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1152 HeapFree(GetProcessHeap(), 0, object);
1153 return hr;
1154 }
1155
1156 TRACE("Created vertex shader %p.\n", object);
1157 *ppVertexShader = (IWineD3DVertexShader *)object;
1158
1159 return WINED3D_OK;
1160 }
1161
1162 static HRESULT WINAPI IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice *iface,
1163 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
1164 IWineD3DGeometryShader **shader, IUnknown *parent,
1165 const struct wined3d_parent_ops *parent_ops)
1166 {
1167 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1168 struct wined3d_geometryshader *object;
1169 HRESULT hr;
1170
1171 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1172 if (!object)
1173 {
1174 ERR("Failed to allocate shader memory.\n");
1175 return E_OUTOFMEMORY;
1176 }
1177
1178 hr = geometryshader_init(object, This, byte_code, output_signature, parent, parent_ops);
1179 if (FAILED(hr))
1180 {
1181 WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
1182 HeapFree(GetProcessHeap(), 0, object);
1183 return hr;
1184 }
1185
1186 TRACE("Created geometry shader %p.\n", object);
1187 *shader = (IWineD3DGeometryShader *)object;
1188
1189 return WINED3D_OK;
1190 }
1191
1192 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1193 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1194 IWineD3DPixelShader **ppPixelShader, IUnknown *parent,
1195 const struct wined3d_parent_ops *parent_ops)
1196 {
1197 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1198 IWineD3DPixelShaderImpl *object;
1199 HRESULT hr;
1200
1201 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1202 if (!object)
1203 {
1204 ERR("Failed to allocate shader memory.\n");
1205 return E_OUTOFMEMORY;
1206 }
1207
1208 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1209 if (FAILED(hr))
1210 {
1211 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1212 HeapFree(GetProcessHeap(), 0, object);
1213 return hr;
1214 }
1215
1216 TRACE("Created pixel shader %p.\n", object);
1217 *ppPixelShader = (IWineD3DPixelShader *)object;
1218
1219 return WINED3D_OK;
1220 }
1221
1222 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1223 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1224 {
1225 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1226 IWineD3DPaletteImpl *object;
1227 HRESULT hr;
1228 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1229
1230 /* Create the new object */
1231 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1232 if(!object) {
1233 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1234 return E_OUTOFMEMORY;
1235 }
1236
1237 object->lpVtbl = &IWineD3DPalette_Vtbl;
1238 object->ref = 1;
1239 object->Flags = Flags;
1240 object->parent = Parent;
1241 object->device = This;
1242 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1243 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1244
1245 if(!object->hpal) {
1246 HeapFree( GetProcessHeap(), 0, object);
1247 return E_OUTOFMEMORY;
1248 }
1249
1250 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1251 if(FAILED(hr)) {
1252 IWineD3DPalette_Release((IWineD3DPalette *) object);
1253 return hr;
1254 }
1255
1256 *Palette = (IWineD3DPalette *) object;
1257
1258 return WINED3D_OK;
1259 }
1260
1261 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1262 HBITMAP hbm;
1263 BITMAP bm;
1264 HRESULT hr;
1265 HDC dcb = NULL, dcs = NULL;
1266 WINEDDCOLORKEY colorkey;
1267
1268 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1269 if(hbm)
1270 {
1271 GetObjectA(hbm, sizeof(BITMAP), &bm);
1272 dcb = CreateCompatibleDC(NULL);
1273 if(!dcb) goto out;
1274 SelectObject(dcb, hbm);
1275 }
1276 else
1277 {
1278 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1279 * couldn't be loaded
1280 */
1281 memset(&bm, 0, sizeof(bm));
1282 bm.bmWidth = 32;
1283 bm.bmHeight = 32;
1284 }
1285
1286 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1287 FALSE, 0, &This->logo_surface, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL,
1288 NULL, &wined3d_null_parent_ops);
1289 if(FAILED(hr)) {
1290 ERR("Wine logo requested, but failed to create surface\n");
1291 goto out;
1292 }
1293
1294 if(dcb) {
1295 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1296 if(FAILED(hr)) goto out;
1297 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1298 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1299
1300 colorkey.dwColorSpaceLowValue = 0;
1301 colorkey.dwColorSpaceHighValue = 0;
1302 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1303 } else {
1304 /* Fill the surface with a white color to show that wined3d is there */
1305 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1306 }
1307
1308 out:
1309 if (dcb) DeleteDC(dcb);
1310 if (hbm) DeleteObject(hbm);
1311 }
1312
1313 /* Context activation is done by the caller. */
1314 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1315 {
1316 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1317 unsigned int i;
1318 /* Under DirectX you can have texture stage operations even if no texture is
1319 bound, whereas opengl will only do texture operations when a valid texture is
1320 bound. We emulate this by creating dummy textures and binding them to each
1321 texture stage, but disable all stages by default. Hence if a stage is enabled
1322 then the default texture will kick in until replaced by a SetTexture call */
1323 ENTER_GL();
1324
1325 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1326 {
1327 /* The dummy texture does not have client storage backing */
1328 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1329 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1330 }
1331
1332 for (i = 0; i < gl_info->limits.textures; ++i)
1333 {
1334 GLubyte white = 255;
1335
1336 /* Make appropriate texture active */
1337 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1338 checkGLcall("glActiveTextureARB");
1339
1340 /* Generate an opengl texture name */
1341 glGenTextures(1, &This->dummyTextureName[i]);
1342 checkGLcall("glGenTextures");
1343 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1344
1345 /* Generate a dummy 2d texture (not using 1d because they cause many
1346 * DRI drivers fall back to sw) */
1347 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1348 checkGLcall("glBindTexture");
1349
1350 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1351 checkGLcall("glTexImage2D");
1352 }
1353
1354 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1355 {
1356 /* Reenable because if supported it is enabled by default */
1357 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1358 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1359 }
1360
1361 LEAVE_GL();
1362 }
1363
1364 /* Context activation is done by the caller. */
1365 static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1366 {
1367 ENTER_GL();
1368 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1369 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1370 LEAVE_GL();
1371
1372 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1373 }
1374
1375 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1376 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1377 {
1378 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1379 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1380 IWineD3DSwapChainImpl *swapchain = NULL;
1381 struct wined3d_context *context;
1382 HRESULT hr;
1383 DWORD state;
1384 unsigned int i;
1385
1386 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1387
1388 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1389 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1390
1391 if (!pPresentationParameters->Windowed)
1392 {
1393 This->focus_window = This->createParms.hFocusWindow;
1394 if (!This->focus_window) This->focus_window = pPresentationParameters->hDeviceWindow;
1395 if (!wined3d_register_window(This->focus_window, This))
1396 {
1397 ERR("Failed to register window %p.\n", This->focus_window);
1398 return E_FAIL;
1399 }
1400 }
1401
1402 TRACE("(%p) : Creating stateblock\n", This);
1403 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1404 hr = IWineD3DDevice_CreateStateBlock(iface,
1405 WINED3DSBT_INIT,
1406 (IWineD3DStateBlock **)&This->stateBlock,
1407 NULL);
1408 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1409 WARN("Failed to create stateblock\n");
1410 goto err_out;
1411 }
1412 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1413 This->updateStateBlock = This->stateBlock;
1414 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1415
1416 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1417 sizeof(IWineD3DSurface *) * gl_info->limits.buffers);
1418 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1419 sizeof(GLenum) * gl_info->limits.buffers);
1420
1421 This->NumberOfPalettes = 1;
1422 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1423 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
1424 ERR("Out of memory!\n");
1425 hr = E_OUTOFMEMORY;
1426 goto err_out;
1427 }
1428 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1429 if(!This->palettes[0]) {
1430 ERR("Out of memory!\n");
1431 hr = E_OUTOFMEMORY;
1432 goto err_out;
1433 }
1434 for (i = 0; i < 256; ++i) {
1435 This->palettes[0][i].peRed = 0xFF;
1436 This->palettes[0][i].peGreen = 0xFF;
1437 This->palettes[0][i].peBlue = 0xFF;
1438 This->palettes[0][i].peFlags = 0xFF;
1439 }
1440 This->currentPalette = 0;
1441
1442 /* Initialize the texture unit mapping to a 1:1 mapping */
1443 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1444 {
1445 if (state < gl_info->limits.fragment_samplers)
1446 {
1447 This->texUnitMap[state] = state;
1448 This->rev_tex_unit_map[state] = state;
1449 } else {
1450 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1451 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1452 }
1453 }
1454
1455 if (This->focus_window) SetFocus(This->focus_window);
1456
1457 /* Setup the implicit swapchain. This also initializes a context. */
1458 TRACE("Creating implicit swapchain\n");
1459 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1460 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1461 if (FAILED(hr))
1462 {
1463 WARN("Failed to create implicit swapchain\n");
1464 goto err_out;
1465 }
1466
1467 This->NumberOfSwapChains = 1;
1468 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1469 if(!This->swapchains) {
1470 ERR("Out of memory!\n");
1471 goto err_out;
1472 }
1473 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1474
1475 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1476 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1477 This->render_targets[0] = swapchain->backBuffer[0];
1478 }
1479 else {
1480 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1481 This->render_targets[0] = swapchain->frontBuffer;
1482 }
1483 IWineD3DSurface_AddRef(This->render_targets[0]);
1484
1485 /* Depth Stencil support */
1486 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
1487 if (NULL != This->stencilBufferTarget) {
1488 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1489 }
1490
1491 hr = This->shader_backend->shader_alloc_private(iface);
1492 if(FAILED(hr)) {
1493 TRACE("Shader private data couldn't be allocated\n");
1494 goto err_out;
1495 }
1496 hr = This->frag_pipe->alloc_private(iface);
1497 if(FAILED(hr)) {
1498 TRACE("Fragment pipeline private data couldn't be allocated\n");
1499 goto err_out;
1500 }
1501 hr = This->blitter->alloc_private(iface);
1502 if(FAILED(hr)) {
1503 TRACE("Blitter private data couldn't be allocated\n");
1504 goto err_out;
1505 }
1506
1507 /* Set up some starting GL setup */
1508
1509 /* Setup all the devices defaults */
1510 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1511
1512 context = context_acquire(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
1513
1514 create_dummy_textures(This);
1515
1516 ENTER_GL();
1517
1518 /* Initialize the current view state */
1519 This->view_ident = 1;
1520 This->contexts[0]->last_was_rhw = 0;
1521 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1522 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1523
1524 switch(wined3d_settings.offscreen_rendering_mode) {
1525 case ORM_FBO:
1526 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
1527 break;
1528
1529 case ORM_PBUFFER:
1530 This->offscreenBuffer = GL_BACK;
1531 break;
1532
1533 case ORM_BACKBUFFER:
1534 {
1535 if (context_get_current()->aux_buffers > 0)
1536 {
1537 TRACE("Using auxilliary buffer for offscreen rendering\n");
1538 This->offscreenBuffer = GL_AUX0;
1539 } else {
1540 TRACE("Using back buffer for offscreen rendering\n");
1541 This->offscreenBuffer = GL_BACK;
1542 }
1543 }
1544 }
1545
1546 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1547 LEAVE_GL();
1548
1549 context_release(context);
1550
1551 /* Clear the screen */
1552 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1553 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1554 0x00, 1.0f, 0);
1555
1556 This->d3d_initialized = TRUE;
1557
1558 if(wined3d_settings.logo) {
1559 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
1560 }
1561 This->highest_dirty_ps_const = 0;
1562 This->highest_dirty_vs_const = 0;
1563 return WINED3D_OK;
1564
1565 err_out:
1566 HeapFree(GetProcessHeap(), 0, This->render_targets);
1567 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1568 HeapFree(GetProcessHeap(), 0, This->swapchains);
1569 This->NumberOfSwapChains = 0;
1570 if(This->palettes) {
1571 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
1572 HeapFree(GetProcessHeap(), 0, This->palettes);
1573 }
1574 This->NumberOfPalettes = 0;
1575 if(swapchain) {
1576 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1577 }
1578 if(This->stateBlock) {
1579 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
1580 This->stateBlock = NULL;
1581 }
1582 if (This->blit_priv) {
1583 This->blitter->free_private(iface);
1584 }
1585 if (This->fragment_priv) {
1586 This->frag_pipe->free_private(iface);
1587 }
1588 if (This->shader_priv) {
1589 This->shader_backend->shader_free_private(iface);
1590 }
1591 if (This->focus_window) wined3d_unregister_window(This->focus_window);
1592 return hr;
1593 }
1594
1595 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
1596 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1597 {
1598 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1599 IWineD3DSwapChainImpl *swapchain = NULL;
1600 HRESULT hr;
1601
1602 /* Setup the implicit swapchain */
1603 TRACE("Creating implicit swapchain\n");
1604 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1605 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1606 if (FAILED(hr))
1607 {
1608 WARN("Failed to create implicit swapchain\n");
1609 goto err_out;
1610 }
1611
1612 This->NumberOfSwapChains = 1;
1613 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1614 if(!This->swapchains) {
1615 ERR("Out of memory!\n");
1616 goto err_out;
1617 }
1618 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1619 return WINED3D_OK;
1620
1621 err_out:
1622 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1623 return hr;
1624 }
1625
1626 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
1627 {
1628 IWineD3DResource_UnLoad(resource);
1629 IWineD3DResource_Release(resource);
1630 return WINED3D_OK;
1631 }
1632
1633 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
1634 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
1635 {
1636 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1637 const struct wined3d_gl_info *gl_info;
1638 struct wined3d_context *context;
1639 int sampler;
1640 UINT i;
1641 TRACE("(%p)\n", This);
1642
1643 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1644
1645 /* I don't think that the interface guarantees that the device is destroyed from the same thread
1646 * it was created. Thus make sure a context is active for the glDelete* calls
1647 */
1648 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
1649 gl_info = context->gl_info;
1650
1651 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
1652
1653 /* Unload resources */
1654 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
1655
1656 TRACE("Deleting high order patches\n");
1657 for(i = 0; i < PATCHMAP_SIZE; i++) {
1658 struct list *e1, *e2;
1659 struct WineD3DRectPatch *patch;
1660 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
1661 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
1662 IWineD3DDevice_DeletePatch(iface, patch->Handle);
1663 }
1664 }
1665
1666 /* Delete the palette conversion shader if it is around */
1667 if(This->paletteConversionShader) {
1668 ENTER_GL();
1669 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
1670 LEAVE_GL();
1671 This->paletteConversionShader = 0;
1672 }
1673
1674 /* Delete the pbuffer context if there is any */
1675 if(This->pbufferContext) context_destroy(This, This->pbufferContext);
1676
1677 /* Delete the mouse cursor texture */
1678 if(This->cursorTexture) {
1679 ENTER_GL();
1680 glDeleteTextures(1, &This->cursorTexture);
1681 LEAVE_GL();
1682 This->cursorTexture = 0;
1683 }
1684
1685 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
1686 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1687 }
1688 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
1689 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
1690 }
1691
1692 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
1693 * private data, it might contain opengl pointers
1694 */
1695 if(This->depth_blt_texture) {
1696 ENTER_GL();
1697 glDeleteTextures(1, &This->depth_blt_texture);
1698 LEAVE_GL();
1699 This->depth_blt_texture = 0;
1700 }
1701 if (This->depth_blt_rb) {
1702 ENTER_GL();
1703 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
1704 LEAVE_GL();
1705 This->depth_blt_rb = 0;
1706 This->depth_blt_rb_w = 0;
1707 This->depth_blt_rb_h = 0;
1708 }
1709
1710 /* Release the update stateblock */
1711 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
1712 if(This->updateStateBlock != This->stateBlock)
1713 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1714 }
1715 This->updateStateBlock = NULL;
1716
1717 { /* because were not doing proper internal refcounts releasing the primary state block
1718 causes recursion with the extra checks in ResourceReleased, to avoid this we have
1719 to set this->stateBlock = NULL; first */
1720 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
1721 This->stateBlock = NULL;
1722
1723 /* Release the stateblock */
1724 if(IWineD3DStateBlock_Release(stateBlock) > 0){
1725 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1726 }
1727 }
1728
1729 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
1730 This->blitter->free_private(iface);
1731 This->frag_pipe->free_private(iface);
1732 This->shader_backend->shader_free_private(iface);
1733
1734 /* Release the buffers (with sanity checks)*/
1735 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1736 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1737 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
1738 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
1739 }
1740 This->stencilBufferTarget = NULL;
1741
1742 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1743 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1744 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1745 }
1746 TRACE("Setting rendertarget to NULL\n");
1747 This->render_targets[0] = NULL;
1748
1749 if (This->auto_depth_stencil_buffer) {
1750 if (IWineD3DSurface_Release(This->auto_depth_stencil_buffer) > 0)
1751 {
1752 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
1753 }
1754 This->auto_depth_stencil_buffer = NULL;
1755 }
1756
1757 context_release(context);
1758
1759 for(i=0; i < This->NumberOfSwapChains; i++) {
1760 TRACE("Releasing the implicit swapchain %d\n", i);
1761 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1762 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1763 }
1764 }
1765
1766 HeapFree(GetProcessHeap(), 0, This->swapchains);
1767 This->swapchains = NULL;
1768 This->NumberOfSwapChains = 0;
1769
1770 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
1771 HeapFree(GetProcessHeap(), 0, This->palettes);
1772 This->palettes = NULL;
1773 This->NumberOfPalettes = 0;
1774
1775 HeapFree(GetProcessHeap(), 0, This->render_targets);
1776 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1777 This->render_targets = NULL;
1778 This->draw_buffers = NULL;
1779
1780 This->d3d_initialized = FALSE;
1781
1782 if (This->focus_window) wined3d_unregister_window(This->focus_window);
1783
1784 return WINED3D_OK;
1785 }
1786
1787 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1788 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1789 unsigned int i;
1790
1791 for(i=0; i < This->NumberOfSwapChains; i++) {
1792 TRACE("Releasing the implicit swapchain %d\n", i);
1793 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1794 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1795 }
1796 }
1797
1798 HeapFree(GetProcessHeap(), 0, This->swapchains);
1799 This->swapchains = NULL;
1800 This->NumberOfSwapChains = 0;
1801 return WINED3D_OK;
1802 }
1803
1804 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
1805 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
1806 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
1807 *
1808 * There is no way to deactivate thread safety once it is enabled.
1809 */
1810 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
1811 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1812
1813 /*For now just store the flag(needed in case of ddraw) */
1814 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
1815 }
1816
1817 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
1818 const WINED3DDISPLAYMODE* pMode) {
1819 DEVMODEW devmode;
1820 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1821 LONG ret;
1822 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(pMode->Format, &This->adapter->gl_info);
1823 RECT clip_rc;
1824
1825 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
1826
1827 /* Resize the screen even without a window:
1828 * The app could have unset it with SetCooperativeLevel, but not called
1829 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
1830 * but we don't have any hwnd
1831 */
1832
1833 memset(&devmode, 0, sizeof(devmode));
1834 devmode.dmSize = sizeof(devmode);
1835 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1836 devmode.dmBitsPerPel = format_desc->byte_count * 8;
1837 devmode.dmPelsWidth = pMode->Width;
1838 devmode.dmPelsHeight = pMode->Height;
1839
1840 devmode.dmDisplayFrequency = pMode->RefreshRate;
1841 if (pMode->RefreshRate != 0) {
1842 devmode.dmFields |= DM_DISPLAYFREQUENCY;
1843 }
1844
1845 /* Only change the mode if necessary */
1846 if( (This->ddraw_width == pMode->Width) &&
1847 (This->ddraw_height == pMode->Height) &&
1848 (This->ddraw_format == pMode->Format) &&
1849 (pMode->RefreshRate == 0) ) {
1850 return WINED3D_OK;
1851 }
1852
1853 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
1854 if (ret != DISP_CHANGE_SUCCESSFUL) {
1855 if(devmode.dmDisplayFrequency != 0) {
1856 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
1857 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
1858 devmode.dmDisplayFrequency = 0;
1859 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
1860 }
1861 if(ret != DISP_CHANGE_SUCCESSFUL) {
1862 return WINED3DERR_NOTAVAILABLE;
1863 }
1864 }
1865
1866 /* Store the new values */
1867 This->ddraw_width = pMode->Width;
1868 This->ddraw_height = pMode->Height;
1869 This->ddraw_format = pMode->Format;
1870
1871 /* And finally clip mouse to our screen */
1872 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
1873 ClipCursor(&clip_rc);
1874
1875 return WINED3D_OK;
1876 }
1877
1878 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
1879 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1880 *ppD3D = This->wined3d;
1881 TRACE("Returning %p.\n", *ppD3D);
1882 IWineD3D_AddRef(*ppD3D);
1883 return WINED3D_OK;
1884 }
1885
1886 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
1887 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1888
1889 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
1890 (This->adapter->TextureRam/(1024*1024)),
1891 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
1892 /* return simulated texture memory left */
1893 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
1894 }
1895
1896 /*****
1897 * Get / Set Stream Source
1898 *****/
1899 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
1900 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
1901 {
1902 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1903 IWineD3DBuffer *oldSrc;
1904
1905 if (StreamNumber >= MAX_STREAMS) {
1906 WARN("Stream out of range %d\n", StreamNumber);
1907 return WINED3DERR_INVALIDCALL;
1908 } else if(OffsetInBytes & 0x3) {
1909 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
1910 return WINED3DERR_INVALIDCALL;
1911 }
1912
1913 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
1914 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
1915
1916 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
1917
1918 if(oldSrc == pStreamData &&
1919 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
1920 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
1921 TRACE("Application is setting the old values over, nothing to do\n");
1922 return WINED3D_OK;
1923 }
1924
1925 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
1926 if (pStreamData) {
1927 This->updateStateBlock->streamStride[StreamNumber] = Stride;
1928 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
1929 }
1930
1931 /* Handle recording of state blocks */
1932 if (This->isRecordingState) {
1933 TRACE("Recording... not performing anything\n");
1934 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
1935 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
1936 return WINED3D_OK;
1937 }
1938
1939 if (pStreamData != NULL) {
1940 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
1941 IWineD3DBuffer_AddRef(pStreamData);
1942 }
1943 if (oldSrc != NULL) {
1944 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
1945 IWineD3DBuffer_Release(oldSrc);
1946 }
1947
1948 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
1949
1950 return WINED3D_OK;
1951 }
1952
1953 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
1954 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
1955 {
1956 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1957
1958 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
1959 This->stateBlock->streamSource[StreamNumber],
1960 This->stateBlock->streamOffset[StreamNumber],
1961 This->stateBlock->streamStride[StreamNumber]);
1962
1963 if (StreamNumber >= MAX_STREAMS) {
1964 WARN("Stream out of range %d\n", StreamNumber);
1965 return WINED3DERR_INVALIDCALL;
1966 }
1967 *pStream = This->stateBlock->streamSource[StreamNumber];
1968 *pStride = This->stateBlock->streamStride[StreamNumber];
1969 if (pOffset) {
1970 *pOffset = This->stateBlock->streamOffset[StreamNumber];
1971 }
1972
1973 if (*pStream != NULL) {
1974 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
1975 }
1976 return WINED3D_OK;
1977 }
1978
1979 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
1980 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1981 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
1982 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
1983
1984 /* Verify input at least in d3d9 this is invalid*/
1985 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
1986 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
1987 return WINED3DERR_INVALIDCALL;
1988 }
1989 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
1990 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
1991 return WINED3DERR_INVALIDCALL;
1992 }
1993 if( Divider == 0 ){
1994 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
1995 return WINED3DERR_INVALIDCALL;
1996 }
1997
1998 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
1999 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2000
2001 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2002 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2003
2004 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2005 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2006 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2007 }
2008
2009 return WINED3D_OK;
2010 }
2011
2012 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2013 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2014
2015 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2016 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2017
2018 TRACE("(%p) : returning %d\n", This, *Divider);
2019
2020 return WINED3D_OK;
2021 }
2022
2023 /*****
2024 * Get / Set & Multiply Transform
2025 *****/
2026 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2027 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2028
2029 /* Most of this routine, comments included copied from ddraw tree initially: */
2030 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2031
2032 /* Handle recording of state blocks */
2033 if (This->isRecordingState) {
2034 TRACE("Recording... not performing anything\n");
2035 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2036 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2037 return WINED3D_OK;
2038 }
2039
2040 /*
2041 * If the new matrix is the same as the current one,
2042 * we cut off any further processing. this seems to be a reasonable
2043 * optimization because as was noticed, some apps (warcraft3 for example)
2044 * tend towards setting the same matrix repeatedly for some reason.
2045 *
2046 * From here on we assume that the new matrix is different, wherever it matters.
2047 */
2048 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2049 TRACE("The app is setting the same matrix over again\n");
2050 return WINED3D_OK;
2051 } else {
2052 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2053 }
2054
2055 /*
2056 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2057 where ViewMat = Camera space, WorldMat = world space.
2058
2059 In OpenGL, camera and world space is combined into GL_MODELVIEW
2060 matrix. The Projection matrix stay projection matrix.
2061 */
2062
2063 /* Capture the times we can just ignore the change for now */
2064 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2065 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2066 /* Handled by the state manager */
2067 }
2068
2069 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2070 return WINED3D_OK;
2071
2072 }
2073 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2074 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2075 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2076 *pMatrix = This->stateBlock->transforms[State];
2077 return WINED3D_OK;
2078 }
2079
2080 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2081 const WINED3DMATRIX *mat = NULL;
2082 WINED3DMATRIX temp;
2083
2084 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2085 * below means it will be recorded in a state block change, but it
2086 * works regardless where it is recorded.
2087 * If this is found to be wrong, change to StateBlock.
2088 */
2089 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2090 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2091
2092 if (State <= HIGHEST_TRANSFORMSTATE)
2093 {
2094 mat = &This->updateStateBlock->transforms[State];
2095 } else {
2096 FIXME("Unhandled transform state!!\n");
2097 }
2098
2099 multiply_matrix(&temp, mat, pMatrix);
2100
2101 /* Apply change via set transform - will reapply to eg. lights this way */
2102 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2103 }
2104
2105 /*****
2106 * Get / Set Light
2107 *****/
2108 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2109 you can reference any indexes you want as long as that number max are enabled at any
2110 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2111 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2112 but when recording, just build a chain pretty much of commands to be replayed. */
2113
2114 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2115 float rho;
2116 struct wined3d_light_info *object = NULL;
2117 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2118 struct list *e;
2119
2120 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2121 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2122
2123 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2124 * the gl driver.
2125 */
2126 if(!pLight) {
2127 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2128 return WINED3DERR_INVALIDCALL;
2129 }
2130
2131 switch(pLight->Type) {
2132 case WINED3DLIGHT_POINT:
2133 case WINED3DLIGHT_SPOT:
2134 case WINED3DLIGHT_PARALLELPOINT:
2135 case WINED3DLIGHT_GLSPOT:
2136 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2137 * most wanted
2138 */
2139 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2140 {
2141 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2142 return WINED3DERR_INVALIDCALL;
2143 }
2144 break;
2145
2146 case WINED3DLIGHT_DIRECTIONAL:
2147 /* Ignores attenuation */
2148 break;
2149
2150 default:
2151 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2152 return WINED3DERR_INVALIDCALL;
2153 }
2154
2155 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2156 {
2157 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2158 if(object->OriginalIndex == Index) break;
2159 object = NULL;
2160 }
2161
2162 if(!object) {
2163 TRACE("Adding new light\n");
2164 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2165 if(!object) {
2166 ERR("Out of memory error when allocating a light\n");
2167 return E_OUTOFMEMORY;
2168 }
2169 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2170 object->glIndex = -1;
2171 object->OriginalIndex = Index;
2172 }
2173
2174 /* Initialize the object */
2175 TRACE("Light %d setting to type %d, Diffuse(%f,%f,%f,%f), Specular(%f,%f,%f,%f), Ambient(%f,%f,%f,%f)\n", Index, pLight->Type,
2176 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2177 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2178 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2179 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2180 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2181 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2182
2183 /* Save away the information */
2184 object->OriginalParms = *pLight;
2185
2186 switch (pLight->Type) {
2187 case WINED3DLIGHT_POINT:
2188 /* Position */
2189 object->lightPosn[0] = pLight->Position.x;
2190 object->lightPosn[1] = pLight->Position.y;
2191 object->lightPosn[2] = pLight->Position.z;
2192 object->lightPosn[3] = 1.0f;
2193 object->cutoff = 180.0f;
2194 /* FIXME: Range */
2195 break;
2196
2197 case WINED3DLIGHT_DIRECTIONAL:
2198 /* Direction */
2199 object->lightPosn[0] = -pLight->Direction.x;
2200 object->lightPosn[1] = -pLight->Direction.y;
2201 object->lightPosn[2] = -pLight->Direction.z;
2202 object->lightPosn[3] = 0.0f;
2203 object->exponent = 0.0f;
2204 object->cutoff = 180.0f;
2205 break;
2206
2207 case WINED3DLIGHT_SPOT:
2208 /* Position */
2209 object->lightPosn[0] = pLight->Position.x;
2210 object->lightPosn[1] = pLight->Position.y;
2211 object->lightPosn[2] = pLight->Position.z;
2212 object->lightPosn[3] = 1.0f;
2213
2214 /* Direction */
2215 object->lightDirn[0] = pLight->Direction.x;
2216 object->lightDirn[1] = pLight->Direction.y;
2217 object->lightDirn[2] = pLight->Direction.z;
2218 object->lightDirn[3] = 1.0f;
2219
2220 /*
2221 * opengl-ish and d3d-ish spot lights use too different models for the
2222 * light "intensity" as a function of the angle towards the main light direction,
2223 * so we only can approximate very roughly.
2224 * however spot lights are rather rarely used in games (if ever used at all).
2225 * furthermore if still used, probably nobody pays attention to such details.
2226 */
2227 if (pLight->Falloff == 0) {
2228 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2229 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2230 * will always be 1.0 for both of them, and we don't have to care for the
2231 * rest of the rather complex calculation
2232 */
2233 object->exponent = 0.0f;
2234 } else {
2235 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2236 if (rho < 0.0001f) rho = 0.0001f;
2237 object->exponent = -0.3f/logf(cosf(rho/2));
2238 }
2239 if (object->exponent > 128.0f)
2240 {
2241 object->exponent = 128.0f;
2242 }
2243 object->cutoff = pLight->Phi*90/M_PI;
2244
2245 /* FIXME: Range */
2246 break;
2247
2248 default:
2249 FIXME("Unrecognized light type %d\n", pLight->Type);
2250 }
2251
2252 /* Update the live definitions if the light is currently assigned a glIndex */
2253 if (object->glIndex != -1 && !This->isRecordingState) {
2254 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2255 }
2256 return WINED3D_OK;
2257 }
2258
2259 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2260 {
2261 struct wined3d_light_info *lightInfo = NULL;
2262 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2263 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2264 struct list *e;
2265 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2266
2267 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2268 {
2269 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2270 if(lightInfo->OriginalIndex == Index) break;
2271 lightInfo = NULL;
2272 }
2273
2274 if (lightInfo == NULL) {
2275 TRACE("Light information requested but light not defined\n");
2276 return WINED3DERR_INVALIDCALL;
2277 }
2278
2279 *pLight = lightInfo->OriginalParms;
2280 return WINED3D_OK;
2281 }
2282
2283 /*****
2284 * Get / Set Light Enable
2285 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2286 *****/
2287 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2288 {
2289 struct wined3d_light_info *lightInfo = NULL;
2290 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2291 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2292 struct list *e;
2293 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2294
2295 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2296 {
2297 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2298 if(lightInfo->OriginalIndex == Index) break;
2299 lightInfo = NULL;
2300 }
2301 TRACE("Found light: %p\n", lightInfo);
2302
2303 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2304 if (lightInfo == NULL) {
2305
2306 TRACE("Light enabled requested but light not defined, so defining one!\n");
2307 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2308
2309 /* Search for it again! Should be fairly quick as near head of list */
2310 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2311 {
2312 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2313 if(lightInfo->OriginalIndex == Index) break;
2314 lightInfo = NULL;
2315 }
2316 if (lightInfo == NULL) {
2317 FIXME("Adding default lights has failed dismally\n");
2318 return WINED3DERR_INVALIDCALL;
2319 }
2320 }
2321
2322 if(!Enable) {
2323 if(lightInfo->glIndex != -1) {
2324 if(!This->isRecordingState) {
2325 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2326 }
2327
2328 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2329 lightInfo->glIndex = -1;
2330 } else {
2331 TRACE("Light already disabled, nothing to do\n");
2332 }
2333 lightInfo->enabled = FALSE;
2334 } else {
2335 lightInfo->enabled = TRUE;
2336 if (lightInfo->glIndex != -1) {
2337 /* nop */
2338 TRACE("Nothing to do as light was enabled\n");
2339 } else {
2340 int i;
2341 /* Find a free gl light */
2342 for(i = 0; i < This->maxConcurrentLights; i++) {
2343 if(This->updateStateBlock->activeLights[i] == NULL) {
2344 This->updateStateBlock->activeLights[i] = lightInfo;
2345 lightInfo->glIndex = i;
2346 break;
2347 }
2348 }
2349 if(lightInfo->glIndex == -1) {
2350 /* Our tests show that Windows returns D3D_OK in this situation, even with
2351 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2352 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2353 * as well for those lights.
2354 *
2355 * TODO: Test how this affects rendering
2356 */
2357 WARN("Too many concurrently active lights\n");
2358 return WINED3D_OK;
2359 }
2360
2361 /* i == lightInfo->glIndex */
2362 if(!This->isRecordingState) {
2363 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2364 }
2365 }
2366 }
2367
2368 return WINED3D_OK;
2369 }
2370
2371 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2372 {
2373 struct wined3d_light_info *lightInfo = NULL;
2374 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2375 struct list *e;
2376 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2377 TRACE("(%p) : for idx(%d)\n", This, Index);
2378
2379 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2380 {
2381 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2382 if(lightInfo->OriginalIndex == Index) break;
2383 lightInfo = NULL;
2384 }
2385
2386 if (lightInfo == NULL) {
2387 TRACE("Light enabled state requested but light not defined\n");
2388 return WINED3DERR_INVALIDCALL;
2389 }
2390 /* true is 128 according to SetLightEnable */
2391 *pEnable = lightInfo->enabled ? 128 : 0;
2392 return WINED3D_OK;
2393 }
2394
2395 /*****
2396 * Get / Set Clip Planes
2397 *****/
2398 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2399 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2400 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2401
2402 /* Validate Index */
2403 if (Index >= This->adapter->gl_info.limits.clipplanes)
2404 {
2405 TRACE("Application has requested clipplane this device doesn't support\n");
2406 return WINED3DERR_INVALIDCALL;
2407 }
2408
2409 This->updateStateBlock->changed.clipplane |= 1 << Index;
2410
2411 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2412 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2413 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2414 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2415 TRACE("Application is setting old values over, nothing to do\n");
2416 return WINED3D_OK;
2417 }
2418
2419 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2420 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2421 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2422 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2423
2424 /* Handle recording of state blocks */
2425 if (This->isRecordingState) {
2426 TRACE("Recording... not performing anything\n");
2427 return WINED3D_OK;
2428 }
2429
2430 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2431
2432 return WINED3D_OK;
2433 }
2434
2435 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2437 TRACE("(%p) : for idx %d\n", This, Index);
2438
2439 /* Validate Index */
2440 if (Index >= This->adapter->gl_info.limits.clipplanes)
2441 {
2442 TRACE("Application has requested clipplane this device doesn't support\n");
2443 return WINED3DERR_INVALIDCALL;
2444 }
2445
2446 pPlane[0] = This->stateBlock->clipplane[Index][0];
2447 pPlane[1] = This->stateBlock->clipplane[Index][1];
2448 pPlane[2] = This->stateBlock->clipplane[Index][2];
2449 pPlane[3] = This->stateBlock->clipplane[Index][3];
2450 return WINED3D_OK;
2451 }
2452
2453 /*****
2454 * Get / Set Clip Plane Status
2455 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2456 *****/
2457 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2458 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2459 FIXME("(%p) : stub\n", This);
2460 if (NULL == pClipStatus) {
2461 return WINED3DERR_INVALIDCALL;
2462 }
2463 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2464 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2465 return WINED3D_OK;
2466 }
2467
2468 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2469 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2470 FIXME("(%p) : stub\n", This);
2471 if (NULL == pClipStatus) {
2472 return WINED3DERR_INVALIDCALL;
2473 }
2474 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2475 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2476 return WINED3D_OK;
2477 }
2478
2479 /*****
2480 * Get / Set Material
2481 *****/
2482 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2483 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2484
2485 This->updateStateBlock->changed.material = TRUE;
2486 This->updateStateBlock->material = *pMaterial;
2487
2488 /* Handle recording of state blocks */
2489 if (This->isRecordingState) {
2490 TRACE("Recording... not performing anything\n");
2491 return WINED3D_OK;
2492 }
2493
2494 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2495 return WINED3D_OK;
2496 }
2497
2498 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2499 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2500 *pMaterial = This->updateStateBlock->material;
2501 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2502 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2503 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2504 pMaterial->Ambient.b, pMaterial->Ambient.a);
2505 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2506 pMaterial->Specular.b, pMaterial->Specular.a);
2507 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2508 pMaterial->Emissive.b, pMaterial->Emissive.a);
2509 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2510
2511 return WINED3D_OK;
2512 }
2513
2514 /*****
2515 * Get / Set Indices
2516 *****/
2517 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
2518 IWineD3DBuffer *pIndexData, WINED3DFORMAT fmt)
2519 {
2520 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2521 IWineD3DBuffer *oldIdxs;
2522
2523 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2524 oldIdxs = This->updateStateBlock->pIndexData;
2525
2526 This->updateStateBlock->changed.indices = TRUE;
2527 This->updateStateBlock->pIndexData = pIndexData;
2528 This->updateStateBlock->IndexFmt = fmt;
2529
2530 /* Handle recording of state blocks */
2531 if (This->isRecordingState) {
2532 TRACE("Recording... not performing anything\n");
2533 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
2534 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2535 return WINED3D_OK;
2536 }
2537
2538 if(oldIdxs != pIndexData) {
2539 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2540 if(pIndexData) {
2541 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2542 IWineD3DBuffer_AddRef(pIndexData);
2543 }
2544 if(oldIdxs) {
2545 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2546 IWineD3DBuffer_Release(oldIdxs);
2547 }
2548 }
2549
2550 return WINED3D_OK;
2551 }
2552
2553 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
2554 {
2555 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2556
2557 *ppIndexData = This->stateBlock->pIndexData;
2558
2559 /* up ref count on ppindexdata */
2560 if (*ppIndexData) {
2561 IWineD3DBuffer_AddRef(*ppIndexData);
2562 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2563 }else{
2564 TRACE("(%p) No index data set\n", This);
2565 }
2566 TRACE("Returning %p\n", *ppIndexData);
2567
2568 return WINED3D_OK;
2569 }
2570
2571 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2572 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2573 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2574 TRACE("(%p)->(%d)\n", This, BaseIndex);
2575
2576 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2577 TRACE("Application is setting the old value over, nothing to do\n");
2578 return WINED3D_OK;
2579 }
2580
2581 This->updateStateBlock->baseVertexIndex = BaseIndex;
2582
2583 if (This->isRecordingState) {
2584 TRACE("Recording... not performing anything\n");
2585 return WINED3D_OK;
2586 }
2587 /* The base vertex index affects the stream sources */
2588 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2589 return WINED3D_OK;
2590 }
2591
2592 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2593 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2594 TRACE("(%p) : base_index %p\n", This, base_index);
2595
2596 *base_index = This->stateBlock->baseVertexIndex;
2597
2598 TRACE("Returning %u\n", *base_index);
2599
2600 return WINED3D_OK;
2601 }
2602
2603 /*****
2604 * Get / Set Viewports
2605 *****/
2606 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2607 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2608
2609 TRACE("(%p)\n", This);
2610 This->updateStateBlock->changed.viewport = TRUE;
2611 This->updateStateBlock->viewport = *pViewport;
2612
2613 /* Handle recording of state blocks */
2614 if (This->isRecordingState) {
2615 TRACE("Recording... not performing anything\n");
2616 return WINED3D_OK;
2617 }
2618
2619 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2620 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2621
2622 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2623 return WINED3D_OK;
2624
2625 }
2626
2627 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2628 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2629 TRACE("(%p)\n", This);
2630 *pViewport = This->stateBlock->viewport;
2631 return WINED3D_OK;
2632 }
2633
2634 /*****
2635 * Get / Set Render States
2636 * TODO: Verify against dx9 definitions
2637 *****/
2638 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2639
2640 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2641 DWORD oldValue = This->stateBlock->renderState[State];
2642
2643 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2644
2645 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
2646 This->updateStateBlock->renderState[State] = Value;
2647
2648 /* Handle recording of state blocks */
2649 if (This->isRecordingState) {
2650 TRACE("Recording... not performing anything\n");
2651 return WINED3D_OK;
2652 }
2653
2654 /* Compared here and not before the assignment to allow proper stateblock recording */
2655 if(Value == oldValue) {
2656 TRACE("Application is setting the old value over, nothing to do\n");
2657 } else {
2658 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2659 }
2660
2661 return WINED3D_OK;
2662 }
2663
2664 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2665 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2666 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2667 *pValue = This->stateBlock->renderState[State];
2668 return WINED3D_OK;
2669 }
2670
2671 /*****
2672 * Get / Set Sampler States
2673 * TODO: Verify against dx9 definitions
2674 *****/
2675
2676 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2677 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2678 DWORD oldValue;
2679
2680 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
2681 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
2682
2683 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2684 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2685 }
2686
2687 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2688 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2689 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2690 }
2691 /**
2692 * SetSampler is designed to allow for more than the standard up to 8 textures
2693 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2694 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2695 *
2696 * http://developer.nvidia.com/object/General_FAQ.html#t6
2697 *
2698 * There are two new settings for GForce
2699 * the sampler one:
2700 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2701 * and the texture one:
2702 * GL_MAX_TEXTURE_COORDS_ARB.
2703 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2704 ******************/
2705
2706 oldValue = This->stateBlock->samplerState[Sampler][Type];
2707 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2708 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
2709
2710 /* Handle recording of state blocks */
2711 if (This->isRecordingState) {
2712 TRACE("Recording... not performing anything\n");
2713 return WINED3D_OK;
2714 }
2715
2716 if(oldValue == Value) {
2717 TRACE("Application is setting the old value over, nothing to do\n");
2718 return WINED3D_OK;
2719 }
2720
2721 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2722
2723 return WINED3D_OK;
2724 }
2725
2726 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2727 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2728
2729 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
2730 This, Sampler, debug_d3dsamplerstate(Type), Type);
2731
2732 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2733 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2734 }
2735
2736 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2737 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2738 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2739 }
2740 *Value = This->stateBlock->samplerState[Sampler][Type];
2741 TRACE("(%p) : Returning %#x\n", This, *Value);
2742
2743 return WINED3D_OK;
2744 }
2745
2746 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2747 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2748
2749 This->updateStateBlock->changed.scissorRect = TRUE;
2750 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2751 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2752 return WINED3D_OK;
2753 }
2754 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2755
2756 if(This->isRecordingState) {
2757 TRACE("Recording... not performing anything\n");
2758 return WINED3D_OK;
2759 }
2760
2761 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2762
2763 return WINED3D_OK;
2764 }
2765
2766 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2767 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2768
2769 *pRect = This->updateStateBlock->scissorRect;
2770 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2771 return WINED3D_OK;
2772 }
2773
2774 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2775 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2776 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2777
2778 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2779
2780 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
2781 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
2782
2783 This->updateStateBlock->vertexDecl = pDecl;
2784 This->updateStateBlock->changed.vertexDecl = TRUE;
2785
2786 if (This->isRecordingState) {
2787 TRACE("Recording... not performing anything\n");
2788 return WINED3D_OK;
2789 } else if(pDecl == oldDecl) {
2790 /* Checked after the assignment to allow proper stateblock recording */
2791 TRACE("Application is setting the old declaration over, nothing to do\n");
2792 return WINED3D_OK;
2793 }
2794
2795 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2796 return WINED3D_OK;
2797 }
2798
2799 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
2800 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2801
2802 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
2803
2804 *ppDecl = This->stateBlock->vertexDecl;
2805 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
2806 return WINED3D_OK;
2807 }
2808
2809 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
2810 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2811 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
2812
2813 This->updateStateBlock->vertexShader = pShader;
2814 This->updateStateBlock->changed.vertexShader = TRUE;
2815
2816 if (This->isRecordingState) {
2817 if(pShader) IWineD3DVertexShader_AddRef(pShader);
2818 if(oldShader) IWineD3DVertexShader_Release(oldShader);
2819 TRACE("Recording... not performing anything\n");
2820 return WINED3D_OK;
2821 } else if(oldShader == pShader) {
2822 /* Checked here to allow proper stateblock recording */
2823 TRACE("App is setting the old shader over, nothing to do\n");
2824 return WINED3D_OK;
2825 }
2826
2827 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
2828 if(pShader) IWineD3DVertexShader_AddRef(pShader);
2829 if(oldShader) IWineD3DVertexShader_Release(oldShader);
2830
2831 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
2832
2833 return WINED3D_OK;
2834 }
2835
2836 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
2837 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2838
2839 if (NULL == ppShader) {
2840 return WINED3DERR_INVALIDCALL;
2841 }
2842 *ppShader = This->stateBlock->vertexShader;
2843 if( NULL != *ppShader)
2844 IWineD3DVertexShader_AddRef(*ppShader);
2845
2846 TRACE("(%p) : returning %p\n", This, *ppShader);
2847 return WINED3D_OK;
2848 }
2849
2850 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
2851 IWineD3DDevice *iface,
2852 UINT start,
2853 CONST BOOL *srcData,
2854 UINT count) {
2855
2856 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2857 unsigned int i, cnt = min(count, MAX_CONST_B - start);
2858
2859 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2860 iface, srcData, start, count);
2861
2862 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
2863
2864 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
2865 for (i = 0; i < cnt; i++)
2866 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
2867
2868 for (i = start; i < cnt + start; ++i) {
2869 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
2870 }
2871
2872 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2873
2874 return WINED3D_OK;
2875 }
2876
2877 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
2878 IWineD3DDevice *iface,
2879 UINT start,
2880 BOOL *dstData,
2881 UINT count) {
2882
2883 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2884 int cnt = min(count, MAX_CONST_B - start);
2885
2886 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2887 iface, dstData, start, count);
2888
2889 if (dstData == NULL || cnt < 0)
2890 return WINED3DERR_INVALIDCALL;
2891
2892 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
2893 return WINED3D_OK;
2894 }
2895
2896 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
2897 IWineD3DDevice *iface,
2898 UINT start,
2899 CONST int *srcData,
2900 UINT count) {
2901
2902 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2903 unsigned int i, cnt = min(count, MAX_CONST_I - start);
2904
2905 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2906 iface, srcData, start, count);
2907
2908 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
2909
2910 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
2911 for (i = 0; i < cnt; i++)
2912 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
2913 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
2914
2915 for (i = start; i < cnt + start; ++i) {
2916 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
2917 }
2918
2919 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2920
2921 return WINED3D_OK;
2922 }
2923
2924 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
2925 IWineD3DDevice *iface,
2926 UINT start,
2927 int *dstData,
2928 UINT count) {
2929
2930 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2931 int cnt = min(count, MAX_CONST_I - start);
2932
2933 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2934 iface, dstData, start, count);
2935
2936 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
2937 return WINED3DERR_INVALIDCALL;
2938
2939 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
2940 return WINED3D_OK;
2941 }
2942
2943 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
2944 IWineD3DDevice *iface,
2945 UINT start,
2946 CONST float *srcData,
2947 UINT count) {
2948
2949 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2950 UINT i;
2951
2952 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2953 iface, srcData, start, count);
2954
2955 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
2956 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
2957 return WINED3DERR_INVALIDCALL;
2958
2959 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
2960 if(TRACE_ON(d3d)) {
2961 for (i = 0; i < count; i++)
2962 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
2963 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
2964 }
2965
2966 if (!This->isRecordingState)
2967 {
2968 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
2969 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2970 }
2971
2972 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
2973 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
2974
2975 return WINED3D_OK;
2976 }
2977
2978 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
2979 IWineD3DDevice *iface,
2980 UINT start,
2981 float *dstData,
2982 UINT count) {
2983
2984 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2985 int cnt = min(count, This->d3d_vshader_constantF - start);
2986
2987 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2988 iface, dstData, start, count);
2989
2990 if (dstData == NULL || cnt < 0)
2991 return WINED3DERR_INVALIDCALL;
2992
2993 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float