34495d396d9b22f09e9a440d54f51892df6d646b
[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) * 4);
2994 return WINED3D_OK;
2995 }
2996
2997 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
2998 DWORD i;
2999 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3000 {
3001 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3002 }
3003 }
3004
3005 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3006 {
3007 DWORD i = This->rev_tex_unit_map[unit];
3008 DWORD j = This->texUnitMap[stage];
3009
3010 This->texUnitMap[stage] = unit;
3011 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3012 {
3013 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3014 }
3015
3016 This->rev_tex_unit_map[unit] = stage;
3017 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3018 {
3019 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3020 }
3021 }
3022
3023 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3024 int i;
3025
3026 This->fixed_function_usage_map = 0;
3027 for (i = 0; i < MAX_TEXTURES; ++i) {
3028 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3029 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3030 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3031 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3032 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3033 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3034 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3035 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3036
3037 if (color_op == WINED3DTOP_DISABLE) {
3038 /* Not used, and disable higher stages */
3039 break;
3040 }
3041
3042 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3043 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3044 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3045 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3046 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3047 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3048 This->fixed_function_usage_map |= (1 << i);
3049 }
3050
3051 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3052 This->fixed_function_usage_map |= (1 << (i + 1));
3053 }
3054 }
3055 }
3056
3057 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3058 unsigned int i, tex;
3059 WORD ffu_map;
3060
3061 device_update_fixed_function_usage_map(This);
3062 ffu_map = This->fixed_function_usage_map;
3063
3064 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3065 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3066 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3067 {
3068 if (!(ffu_map & 1)) continue;
3069
3070 if (This->texUnitMap[i] != i) {
3071 device_map_stage(This, i, i);
3072 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3073 markTextureStagesDirty(This, i);
3074 }
3075 }
3076 return;
3077 }
3078
3079 /* Now work out the mapping */
3080 tex = 0;
3081 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3082 {
3083 if (!(ffu_map & 1)) continue;
3084
3085 if (This->texUnitMap[i] != tex) {
3086 device_map_stage(This, i, tex);
3087 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3088 markTextureStagesDirty(This, i);
3089 }
3090
3091 ++tex;
3092 }
3093 }
3094
3095 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3096 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3097 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3098 unsigned int i;
3099
3100 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3101 if (sampler_type[i] && This->texUnitMap[i] != i)
3102 {
3103 device_map_stage(This, i, i);
3104 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3105 if (i < MAX_TEXTURES) {
3106 markTextureStagesDirty(This, i);
3107 }
3108 }
3109 }
3110 }
3111
3112 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3113 const DWORD *vshader_sampler_tokens, DWORD unit)
3114 {
3115 DWORD current_mapping = This->rev_tex_unit_map[unit];
3116
3117 /* Not currently used */
3118 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3119
3120 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3121 /* Used by a fragment sampler */
3122
3123 if (!pshader_sampler_tokens) {
3124 /* No pixel shader, check fixed function */
3125 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3126 }
3127
3128 /* Pixel shader, check the shader's sampler map */
3129 return !pshader_sampler_tokens[current_mapping];
3130 }
3131
3132 /* Used by a vertex sampler */
3133 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3134 }
3135
3136 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3137 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3138 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3139 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3140 int start = min(MAX_COMBINED_SAMPLERS, This->adapter->gl_info.limits.combined_samplers) - 1;
3141 int i;
3142
3143 if (ps) {
3144 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3145
3146 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3147 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3148 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3149 }
3150
3151 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3152 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3153 if (vshader_sampler_type[i])
3154 {
3155 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3156 {
3157 /* Already mapped somewhere */
3158 continue;
3159 }
3160
3161 while (start >= 0) {
3162 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3163 {
3164 device_map_stage(This, vsampler_idx, start);
3165 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3166
3167 --start;
3168 break;
3169 }
3170
3171 --start;
3172 }
3173 }
3174 }
3175 }
3176
3177 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3178 BOOL vs = use_vs(This->stateBlock);
3179 BOOL ps = use_ps(This->stateBlock);
3180 /*
3181 * Rules are:
3182 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3183 * that would be really messy and require shader recompilation
3184 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3185 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3186 */
3187 if (ps) {
3188 device_map_psamplers(This);
3189 } else {
3190 device_map_fixed_function_samplers(This);
3191 }
3192
3193 if (vs) {
3194 device_map_vsamplers(This, ps);
3195 }
3196 }
3197
3198 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3199 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3200 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3201 This->updateStateBlock->pixelShader = pShader;
3202 This->updateStateBlock->changed.pixelShader = TRUE;
3203
3204 /* Handle recording of state blocks */
3205 if (This->isRecordingState) {
3206 TRACE("Recording... not performing anything\n");
3207 }
3208
3209 if (This->isRecordingState) {
3210 TRACE("Recording... not performing anything\n");
3211 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3212 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3213 return WINED3D_OK;
3214 }
3215
3216 if(pShader == oldShader) {
3217 TRACE("App is setting the old pixel shader over, nothing to do\n");
3218 return WINED3D_OK;
3219 }
3220
3221 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3222 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3223
3224 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3225 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3226
3227 return WINED3D_OK;
3228 }
3229
3230 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3231 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3232
3233 if (NULL == ppShader) {
3234 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3235 return WINED3DERR_INVALIDCALL;
3236 }
3237
3238 *ppShader = This->stateBlock->pixelShader;
3239 if (NULL != *ppShader) {
3240 IWineD3DPixelShader_AddRef(*ppShader);
3241 }
3242 TRACE("(%p) : returning %p\n", This, *ppShader);
3243 return WINED3D_OK;
3244 }
3245
3246 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3247 IWineD3DDevice *iface,
3248 UINT start,
3249 CONST BOOL *srcData,
3250 UINT count) {
3251
3252 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3253 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3254
3255 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3256 iface, srcData, start, count);
3257
3258 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3259
3260 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3261 for (i = 0; i < cnt; i++)
3262 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3263
3264 for (i = start; i < cnt + start; ++i) {
3265 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3266 }
3267
3268 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3269
3270 return WINED3D_OK;
3271 }
3272
3273 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3274 IWineD3DDevice *iface,
3275 UINT start,
3276 BOOL *dstData,
3277 UINT count) {
3278
3279 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3280 int cnt = min(count, MAX_CONST_B - start);
3281
3282 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3283 iface, dstData, start, count);
3284
3285 if (dstData == NULL || cnt < 0)
3286 return WINED3DERR_INVALIDCALL;
3287
3288 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3289 return WINED3D_OK;
3290 }
3291
3292 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3293 IWineD3DDevice *iface,
3294 UINT start,
3295 CONST int *srcData,
3296 UINT count) {
3297
3298 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3299 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3300
3301 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3302 iface, srcData, start, count);
3303
3304 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3305
3306 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3307 for (i = 0; i < cnt; i++)
3308 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3309 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3310
3311 for (i = start; i < cnt + start; ++i) {
3312 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3313 }
3314
3315 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3316
3317 return WINED3D_OK;
3318 }
3319
3320 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3321 IWineD3DDevice *iface,
3322 UINT start,
3323 int *dstData,
3324 UINT count) {
3325
3326 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3327 int cnt = min(count, MAX_CONST_I - start);
3328
3329 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3330 iface, dstData, start, count);
3331
3332 if (dstData == NULL || cnt < 0)
3333 return WINED3DERR_INVALIDCALL;
3334
3335 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3336 return WINED3D_OK;
3337 }
3338
3339 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3340 IWineD3DDevice *iface,
3341 UINT start,
3342 CONST float *srcData,
3343 UINT count) {
3344
3345 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3346 UINT i;
3347
3348 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3349 iface, srcData, start, count);
3350
3351 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3352 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3353 return WINED3DERR_INVALIDCALL;
3354
3355 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3356 if(TRACE_ON(d3d)) {
3357 for (i = 0; i < count; i++)
3358 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3359 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3360 }
3361
3362 if (!This->isRecordingState)
3363 {
3364 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3365 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3366 }
3367
3368 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3369 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3370
3371 return WINED3D_OK;
3372 }
3373
3374 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3375 IWineD3DDevice *iface,
3376 UINT start,
3377 float *dstData,
3378 UINT count) {
3379
3380 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3381 int cnt = min(count, This->d3d_pshader_constantF - start);
3382
3383 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3384 iface, dstData, start, count);
3385
3386 if (dstData == NULL || cnt < 0)
3387 return WINED3DERR_INVALIDCALL;
3388
3389 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3390 return WINED3D_OK;
3391 }
3392
3393 /* Context activation is done by the caller. */
3394 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3395 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3396 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3397 DWORD DestFVF)
3398 {
3399 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3400 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3401 unsigned int i;
3402 WINED3DVIEWPORT vp;
3403 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3404 BOOL doClip;
3405 DWORD numTextures;
3406
3407 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3408 {
3409 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3410 }
3411
3412 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3413 {
3414 ERR("Source has no position mask\n");
3415 return WINED3DERR_INVALIDCALL;
3416 }
3417
3418 /* We might access VBOs from this code, so hold the lock */
3419 ENTER_GL();
3420
3421 if (dest->resource.allocatedMemory == NULL) {
3422 buffer_get_sysmem(dest);
3423 }
3424
3425 /* Get a pointer into the destination vbo(create one if none exists) and
3426 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3427 */
3428 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3429 {
3430 dest->flags |= WINED3D_BUFFER_CREATEBO;
3431 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3432 }
3433
3434 if (dest->buffer_object)
3435 {
3436 unsigned char extrabytes = 0;
3437 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3438 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3439 * this may write 4 extra bytes beyond the area that should be written
3440 */
3441 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3442 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3443 if(!dest_conv_addr) {
3444 ERR("Out of memory\n");
3445 /* Continue without storing converted vertices */
3446 }
3447 dest_conv = dest_conv_addr;
3448 }
3449
3450 /* Should I clip?
3451 * a) WINED3DRS_CLIPPING is enabled
3452 * b) WINED3DVOP_CLIP is passed
3453 */
3454 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3455 static BOOL warned = FALSE;
3456 /*
3457 * The clipping code is not quite correct. Some things need
3458 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3459 * so disable clipping for now.
3460 * (The graphics in Half-Life are broken, and my processvertices
3461 * test crashes with IDirect3DDevice3)
3462 doClip = TRUE;
3463 */
3464 doClip = FALSE;
3465 if(!warned) {
3466 warned = TRUE;
3467 FIXME("Clipping is broken and disabled for now\n");
3468 }
3469 } else doClip = FALSE;
3470 dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3471
3472 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3473 WINED3DTS_VIEW,
3474 &view_mat);
3475 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3476 WINED3DTS_PROJECTION,
3477 &proj_mat);
3478 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3479 WINED3DTS_WORLDMATRIX(0),
3480 &world_mat);
3481
3482 TRACE("View mat:\n");
3483 TRACE("%f %f %f %f\n", view_mat.u.s._11, view_mat.u.s._12, view_mat.u.s._13, view_mat.u.s._14);
3484 TRACE("%f %f %f %f\n", view_mat.u.s._21, view_mat.u.s._22, view_mat.u.s._23, view_mat.u.s._24);
3485 TRACE("%f %f %f %f\n", view_mat.u.s._31, view_mat.u.s._32, view_mat.u.s._33, view_mat.u.s._34);
3486 TRACE("%f %f %f %f\n", view_mat.u.s._41, view_mat.u.s._42, view_mat.u.s._43, view_mat.u.s._44);
3487
3488 TRACE("Proj mat:\n");
3489 TRACE("%f %f %f %f\n", proj_mat.u.s._11, proj_mat.u.s._12, proj_mat.u.s._13, proj_mat.u.s._14);
3490 TRACE("%f %f %f %f\n", proj_mat.u.s._21, proj_mat.u.s._22, proj_mat.u.s._23, proj_mat.u.s._24);
3491 TRACE("%f %f %f %f\n", proj_mat.u.s._31, proj_mat.u.s._32, proj_mat.u.s._33, proj_mat.u.s._34);
3492 TRACE("%f %f %f %f\n", proj_mat.u.s._41, proj_mat.u.s._42, proj_mat.u.s._43, proj_mat.u.s._44);
3493
3494 TRACE("World mat:\n");
3495 TRACE("%f %f %f %f\n", world_mat.u.s._11, world_mat.u.s._12, world_mat.u.s._13, world_mat.u.s._14);
3496 TRACE("%f %f %f %f\n", world_mat.u.s._21, world_mat.u.s._22, world_mat.u.s._23, world_mat.u.s._24);
3497 TRACE("%f %f %f %f\n", world_mat.u.s._31, world_mat.u.s._32, world_mat.u.s._33, world_mat.u.s._34);
3498 TRACE("%f %f %f %f\n", world_mat.u.s._41, world_mat.u.s._42, world_mat.u.s._43, world_mat.u.s._44);
3499
3500 /* Get the viewport */
3501 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3502 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3503 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3504
3505 multiply_matrix(&mat,&view_mat,&world_mat);
3506 multiply_matrix(&mat,&proj_mat,&mat);
3507
3508 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3509
3510 for (i = 0; i < dwCount; i+= 1) {
3511 unsigned int tex_index;
3512
3513 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3514 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3515 /* The position first */
3516 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3517 const float *p = (const float *)(element->data + i * element->stride);
3518 float x, y, z, rhw;
3519 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3520
3521 /* Multiplication with world, view and projection matrix */
3522 x = (p[0] * mat.u.s._11) + (p[1] * mat.u.s._21) + (p[2] * mat.u.s._31) + (1.0f * mat.u.s._41);
3523 y = (p[0] * mat.u.s._12) + (p[1] * mat.u.s._22) + (p[2] * mat.u.s._32) + (1.0f * mat.u.s._42);
3524 z = (p[0] * mat.u.s._13) + (p[1] * mat.u.s._23) + (p[2] * mat.u.s._33) + (1.0f * mat.u.s._43);
3525 rhw = (p[0] * mat.u.s._14) + (p[1] * mat.u.s._24) + (p[2] * mat.u.s._34) + (1.0f * mat.u.s._44);
3526
3527 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3528
3529 /* WARNING: The following things are taken from d3d7 and were not yet checked
3530 * against d3d8 or d3d9!
3531 */
3532
3533 /* Clipping conditions: From msdn
3534 *
3535 * A vertex is clipped if it does not match the following requirements
3536 * -rhw < x <= rhw
3537 * -rhw < y <= rhw
3538 * 0 < z <= rhw
3539 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3540 *
3541 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3542 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3543 *
3544 */
3545
3546 if( !doClip ||
3547 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3548 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3549 ( rhw > eps ) ) ) {
3550
3551 /* "Normal" viewport transformation (not clipped)
3552 * 1) The values are divided by rhw
3553 * 2) The y axis is negative, so multiply it with -1
3554 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3555 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3556 * 4) Multiply x with Width/2 and add Width/2
3557 * 5) The same for the height
3558 * 6) Add the viewpoint X and Y to the 2D coordinates and
3559 * The minimum Z value to z
3560 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3561 *
3562 * Well, basically it's simply a linear transformation into viewport
3563 * coordinates
3564 */
3565
3566 x /= rhw;
3567 y /= rhw;
3568 z /= rhw;
3569
3570 y *= -1;
3571
3572 x *= vp.Width / 2;
3573 y *= vp.Height / 2;
3574 z *= vp.MaxZ - vp.MinZ;
3575
3576 x += vp.Width / 2 + vp.X;
3577 y += vp.Height / 2 + vp.Y;
3578 z += vp.MinZ;
3579
3580 rhw = 1 / rhw;
3581 } else {
3582 /* That vertex got clipped
3583 * Contrary to OpenGL it is not dropped completely, it just
3584 * undergoes a different calculation.
3585 */
3586 TRACE("Vertex got clipped\n");
3587 x += rhw;
3588 y += rhw;
3589
3590 x /= 2;
3591 y /= 2;
3592
3593 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3594 * outside of the main vertex buffer memory. That needs some more
3595 * investigation...
3596 */
3597 }
3598
3599 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3600
3601
3602 ( (float *) dest_ptr)[0] = x;
3603 ( (float *) dest_ptr)[1] = y;
3604 ( (float *) dest_ptr)[2] = z;
3605 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3606
3607 dest_ptr += 3 * sizeof(float);
3608
3609 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3610 dest_ptr += sizeof(float);
3611 }
3612
3613 if(dest_conv) {
3614 float w = 1 / rhw;
3615 ( (float *) dest_conv)[0] = x * w;
3616 ( (float *) dest_conv)[1] = y * w;
3617 ( (float *) dest_conv)[2] = z * w;
3618 ( (float *) dest_conv)[3] = w;
3619
3620 dest_conv += 3 * sizeof(float);
3621
3622 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3623 dest_conv += sizeof(float);
3624 }
3625 }
3626 }
3627 if (DestFVF & WINED3DFVF_PSIZE) {
3628 dest_ptr += sizeof(DWORD);
3629 if(dest_conv) dest_conv += sizeof(DWORD);
3630 }
3631 if (DestFVF & WINED3DFVF_NORMAL) {
3632 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
3633 const float *normal = (const float *)(element->data + i * element->stride);
3634 /* AFAIK this should go into the lighting information */
3635 FIXME("Didn't expect the destination to have a normal\n");
3636 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3637 if(dest_conv) {
3638 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3639 }
3640 }
3641
3642 if (DestFVF & WINED3DFVF_DIFFUSE) {
3643 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
3644 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
3645 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
3646 {
3647 static BOOL warned = FALSE;
3648
3649 if(!warned) {
3650 ERR("No diffuse color in source, but destination has one\n");
3651 warned = TRUE;
3652 }
3653
3654 *( (DWORD *) dest_ptr) = 0xffffffff;
3655 dest_ptr += sizeof(DWORD);
3656
3657 if(dest_conv) {
3658 *( (DWORD *) dest_conv) = 0xffffffff;
3659 dest_conv += sizeof(DWORD);
3660 }
3661 }
3662 else {
3663 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3664 if(dest_conv) {
3665 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3666 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3667 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3668 dest_conv += sizeof(DWORD);
3669 }
3670 }
3671 }
3672
3673 if (DestFVF & WINED3DFVF_SPECULAR)
3674 {
3675 /* What's the color value in the feedback buffer? */
3676 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
3677 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
3678 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
3679 {
3680 static BOOL warned = FALSE;
3681
3682 if(!warned) {
3683 ERR("No specular color in source, but destination has one\n");
3684 warned = TRUE;
3685 }
3686
3687 *( (DWORD *) dest_ptr) = 0xFF000000;
3688 dest_ptr += sizeof(DWORD);
3689
3690 if(dest_conv) {
3691 *( (DWORD *) dest_conv) = 0xFF000000;
3692 dest_conv += sizeof(DWORD);
3693 }
3694 }
3695 else {
3696 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3697 if(dest_conv) {
3698 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3699 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3700 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3701 dest_conv += sizeof(DWORD);
3702 }
3703 }
3704 }
3705
3706 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3707 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
3708 const float *tex_coord = (const float *)(element->data + i * element->stride);
3709 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
3710 {
3711 ERR("No source texture, but destination requests one\n");
3712 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3713 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3714 }
3715 else {
3716 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3717 if(dest_conv) {
3718 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3719 }
3720 }
3721 }
3722 }
3723
3724 if(dest_conv) {
3725 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
3726 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3727 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3728 dwCount * get_flexible_vertex_size(DestFVF),
3729 dest_conv_addr));
3730 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3731 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3732 }
3733
3734 LEAVE_GL();
3735
3736 return WINED3D_OK;
3737 }
3738 #undef copy_and_next
3739
3740 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
3741 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
3742 DWORD DestFVF)
3743 {
3744 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3745 struct wined3d_stream_info stream_info;
3746 struct wined3d_context *context;
3747 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
3748 HRESULT hr;
3749
3750 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3751
3752 if(pVertexDecl) {
3753 ERR("Output vertex declaration not implemented yet\n");
3754 }
3755
3756 /* Need any context to write to the vbo. */
3757 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
3758
3759 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
3760 * control the streamIsUP flag, thus restore it afterwards.
3761 */
3762 This->stateBlock->streamIsUP = FALSE;
3763 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
3764 This->stateBlock->streamIsUP = streamWasUP;
3765
3766 if(vbo || SrcStartIndex) {
3767 unsigned int i;
3768 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
3769 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
3770 *
3771 * Also get the start index in, but only loop over all elements if there's something to add at all.
3772 */
3773 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
3774 {
3775 struct wined3d_stream_info_element *e;
3776
3777 if (!(stream_info.use_map & (1 << i))) continue;
3778
3779 e = &stream_info.elements[i];
3780 if (e->buffer_object)
3781 {
3782 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
3783 e->buffer_object = 0;
3784 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
3785 ENTER_GL();
3786 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
3787 vb->buffer_object = 0;
3788 LEAVE_GL();
3789 }
3790 if (e->data) e->data += e->stride * SrcStartIndex;
3791 }
3792 }
3793
3794 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
3795 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
3796
3797 context_release(context);
3798
3799 return hr;
3800 }
3801
3802 /*****
3803 * Get / Set Texture Stage States
3804 * TODO: Verify against dx9 definitions
3805 *****/
3806 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3807 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3808 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3809
3810 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3811
3812 if (Stage >= MAX_TEXTURES) {
3813 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
3814 return WINED3D_OK;
3815 }
3816
3817 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
3818 This->updateStateBlock->textureState[Stage][Type] = Value;
3819
3820 if (This->isRecordingState) {
3821 TRACE("Recording... not performing anything\n");
3822 return WINED3D_OK;
3823 }
3824
3825 /* Checked after the assignments to allow proper stateblock recording */
3826 if(oldValue == Value) {
3827 TRACE("App is setting the old value over, nothing to do\n");
3828 return WINED3D_OK;
3829 }
3830
3831 if(Stage > This->stateBlock->lowest_disabled_stage &&
3832 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3833 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3834 * Changes in other states are important on disabled stages too
3835 */
3836 return WINED3D_OK;
3837 }
3838
3839 if(Type == WINED3DTSS_COLOROP) {
3840 unsigned int i;
3841
3842 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
3843 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3844 * they have to be disabled
3845 *
3846 * The current stage is dirtified below.
3847 */
3848 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
3849 TRACE("Additionally dirtifying stage %u\n", i);
3850 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3851 }
3852 This->stateBlock->lowest_disabled_stage = Stage;
3853 TRACE("New lowest disabled: %u\n", Stage);
3854 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
3855 /* Previously disabled stage enabled. Stages above it may need enabling
3856 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3857 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3858 *
3859 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3860 */
3861
3862 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
3863 {
3864 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
3865 break;
3866 }
3867 TRACE("Additionally dirtifying stage %u due to enable\n", i);
3868 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3869 }
3870 This->stateBlock->lowest_disabled_stage = i;
3871 TRACE("New lowest disabled: %u\n", i);
3872 }
3873 }
3874
3875 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
3876
3877 return WINED3D_OK;
3878 }
3879
3880 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
3881 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3882 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
3883 *pValue = This->updateStateBlock->textureState[Stage][Type];
3884 return WINED3D_OK;
3885 }
3886
3887 /*****
3888 * Get / Set Texture
3889 *****/
3890 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
3891 DWORD stage, IWineD3DBaseTexture *texture)
3892 {
3893 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3894 IWineD3DBaseTexture *prev;
3895
3896 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
3897
3898 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
3899 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3900
3901 /* Windows accepts overflowing this array... we do not. */
3902 if (stage >= sizeof(This->stateBlock->textures) / sizeof(*This->stateBlock->textures))
3903 {
3904 WARN("Ignoring invalid stage %u.\n", stage);
3905 return WINED3D_OK;
3906 }
3907
3908 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
3909 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
3910 {
3911 WARN("Rejecting attempt to set scratch texture.\n");
3912 return WINED3DERR_INVALIDCALL;
3913 }
3914
3915 This->updateStateBlock->changed.textures |= 1 << stage;
3916
3917 prev = This->updateStateBlock->textures[stage];
3918 TRACE("Previous texture %p.\n", prev);
3919
3920 if (texture == prev)
3921 {
3922 TRACE("App is setting the same texture again, nothing to do.\n");
3923 return WINED3D_OK;
3924 }
3925
3926 TRACE("Setting new texture to %p.\n", texture);
3927 This->updateStateBlock->textures[stage] = texture;
3928
3929 if (This->isRecordingState)
3930 {
3931 TRACE("Recording... not performing anything\n");
3932
3933 if (texture) IWineD3DBaseTexture_AddRef(texture);
3934 if (prev) IWineD3DBaseTexture_Release(prev);
3935
3936 return WINED3D_OK;
3937 }
3938
3939 if (texture)
3940 {
3941 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
3942 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
3943 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(texture);
3944
3945 IWineD3DBaseTexture_AddRef(texture);
3946
3947 if (!prev || dimensions != IWineD3DBaseTexture_GetTextureDimensions(prev))
3948 {
3949 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3950 }
3951
3952 if (!prev && stage < MAX_TEXTURES)
3953 {
3954 /* The source arguments for color and alpha ops have different
3955 * meanings when a NULL texture is bound, so the COLOROP and
3956 * ALPHAOP have to be dirtified. */
3957 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
3958 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
3959 }
3960
3961 if (bind_count == 1) t->baseTexture.sampler = stage;
3962 }
3963
3964 if (prev)
3965 {
3966 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
3967 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
3968
3969 IWineD3DBaseTexture_Release(prev);
3970
3971 if (!texture && stage < MAX_TEXTURES)
3972 {
3973 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
3974 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
3975 }
3976
3977 if (bind_count && t->baseTexture.sampler == stage)
3978 {
3979 unsigned int i;
3980
3981 /* Search for other stages the texture is bound to. Shouldn't
3982 * happen if applications bind textures to a single stage only. */
3983 TRACE("Searching for other stages the texture is bound to.\n");
3984 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
3985 {
3986 if (This->updateStateBlock->textures[i] == prev)
3987 {
3988 TRACE("Texture is also bound to stage %u.\n", i);
3989 t->baseTexture.sampler = i;
3990 break;
3991 }
3992 }
3993 }
3994 }
3995
3996 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
3997
3998 return WINED3D_OK;
3999 }
4000
4001 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4002 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4003
4004 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4005
4006 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4007 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4008 }
4009
4010 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4011 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4012 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4013 }
4014
4015 *ppTexture=This->stateBlock->textures[Stage];
4016 if (*ppTexture)
4017 IWineD3DBaseTexture_AddRef(*ppTexture);
4018
4019 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4020
4021 return WINED3D_OK;
4022 }
4023
4024 /*****
4025 * Get Back Buffer
4026 *****/
4027 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4028 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4029 {
4030 IWineD3DSwapChain *swapchain;
4031 HRESULT hr;
4032
4033 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4034 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4035
4036 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4037 if (FAILED(hr))
4038 {
4039 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4040 return hr;
4041 }
4042
4043 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4044 IWineD3DSwapChain_Release(swapchain);
4045 if (FAILED(hr))
4046 {
4047 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4048 return hr;
4049 }
4050
4051 return WINED3D_OK;
4052 }
4053
4054 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4055 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4056 WARN("(%p) : stub, calling idirect3d for now\n", This);
4057 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
4058 }
4059
4060 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4061 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4062 IWineD3DSwapChain *swapChain;
4063 HRESULT hr;
4064
4065 if(iSwapChain > 0) {
4066 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4067 if (hr == WINED3D_OK) {
4068 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4069 IWineD3DSwapChain_Release(swapChain);
4070 } else {
4071 FIXME("(%p) Error getting display mode\n", This);
4072 }
4073 } else {
4074 /* Don't read the real display mode,
4075 but return the stored mode instead. X11 can't change the color
4076 depth, and some apps are pretty angry if they SetDisplayMode from
4077 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4078
4079 Also don't relay to the swapchain because with ddraw it's possible
4080 that there isn't a swapchain at all */
4081 pMode->Width = This->ddraw_width;
4082 pMode->Height = This->ddraw_height;
4083 pMode->Format = This->ddraw_format;
4084 pMode->RefreshRate = 0;
4085 hr = WINED3D_OK;
4086 }
4087
4088 return hr;
4089 }
4090
4091 /*****
4092 * Stateblock related functions
4093 *****/
4094
4095 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4096 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4097 IWineD3DStateBlock *stateblock;
4098 HRESULT hr;
4099
4100 TRACE("(%p)\n", This);
4101
4102 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4103
4104 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4105 if (FAILED(hr)) return hr;
4106
4107 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4108 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4109 This->isRecordingState = TRUE;
4110
4111 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4112
4113 return WINED3D_OK;
4114 }
4115
4116 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4117 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4118 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4119
4120 if (!This->isRecordingState) {
4121 WARN("(%p) not recording! returning error\n", This);
4122 *ppStateBlock = NULL;
4123 return WINED3DERR_INVALIDCALL;
4124 }
4125
4126 stateblock_init_contained_states(object);
4127
4128 *ppStateBlock = (IWineD3DStateBlock*) object;
4129 This->isRecordingState = FALSE;
4130 This->updateStateBlock = This->stateBlock;
4131 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4132 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4133 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4134 return WINED3D_OK;
4135 }
4136
4137 /*****
4138 * Scene related functions
4139 *****/
4140 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4141 /* At the moment we have no need for any functionality at the beginning
4142 of a scene */
4143 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4144 TRACE("(%p)\n", This);
4145
4146 if(This->inScene) {
4147 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4148 return WINED3DERR_INVALIDCALL;
4149 }
4150 This->inScene = TRUE;
4151 return WINED3D_OK;
4152 }
4153
4154 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4155 {
4156 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4157 struct wined3d_context *context;
4158
4159 TRACE("(%p)\n", This);
4160
4161 if(!This->inScene) {
4162 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4163 return WINED3DERR_INVALIDCALL;
4164 }
4165
4166 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
4167 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4168 wglFlush();
4169 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4170 * fails. */
4171 context_release(context);
4172
4173 This->inScene = FALSE;
4174 return WINED3D_OK;
4175 }
4176
4177 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4178 const RECT *pSourceRect, const RECT *pDestRect,
4179 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4180 {
4181 IWineD3DSwapChain *swapChain = NULL;
4182 int i;
4183 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4184
4185 TRACE("iface %p.\n", iface);
4186
4187 for(i = 0 ; i < swapchains ; i ++) {
4188
4189 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4190 TRACE("presentinng chain %d, %p\n", i, swapChain);
4191 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4192 IWineD3DSwapChain_Release(swapChain);
4193 }
4194
4195 return WINED3D_OK;
4196 }
4197
4198 /* Not called from the VTable (internal subroutine) */
4199 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4200 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4201 float Z, DWORD Stencil) {
4202 GLbitfield glMask = 0;
4203 unsigned int i;
4204 WINED3DRECT curRect;
4205 RECT vp_rect;
4206 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4207 UINT drawable_width, drawable_height;
4208 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4209 IWineD3DSwapChainImpl *swapchain = NULL;
4210 struct wined3d_context *context;
4211
4212 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4213 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4214 * for the cleared parts, and the untouched parts.
4215 *
4216 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4217 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4218 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4219 * checking all this if the dest surface is in the drawable anyway.
4220 */
4221 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4222 while(1) {
4223 if(vp->X != 0 || vp->Y != 0 ||
4224 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4225 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4226 break;
4227 }
4228 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4229 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4230 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4231 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4232 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4233 break;
4234 }
4235 if(Count > 0 && pRects && (
4236 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4237 pRects[0].x2 < target->currentDesc.Width ||
4238 pRects[0].y2 < target->currentDesc.Height)) {
4239 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4240 break;
4241 }
4242 break;
4243 }
4244 }
4245
4246 context = context_acquire(This, (IWineD3DSurface *)target, CTXUSAGE_CLEAR);
4247
4248 target->get_drawable_size(context, &drawable_width, &drawable_height);
4249
4250 ENTER_GL();
4251
4252 /* Only set the values up once, as they are not changing */
4253 if (Flags & WINED3DCLEAR_STENCIL) {
4254 glClearStencil(Stencil);
4255 checkGLcall("glClearStencil");
4256 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4257 glStencilMask(0xFFFFFFFF);
4258 }
4259
4260 if (Flags & WINED3DCLEAR_ZBUFFER) {
4261 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4262 glDepthMask(GL_TRUE);
4263 glClearDepth(Z);
4264 checkGLcall("glClearDepth");
4265 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4266 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4267
4268 if (vp->X != 0 || vp->Y != 0 ||
4269 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
4270 surface_load_ds_location(This->stencilBufferTarget, context, location);
4271 }
4272 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4273 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4274 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
4275 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
4276 surface_load_ds_location(This->stencilBufferTarget, context, location);
4277 }
4278 else if (Count > 0 && pRects && (
4279 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4280 pRects[0].x2 < depth_stencil->currentDesc.Width ||
4281 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
4282 surface_load_ds_location(This->stencilBufferTarget, context, location);
4283 }
4284 }
4285
4286 if (Flags & WINED3DCLEAR_TARGET) {
4287 TRACE("Clearing screen with glClear to color %x\n", Color);
4288 glClearColor(D3DCOLOR_R(Color),
4289 D3DCOLOR_G(Color),
4290 D3DCOLOR_B(Color),
4291 D3DCOLOR_A(Color));
4292 checkGLcall("glClearColor");
4293
4294 /* Clear ALL colors! */
4295 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4296 glMask = glMask | GL_COLOR_BUFFER_BIT;
4297 }
4298
4299 vp_rect.left = vp->X;
4300 vp_rect.top = vp->Y;
4301 vp_rect.right = vp->X + vp->Width;
4302 vp_rect.bottom = vp->Y + vp->Height;
4303 if (!(Count > 0 && pRects)) {
4304 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4305 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4306 }
4307 if (context->render_offscreen)
4308 {
4309 glScissor(vp_rect.left, vp_rect.top,
4310 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4311 } else {
4312 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
4313 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4314 }
4315 checkGLcall("glScissor");
4316 glClear(glMask);
4317 checkGLcall("glClear");
4318 } else {
4319 /* Now process each rect in turn */
4320 for (i = 0; i < Count; i++) {
4321 /* Note gl uses lower left, width/height */
4322 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
4323 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4324 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
4325 }
4326 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
4327 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
4328 curRect.x1, (target->currentDesc.Height - curRect.y2),
4329 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4330
4331 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4332 * The rectangle is not cleared, no error is returned, but further rectanlges are
4333 * still cleared if they are valid
4334 */
4335 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
4336 TRACE("Rectangle with negative dimensions, ignoring\n");
4337 continue;
4338 }
4339
4340 if (context->render_offscreen)
4341 {
4342 glScissor(curRect.x1, curRect.y1,
4343 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4344 } else {
4345 glScissor(curRect.x1, drawable_height - curRect.y2,
4346 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4347 }
4348 checkGLcall("glScissor");
4349
4350 glClear(glMask);
4351 checkGLcall("glClear");
4352 }
4353 }
4354
4355 /* Restore the old values (why..?) */
4356 if (Flags & WINED3DCLEAR_STENCIL) {
4357 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4358 }
4359 if (Flags & WINED3DCLEAR_TARGET) {
4360 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4361 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4362 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4363 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4364 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4365
4366 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4367 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4368 */
4369 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, TRUE);
4370 }
4371 if (Flags & WINED3DCLEAR_ZBUFFER) {
4372 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
4373 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4374 surface_modify_ds_location(This->stencilBufferTarget, location);
4375 }
4376
4377 LEAVE_GL();
4378
4379 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
4380 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
4381 wglFlush();
4382 }
4383 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
4384 }
4385
4386 context_release(context);
4387
4388 return WINED3D_OK;
4389 }
4390
4391 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4392 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4393 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4394 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4395
4396 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4397 Count, pRects, Flags, Color, Z, Stencil);
4398
4399 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4400 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4401 /* TODO: What about depth stencil buffers without stencil bits? */
4402 return WINED3DERR_INVALIDCALL;
4403 }
4404
4405 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
4406 }
4407
4408 /*****
4409 * Drawing functions
4410 *****/
4411
4412 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4413 WINED3DPRIMITIVETYPE primitive_type)
4414 {
4415 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4416
4417 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4418
4419 This->updateStateBlock->changed.primitive_type = TRUE;
4420 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4421 }
4422
4423 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4424 WINED3DPRIMITIVETYPE *primitive_type)
4425 {
4426 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4427
4428 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4429
4430 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
4431
4432 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4433 }
4434
4435 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4436 {
4437 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4438
4439 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4440
4441 if(!This->stateBlock->vertexDecl) {
4442 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4443 return WINED3DERR_INVALIDCALL;
4444 }
4445
4446 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4447 if(This->stateBlock->streamIsUP) {
4448 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4449 This->stateBlock->streamIsUP = FALSE;
4450 }
4451
4452 if(This->stateBlock->loadBaseVertexIndex != 0) {
4453 This->stateBlock->loadBaseVertexIndex = 0;
4454 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4455 }
4456 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4457 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4458 return WINED3D_OK;
4459 }
4460
4461 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4462 {
4463 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4464 UINT idxStride = 2;
4465 IWineD3DBuffer *pIB;
4466 GLuint vbo;
4467
4468 pIB = This->stateBlock->pIndexData;
4469 if (!pIB) {
4470 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4471 * without an index buffer set. (The first time at least...)
4472 * D3D8 simply dies, but I doubt it can do much harm to return
4473 * D3DERR_INVALIDCALL there as well. */
4474 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4475 return WINED3DERR_INVALIDCALL;
4476 }
4477
4478 if(!This->stateBlock->vertexDecl) {
4479 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4480 return WINED3DERR_INVALIDCALL;
4481 }
4482
4483 if(This->stateBlock->streamIsUP) {
4484 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4485 This->stateBlock->streamIsUP = FALSE;
4486 }
4487 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
4488
4489 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4490
4491 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
4492 idxStride = 2;
4493 } else {
4494 idxStride = 4;
4495 }
4496
4497 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4498 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4499 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4500 }
4501
4502 drawPrimitive(iface, index_count, startIndex, idxStride,
4503 vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
4504
4505 return WINED3D_OK;
4506 }
4507
4508 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4509 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4510 {
4511 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4512 IWineD3DBuffer *vb;
4513
4514 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4515 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4516
4517 if(!This->stateBlock->vertexDecl) {
4518 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4519 return WINED3DERR_INVALIDCALL;
4520 }
4521
4522 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4523 vb = This->stateBlock->streamSource[0];
4524 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4525 if (vb) IWineD3DBuffer_Release(vb);
4526 This->stateBlock->streamOffset[0] = 0;
4527 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4528 This->stateBlock->streamIsUP = TRUE;
4529 This->stateBlock->loadBaseVertexIndex = 0;
4530
4531 /* TODO: Only mark dirty if drawing from a different UP address */
4532 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4533
4534 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4535
4536 /* MSDN specifies stream zero settings must be set to NULL */
4537 This->stateBlock->streamStride[0] = 0;
4538 This->stateBlock->streamSource[0] = NULL;
4539
4540 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4541 * the new stream sources or use UP drawing again
4542 */
4543 return WINED3D_OK;
4544 }
4545
4546 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4547 UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
4548 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4549 {
4550 int idxStride;
4551 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4552 IWineD3DBuffer *vb;
4553 IWineD3DBuffer *ib;
4554
4555 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4556 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4557
4558 if(!This->stateBlock->vertexDecl) {
4559 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4560 return WINED3DERR_INVALIDCALL;
4561 }
4562
4563 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4564 idxStride = 2;
4565 } else {
4566 idxStride = 4;
4567 }
4568
4569 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4570 vb = This->stateBlock->streamSource[0];
4571 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4572 if (vb) IWineD3DBuffer_Release(vb);
4573 This->stateBlock->streamIsUP = TRUE;
4574 This->stateBlock->streamOffset[0] = 0;
4575 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4576
4577 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4578 This->stateBlock->baseVertexIndex = 0;
4579 This->stateBlock->loadBaseVertexIndex = 0;
4580 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4581 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4582 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4583
4584 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4585
4586 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4587 This->stateBlock->streamSource[0] = NULL;
4588 This->stateBlock->streamStride[0] = 0;
4589 ib = This->stateBlock->pIndexData;
4590 if(ib) {
4591 IWineD3DBuffer_Release(ib);
4592 This->stateBlock->pIndexData = NULL;
4593 }
4594 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4595 * SetStreamSource to specify a vertex buffer
4596 */
4597
4598 return WINED3D_OK;
4599 }
4600
4601 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4602 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4603 {
4604 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4605
4606 /* Mark the state dirty until we have nicer tracking
4607 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4608 * that value.
4609 */
4610 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4611 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4612 This->stateBlock->baseVertexIndex = 0;
4613 This->up_strided = DrawPrimStrideData;
4614 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4615 This->up_strided = NULL;
4616 return WINED3D_OK;
4617 }
4618
4619 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4620 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4621 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
4622 {
4623 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4624 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4625
4626 /* Mark the state dirty until we have nicer tracking
4627 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4628 * that value.
4629 */
4630 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4631 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4632 This->stateBlock->streamIsUP = TRUE;
4633 This->stateBlock->baseVertexIndex = 0;
4634 This->up_strided = DrawPrimStrideData;
4635 drawPrimitive(iface, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4636 This->up_strided = NULL;
4637 return WINED3D_OK;
4638 }
4639
4640 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4641 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
4642 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
4643 {
4644 WINED3DLOCKED_BOX src;
4645 WINED3DLOCKED_BOX dst;
4646 HRESULT hr;
4647
4648 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
4649 iface, pSourceVolume, pDestinationVolume);
4650
4651 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4652 * dirtification to improve loading performance.
4653 */
4654 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4655 if(FAILED(hr)) return hr;
4656 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4657 if(FAILED(hr)) {
4658 IWineD3DVolume_UnlockBox(pSourceVolume);
4659 return hr;
4660 }
4661
4662 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
4663
4664 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
4665 if(FAILED(hr)) {
4666 IWineD3DVolume_UnlockBox(pSourceVolume);
4667 } else {
4668 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
4669 }
4670 return hr;
4671 }
4672
4673 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
4674 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
4675 {
4676 unsigned int level_count, i;
4677 WINED3DRESOURCETYPE type;
4678 HRESULT hr;
4679
4680 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
4681
4682 /* Verify that the source and destination textures are non-NULL. */
4683 if (!src_texture || !dst_texture)
4684 {
4685 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4686 return WINED3DERR_INVALIDCALL;
4687 }
4688
4689 if (src_texture == dst_texture)
4690 {
4691 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4692 return WINED3DERR_INVALIDCALL;
4693 }
4694
4695 /* Verify that the source and destination textures are the same type. */
4696 type = IWineD3DBaseTexture_GetType(src_texture);
4697 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
4698 {
4699 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4700 return WINED3DERR_INVALIDCALL;
4701 }
4702
4703 /* Check that both textures have the identical numbers of levels. */
4704 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
4705 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
4706 {
4707 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4708 return WINED3DERR_INVALIDCALL;
4709 }
4710
4711 /* Make sure that the destination texture is loaded. */
4712 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
4713
4714 /* Update every surface level of the texture. */
4715 switch (type)
4716 {
4717 case WINED3DRTYPE_TEXTURE:
4718 {
4719 IWineD3DSurface *src_surface;
4720 IWineD3DSurface *dst_surface;
4721
4722 for (i = 0; i < level_count; ++i)
4723 {
4724 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
4725 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
4726 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4727 IWineD3DSurface_Release(dst_surface);
4728 IWineD3DSurface_Release(src_surface);
4729 if (FAILED(hr))
4730 {
4731 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4732 return hr;
4733 }
4734 }
4735 break;
4736 }
4737
4738 case WINED3DRTYPE_CUBETEXTURE:
4739 {
4740 IWineD3DSurface *src_surface;
4741 IWineD3DSurface *dst_surface;
4742 WINED3DCUBEMAP_FACES face;
4743
4744 for (i = 0; i < level_count; ++i)
4745 {
4746 /* Update each cube face. */
4747 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
4748 {
4749 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
4750 face, i, &src_surface);
4751 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4752 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
4753 face, i, &dst_surface);
4754 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4755 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4756 IWineD3DSurface_Release(dst_surface);
4757 IWineD3DSurface_Release(src_surface);
4758 if (FAILED(hr))
4759 {
4760 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4761 return hr;
4762 }
4763 }
4764 }
4765 break;
4766 }
4767
4768 case WINED3DRTYPE_VOLUMETEXTURE:
4769 {
4770 IWineD3DVolume *src_volume;
4771 IWineD3DVolume *dst_volume;
4772
4773 for (i = 0; i < level_count; ++i)
4774 {
4775 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
4776 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
4777 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
4778 IWineD3DVolume_Release(dst_volume);
4779 IWineD3DVolume_Release(src_volume);
4780 if (FAILED(hr))
4781 {
4782 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
4783 return hr;
4784 }
4785 }
4786 break;
4787 }
4788
4789 default:
4790 FIXME("Unsupported texture type %#x.\n", type);
4791 return WINED3DERR_INVALIDCALL;
4792 }
4793
4794 return WINED3D_OK;
4795 }
4796
4797 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4798 IWineD3DSwapChain *swapChain;
4799 HRESULT hr;
4800 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4801 if(hr == WINED3D_OK) {
4802 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4803 IWineD3DSwapChain_Release(swapChain);
4804 }
4805 return hr;
4806 }
4807
4808 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4809 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4810 IWineD3DBaseTextureImpl *texture;
4811 DWORD i;
4812
4813 TRACE("(%p) : %p\n", This, pNumPasses);
4814
4815 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4816 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
4817 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4818 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4819 }
4820 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
4821 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4822 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4823 }
4824
4825 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
4826 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
4827
4828 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
4829 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
4830 return E_FAIL;
4831 }
4832 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
4833 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
4834 return E_FAIL;
4835 }
4836 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
4837 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
4838 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
4839 return E_FAIL;
4840 }
4841 }
4842
4843 /* return a sensible default */
4844 *pNumPasses = 1;
4845
4846 TRACE("returning D3D_OK\n");
4847 return WINED3D_OK;
4848 }
4849
4850 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
4851 {
4852 int i;
4853
4854 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4855 {
4856 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
4857 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8_UINT
4858 || texture->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM))
4859 {
4860 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
4861 }
4862 }
4863 }
4864
4865 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4866 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4867 int j;
4868 UINT NewSize;
4869 PALETTEENTRY **palettes;
4870
4871 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4872
4873 if (PaletteNumber >= MAX_PALETTES) {
4874 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4875 return WINED3DERR_INVALIDCALL;
4876 }
4877
4878 if (PaletteNumber >= This->NumberOfPalettes) {
4879 NewSize = This->NumberOfPalettes;
4880 do {
4881 NewSize *= 2;
4882 } while(PaletteNumber >= NewSize);
4883 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
4884 if (!palettes) {
4885 ERR("Out of memory!\n");
4886 return E_OUTOFMEMORY;
4887 }
4888 This->palettes = palettes;
4889 This->NumberOfPalettes = NewSize;
4890 }
4891
4892 if (!This->palettes[PaletteNumber]) {
4893 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
4894 if (!This->palettes[PaletteNumber]) {
4895 ERR("Out of memory!\n");
4896 return E_OUTOFMEMORY;
4897 }
4898 }
4899
4900 for (j = 0; j < 256; ++j) {
4901 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
4902 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
4903 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
4904 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
4905 }
4906 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
4907 TRACE("(%p) : returning\n", This);
4908 return WINED3D_OK;
4909 }
4910
4911 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
4912 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4913 int j;
4914 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4915 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
4916 /* What happens in such situation isn't documented; Native seems to silently abort
4917 on such conditions. Return Invalid Call. */
4918 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
4919 return WINED3DERR_INVALIDCALL;
4920 }
4921 for (j = 0; j < 256; ++j) {
4922 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
4923 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
4924 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
4925 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
4926 }
4927 TRACE("(%p) : returning\n", This);
4928 return WINED3D_OK;
4929 }
4930
4931 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
4932 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4933 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4934 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
4935 (tested with reference rasterizer). Return Invalid Call. */
4936 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
4937 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
4938 return WINED3DERR_INVALIDCALL;
4939 }
4940 /*TODO: stateblocks */
4941 if (This->currentPalette != PaletteNumber) {
4942 This->currentPalette = PaletteNumber;
4943 dirtify_p8_texture_samplers(This);
4944 }
4945 TRACE("(%p) : returning\n", This);
4946 return WINED3D_OK;
4947 }
4948
4949 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
4950 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4951 if (PaletteNumber == NULL) {
4952 WARN("(%p) : returning Invalid Call\n", This);
4953 return WINED3DERR_INVALIDCALL;
4954 }
4955 /*TODO: stateblocks */
4956 *PaletteNumber = This->currentPalette;
4957 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
4958 return WINED3D_OK;
4959 }
4960
4961 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
4962 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4963 static BOOL warned;
4964 if (!warned)
4965 {
4966 FIXME("(%p) : stub\n", This);
4967 warned = TRUE;
4968 }
4969
4970 This->softwareVertexProcessing = bSoftware;
4971 return WINED3D_OK;
4972 }
4973
4974
4975 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
4976 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4977 static BOOL warned;
4978 if (!warned)
4979 {
4980 FIXME("(%p) : stub\n", This);
4981 warned = TRUE;
4982 }
4983 return This->softwareVertexProcessing;
4984 }
4985
4986 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
4987 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
4988 {
4989 IWineD3DSwapChain *swapchain;
4990 HRESULT hr;
4991
4992 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
4993 iface, swapchain_idx, raster_status);
4994
4995 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4996 if (FAILED(hr))
4997 {
4998 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4999 return hr;
5000 }
5001
5002 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5003 IWineD3DSwapChain_Release(swapchain);
5004 if (FAILED(hr))
5005 {
5006 WARN("Failed to get raster status, hr %#x.\n", hr);
5007 return hr;
5008 }
5009
5010 return WINED3D_OK;
5011 }
5012
5013 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5014 {
5015 static BOOL warned;
5016 if(nSegments != 0.0f) {
5017 if (!warned)
5018 {
5019 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5020 warned = TRUE;
5021 }
5022 }
5023 return WINED3D_OK;
5024 }
5025
5026 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5027 {
5028 static BOOL warned;
5029 if (!warned)
5030 {
5031 FIXME("iface %p stub!\n", iface);
5032 warned = TRUE;
5033 }
5034 return 0.0f;
5035 }
5036
5037 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5038 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5039 /** TODO: remove casts to IWineD3DSurfaceImpl
5040 * NOTE: move code to surface to accomplish this
5041 ****************************************/
5042 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5043 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)pDestinationSurface;
5044 int srcWidth, srcHeight;
5045 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5046 WINED3DFORMAT destFormat, srcFormat;
5047 UINT destSize;
5048 int srcLeft, destLeft, destTop;
5049 WINED3DPOOL srcPool, destPool;
5050 int offset = 0;
5051 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5052 const struct GlPixelFormatDesc *src_format_desc, *dst_format_desc;
5053 GLenum dummy;
5054 DWORD sampler;
5055 int bpp;
5056 CONVERT_TYPES convert = NO_CONVERSION;
5057 struct wined3d_context *context;
5058
5059 WINED3DSURFACE_DESC winedesc;
5060
5061 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5062
5063 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5064 srcSurfaceWidth = winedesc.width;
5065 srcSurfaceHeight = winedesc.height;
5066 srcPool = winedesc.pool;
5067 srcFormat = winedesc.format;
5068
5069 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5070 destSurfaceWidth = winedesc.width;
5071 destSurfaceHeight = winedesc.height;
5072 destPool = winedesc.pool;
5073 destFormat = winedesc.format;
5074 destSize = winedesc.size;
5075
5076 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5077 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5078 return WINED3DERR_INVALIDCALL;
5079 }
5080
5081 /* This call loads the opengl surface directly, instead of copying the surface to the
5082 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5083 * copy in sysmem and use regular surface loading.
5084 */
5085 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5086 if(convert != NO_CONVERSION) {
5087 return IWineD3DSurface_BltFast(pDestinationSurface,
5088 pDestPoint ? pDestPoint->x : 0,
5089 pDestPoint ? pDestPoint->y : 0,
5090 pSourceSurface, pSourceRect, 0);
5091 }
5092
5093 if (destFormat == WINED3DFMT_UNKNOWN) {
5094 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5095 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5096
5097 /* Get the update surface description */
5098 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5099 }
5100
5101 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5102
5103 ENTER_GL();
5104 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5105 checkGLcall("glActiveTextureARB");
5106 LEAVE_GL();
5107
5108 /* Make sure the surface is loaded and up to date */
5109 surface_internal_preload(pDestinationSurface, SRGB_RGB);
5110 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
5111
5112 src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
5113 dst_format_desc = dst_impl->resource.format_desc;
5114
5115 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5116 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5117 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5118 srcLeft = pSourceRect ? pSourceRect->left : 0;
5119 destLeft = pDestPoint ? pDestPoint->x : 0;
5120 destTop = pDestPoint ? pDestPoint->y : 0;
5121
5122
5123 /* This function doesn't support compressed textures
5124 the pitch is just bytesPerPixel * width */
5125 if(srcWidth != srcSurfaceWidth || srcLeft ){
5126 rowoffset = srcSurfaceWidth * src_format_desc->byte_count;
5127 offset += srcLeft * src_format_desc->byte_count;
5128 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5129 }
5130 /* TODO DXT formats */
5131
5132 if(pSourceRect != NULL && pSourceRect->top != 0){
5133 offset += pSourceRect->top * srcSurfaceWidth * src_format_desc->byte_count;
5134 }
5135 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5136 This, dst_impl->texture_level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
5137 dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5138
5139 /* Sanity check */
5140 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5141
5142 /* need to lock the surface to get the data */
5143 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5144 }
5145
5146 ENTER_GL();
5147
5148 /* TODO: Cube and volume support */
5149 if(rowoffset != 0){
5150 /* not a whole row so we have to do it a line at a time */
5151 int j;
5152
5153 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5154 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5155
5156 for (j = destTop; j < (srcHeight + destTop); ++j)
5157 {
5158 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, j,
5159 srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
5160 data += rowoffset;
5161 }
5162
5163 } else { /* Full width, so just write out the whole texture */
5164 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5165
5166 if (dst_format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
5167 {
5168 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth)
5169 {
5170 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across. */
5171 FIXME("Updating part of a compressed texture is not supported.\n");
5172 }
5173 if (destFormat != srcFormat)
5174 {
5175 FIXME("Updating mixed format compressed textures is not supported.\n");
5176 }
5177 else
5178 {
5179 GL_EXTCALL(glCompressedTexImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5180 dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
5181 }
5182 }
5183 else
5184 {
5185 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, destTop,
5186 srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
5187 }
5188 }
5189 checkGLcall("glTexSubImage2D");
5190
5191 LEAVE_GL();
5192 context_release(context);
5193
5194 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5195 sampler = This->rev_tex_unit_map[0];
5196 if (sampler != WINED3D_UNMAPPED_STAGE)
5197 {
5198 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5199 }
5200
5201 return WINED3D_OK;
5202 }
5203
5204 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5205 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5206 struct WineD3DRectPatch *patch;
5207 GLenum old_primitive_type;
5208 unsigned int i;
5209 struct list *e;
5210 BOOL found;
5211 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5212
5213 if(!(Handle || pRectPatchInfo)) {
5214 /* TODO: Write a test for the return value, thus the FIXME */
5215 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5216 return WINED3DERR_INVALIDCALL;
5217 }
5218
5219 if(Handle) {
5220 i = PATCHMAP_HASHFUNC(Handle);
5221 found = FALSE;
5222 LIST_FOR_EACH(e, &This->patches[i]) {
5223 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5224 if(patch->Handle == Handle) {
5225 found = TRUE;
5226 break;
5227 }
5228 }
5229
5230 if(!found) {
5231 TRACE("Patch does not exist. Creating a new one\n");
5232 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5233 patch->Handle = Handle;
5234 list_add_head(&This->patches[i], &patch->entry);
5235 } else {
5236 TRACE("Found existing patch %p\n", patch);
5237 }
5238 } else {
5239 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5240 * attributes we have to tesselate, read back, and draw. This needs a patch
5241 * management structure instance. Create one.
5242 *
5243 * A possible improvement is to check if a vertex shader is used, and if not directly
5244 * draw the patch.
5245 */
5246 FIXME("Drawing an uncached patch. This is slow\n");
5247 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5248 }
5249
5250 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5251 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5252 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5253 HRESULT hr;
5254 TRACE("Tesselation density or patch info changed, retesselating\n");
5255
5256 if(pRectPatchInfo) {
5257 patch->RectPatchInfo = *pRectPatchInfo;
5258 }
5259 patch->numSegs[0] = pNumSegs[0];
5260 patch->numSegs[1] = pNumSegs[1];
5261 patch->numSegs[2] = pNumSegs[2];
5262 patch->numSegs[3] = pNumSegs[3];
5263
5264 hr = tesselate_rectpatch(This, patch);
5265 if(FAILED(hr)) {
5266 WARN("Patch tesselation failed\n");
5267
5268 /* Do not release the handle to store the params of the patch */
5269 if(!Handle) {
5270 HeapFree(GetProcessHeap(), 0, patch);
5271 }
5272 return hr;
5273 }
5274 }
5275
5276 This->currentPatch = patch;
5277 old_primitive_type = This->stateBlock->gl_primitive_type;
5278 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5279 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5280 This->stateBlock->gl_primitive_type = old_primitive_type;
5281 This->currentPatch = NULL;
5282
5283 /* Destroy uncached patches */
5284 if(!Handle) {
5285 HeapFree(GetProcessHeap(), 0, patch->mem);
5286 HeapFree(GetProcessHeap(), 0, patch);
5287 }
5288 return WINED3D_OK;
5289 }
5290
5291 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5292 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5293 {
5294 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5295 iface, handle, segment_count, patch_info);
5296
5297 return WINED3D_OK;
5298 }
5299
5300 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5301 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5302 int i;
5303 struct WineD3DRectPatch *patch;
5304 struct list *e;
5305 TRACE("(%p) Handle(%d)\n", This, Handle);
5306
5307 i = PATCHMAP_HASHFUNC(Handle);
5308 LIST_FOR_EACH(e, &This->patches[i]) {
5309 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5310 if(patch->Handle == Handle) {
5311 TRACE("Deleting patch %p\n", patch);
5312 list_remove(&patch->entry);
5313 HeapFree(GetProcessHeap(), 0, patch->mem);
5314 HeapFree(GetProcessHeap(), 0, patch);
5315 return WINED3D_OK;
5316 }
5317 }
5318
5319 /* TODO: Write a test for the return value */
5320 FIXME("Attempt to destroy nonexistent patch\n");
5321 return WINED3DERR_INVALIDCALL;
5322 }
5323
5324 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5325 HRESULT hr;
5326 IWineD3DSwapChain *swapchain;
5327
5328 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5329 if (SUCCEEDED(hr)) {
5330 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5331 return swapchain;
5332 }
5333
5334 return NULL;
5335 }
5336
5337 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
5338 const WINED3DRECT *rect, const float color[4])
5339 {
5340 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5341 struct wined3d_context *context;
5342
5343 if (!surface_is_offscreen(surface))
5344 {
5345 TRACE("Surface %p is onscreen\n", surface);
5346
5347 context = context_acquire(This, surface, CTXUSAGE_RESOURCELOAD);
5348 ENTER_GL();
5349 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
5350 context_set_draw_buffer(context, surface_get_gl_buffer(surface));
5351 }
5352 else
5353 {
5354 TRACE("Surface %p is offscreen\n", surface);
5355
5356 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5357 ENTER_GL();
5358 context_bind_fbo(context, GL_FRAMEBUFFER, &context->dst_fbo);
5359 context_attach_surface_fbo(context, GL_FRAMEBUFFER, 0, surface);
5360 context_attach_depth_stencil_fbo(context, GL_FRAMEBUFFER, NULL, FALSE);
5361 }
5362
5363 if (rect) {
5364 glEnable(GL_SCISSOR_TEST);
5365 if(surface_is_offscreen(surface)) {
5366 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5367 } else {
5368 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5369 rect->x2 - rect->x1, rect->y2 - rect->y1);
5370 }
5371 checkGLcall("glScissor");
5372 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5373 } else {
5374 glDisable(GL_SCISSOR_TEST);
5375 }
5376 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5377
5378 glDisable(GL_BLEND);
5379 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
5380
5381 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5382 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5383
5384 glClearColor(color[0], color[1], color[2], color[3]);
5385 glClear(GL_COLOR_BUFFER_BIT);
5386 checkGLcall("glClear");
5387
5388 LEAVE_GL();
5389 context_release(context);
5390 }
5391
5392 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
5393 unsigned int r, g, b, a;
5394 DWORD ret;
5395
5396 if (destfmt == WINED3DFMT_B8G8R8A8_UNORM
5397 || destfmt == WINED3DFMT_B8G8R8X8_UNORM
5398 || destfmt == WINED3DFMT_B8G8R8_UNORM)
5399 return color;
5400
5401 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
5402
5403 a = (color & 0xff000000) >> 24;
5404 r = (color & 0x00ff0000) >> 16;
5405 g = (color & 0x0000ff00) >> 8;
5406 b = (color & 0x000000ff) >> 0;
5407
5408 switch(destfmt)
5409 {
5410 case WINED3DFMT_B5G6R5_UNORM:
5411 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
5412 r = (r * 32) / 256;
5413 g = (g * 64) / 256;
5414 b = (b * 32) / 256;
5415 ret = r << 11;
5416 ret |= g << 5;
5417 ret |= b;
5418 TRACE("Returning %08x\n", ret);
5419 return ret;
5420
5421 case WINED3DFMT_B5G5R5X1_UNORM:
5422 case WINED3DFMT_B5G5R5A1_UNORM:
5423 a = (a * 2) / 256;
5424 r = (r * 32) / 256;
5425 g = (g * 32) / 256;
5426 b = (b * 32) / 256;
5427 ret = a << 15;
5428 ret |= r << 10;
5429 ret |= g << 5;
5430 ret |= b << 0;
5431 TRACE("Returning %08x\n", ret);
5432 return ret;
5433
5434 case WINED3DFMT_A8_UNORM:
5435 TRACE("Returning %08x\n", a);
5436 return a;
5437
5438 case WINED3DFMT_B4G4R4X4_UNORM:
5439 case WINED3DFMT_B4G4R4A4_UNORM:
5440 a = (a * 16) / 256;
5441 r = (r * 16) / 256;
5442 g = (g * 16) / 256;
5443 b = (b * 16) / 256;
5444 ret = a << 12;
5445 ret |= r << 8;
5446 ret |= g << 4;
5447 ret |= b << 0;
5448 TRACE("Returning %08x\n", ret);
5449 return ret;
5450
5451 case WINED3DFMT_B2G3R3_UNORM:
5452 r = (r * 8) / 256;
5453 g = (g * 8) / 256;
5454 b = (b * 4) / 256;
5455 ret = r << 5;
5456 ret |= g << 2;
5457 ret |= b << 0;
5458 TRACE("Returning %08x\n", ret);
5459 return ret;
5460
5461 case WINED3DFMT_R8G8B8X8_UNORM:
5462 case WINED3DFMT_R8G8B8A8_UNORM:
5463 ret = a << 24;
5464 ret |= b << 16;
5465 ret |= g << 8;
5466 ret |= r << 0;
5467 TRACE("Returning %08x\n", ret);
5468 return ret;
5469
5470 case WINED3DFMT_B10G10R10A2_UNORM:
5471 a = (a * 4) / 256;
5472 r = (r * 1024) / 256;
5473 g = (g * 1024) / 256;
5474 b = (b * 1024) / 256;
5475 ret = a << 30;
5476 ret |= r << 20;
5477 ret |= g << 10;
5478 ret |= b << 0;
5479 TRACE("Returning %08x\n", ret);
5480 return ret;
5481
5482 case WINED3DFMT_R10G10B10A2_UNORM:
5483 a = (a * 4) / 256;
5484 r = (r * 1024) / 256;
5485 g = (g * 1024) / 256;
5486 b = (b * 1024) / 256;
5487 ret = a << 30;
5488 ret |= b << 20;
5489 ret |= g << 10;
5490 ret |= r << 0;
5491 TRACE("Returning %08x\n", ret);
5492 return ret;
5493
5494 default:
5495 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
5496 return 0;
5497 }
5498 }
5499
5500 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5501 IWineD3DSurface *pSurface, const WINED3DRECT *pRect, WINED3DCOLOR color)
5502 {
5503 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5504 WINEDDBLTFX BltFx;
5505
5506 TRACE("iface %p, surface %p, rect %p, color 0x%08x.\n", iface, pSurface, pRect, color);
5507
5508 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5509 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5510 return WINED3DERR_INVALIDCALL;
5511 }
5512
5513 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5514 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
5515 color_fill_fbo(iface, pSurface, pRect, c);
5516 return WINED3D_OK;
5517 } else {
5518 /* Just forward this to the DirectDraw blitting engine */
5519 memset(&BltFx, 0, sizeof(BltFx));
5520 BltFx.dwSize = sizeof(BltFx);
5521 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
5522 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
5523 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5524 }
5525 }
5526
5527 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5528 IWineD3DRendertargetView *rendertarget_view, const float color[4])
5529 {
5530 IWineD3DResource *resource;
5531 IWineD3DSurface *surface;
5532 HRESULT hr;
5533
5534 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5535 if (FAILED(hr))
5536 {
5537 ERR("Failed to get resource, hr %#x\n", hr);
5538 return;
5539 }
5540
5541 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5542 {
5543 FIXME("Only supported on surface resources\n");
5544 IWineD3DResource_Release(resource);
5545 return;
5546 }
5547
5548 surface = (IWineD3DSurface *)resource;
5549
5550 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
5551 {
5552 color_fill_fbo(iface, surface, NULL, color);
5553 }
5554 else
5555 {
5556 WINEDDBLTFX BltFx;
5557 WINED3DCOLOR c;
5558
5559 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
5560
5561 c = ((DWORD)(color[2] * 255.0f));
5562 c |= ((DWORD)(color[1] * 255.0f)) << 8;
5563 c |= ((DWORD)(color[0] * 255.0f)) << 16;
5564 c |= ((DWORD)(color[3] * 255.0f)) << 24;
5565
5566 /* Just forward this to the DirectDraw blitting engine */
5567 memset(&BltFx, 0, sizeof(BltFx));
5568 BltFx.dwSize = sizeof(BltFx);
5569 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
5570 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5571 if (FAILED(hr))
5572 {
5573 ERR("Blt failed, hr %#x\n", hr);
5574 }
5575 }
5576
5577 IWineD3DResource_Release(resource);
5578 }
5579
5580 /* rendertarget and depth stencil functions */
5581 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5582 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5583
5584 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5585 {
5586 ERR("(%p) : Only %d render targets are supported.\n",
5587 This, This->adapter->gl_info.limits.buffers);
5588 return WINED3DERR_INVALIDCALL;
5589 }
5590
5591 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5592 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5593 /* Note inc ref on returned surface */
5594 if(*ppRenderTarget != NULL)
5595 IWineD3DSurface_AddRef(*ppRenderTarget);
5596 return WINED3D_OK;
5597 }
5598
5599 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface,
5600 IWineD3DSurface *Front, IWineD3DSurface *Back)
5601 {
5602 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5603 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5604 IWineD3DSwapChainImpl *Swapchain;
5605 HRESULT hr;
5606
5607 TRACE("iface %p, front %p, back %p.\n", iface, Front, Back);
5608
5609 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5610 if(hr != WINED3D_OK) {
5611 ERR("Can't get the swapchain\n");
5612 return hr;
5613 }
5614
5615 /* Make sure to release the swapchain */
5616 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5617
5618 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5619 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5620 return WINED3DERR_INVALIDCALL;
5621 }
5622 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5623 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5624 return WINED3DERR_INVALIDCALL;
5625 }
5626
5627 if(Swapchain->frontBuffer != Front) {
5628 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5629
5630 if(Swapchain->frontBuffer)
5631 {
5632 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5633 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
5634 }
5635 Swapchain->frontBuffer = Front;
5636
5637 if(Swapchain->frontBuffer) {
5638 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5639 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
5640 }
5641 }
5642
5643 if(Back && !Swapchain->backBuffer) {
5644 /* We need memory for the back buffer array - only one back buffer this way */
5645 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5646 if(!Swapchain->backBuffer) {
5647 ERR("Out of memory\n");
5648 return E_OUTOFMEMORY;
5649 }
5650 }
5651
5652 if(Swapchain->backBuffer[0] != Back) {
5653 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5654
5655 /* What to do about the context here in the case of multithreading? Not sure.
5656 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5657 */
5658 WARN("No active context?\n");
5659
5660 ENTER_GL();
5661 if(!Swapchain->backBuffer[0]) {
5662 /* GL was told to draw to the front buffer at creation,
5663 * undo that
5664 */
5665 glDrawBuffer(GL_BACK);
5666 checkGLcall("glDrawBuffer(GL_BACK)");
5667 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5668 Swapchain->presentParms.BackBufferCount = 1;
5669 } else if (!Back) {
5670 /* That makes problems - disable for now */
5671 /* glDrawBuffer(GL_FRONT); */
5672 checkGLcall("glDrawBuffer(GL_FRONT)");
5673 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5674 Swapchain->presentParms.BackBufferCount = 0;
5675 }
5676 LEAVE_GL();
5677
5678 if(Swapchain->backBuffer[0])
5679 {
5680 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5681 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
5682 }
5683 Swapchain->backBuffer[0] = Back;
5684
5685 if(Swapchain->backBuffer[0]) {
5686 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5687 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags |= SFLAG_SWAPCHAIN;
5688 } else {
5689 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5690 Swapchain->backBuffer = NULL;
5691 }
5692
5693 }
5694
5695 return WINED3D_OK;
5696 }
5697
5698 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5699 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5700 *ppZStencilSurface = This->stencilBufferTarget;
5701 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5702
5703 if(*ppZStencilSurface != NULL) {
5704 /* Note inc ref on returned surface */
5705 IWineD3DSurface_AddRef(*ppZStencilSurface);
5706 return WINED3D_OK;
5707 } else {
5708 return WINED3DERR_NOTFOUND;
5709 }
5710 }
5711
5712 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
5713 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
5714 {
5715 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5716 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5717 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
5718 const struct wined3d_gl_info *gl_info;
5719 struct wined3d_context *context;
5720 GLenum gl_filter;
5721 POINT offset = {0, 0};
5722
5723 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
5724 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
5725 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
5726 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
5727
5728 switch (filter) {
5729 case WINED3DTEXF_LINEAR:
5730 gl_filter = GL_LINEAR;
5731 break;
5732
5733 default:
5734 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5735 case WINED3DTEXF_NONE:
5736 case WINED3DTEXF_POINT:
5737 gl_filter = GL_NEAREST;
5738 break;
5739 }
5740
5741 /* Attach src surface to src fbo */
5742 src_swapchain = get_swapchain(src_surface);
5743 dst_swapchain = get_swapchain(dst_surface);
5744
5745 if (src_swapchain) context = context_acquire(This, src_surface, CTXUSAGE_RESOURCELOAD);
5746 else if (dst_swapchain) context = context_acquire(This, dst_surface, CTXUSAGE_RESOURCELOAD);
5747 else context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5748
5749 gl_info = context->gl_info;
5750
5751 if (!surface_is_offscreen(src_surface))
5752 {
5753 GLenum buffer = surface_get_gl_buffer(src_surface);
5754
5755 TRACE("Source surface %p is onscreen\n", src_surface);
5756 /* Make sure the drawable is up to date. In the offscreen case
5757 * attach_surface_fbo() implicitly takes care of this. */
5758 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
5759
5760 if(buffer == GL_FRONT) {
5761 RECT windowsize;
5762 UINT h;
5763 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
5764 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
5765 h = windowsize.bottom - windowsize.top;
5766 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
5767 src_rect->y1 = offset.y + h - src_rect->y1;
5768 src_rect->y2 = offset.y + h - src_rect->y2;
5769 } else {
5770 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
5771 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
5772 }
5773
5774 ENTER_GL();
5775 context_bind_fbo(context, GL_READ_FRAMEBUFFER, NULL);
5776 glReadBuffer(buffer);
5777 checkGLcall("glReadBuffer()");
5778 } else {
5779 TRACE("Source surface %p is offscreen\n", src_surface);
5780 ENTER_GL();
5781 context_bind_fbo(context, GL_READ_FRAMEBUFFER, &context->src_fbo);
5782 context_attach_surface_fbo(context, GL_READ_FRAMEBUFFER, 0, src_surface);
5783 glReadBuffer(GL_COLOR_ATTACHMENT0);
5784 checkGLcall("glReadBuffer()");
5785 context_attach_depth_stencil_fbo(context, GL_READ_FRAMEBUFFER, NULL, FALSE);
5786 }
5787 LEAVE_GL();
5788
5789 /* Attach dst surface to dst fbo */
5790 if (!surface_is_offscreen(dst_surface))
5791 {
5792 GLenum buffer = surface_get_gl_buffer(dst_surface);
5793
5794 TRACE("Destination surface %p is onscreen\n", dst_surface);
5795 /* Make sure the drawable is up to date. In the offscreen case
5796 * attach_surface_fbo() implicitly takes care of this. */
5797 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
5798
5799 if(buffer == GL_FRONT) {
5800 RECT windowsize;
5801 UINT h;
5802 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
5803 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
5804 h = windowsize.bottom - windowsize.top;
5805 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
5806 dst_rect->y1 = offset.y + h - dst_rect->y1;
5807 dst_rect->y2 = offset.y + h - dst_rect->y2;
5808 } else {
5809 /* Screen coords = window coords, surface height = window height */
5810 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
5811 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
5812 }
5813
5814 ENTER_GL();
5815 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, NULL);
5816 context_set_draw_buffer(context, buffer);
5817 }
5818 else
5819 {
5820 TRACE("Destination surface %p is offscreen\n", dst_surface);
5821
5822 ENTER_GL();
5823 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, &context->dst_fbo);
5824 context_attach_surface_fbo(context, GL_DRAW_FRAMEBUFFER, 0, dst_surface);
5825 context_set_draw_buffer(context, GL_COLOR_ATTACHMENT0);
5826 context_attach_depth_stencil_fbo(context, GL_DRAW_FRAMEBUFFER, NULL, FALSE);
5827 }
5828 glDisable(GL_SCISSOR_TEST);
5829 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5830
5831 if (flip) {
5832 gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5833 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter);
5834 checkGLcall("glBlitFramebuffer()");
5835 } else {
5836 gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5837 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter);
5838 checkGLcall("glBlitFramebuffer()");
5839 }
5840
5841 LEAVE_GL();
5842 context_release(context);
5843
5844 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
5845 }
5846
5847 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget,
5848 BOOL set_viewport) {
5849 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5850
5851 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5852
5853 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5854 {
5855 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
5856 This, RenderTargetIndex, This->adapter->gl_info.limits.buffers);
5857 return WINED3DERR_INVALIDCALL;
5858 }
5859
5860 /* MSDN says that null disables the render target
5861 but a device must always be associated with a render target
5862 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5863 */
5864 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5865 FIXME("Trying to set render target 0 to NULL\n");
5866 return WINED3DERR_INVALIDCALL;
5867 }
5868 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5869 FIXME("(%p)Trying to set the render target to a surface(%p) that wasn't created with a usage of WINED3DUSAGE_RENDERTARGET\n",This ,pRenderTarget);
5870 return WINED3DERR_INVALIDCALL;
5871 }
5872
5873 /* If we are trying to set what we already have, don't bother */
5874 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5875 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5876 return WINED3D_OK;
5877 }
5878 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5879 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5880 This->render_targets[RenderTargetIndex] = pRenderTarget;
5881
5882 /* Render target 0 is special */
5883 if(RenderTargetIndex == 0 && set_viewport) {
5884 /* Finally, reset the viewport and scissor rect as the MSDN states.
5885 * Tests show that stateblock recording is ignored, the change goes
5886 * directly into the primary stateblock.
5887 */
5888 This->stateBlock->viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5889 This->stateBlock->viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5890 This->stateBlock->viewport.X = 0;
5891 This->stateBlock->viewport.Y = 0;
5892 This->stateBlock->viewport.MaxZ = 1.0f;
5893 This->stateBlock->viewport.MinZ = 0.0f;
5894 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
5895
5896 This->stateBlock->scissorRect.top = 0;
5897 This->stateBlock->scissorRect.left = 0;
5898 This->stateBlock->scissorRect.right = This->stateBlock->viewport.Width;
5899 This->stateBlock->scissorRect.bottom = This->stateBlock->viewport.Height;
5900 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5901 }
5902 return WINED3D_OK;
5903 }
5904
5905 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5906 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5907 HRESULT hr = WINED3D_OK;
5908 IWineD3DSurface *tmp;
5909
5910 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
5911
5912 if (pNewZStencil == This->stencilBufferTarget) {
5913 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5914 } else {
5915 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
5916 * depending on the renter target implementation being used.
5917 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5918 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5919 * stencil buffer and incur an extra memory overhead
5920 ******************************************************/
5921
5922 if (This->stencilBufferTarget) {
5923 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5924 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
5925 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
5926 } else {
5927 struct wined3d_context *context = context_acquire(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5928 surface_load_ds_location(This->stencilBufferTarget, context, SFLAG_DS_OFFSCREEN);
5929 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
5930 context_release(context);
5931 }
5932 }
5933
5934 tmp = This->stencilBufferTarget;
5935 This->stencilBufferTarget = pNewZStencil;
5936 /* should we be calling the parent or the wined3d surface? */
5937 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5938 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5939 hr = WINED3D_OK;
5940
5941 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
5942 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5943 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5944 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5945 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5946 }
5947 }
5948
5949 return hr;
5950 }
5951
5952 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5953 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5954 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5955 /* TODO: the use of Impl is deprecated. */
5956 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5957 WINED3DLOCKED_RECT lockedRect;
5958
5959 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5960
5961 /* some basic validation checks */
5962 if(This->cursorTexture) {
5963 struct wined3d_context *context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5964 ENTER_GL();
5965 glDeleteTextures(1, &This->cursorTexture);
5966 LEAVE_GL();
5967 context_release(context);
5968 This->cursorTexture = 0;
5969 }
5970
5971 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
5972 This->haveHardwareCursor = TRUE;
5973 else
5974 This->haveHardwareCursor = FALSE;
5975
5976 if(pCursorBitmap) {
5977 WINED3DLOCKED_RECT rect;
5978
5979 /* MSDN: Cursor must be A8R8G8B8 */
5980 if (pSur->resource.format_desc->format != WINED3DFMT_B8G8R8A8_UNORM)
5981 {
5982 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5983 return WINED3DERR_INVALIDCALL;
5984 }
5985
5986 /* MSDN: Cursor must be smaller than the display mode */
5987 if(pSur->currentDesc.Width > This->ddraw_width ||
5988 pSur->currentDesc.Height > This->ddraw_height) {
5989 ERR("(%p) : Surface(%p) is %dx%d pixels, but screen res is %dx%d\n", This, pSur, pSur->currentDesc.Width, pSur->currentDesc.Height, This->ddraw_width, This->ddraw_height);
5990 return WINED3DERR_INVALIDCALL;
5991 }
5992
5993 if (!This->haveHardwareCursor) {
5994 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5995
5996 /* Do not store the surface's pointer because the application may
5997 * release it after setting the cursor image. Windows doesn't
5998 * addref the set surface, so we can't do this either without
5999 * creating circular refcount dependencies. Copy out the gl texture
6000 * instead.
6001 */
6002 This->cursorWidth = pSur->currentDesc.Width;
6003 This->cursorHeight = pSur->currentDesc.Height;
6004 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6005 {
6006 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
6007 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(WINED3DFMT_B8G8R8A8_UNORM, gl_info);
6008 struct wined3d_context *context;
6009 char *mem, *bits = rect.pBits;
6010 GLint intfmt = glDesc->glInternal;
6011 GLint format = glDesc->glFormat;
6012 GLint type = glDesc->glType;
6013 INT height = This->cursorHeight;
6014 INT width = This->cursorWidth;
6015 INT bpp = glDesc->byte_count;
6016 DWORD sampler;
6017 INT i;
6018
6019 /* Reformat the texture memory (pitch and width can be
6020 * different) */
6021 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6022 for(i = 0; i < height; i++)
6023 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6024 IWineD3DSurface_UnlockRect(pCursorBitmap);
6025
6026 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6027
6028 ENTER_GL();
6029
6030 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6031 {
6032 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6033 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6034 }
6035
6036 /* Make sure that a proper texture unit is selected */
6037 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6038 checkGLcall("glActiveTextureARB");
6039 sampler = This->rev_tex_unit_map[0];
6040 if (sampler != WINED3D_UNMAPPED_STAGE)
6041 {
6042 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6043 }
6044 /* Create a new cursor texture */
6045 glGenTextures(1, &This->cursorTexture);
6046 checkGLcall("glGenTextures");
6047 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6048 checkGLcall("glBindTexture");
6049 /* Copy the bitmap memory into the cursor texture */
6050 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6051 HeapFree(GetProcessHeap(), 0, mem);
6052 checkGLcall("glTexImage2D");
6053
6054 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6055 {
6056 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6057 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6058 }
6059
6060 LEAVE_GL();
6061
6062 context_release(context);
6063 }
6064 else
6065 {
6066 FIXME("A cursor texture was not returned.\n");
6067 This->cursorTexture = 0;
6068 }
6069 }
6070 else
6071 {
6072 /* Draw a hardware cursor */
6073 ICONINFO cursorInfo;
6074 HCURSOR cursor;
6075 /* Create and clear maskBits because it is not needed for
6076 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6077 * chunks. */
6078 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6079 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6080 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6081 WINED3DLOCK_NO_DIRTY_UPDATE |
6082 WINED3DLOCK_READONLY
6083 );
6084 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6085 pSur->currentDesc.Height);
6086
6087 cursorInfo.fIcon = FALSE;
6088 cursorInfo.xHotspot = XHotSpot;
6089 cursorInfo.yHotspot = YHotSpot;
6090 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6091 1, 1, maskBits);
6092 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6093 1, 32, lockedRect.pBits);
6094 IWineD3DSurface_UnlockRect(pCursorBitmap);
6095 /* Create our cursor and clean up. */
6096 cursor = CreateIconIndirect(&cursorInfo);
6097 SetCursor(cursor);
6098 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6099 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6100 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6101 This->hardwareCursor = cursor;
6102 HeapFree(GetProcessHeap(), 0, maskBits);
6103 }
6104 }
6105
6106 This->xHotSpot = XHotSpot;
6107 This->yHotSpot = YHotSpot;
6108 return WINED3D_OK;
6109 }
6110
6111 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6112 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6113 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6114
6115 This->xScreenSpace = XScreenSpace;
6116 This->yScreenSpace = YScreenSpace;
6117
6118 return;
6119
6120 }
6121
6122 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6123 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6124 BOOL oldVisible = This->bCursorVisible;
6125 POINT pt;
6126
6127 TRACE("(%p) : visible(%d)\n", This, bShow);
6128
6129 /*
6130 * When ShowCursor is first called it should make the cursor appear at the OS's last
6131 * known cursor position. Because of this, some applications just repetitively call
6132 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6133 */
6134 GetCursorPos(&pt);
6135 This->xScreenSpace = pt.x;
6136 This->yScreenSpace = pt.y;
6137
6138 if (This->haveHardwareCursor) {
6139 This->bCursorVisible = bShow;
6140 if (bShow)
6141 SetCursor(This->hardwareCursor);
6142 else
6143 SetCursor(NULL);
6144 }
6145 else
6146 {
6147 if (This->cursorTexture)
6148 This->bCursorVisible = bShow;
6149 }
6150
6151 return oldVisible;
6152 }
6153
6154 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6155 TRACE("checking resource %p for eviction\n", resource);
6156 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6157 TRACE("Evicting %p\n", resource);
6158 IWineD3DResource_UnLoad(resource);
6159 }
6160 IWineD3DResource_Release(resource);
6161 return S_OK;
6162 }
6163
6164 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6165 {
6166 TRACE("iface %p.\n", iface);
6167
6168 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6169 return WINED3D_OK;
6170 }
6171
6172 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6173 {
6174 IWineD3DDeviceImpl *device = surface->resource.device;
6175 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6176
6177 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6178 if(surface->Flags & SFLAG_DIBSECTION) {
6179 /* Release the DC */
6180 SelectObject(surface->hDC, surface->dib.holdbitmap);
6181 DeleteDC(surface->hDC);
6182 /* Release the DIB section */
6183 DeleteObject(surface->dib.DIBsection);
6184 surface->dib.bitmap_data = NULL;
6185 surface->resource.allocatedMemory = NULL;
6186 surface->Flags &= ~SFLAG_DIBSECTION;
6187 }
6188 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6189 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6190 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6191 || gl_info->supported[WINE_NORMALIZED_TEXRECT])
6192 {
6193 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6194 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6195 } else {
6196 surface->pow2Width = surface->pow2Height = 1;
6197 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6198 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6199 }
6200 surface->glRect.left = 0;
6201 surface->glRect.top = 0;
6202 surface->glRect.right = surface->pow2Width;
6203 surface->glRect.bottom = surface->pow2Height;
6204
6205 if (surface->texture_name)
6206 {
6207 struct wined3d_context *context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
6208 ENTER_GL();
6209 glDeleteTextures(1, &surface->texture_name);
6210 LEAVE_GL();
6211 context_release(context);
6212 surface->texture_name = 0;
6213 surface->Flags &= ~SFLAG_CLIENT;
6214 }
6215 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6216 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6217 surface->Flags |= SFLAG_NONPOW2;
6218 } else {
6219 surface->Flags &= ~SFLAG_NONPOW2;
6220 }
6221 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6222 surface->resource.allocatedMemory = NULL;
6223 surface->resource.heapMemory = NULL;
6224 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6225
6226 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6227 * to a FBO */
6228 if(!surface_init_sysmem((IWineD3DSurface *) surface))
6229 {
6230 return E_OUTOFMEMORY;
6231 }
6232 return WINED3D_OK;
6233 }
6234
6235 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6236 TRACE("Unloading resource %p\n", resource);
6237 IWineD3DResource_UnLoad(resource);
6238 IWineD3DResource_Release(resource);
6239 return S_OK;
6240 }
6241
6242 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6243 {
6244 UINT i, count;
6245 WINED3DDISPLAYMODE m;
6246 HRESULT hr;
6247
6248 /* All Windowed modes are supported, as is leaving the current mode */
6249 if(pp->Windowed) return TRUE;
6250 if(!pp->BackBufferWidth) return TRUE;
6251 if(!pp->BackBufferHeight) return TRUE;
6252
6253 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6254 for(i = 0; i < count; i++) {
6255 memset(&m, 0, sizeof(m));
6256 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6257 if(FAILED(hr)) {
6258 ERR("EnumAdapterModes failed\n");
6259 }
6260 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6261 /* Mode found, it is supported */
6262 return TRUE;
6263 }
6264 }
6265 /* Mode not found -> not supported */
6266 return FALSE;
6267 }
6268
6269 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6270 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6271 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6272 const struct wined3d_gl_info *gl_info;
6273 struct wined3d_context *context;
6274 IWineD3DBaseShaderImpl *shader;
6275
6276 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6277 gl_info = context->gl_info;
6278
6279 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6280 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6281 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6282 }
6283
6284 ENTER_GL();
6285 if(This->depth_blt_texture) {
6286 glDeleteTextures(1, &This->depth_blt_texture);
6287 This->depth_blt_texture = 0;
6288 }
6289 if (This->depth_blt_rb) {
6290 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6291 This->depth_blt_rb = 0;
6292 This->depth_blt_rb_w = 0;
6293 This->depth_blt_rb_h = 0;
6294 }
6295 LEAVE_GL();
6296
6297 This->blitter->free_private(iface);
6298 This->frag_pipe->free_private(iface);
6299 This->shader_backend->shader_free_private(iface);
6300 destroy_dummy_textures(This, gl_info);
6301
6302 context_release(context);
6303
6304 while (This->numContexts)
6305 {
6306 context_destroy(This, This->contexts[0]);
6307 }
6308 HeapFree(GetProcessHeap(), 0, swapchain->context);
6309 swapchain->context = NULL;
6310 swapchain->num_contexts = 0;
6311 }
6312
6313 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6314 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6315 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6316 struct wined3d_context *context;
6317 HRESULT hr;
6318 IWineD3DSurfaceImpl *target;
6319
6320 /* Recreate the primary swapchain's context */
6321 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6322 if (!swapchain->context)
6323 {
6324 ERR("Failed to allocate memory for swapchain context array.\n");
6325 return E_OUTOFMEMORY;
6326 }
6327
6328 target = (IWineD3DSurfaceImpl *)(swapchain->backBuffer ? swapchain->backBuffer[0] : swapchain->frontBuffer);
6329 context = context_create(This, target, swapchain->win_handle, FALSE, &swapchain->presentParms);
6330 if (!context)
6331 {
6332 WARN("Failed to create context.\n");
6333 HeapFree(GetProcessHeap(), 0, swapchain->context);
6334 return E_FAIL;
6335 }
6336
6337 swapchain->context[0] = context;
6338 swapchain->num_contexts = 1;
6339 create_dummy_textures(This);
6340 context_release(context);
6341
6342 hr = This->shader_backend->shader_alloc_private(iface);
6343 if (FAILED(hr))
6344 {
6345 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6346 goto err;
6347 }
6348
6349 hr = This->frag_pipe->alloc_private(iface);
6350 if (FAILED(hr))
6351 {
6352 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6353 This->shader_backend->shader_free_private(iface);
6354 goto err;
6355 }
6356
6357 hr = This->blitter->alloc_private(iface);
6358 if (FAILED(hr))
6359 {
6360 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6361 This->frag_pipe->free_private(iface);
6362 This->shader_backend->shader_free_private(iface);
6363 goto err;
6364 }
6365
6366 return WINED3D_OK;
6367
6368 err:
6369 context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6370 destroy_dummy_textures(This, context->gl_info);
6371 context_release(context);
6372 context_destroy(This, context);
6373 HeapFree(GetProcessHeap(), 0, swapchain->context);
6374 swapchain->num_contexts = 0;
6375 return hr;
6376 }
6377
6378 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6379 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6380 IWineD3DSwapChainImpl *swapchain;
6381 HRESULT hr;
6382 BOOL DisplayModeChanged = FALSE;
6383 WINED3DDISPLAYMODE mode;
6384 TRACE("(%p)\n", This);
6385
6386 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6387 if(FAILED(hr)) {
6388 ERR("Failed to get the first implicit swapchain\n");
6389 return hr;
6390 }
6391
6392 if(!is_display_mode_supported(This, pPresentationParameters)) {
6393 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6394 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6395 pPresentationParameters->BackBufferHeight);
6396 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6397 return WINED3DERR_INVALIDCALL;
6398 }
6399
6400 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6401 * on an existing gl context, so there's no real need for recreation.
6402 *
6403 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6404 *
6405 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6406 */
6407 TRACE("New params:\n");
6408 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6409 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6410 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6411 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6412 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6413 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6414 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6415 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6416 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6417 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6418 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6419 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6420 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6421
6422 /* No special treatment of these parameters. Just store them */
6423 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6424 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6425 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6426 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6427
6428 /* What to do about these? */
6429 if(pPresentationParameters->BackBufferCount != 0 &&
6430 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6431 ERR("Cannot change the back buffer count yet\n");
6432 }
6433 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6434 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6435 ERR("Cannot change the back buffer format yet\n");
6436 }
6437 if(pPresentationParameters->hDeviceWindow != NULL &&
6438 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6439 ERR("Cannot change the device window yet\n");
6440 }
6441 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
6442 HRESULT hrc;
6443
6444 TRACE("Creating the depth stencil buffer\n");
6445
6446 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6447 This->parent,
6448 pPresentationParameters->BackBufferWidth,
6449 pPresentationParameters->BackBufferHeight,
6450 pPresentationParameters->AutoDepthStencilFormat,
6451 pPresentationParameters->MultiSampleType,
6452 pPresentationParameters->MultiSampleQuality,
6453 FALSE,
6454 &This->auto_depth_stencil_buffer);
6455
6456 if (FAILED(hrc)) {
6457 ERR("Failed to create the depth stencil buffer\n");
6458 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6459 return WINED3DERR_INVALIDCALL;
6460 }
6461 }
6462
6463 /* Reset the depth stencil */
6464 if (pPresentationParameters->EnableAutoDepthStencil)
6465 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
6466 else
6467 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6468
6469 TRACE("Resetting stateblock\n");
6470 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6471 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6472
6473 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
6474
6475 if(pPresentationParameters->Windowed) {
6476 mode.Width = swapchain->orig_width;
6477 mode.Height = swapchain->orig_height;
6478 mode.RefreshRate = 0;
6479 mode.Format = swapchain->presentParms.BackBufferFormat;
6480 } else {
6481 mode.Width = pPresentationParameters->BackBufferWidth;
6482 mode.Height = pPresentationParameters->BackBufferHeight;
6483 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6484 mode.Format = swapchain->presentParms.BackBufferFormat;
6485 }
6486
6487 /* Should Width == 800 && Height == 0 set 800x600? */
6488 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6489 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6490 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6491 {
6492 UINT i;
6493
6494 if(!pPresentationParameters->Windowed) {
6495 DisplayModeChanged = TRUE;
6496 }
6497 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6498 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6499
6500 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6501 if(FAILED(hr))
6502 {
6503 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6504 return hr;
6505 }
6506
6507 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6508 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6509 if(FAILED(hr))
6510 {
6511 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6512 return hr;
6513 }
6514 }
6515 if(This->auto_depth_stencil_buffer) {
6516 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
6517 if(FAILED(hr))
6518 {
6519 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6520 return hr;
6521 }
6522 }
6523 }
6524
6525 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6526 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6527 DisplayModeChanged) {
6528
6529 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6530
6531 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
6532 if(swapchain->presentParms.Windowed) {
6533 /* switch from windowed to fs */
6534 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6535 pPresentationParameters->BackBufferHeight);
6536 } else {
6537 /* Fullscreen -> fullscreen mode change */
6538 MoveWindow(swapchain->win_handle, 0, 0,
6539 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6540 TRUE);
6541 }
6542 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
6543 /* Fullscreen -> windowed switch */
6544 swapchain_restore_fullscreen_window(swapchain);
6545 }
6546 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6547 } else if(!pPresentationParameters->Windowed) {
6548 DWORD style = This->style, exStyle = This->exStyle;
6549 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6550 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6551 * Reset to clear up their mess. Guild Wars also loses the device during that.
6552 */
6553 This->style = 0;
6554 This->exStyle = 0;
6555 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6556 pPresentationParameters->BackBufferHeight);
6557 This->style = style;
6558 This->exStyle = exStyle;
6559 }
6560
6561 /* Note: No parent needed for initial internal stateblock */
6562 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
6563 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6564 else TRACE("Created stateblock %p\n", This->stateBlock);
6565 This->updateStateBlock = This->stateBlock;
6566 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6567
6568 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
6569 if(FAILED(hr)) {
6570 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6571 }
6572
6573 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6574 {
6575 RECT client_rect;
6576 GetClientRect(swapchain->win_handle, &client_rect);
6577
6578 if(!swapchain->presentParms.BackBufferCount)
6579 {
6580 TRACE("Single buffered rendering\n");
6581 swapchain->render_to_fbo = FALSE;
6582 }
6583 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6584 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6585 {
6586 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6587 swapchain->presentParms.BackBufferWidth,
6588 swapchain->presentParms.BackBufferHeight,
6589 client_rect.right, client_rect.bottom);
6590 swapchain->render_to_fbo = TRUE;
6591 }
6592 else
6593 {
6594 TRACE("Rendering directly to GL_BACK\n");
6595 swapchain->render_to_fbo = FALSE;
6596 }
6597 }
6598
6599 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
6600 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6601
6602 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6603 * first use
6604 */
6605 return hr;
6606 }
6607
6608 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6609 {
6610 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6611
6612 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6613
6614 return WINED3D_OK;
6615 }
6616
6617
6618 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6619 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6620 TRACE("(%p) : pParameters %p\n", This, pParameters);
6621
6622 *pParameters = This->createParms;
6623 return WINED3D_OK;
6624 }
6625
6626 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6627 IWineD3DSwapChain *swapchain;
6628
6629 TRACE("Relaying to swapchain\n");
6630
6631 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6632 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6633 IWineD3DSwapChain_Release(swapchain);
6634 }
6635 }
6636
6637 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6638 IWineD3DSwapChain *swapchain;
6639
6640 TRACE("Relaying to swapchain\n");
6641
6642 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6643 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6644 IWineD3DSwapChain_Release(swapchain);
6645 }
6646 }
6647
6648
6649 /** ********************************************************
6650 * Notification functions
6651 ** ********************************************************/
6652 /** This function must be called in the release of a resource when ref == 0,
6653 * the contents of resource must still be correct,
6654 * any handles to other resource held by the caller must be closed
6655 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6656 *****************************************************/
6657 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6658 {
6659 TRACE("(%p) : Adding resource %p\n", This, resource);
6660
6661 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6662 }
6663
6664 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6665 {
6666 TRACE("(%p) : Removing resource %p\n", This, resource);
6667
6668 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6669 }
6670
6671 void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6672 {
6673 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6674 int counter;
6675
6676 TRACE("(%p) : resource %p\n", This, resource);
6677
6678 context_resource_released((IWineD3DDevice *)This, resource, type);
6679
6680 switch (type) {
6681 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6682 case WINED3DRTYPE_SURFACE: {
6683 unsigned int i;
6684
6685 if (This->d3d_initialized)
6686 {
6687 for (i = 0; i < This->adapter->gl_info.limits.buffers; ++i)
6688 {
6689 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
6690 This->render_targets[i] = NULL;
6691 }
6692 }
6693 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
6694 This->stencilBufferTarget = NULL;
6695 }
6696 }
6697
6698 break;
6699 }
6700 case WINED3DRTYPE_TEXTURE:
6701 case WINED3DRTYPE_CUBETEXTURE:
6702 case WINED3DRTYPE_VOLUMETEXTURE:
6703 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6704 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6705 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6706 This->stateBlock->textures[counter] = NULL;
6707 }
6708 if (This->updateStateBlock != This->stateBlock ){
6709 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6710 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6711 This->updateStateBlock->textures[counter] = NULL;
6712 }
6713 }
6714 }
6715 break;
6716 case WINED3DRTYPE_VOLUME:
6717 /* TODO: nothing really? */
6718 break;
6719 case WINED3DRTYPE_BUFFER:
6720 {
6721 int streamNumber;
6722 TRACE("Cleaning up stream pointers\n");
6723
6724 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6725 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6726 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6727 */
6728 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6729 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6730 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6731 This->updateStateBlock->streamSource[streamNumber] = 0;
6732 /* Set changed flag? */
6733 }
6734 }
6735 if (This->stateBlock != NULL ) { /* only happens if there is an error in the application, or on reset/release (because we don't manage internal tracking properly) */
6736 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6737 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6738 This->stateBlock->streamSource[streamNumber] = 0;
6739 }
6740 }
6741 }
6742
6743 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6744 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6745 This->updateStateBlock->pIndexData = NULL;
6746 }
6747 }
6748 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6749 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6750 This->stateBlock->pIndexData = NULL;
6751 }
6752 }
6753 }
6754 break;
6755
6756 default:
6757 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6758 break;
6759 }
6760
6761
6762 /* Remove the resource from the resourceStore */
6763 device_resource_remove(This, resource);
6764
6765 TRACE("Resource released\n");
6766
6767 }
6768
6769 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6770 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6771 IWineD3DResourceImpl *resource, *cursor;
6772 HRESULT ret;
6773 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6774
6775 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6776 TRACE("enumerating resource %p\n", resource);
6777 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6778 ret = pCallback((IWineD3DResource *) resource, pData);
6779 if(ret == S_FALSE) {
6780 TRACE("Canceling enumeration\n");
6781 break;
6782 }
6783 }
6784 return WINED3D_OK;
6785 }
6786
6787 /**********************************************************
6788 * IWineD3DDevice VTbl follows
6789 **********************************************************/
6790
6791 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6792 {
6793 /*** IUnknown methods ***/
6794 IWineD3DDeviceImpl_QueryInterface,
6795 IWineD3DDeviceImpl_AddRef,
6796 IWineD3DDeviceImpl_Release,
6797 /*** IWineD3DDevice methods ***/
6798 IWineD3DDeviceImpl_GetParent,
6799 /*** Creation methods**/
6800 IWineD3DDeviceImpl_CreateBuffer,
6801 IWineD3DDeviceImpl_CreateVertexBuffer,
6802 IWineD3DDeviceImpl_CreateIndexBuffer,
6803 IWineD3DDeviceImpl_CreateStateBlock,
6804 IWineD3DDeviceImpl_CreateSurface,
6805 IWineD3DDeviceImpl_CreateRendertargetView,
6806 IWineD3DDeviceImpl_CreateTexture,
6807 IWineD3DDeviceImpl_CreateVolumeTexture,
6808 IWineD3DDeviceImpl_CreateVolume,
6809 IWineD3DDeviceImpl_CreateCubeTexture,
6810 IWineD3DDeviceImpl_CreateQuery,
6811 IWineD3DDeviceImpl_CreateSwapChain,
6812 IWineD3DDeviceImpl_CreateVertexDeclaration,
6813 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6814 IWineD3DDeviceImpl_CreateVertexShader,
6815 IWineD3DDeviceImpl_CreateGeometryShader,
6816 IWineD3DDeviceImpl_CreatePixelShader,
6817 IWineD3DDeviceImpl_CreatePalette,
6818 /*** Odd functions **/
6819 IWineD3DDeviceImpl_Init3D,
6820 IWineD3DDeviceImpl_InitGDI,
6821 IWineD3DDeviceImpl_Uninit3D,
6822 IWineD3DDeviceImpl_UninitGDI,
6823 IWineD3DDeviceImpl_SetMultithreaded,
6824 IWineD3DDeviceImpl_EvictManagedResources,
6825 IWineD3DDeviceImpl_GetAvailableTextureMem,
6826 IWineD3DDeviceImpl_GetBackBuffer,
6827 IWineD3DDeviceImpl_GetCreationParameters,
6828 IWineD3DDeviceImpl_GetDeviceCaps,
6829 IWineD3DDeviceImpl_GetDirect3D,
6830 IWineD3DDeviceImpl_GetDisplayMode,
6831 IWineD3DDeviceImpl_SetDisplayMode,
6832 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6833 IWineD3DDeviceImpl_GetRasterStatus,
6834 IWineD3DDeviceImpl_GetSwapChain,
6835 IWineD3DDeviceImpl_Reset,
6836 IWineD3DDeviceImpl_SetDialogBoxMode,
6837 IWineD3DDeviceImpl_SetCursorProperties,
6838 IWineD3DDeviceImpl_SetCursorPosition,
6839 IWineD3DDeviceImpl_ShowCursor,
6840 /*** Getters and setters **/
6841 IWineD3DDeviceImpl_SetClipPlane,
6842 IWineD3DDeviceImpl_GetClipPlane,
6843 IWineD3DDeviceImpl_SetClipStatus,
6844 IWineD3DDeviceImpl_GetClipStatus,
6845 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6846 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6847 IWineD3DDeviceImpl_SetDepthStencilSurface,
6848 IWineD3DDeviceImpl_GetDepthStencilSurface,
6849 IWineD3DDeviceImpl_SetGammaRamp,
6850 IWineD3DDeviceImpl_GetGammaRamp,
6851 IWineD3DDeviceImpl_SetIndexBuffer,
6852 IWineD3DDeviceImpl_GetIndexBuffer,
6853 IWineD3DDeviceImpl_SetBaseVertexIndex,
6854 IWineD3DDeviceImpl_GetBaseVertexIndex,
6855 IWineD3DDeviceImpl_SetLight,
6856 IWineD3DDeviceImpl_GetLight,
6857 IWineD3DDeviceImpl_SetLightEnable,
6858 IWineD3DDeviceImpl_GetLightEnable,
6859 IWineD3DDeviceImpl_SetMaterial,
6860 IWineD3DDeviceImpl_GetMaterial,
6861 IWineD3DDeviceImpl_SetNPatchMode,
6862 IWineD3DDeviceImpl_GetNPatchMode,
6863 IWineD3DDeviceImpl_SetPaletteEntries,
6864 IWineD3DDeviceImpl_GetPaletteEntries,
6865 IWineD3DDeviceImpl_SetPixelShader,
6866 IWineD3DDeviceImpl_GetPixelShader,
6867 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6868 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6869 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6870 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6871 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6872 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6873 IWineD3DDeviceImpl_SetRenderState,
6874 IWineD3DDeviceImpl_GetRenderState,
6875 IWineD3DDeviceImpl_SetRenderTarget,
6876 IWineD3DDeviceImpl_GetRenderTarget,
6877 IWineD3DDeviceImpl_SetFrontBackBuffers,
6878 IWineD3DDeviceImpl_SetSamplerState,
6879 IWineD3DDeviceImpl_GetSamplerState,
6880 IWineD3DDeviceImpl_SetScissorRect,
6881 IWineD3DDeviceImpl_GetScissorRect,
6882 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6883 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6884 IWineD3DDeviceImpl_SetStreamSource,
6885 IWineD3DDeviceImpl_GetStreamSource,
6886 IWineD3DDeviceImpl_SetStreamSourceFreq,
6887 IWineD3DDeviceImpl_GetStreamSourceFreq,
6888 IWineD3DDeviceImpl_SetTexture,
6889 IWineD3DDeviceImpl_GetTexture,
6890 IWineD3DDeviceImpl_SetTextureStageState,
6891 IWineD3DDeviceImpl_GetTextureStageState,
6892 IWineD3DDeviceImpl_SetTransform,
6893 IWineD3DDeviceImpl_GetTransform,
6894 IWineD3DDeviceImpl_SetVertexDeclaration,
6895 IWineD3DDeviceImpl_GetVertexDeclaration,
6896 IWineD3DDeviceImpl_SetVertexShader,
6897 IWineD3DDeviceImpl_GetVertexShader,
6898 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6899 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6900 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6901 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6902 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6903 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6904 IWineD3DDeviceImpl_SetViewport,
6905 IWineD3DDeviceImpl_GetViewport,
6906 IWineD3DDeviceImpl_MultiplyTransform,
6907 IWineD3DDeviceImpl_ValidateDevice,
6908 IWineD3DDeviceImpl_ProcessVertices,
6909 /*** State block ***/
6910 IWineD3DDeviceImpl_BeginStateBlock,
6911 IWineD3DDeviceImpl_EndStateBlock,
6912 /*** Scene management ***/
6913 IWineD3DDeviceImpl_BeginScene,
6914 IWineD3DDeviceImpl_EndScene,
6915 IWineD3DDeviceImpl_Present,
6916 IWineD3DDeviceImpl_Clear,
6917 IWineD3DDeviceImpl_ClearRendertargetView,
6918 /*** Drawing ***/
6919 IWineD3DDeviceImpl_SetPrimitiveType,
6920 IWineD3DDeviceImpl_GetPrimitiveType,
6921 IWineD3DDeviceImpl_DrawPrimitive,
6922 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6923 IWineD3DDeviceImpl_DrawPrimitiveUP,
6924 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6925 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6926 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6927 IWineD3DDeviceImpl_DrawRectPatch,
6928 IWineD3DDeviceImpl_DrawTriPatch,
6929 IWineD3DDeviceImpl_DeletePatch,
6930 IWineD3DDeviceImpl_ColorFill,
6931 IWineD3DDeviceImpl_UpdateTexture,
6932 IWineD3DDeviceImpl_UpdateSurface,
6933 IWineD3DDeviceImpl_GetFrontBufferData,
6934 /*** object tracking ***/
6935 IWineD3DDeviceImpl_EnumResources
6936 };
6937
6938 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
6939 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
6940 IUnknown *parent, IWineD3DDeviceParent *device_parent)
6941 {
6942 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
6943 const struct fragment_pipeline *fragment_pipeline;
6944 struct shader_caps shader_caps;
6945 struct fragment_caps ffp_caps;
6946 WINED3DDISPLAYMODE mode;
6947 unsigned int i;
6948 HRESULT hr;
6949
6950 device->lpVtbl = &IWineD3DDevice_Vtbl;
6951 device->ref = 1;
6952 device->wined3d = (IWineD3D *)wined3d;
6953 IWineD3D_AddRef(device->wined3d);
6954 device->adapter = wined3d->adapter_count ? adapter : NULL;
6955 device->parent = parent;
6956 device->device_parent = device_parent;
6957 list_init(&device->resources);
6958 list_init(&device->shaders);
6959
6960 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
6961 device->posFixup[0] = 1.0f; /* This is needed to get the x coord unmodified through a MAD. */
6962
6963 /* Get the initial screen setup for ddraw. */
6964 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
6965 if (FAILED(hr))
6966 {
6967 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
6968 IWineD3D_Release(device->wined3d);
6969 return hr;
6970 }
6971 device->ddraw_width = mode.Width;
6972 device->ddraw_height = mode.Height;
6973 device->ddraw_format = mode.Format;
6974
6975 /* Save the creation parameters. */
6976 device->createParms.AdapterOrdinal = adapter_idx;
6977 device->createParms.DeviceType = device_type;
6978 device->createParms.hFocusWindow = focus_window;
6979 device->createParms.BehaviorFlags = flags;
6980
6981 device->devType = device_type;
6982 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
6983
6984 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
6985 device->shader_backend = select_shader_backend(adapter, device_type);
6986
6987 memset(&shader_caps, 0, sizeof(shader_caps));
6988 device->shader_backend->shader_get_caps(device_type, &adapter->gl_info, &shader_caps);
6989 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
6990 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
6991 device->vs_clipping = shader_caps.VSClipping;
6992
6993 memset(&ffp_caps, 0, sizeof(ffp_caps));
6994 fragment_pipeline = select_fragment_implementation(adapter, device_type);
6995 device->frag_pipe = fragment_pipeline;
6996 fragment_pipeline->get_caps(device_type, &adapter->gl_info, &ffp_caps);
6997 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
6998 device->max_ffp_texture_stages = ffp_caps.MaxTextureBlendStages;
6999
7000 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
7001 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
7002 if (FAILED(hr))
7003 {
7004 ERR("Failed to compile state table, hr %#x.\n", hr);
7005 IWineD3D_Release(device->wined3d);
7006 return hr;
7007 }
7008
7009 device->blitter = select_blit_implementation(adapter, device_type);
7010
7011 return WINED3D_OK;
7012 }
7013
7014
7015 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7016 DWORD rep = This->StateTable[state].representative;
7017 struct wined3d_context *context;
7018 DWORD idx;
7019 BYTE shift;
7020 UINT i;
7021
7022 for(i = 0; i < This->numContexts; i++) {
7023 context = This->contexts[i];
7024 if(isStateDirty(context, rep)) continue;
7025
7026 context->dirtyArray[context->numDirtyEntries++] = rep;
7027 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
7028 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
7029 context->isStateDirty[idx] |= (1 << shift);
7030 }
7031 }
7032
7033 void get_drawable_size_pbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7034 {
7035 IWineD3DDeviceImpl *device = ((IWineD3DSurfaceImpl *)context->current_rt)->resource.device;
7036 /* The drawable size of a pbuffer render target is the current pbuffer size. */
7037 *width = device->pbufferWidth;
7038 *height = device->pbufferHeight;
7039 }
7040
7041 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7042 {
7043 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->current_rt;
7044 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7045 *width = surface->pow2Width;
7046 *height = surface->pow2Height;
7047 }
7048
7049 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7050 {
7051 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->surface;
7052 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7053 * current context's drawable, which is the size of the back buffer of the swapchain
7054 * the active context belongs to. The back buffer of the swapchain is stored as the
7055 * surface the context belongs to. */
7056 *width = surface->currentDesc.Width;
7057 *height = surface->currentDesc.Height;
7058 }
7059
7060 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window,
7061 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
7062 {
7063 if (device->filter_messages)
7064 {
7065 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
7066 window, message, wparam, lparam);
7067 return DefWindowProcW(window, message, wparam, lparam);
7068 }
7069
7070 if (message == WM_DESTROY)
7071 {
7072 TRACE("unregister window %p.\n", window);
7073 wined3d_unregister_window(window);
7074
7075 if (device->focus_window == window) device->focus_window = NULL;
7076 else ERR("Window %p is not the focus window for device %p.\n", window, device);
7077 }
7078
7079 return CallWindowProcW(proc, window, message, wparam, lparam);
7080 }