VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/Wine/wined3d/device.c@ 33656

Last change on this file since 33656 was 33656, checked in by vboxsync, 14 years ago

*: rebrand Sun (L)GPL disclaimers

  • Property svn:eol-style set to native
File size: 271.1 KB
Line 
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/*
30 * Oracle LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
31 * other than GPL or LGPL is available it will apply instead, Oracle elects to use only
32 * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
33 * a choice of LGPL license versions is made available with the language indicating
34 * that LGPLv2 or any later version may be used, or where a choice of which version
35 * of the LGPL is applied is otherwise unspecified.
36 */
37
38#include "config.h"
39#include <stdio.h>
40#ifdef HAVE_FLOAT_H
41# include <float.h>
42#endif
43#include "wined3d_private.h"
44
45WINE_DEFAULT_DEBUG_CHANNEL(d3d);
46#define GLINFO_LOCATION This->adapter->gl_info
47
48/* Define the default light parameters as specified by MSDN */
49const WINED3DLIGHT WINED3D_default_light = {
50
51 WINED3DLIGHT_DIRECTIONAL, /* Type */
52 { 1.0f, 1.0f, 1.0f, 0.0f }, /* Diffuse r,g,b,a */
53 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Specular r,g,b,a */
54 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Ambient r,g,b,a, */
55 { 0.0f, 0.0f, 0.0f }, /* Position x,y,z */
56 { 0.0f, 0.0f, 1.0f }, /* Direction x,y,z */
57 0.0f, /* Range */
58 0.0f, /* Falloff */
59 0.0f, 0.0f, 0.0f, /* Attenuation 0,1,2 */
60 0.0f, /* Theta */
61 0.0f /* Phi */
62};
63
64/**********************************************************
65 * Global variable / Constants follow
66 **********************************************************/
67const float identity[] =
68{
69 1.0f, 0.0f, 0.0f, 0.0f,
70 0.0f, 1.0f, 0.0f, 0.0f,
71 0.0f, 0.0f, 1.0f, 0.0f,
72 0.0f, 0.0f, 0.0f, 1.0f,
73}; /* When needed for comparisons */
74
75/* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these
76 * actually have the same values in GL and D3D. */
77static GLenum gl_primitive_type_from_d3d(WINED3DPRIMITIVETYPE primitive_type)
78{
79 switch(primitive_type)
80 {
81 case WINED3DPT_POINTLIST:
82 return GL_POINTS;
83
84 case WINED3DPT_LINELIST:
85 return GL_LINES;
86
87 case WINED3DPT_LINESTRIP:
88 return GL_LINE_STRIP;
89
90 case WINED3DPT_TRIANGLELIST:
91 return GL_TRIANGLES;
92
93 case WINED3DPT_TRIANGLESTRIP:
94 return GL_TRIANGLE_STRIP;
95
96 case WINED3DPT_TRIANGLEFAN:
97 return GL_TRIANGLE_FAN;
98
99 case WINED3DPT_LINELIST_ADJ:
100 return GL_LINES_ADJACENCY_ARB;
101
102 case WINED3DPT_LINESTRIP_ADJ:
103 return GL_LINE_STRIP_ADJACENCY_ARB;
104
105 case WINED3DPT_TRIANGLELIST_ADJ:
106 return GL_TRIANGLES_ADJACENCY_ARB;
107
108 case WINED3DPT_TRIANGLESTRIP_ADJ:
109 return GL_TRIANGLE_STRIP_ADJACENCY_ARB;
110
111 default:
112 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
113 return GL_NONE;
114 }
115}
116
117static WINED3DPRIMITIVETYPE d3d_primitive_type_from_gl(GLenum primitive_type)
118{
119 switch(primitive_type)
120 {
121 case GL_POINTS:
122 return WINED3DPT_POINTLIST;
123
124 case GL_LINES:
125 return WINED3DPT_LINELIST;
126
127 case GL_LINE_STRIP:
128 return WINED3DPT_LINESTRIP;
129
130 case GL_TRIANGLES:
131 return WINED3DPT_TRIANGLELIST;
132
133 case GL_TRIANGLE_STRIP:
134 return WINED3DPT_TRIANGLESTRIP;
135
136 case GL_TRIANGLE_FAN:
137 return WINED3DPT_TRIANGLEFAN;
138
139 case GL_LINES_ADJACENCY_ARB:
140 return WINED3DPT_LINELIST_ADJ;
141
142 case GL_LINE_STRIP_ADJACENCY_ARB:
143 return WINED3DPT_LINESTRIP_ADJ;
144
145 case GL_TRIANGLES_ADJACENCY_ARB:
146 return WINED3DPT_TRIANGLELIST_ADJ;
147
148 case GL_TRIANGLE_STRIP_ADJACENCY_ARB:
149 return WINED3DPT_TRIANGLESTRIP_ADJ;
150
151 default:
152 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
153 return WINED3DPT_UNDEFINED;
154 }
155}
156
157static BOOL fixed_get_input(BYTE usage, BYTE usage_idx, unsigned int *regnum)
158{
159 if ((usage == WINED3DDECLUSAGE_POSITION || usage == WINED3DDECLUSAGE_POSITIONT) && usage_idx == 0)
160 *regnum = WINED3D_FFP_POSITION;
161 else if (usage == WINED3DDECLUSAGE_BLENDWEIGHT && usage_idx == 0)
162 *regnum = WINED3D_FFP_BLENDWEIGHT;
163 else if (usage == WINED3DDECLUSAGE_BLENDINDICES && usage_idx == 0)
164 *regnum = WINED3D_FFP_BLENDINDICES;
165 else if (usage == WINED3DDECLUSAGE_NORMAL && usage_idx == 0)
166 *regnum = WINED3D_FFP_NORMAL;
167 else if (usage == WINED3DDECLUSAGE_PSIZE && usage_idx == 0)
168 *regnum = WINED3D_FFP_PSIZE;
169 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 0)
170 *regnum = WINED3D_FFP_DIFFUSE;
171 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 1)
172 *regnum = WINED3D_FFP_SPECULAR;
173 else if (usage == WINED3DDECLUSAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
174 *regnum = WINED3D_FFP_TEXCOORD0 + usage_idx;
175 else
176 {
177 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage), usage_idx);
178 *regnum = ~0U;
179 return FALSE;
180 }
181
182 return TRUE;
183}
184
185/* Context activation is done by the caller. */
186void device_stream_info_from_declaration(IWineD3DDeviceImpl *This,
187 BOOL use_vshader, struct wined3d_stream_info *stream_info, BOOL *fixup)
188{
189 /* We need to deal with frequency data! */
190 IWineD3DVertexDeclarationImpl *declaration = (IWineD3DVertexDeclarationImpl *)This->stateBlock->vertexDecl;
191 unsigned int i;
192
193 stream_info->use_map = 0;
194 stream_info->swizzle_map = 0;
195
196 /* Check for transformed vertices, disable vertex shader if present. */
197 stream_info->position_transformed = declaration->position_transformed;
198 if (declaration->position_transformed) use_vshader = FALSE;
199
200 /* Translate the declaration into strided data. */
201 for (i = 0; i < declaration->element_count; ++i)
202 {
203 const struct wined3d_vertex_declaration_element *element = &declaration->elements[i];
204 GLuint buffer_object = 0;
205 const BYTE *data = NULL;
206 BOOL stride_used;
207 unsigned int idx;
208 DWORD stride;
209
210 TRACE("%p Element %p (%u of %u)\n", declaration->elements,
211 element, i + 1, declaration->element_count);
212
213 if (!This->stateBlock->streamSource[element->input_slot]) continue;
214
215 stride = This->stateBlock->streamStride[element->input_slot];
216 if (This->stateBlock->streamIsUP)
217 {
218 TRACE("Stream %u is UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
219 buffer_object = 0;
220 data = (BYTE *)This->stateBlock->streamSource[element->input_slot];
221 }
222 else
223 {
224 TRACE("Stream %u isn't UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
225 data = buffer_get_memory(This->stateBlock->streamSource[element->input_slot], &buffer_object);
226
227 /* Can't use vbo's if the base vertex index is negative. OpenGL doesn't accept negative offsets
228 * (or rather offsets bigger than the vbo, because the pointer is unsigned), so use system memory
229 * sources. In most sane cases the pointer - offset will still be > 0, otherwise it will wrap
230 * around to some big value. Hope that with the indices, the driver wraps it back internally. If
231 * not, drawStridedSlow is needed, including a vertex buffer path. */
232 if (This->stateBlock->loadBaseVertexIndex < 0)
233 {
234 WARN("loadBaseVertexIndex is < 0 (%d), not using vbos\n", This->stateBlock->loadBaseVertexIndex);
235 buffer_object = 0;
236 data = buffer_get_sysmem((struct wined3d_buffer *)This->stateBlock->streamSource[element->input_slot]);
237 if ((UINT_PTR)data < -This->stateBlock->loadBaseVertexIndex * stride)
238 {
239 FIXME("System memory vertex data load offset is negative!\n");
240 }
241 }
242
243 if (fixup)
244 {
245 if (buffer_object) *fixup = TRUE;
246 else if (*fixup && !use_vshader
247 && (element->usage == WINED3DDECLUSAGE_COLOR
248 || element->usage == WINED3DDECLUSAGE_POSITIONT))
249 {
250 static BOOL warned = FALSE;
251 if (!warned)
252 {
253 /* This may be bad with the fixed function pipeline. */
254 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
255 warned = TRUE;
256 }
257 }
258 }
259 }
260 data += element->offset;
261
262 TRACE("offset %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx);
263
264 if (use_vshader)
265 {
266 if (element->output_slot == ~0U)
267 {
268 /* TODO: Assuming vertexdeclarations are usually used with the
269 * same or a similar shader, it might be worth it to store the
270 * last used output slot and try that one first. */
271 stride_used = vshader_get_input(This->stateBlock->vertexShader,
272 element->usage, element->usage_idx, &idx);
273 }
274 else
275 {
276 idx = element->output_slot;
277 stride_used = TRUE;
278 }
279 }
280 else
281 {
282 if (!element->ffp_valid)
283 {
284 WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
285 debug_d3dformat(element->format_desc->format), debug_d3ddeclusage(element->usage));
286 stride_used = FALSE;
287 }
288 else
289 {
290 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
291 }
292 }
293
294 if (stride_used)
295 {
296 TRACE("Load %s array %u [usage %s, usage_idx %u, "
297 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
298 use_vshader ? "shader": "fixed function", idx,
299 debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot,
300 element->offset, stride, debug_d3dformat(element->format_desc->format), buffer_object);
301
302 stream_info->elements[idx].format_desc = element->format_desc;
303 stream_info->elements[idx].stride = stride;
304 stream_info->elements[idx].data = data;
305 stream_info->elements[idx].stream_idx = element->input_slot;
306 stream_info->elements[idx].buffer_object = buffer_object;
307
308 if (!This->adapter->gl_info.supported[ARB_VERTEX_ARRAY_BGRA]
309 && element->format_desc->format == WINED3DFMT_B8G8R8A8_UNORM)
310 {
311 stream_info->swizzle_map |= 1 << idx;
312 }
313 stream_info->use_map |= 1 << idx;
314 }
315 }
316
317 This->num_buffer_queries = 0;
318 if (!This->stateBlock->streamIsUP)
319 {
320 WORD map = stream_info->use_map;
321
322 /* PreLoad all the vertex buffers. */
323 for (i = 0; map; map >>= 1, ++i)
324 {
325 struct wined3d_stream_info_element *element;
326 struct wined3d_buffer *buffer;
327 struct wined3d_event_query *query;
328
329 if (!(map & 1)) continue;
330
331 element = &stream_info->elements[i];
332 buffer = (struct wined3d_buffer *)This->stateBlock->streamSource[element->stream_idx];
333 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)buffer);
334
335 /* If PreLoad dropped the buffer object, update the stream info. */
336 if (buffer->buffer_object != element->buffer_object)
337 {
338 element->buffer_object = 0;
339 element->data = buffer_get_sysmem(buffer) + (ptrdiff_t)element->data;
340 }
341
342 query = ((struct wined3d_buffer *) buffer)->query;
343 if(query)
344 {
345 This->buffer_queries[This->num_buffer_queries++] = query;
346 }
347 }
348 }
349}
350
351static void stream_info_element_from_strided(const struct wined3d_gl_info *gl_info,
352 const struct WineDirect3DStridedData *strided, struct wined3d_stream_info_element *e)
353{
354 const struct wined3d_format_desc *format_desc = getFormatDescEntry(strided->format, gl_info);
355 e->format_desc = format_desc;
356 e->stride = strided->dwStride;
357 e->data = strided->lpData;
358 e->stream_idx = 0;
359 e->buffer_object = 0;
360}
361
362static void device_stream_info_from_strided(const struct wined3d_gl_info *gl_info,
363 const struct WineDirect3DVertexStridedData *strided, struct wined3d_stream_info *stream_info)
364{
365 unsigned int i;
366
367 memset(stream_info, 0, sizeof(*stream_info));
368
369 if (strided->position.lpData)
370 stream_info_element_from_strided(gl_info, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
371 if (strided->normal.lpData)
372 stream_info_element_from_strided(gl_info, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
373 if (strided->diffuse.lpData)
374 stream_info_element_from_strided(gl_info, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
375 if (strided->specular.lpData)
376 stream_info_element_from_strided(gl_info, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);
377
378 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
379 {
380 if (strided->texCoords[i].lpData)
381 stream_info_element_from_strided(gl_info, &strided->texCoords[i],
382 &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
383 }
384
385 stream_info->position_transformed = strided->position_transformed;
386
387 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
388 {
389 if (!stream_info->elements[i].format_desc) continue;
390
391 if (!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
392 && stream_info->elements[i].format_desc->format == WINED3DFMT_B8G8R8A8_UNORM)
393 {
394 stream_info->swizzle_map |= 1 << i;
395 }
396 stream_info->use_map |= 1 << i;
397 }
398}
399
400static void device_trace_strided_stream_info(const struct wined3d_stream_info *stream_info)
401{
402 TRACE("Strided Data:\n");
403 TRACE_STRIDED(stream_info, WINED3D_FFP_POSITION);
404 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDWEIGHT);
405 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDINDICES);
406 TRACE_STRIDED(stream_info, WINED3D_FFP_NORMAL);
407 TRACE_STRIDED(stream_info, WINED3D_FFP_PSIZE);
408 TRACE_STRIDED(stream_info, WINED3D_FFP_DIFFUSE);
409 TRACE_STRIDED(stream_info, WINED3D_FFP_SPECULAR);
410 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD0);
411 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD1);
412 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD2);
413 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD3);
414 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD4);
415 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD5);
416 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD6);
417 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD7);
418}
419
420/* Context activation is done by the caller. */
421void device_update_stream_info(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
422{
423 struct wined3d_stream_info *stream_info = &device->strided_streams;
424 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
425 BOOL vs = stateblock->vertexShader && device->vs_selected_mode != SHADER_NONE;
426 BOOL fixup = FALSE;
427
428 if (device->up_strided)
429 {
430 /* Note: this is a ddraw fixed-function code path. */
431 TRACE("=============================== Strided Input ================================\n");
432 device_stream_info_from_strided(gl_info, device->up_strided, stream_info);
433 if (TRACE_ON(d3d)) device_trace_strided_stream_info(stream_info);
434 }
435 else
436 {
437 TRACE("============================= Vertex Declaration =============================\n");
438 device_stream_info_from_declaration(device, vs, stream_info, &fixup);
439 }
440
441 if (vs && !stream_info->position_transformed)
442 {
443 if (((IWineD3DVertexDeclarationImpl *)stateblock->vertexDecl)->half_float_conv_needed && !fixup)
444 {
445 TRACE("Using drawStridedSlow with vertex shaders for FLOAT16 conversion.\n");
446 device->useDrawStridedSlow = TRUE;
447 }
448 else
449 {
450 device->useDrawStridedSlow = FALSE;
451 }
452 }
453 else
454 {
455 WORD slow_mask = (1 << WINED3D_FFP_PSIZE);
456 slow_mask |= -!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
457 & ((1 << WINED3D_FFP_DIFFUSE) | (1 << WINED3D_FFP_SPECULAR));
458
459 if ((stream_info->position_transformed || (stream_info->use_map & slow_mask)) && !fixup)
460 {
461 device->useDrawStridedSlow = TRUE;
462 }
463 else
464 {
465 device->useDrawStridedSlow = FALSE;
466 }
467 }
468}
469
470static void device_preload_texture(IWineD3DStateBlockImpl *stateblock, unsigned int idx)
471{
472 IWineD3DBaseTextureImpl *texture;
473 enum WINED3DSRGB srgb;
474
475 if (!(texture = (IWineD3DBaseTextureImpl *)stateblock->textures[idx])) return;
476 srgb = stateblock->samplerState[idx][WINED3DSAMP_SRGBTEXTURE] ? SRGB_SRGB : SRGB_RGB;
477 texture->baseTexture.internal_preload((IWineD3DBaseTexture *)texture, srgb);
478}
479
480void device_preload_textures(IWineD3DDeviceImpl *device)
481{
482 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
483 unsigned int i;
484
485 if (use_vs(stateblock))
486 {
487 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i)
488 {
489 if (((IWineD3DBaseShaderImpl *)stateblock->vertexShader)->baseShader.reg_maps.sampler_type[i])
490 device_preload_texture(stateblock, MAX_FRAGMENT_SAMPLERS + i);
491 }
492 }
493
494 if (use_ps(stateblock))
495 {
496 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i)
497 {
498 if (((IWineD3DBaseShaderImpl *)stateblock->pixelShader)->baseShader.reg_maps.sampler_type[i])
499 device_preload_texture(stateblock, i);
500 }
501 }
502 else
503 {
504 WORD ffu_map = device->fixed_function_usage_map;
505
506 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
507 {
508 if (ffu_map & 1)
509 device_preload_texture(stateblock, i);
510 }
511 }
512}
513
514BOOL device_context_add(IWineD3DDeviceImpl *device, struct wined3d_context *context)
515{
516 struct wined3d_context **new_array;
517
518 TRACE("Adding context %p.\n", context);
519
520 if (!device->contexts) new_array = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_array));
521 else new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, sizeof(*new_array) * (device->numContexts + 1));
522
523 if (!new_array)
524 {
525 ERR("Failed to grow the context array.\n");
526 return FALSE;
527 }
528
529 new_array[device->numContexts++] = context;
530 device->contexts = new_array;
531 return TRUE;
532}
533
534void device_context_remove(IWineD3DDeviceImpl *device, struct wined3d_context *context)
535{
536 struct wined3d_context **new_array;
537 BOOL found = FALSE;
538 UINT i;
539
540 TRACE("Removing context %p.\n", context);
541
542 for (i = 0; i < device->numContexts; ++i)
543 {
544 if (device->contexts[i] == context)
545 {
546 found = TRUE;
547 break;
548 }
549 }
550
551 if (!found)
552 {
553 ERR("Context %p doesn't exist in context array.\n", context);
554 return;
555 }
556
557 if (!--device->numContexts)
558 {
559 HeapFree(GetProcessHeap(), 0, device->contexts);
560 device->contexts = NULL;
561 return;
562 }
563
564 memmove(&device->contexts[i], &device->contexts[i + 1], (device->numContexts - i) * sizeof(*device->contexts));
565 new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, device->numContexts * sizeof(*device->contexts));
566 if (!new_array)
567 {
568 ERR("Failed to shrink context array. Oh well.\n");
569 return;
570 }
571
572 device->contexts = new_array;
573}
574
575
576/**********************************************************
577 * IUnknown parts follows
578 **********************************************************/
579
580static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
581{
582 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
583
584 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
585 if (IsEqualGUID(riid, &IID_IUnknown)
586 || IsEqualGUID(riid, &IID_IWineD3DBase)
587 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
588 IUnknown_AddRef(iface);
589 *ppobj = This;
590 return S_OK;
591 }
592 *ppobj = NULL;
593 return E_NOINTERFACE;
594}
595
596static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
597 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
598 ULONG refCount = InterlockedIncrement(&This->ref);
599
600 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
601 return refCount;
602}
603
604static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
605 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
606 ULONG refCount = InterlockedDecrement(&This->ref);
607
608 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
609
610 if (!refCount) {
611 UINT i;
612
613 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
614 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
615 This->multistate_funcs[i] = NULL;
616 }
617
618 /* TODO: Clean up all the surfaces and textures! */
619 /* NOTE: You must release the parent if the object was created via a callback
620 ** ***************************/
621
622 if (!list_empty(&This->resources))
623 {
624 IWineD3DResourceImpl *resource;
625 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
626
627 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
628 {
629 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
630 FIXME("Leftover resource %p with type %s (%#x).\n",
631 resource, debug_d3dresourcetype(type), type);
632 }
633 }
634
635 if(This->contexts) ERR("Context array not freed!\n");
636 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
637 This->haveHardwareCursor = FALSE;
638
639 IWineD3D_Release(This->wined3d);
640 This->wined3d = NULL;
641 HeapFree(GetProcessHeap(), 0, This);
642 TRACE("Freed device %p\n", This);
643 This = NULL;
644 }
645 return refCount;
646}
647
648/**********************************************************
649 * IWineD3DDevice implementation follows
650 **********************************************************/
651static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
652 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
653 *pParent = This->parent;
654 IUnknown_AddRef(This->parent);
655 return WINED3D_OK;
656}
657
658static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
659 const void *data, IUnknown *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **buffer)
660{
661 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
662 struct wined3d_buffer *object;
663 HRESULT hr;
664
665 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
666
667 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
668 if (!object)
669 {
670 ERR("Failed to allocate memory\n");
671 return E_OUTOFMEMORY;
672 }
673
674 FIXME("Ignoring access flags (pool)\n");
675
676 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
677 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
678 if (FAILED(hr))
679 {
680 WARN("Failed to initialize buffer, hr %#x.\n", hr);
681 HeapFree(GetProcessHeap(), 0, object);
682 return hr;
683 }
684 object->desc = *desc;
685
686 TRACE("Created buffer %p.\n", object);
687
688 *buffer = (IWineD3DBuffer *)object;
689
690 return WINED3D_OK;
691}
692
693static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface,
694 UINT Size, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppVertexBuffer,
695 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
696{
697 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
698 struct wined3d_buffer *object;
699 HRESULT hr;
700
701 TRACE("iface %p, size %u, usage %#x, pool %#x, buffer %p, parent %p, parent_ops %p.\n",
702 iface, Size, Usage, Pool, ppVertexBuffer, parent, parent_ops);
703
704 if (Pool == WINED3DPOOL_SCRATCH)
705 {
706 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
707 * anyway, SCRATCH vertex buffers aren't usable anywhere
708 */
709 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
710 *ppVertexBuffer = NULL;
711 return WINED3DERR_INVALIDCALL;
712 }
713
714 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
715 if (!object)
716 {
717 ERR("Out of memory\n");
718 *ppVertexBuffer = NULL;
719 return WINED3DERR_OUTOFVIDEOMEMORY;
720 }
721
722 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
723 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
724 if (FAILED(hr))
725 {
726 WARN("Failed to initialize buffer, hr %#x.\n", hr);
727 HeapFree(GetProcessHeap(), 0, object);
728 return hr;
729 }
730
731 TRACE("Created buffer %p.\n", object);
732 *ppVertexBuffer = (IWineD3DBuffer *)object;
733
734 return WINED3D_OK;
735}
736
737static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
738 UINT Length, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppIndexBuffer,
739 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
740{
741 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
742 struct wined3d_buffer *object;
743 HRESULT hr;
744
745 TRACE("(%p) Creating index buffer\n", This);
746
747 /* Allocate the storage for the device */
748 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
749 if (!object)
750 {
751 ERR("Out of memory\n");
752 *ppIndexBuffer = NULL;
753 return WINED3DERR_OUTOFVIDEOMEMORY;
754 }
755
756 hr = buffer_init(object, This, Length, Usage | WINED3DUSAGE_STATICDECL,
757 WINED3DFMT_UNKNOWN, Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL,
758 parent, parent_ops);
759 if (FAILED(hr))
760 {
761 WARN("Failed to initialize buffer, hr %#x\n", hr);
762 HeapFree(GetProcessHeap(), 0, object);
763 return hr;
764 }
765
766 TRACE("Created buffer %p.\n", object);
767
768 *ppIndexBuffer = (IWineD3DBuffer *) object;
769
770 return WINED3D_OK;
771}
772
773static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
774 WINED3DSTATEBLOCKTYPE type, IWineD3DStateBlock **stateblock, IUnknown *parent)
775{
776 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
777 IWineD3DStateBlockImpl *object;
778 HRESULT hr;
779
780 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
781 if(!object)
782 {
783 ERR("Failed to allocate stateblock memory.\n");
784 return E_OUTOFMEMORY;
785 }
786
787 hr = stateblock_init(object, This, type);
788 if (FAILED(hr))
789 {
790 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
791 HeapFree(GetProcessHeap(), 0, object);
792 return hr;
793 }
794
795 TRACE("Created stateblock %p.\n", object);
796 *stateblock = (IWineD3DStateBlock *)object;
797
798 return WINED3D_OK;
799}
800
801static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
802 WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,
803 DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality,
804 WINED3DSURFTYPE Impl, IUnknown *parent, const struct wined3d_parent_ops *parent_ops
805#ifdef VBOX_WITH_WDDM
806 , HANDLE *shared_handle
807 , void *pvClientMem
808#endif
809 )
810{
811 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
812 IWineD3DSurfaceImpl *object;
813 HRESULT hr;
814
815 TRACE("iface %p, width %u, height %u, format %s (%#x), lockable %#x, discard %#x, level %u\n",
816 iface, Width, Height, debug_d3dformat(Format), Format, Lockable, Discard, Level);
817 TRACE("surface %p, usage %s (%#x), pool %s (%#x), multisample_type %#x, multisample_quality %u\n",
818 ppSurface, debug_d3dusage(Usage), Usage, debug_d3dpool(Pool), Pool, MultiSample, MultisampleQuality);
819 TRACE("surface_type %#x, parent %p, parent_ops %p.\n", Impl, parent, parent_ops);
820
821 if (Impl == SURFACE_OPENGL && !This->adapter)
822 {
823 ERR("OpenGL surfaces are not available without OpenGL.\n");
824 return WINED3DERR_NOTAVAILABLE;
825 }
826
827 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
828 if (!object)
829 {
830 ERR("Failed to allocate surface memory.\n");
831 return WINED3DERR_OUTOFVIDEOMEMORY;
832 }
833
834 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
835 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops
836#ifdef VBOX_WITH_WDDM
837 , shared_handle
838 , pvClientMem
839#endif
840 );
841 if (FAILED(hr))
842 {
843 WARN("Failed to initialize surface, returning %#x.\n", hr);
844 HeapFree(GetProcessHeap(), 0, object);
845 return hr;
846 }
847
848 TRACE("(%p) : Created surface %p\n", This, object);
849
850 *ppSurface = (IWineD3DSurface *)object;
851
852 return hr;
853}
854
855static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
856 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
857{
858 struct wined3d_rendertarget_view *object;
859
860 TRACE("iface %p, resource %p, parent %p, rendertarget_view %p.\n",
861 iface, resource, parent, rendertarget_view);
862
863 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
864 if (!object)
865 {
866 ERR("Failed to allocate memory\n");
867 return E_OUTOFMEMORY;
868 }
869
870 wined3d_rendertarget_view_init(object, resource, parent);
871
872 TRACE("Created render target view %p.\n", object);
873 *rendertarget_view = (IWineD3DRendertargetView *)object;
874
875 return WINED3D_OK;
876}
877
878static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
879 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
880 IWineD3DTexture **ppTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops
881#ifdef VBOX_WITH_WDDM
882 , HANDLE *shared_handle
883 , void *pvClientMem
884#endif
885 )
886{
887 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
888 IWineD3DTextureImpl *object;
889 HRESULT hr;
890
891 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
892 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
893 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
894
895 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
896 if (!object)
897 {
898 ERR("Out of memory\n");
899 *ppTexture = NULL;
900 return WINED3DERR_OUTOFVIDEOMEMORY;
901 }
902
903 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops
904#ifdef VBOX_WITH_WDDM
905 , shared_handle
906 , pvClientMem
907#endif
908 );
909 if (FAILED(hr))
910 {
911 WARN("Failed to initialize texture, returning %#x\n", hr);
912 HeapFree(GetProcessHeap(), 0, object);
913 *ppTexture = NULL;
914 return hr;
915 }
916
917 *ppTexture = (IWineD3DTexture *)object;
918
919 TRACE("(%p) : Created texture %p\n", This, object);
920
921 return WINED3D_OK;
922}
923
924static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
925 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
926 IWineD3DVolumeTexture **ppVolumeTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
927{
928 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
929 IWineD3DVolumeTextureImpl *object;
930 HRESULT hr;
931
932 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
933 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
934
935 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
936 if (!object)
937 {
938 ERR("Out of memory\n");
939 *ppVolumeTexture = NULL;
940 return WINED3DERR_OUTOFVIDEOMEMORY;
941 }
942
943 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
944 if (FAILED(hr))
945 {
946 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
947 HeapFree(GetProcessHeap(), 0, object);
948 *ppVolumeTexture = NULL;
949 return hr;
950 }
951
952 TRACE("(%p) : Created volume texture %p.\n", This, object);
953 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
954
955 return WINED3D_OK;
956}
957
958static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
959 UINT Depth, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DVolume **ppVolume,
960 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
961{
962 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
963 IWineD3DVolumeImpl *object;
964 HRESULT hr;
965
966 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
967 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
968
969 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
970 if (!object)
971 {
972 ERR("Out of memory\n");
973 *ppVolume = NULL;
974 return WINED3DERR_OUTOFVIDEOMEMORY;
975 }
976
977 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
978 if (FAILED(hr))
979 {
980 WARN("Failed to initialize volume, returning %#x.\n", hr);
981 HeapFree(GetProcessHeap(), 0, object);
982 return hr;
983 }
984
985 TRACE("(%p) : Created volume %p.\n", This, object);
986 *ppVolume = (IWineD3DVolume *)object;
987
988 return WINED3D_OK;
989}
990
991static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
992 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture,
993 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
994{
995 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
996 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
997 HRESULT hr;
998
999 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1000 if (!object)
1001 {
1002 ERR("Out of memory\n");
1003 *ppCubeTexture = NULL;
1004 return WINED3DERR_OUTOFVIDEOMEMORY;
1005 }
1006
1007 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
1008 if (FAILED(hr))
1009 {
1010 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
1011 HeapFree(GetProcessHeap(), 0, object);
1012 *ppCubeTexture = NULL;
1013 return hr;
1014 }
1015
1016 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1017 *ppCubeTexture = (IWineD3DCubeTexture *)object;
1018
1019 return WINED3D_OK;
1020}
1021
1022static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface,
1023 WINED3DQUERYTYPE type, IWineD3DQuery **query, IUnknown *parent)
1024{
1025 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1026 IWineD3DQueryImpl *object;
1027 HRESULT hr;
1028
1029 TRACE("iface %p, type %#x, query %p, parent %p.\n", iface, type, query, parent);
1030
1031 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1032 if (!object)
1033 {
1034 ERR("Failed to allocate query memory.\n");
1035 return E_OUTOFMEMORY;
1036 }
1037
1038 hr = query_init(object, This, type, parent);
1039 if (FAILED(hr))
1040 {
1041 WARN("Failed to initialize query, hr %#x.\n", hr);
1042 HeapFree(GetProcessHeap(), 0, object);
1043 return hr;
1044 }
1045
1046 TRACE("Created query %p.\n", object);
1047 *query = (IWineD3DQuery *)object;
1048
1049 return WINED3D_OK;
1050}
1051
1052static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1053 WINED3DPRESENT_PARAMETERS *present_parameters, IWineD3DSwapChain **swapchain,
1054 IUnknown *parent, WINED3DSURFTYPE surface_type)
1055{
1056 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1057 IWineD3DSwapChainImpl *object;
1058 HRESULT hr;
1059
1060 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
1061 iface, present_parameters, swapchain, parent, surface_type);
1062
1063 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1064 if (!object)
1065 {
1066 ERR("Failed to allocate swapchain memory.\n");
1067 return E_OUTOFMEMORY;
1068 }
1069
1070 hr = swapchain_init(object, surface_type, This, present_parameters, parent);
1071 if (FAILED(hr))
1072 {
1073 WARN("Failed to initialize swapchain, hr %#x.\n", hr);
1074 HeapFree(GetProcessHeap(), 0, object);
1075 return hr;
1076 }
1077
1078 TRACE("Created swapchain %p.\n", object);
1079 *swapchain = (IWineD3DSwapChain *)object;
1080
1081 return WINED3D_OK;
1082}
1083
1084/** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1085static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1086 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1087 TRACE("(%p)\n", This);
1088
1089 return This->NumberOfSwapChains;
1090}
1091
1092static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1093 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1094 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1095
1096 if(iSwapChain < This->NumberOfSwapChains) {
1097 *pSwapChain = This->swapchains[iSwapChain];
1098 IWineD3DSwapChain_AddRef(*pSwapChain);
1099 TRACE("(%p) returning %p\n", This, *pSwapChain);
1100 return WINED3D_OK;
1101 } else {
1102 TRACE("Swapchain out of range\n");
1103 *pSwapChain = NULL;
1104 return WINED3DERR_INVALIDCALL;
1105 }
1106}
1107
1108static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
1109 IWineD3DVertexDeclaration **declaration, IUnknown *parent, const struct wined3d_parent_ops *parent_ops,
1110 const WINED3DVERTEXELEMENT *elements, UINT element_count)
1111{
1112 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1113 IWineD3DVertexDeclarationImpl *object = NULL;
1114 HRESULT hr;
1115
1116 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
1117 iface, declaration, parent, elements, element_count);
1118
1119 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1120 if(!object)
1121 {
1122 ERR("Failed to allocate vertex declaration memory.\n");
1123 return E_OUTOFMEMORY;
1124 }
1125
1126 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1127 if (FAILED(hr))
1128 {
1129 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1130 HeapFree(GetProcessHeap(), 0, object);
1131 return hr;
1132 }
1133
1134 TRACE("Created vertex declaration %p.\n", object);
1135 *declaration = (IWineD3DVertexDeclaration *)object;
1136
1137 return WINED3D_OK;
1138}
1139
1140struct wined3d_fvf_convert_state
1141{
1142 const struct wined3d_gl_info *gl_info;
1143 WINED3DVERTEXELEMENT *elements;
1144 UINT offset;
1145 UINT idx;
1146};
1147
1148static void append_decl_element(struct wined3d_fvf_convert_state *state,
1149 WINED3DFORMAT format, WINED3DDECLUSAGE usage, UINT usage_idx)
1150{
1151 WINED3DVERTEXELEMENT *elements = state->elements;
1152 const struct wined3d_format_desc *format_desc;
1153 UINT offset = state->offset;
1154 UINT idx = state->idx;
1155
1156 elements[idx].format = format;
1157 elements[idx].input_slot = 0;
1158 elements[idx].offset = offset;
1159 elements[idx].output_slot = 0;
1160 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1161 elements[idx].usage = usage;
1162 elements[idx].usage_idx = usage_idx;
1163
1164 format_desc = getFormatDescEntry(format, state->gl_info);
1165 state->offset += format_desc->component_count * format_desc->component_size;
1166 ++state->idx;
1167}
1168
1169static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1170 DWORD fvf, WINED3DVERTEXELEMENT **ppVertexElements)
1171{
1172 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1173 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1174 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1175 BOOL has_blend_idx = has_blend &&
1176 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1177 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1178 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1179 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1180 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1181 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1182 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1183
1184 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1185 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1186 struct wined3d_fvf_convert_state state;
1187 unsigned int size;
1188 unsigned int idx;
1189 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1190 if (has_blend_idx) num_blends--;
1191
1192 /* Compute declaration size */
1193 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1194 has_psize + has_diffuse + has_specular + num_textures;
1195
1196 state.gl_info = gl_info;
1197 state.elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*state.elements));
1198 if (!state.elements) return ~0U;
1199 state.offset = 0;
1200 state.idx = 0;
1201
1202 if (has_pos)
1203 {
1204 if (!has_blend && (fvf & WINED3DFVF_XYZRHW))
1205 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITIONT, 0);
1206 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW)
1207 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1208 else
1209 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1210 }
1211
1212 if (has_blend && (num_blends > 0))
1213 {
1214 if ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1215 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1216 else
1217 {
1218 switch (num_blends)
1219 {
1220 case 1:
1221 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1222 break;
1223 case 2:
1224 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1225 break;
1226 case 3:
1227 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1228 break;
1229 case 4:
1230 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1231 break;
1232 default:
1233 ERR("Unexpected amount of blend values: %u\n", num_blends);
1234 }
1235 }
1236 }
1237
1238 if (has_blend_idx)
1239 {
1240 if ((fvf & WINED3DFVF_LASTBETA_UBYTE4)
1241 || ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1242 append_decl_element(&state, WINED3DFMT_R8G8B8A8_UINT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1243 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1244 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDINDICES, 0);
1245 else
1246 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1247 }
1248
1249 if (has_normal) append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_NORMAL, 0);
1250 if (has_psize) append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_PSIZE, 0);
1251 if (has_diffuse) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 0);
1252 if (has_specular) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 1);
1253
1254 for (idx = 0; idx < num_textures; ++idx)
1255 {
1256 switch ((texcoords >> (idx * 2)) & 0x03)
1257 {
1258 case WINED3DFVF_TEXTUREFORMAT1:
1259 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1260 break;
1261 case WINED3DFVF_TEXTUREFORMAT2:
1262 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1263 break;
1264 case WINED3DFVF_TEXTUREFORMAT3:
1265 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1266 break;
1267 case WINED3DFVF_TEXTUREFORMAT4:
1268 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1269 break;
1270 }
1271 }
1272
1273 *ppVertexElements = state.elements;
1274 return size;
1275}
1276
1277static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1278 IWineD3DVertexDeclaration **declaration, IUnknown *parent,
1279 const struct wined3d_parent_ops *parent_ops, DWORD fvf)
1280{
1281 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1282 WINED3DVERTEXELEMENT *elements;
1283 unsigned int size;
1284 DWORD hr;
1285
1286 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1287
1288 size = ConvertFvfToDeclaration(This, fvf, &elements);
1289 if (size == ~0U) return E_OUTOFMEMORY;
1290
1291 hr = IWineD3DDevice_CreateVertexDeclaration(iface, declaration, parent, parent_ops, elements, size);
1292 HeapFree(GetProcessHeap(), 0, elements);
1293 return hr;
1294}
1295
1296static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1297 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1298 IWineD3DVertexShader **ppVertexShader, IUnknown *parent,
1299 const struct wined3d_parent_ops *parent_ops)
1300{
1301 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1302 IWineD3DVertexShaderImpl *object;
1303 HRESULT hr;
1304
1305 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1306 if (!object)
1307 {
1308 ERR("Failed to allocate shader memory.\n");
1309 return E_OUTOFMEMORY;
1310 }
1311
1312 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1313 if (FAILED(hr))
1314 {
1315 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1316 HeapFree(GetProcessHeap(), 0, object);
1317 return hr;
1318 }
1319
1320 TRACE("Created vertex shader %p.\n", object);
1321 *ppVertexShader = (IWineD3DVertexShader *)object;
1322
1323 return WINED3D_OK;
1324}
1325
1326static HRESULT WINAPI IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice *iface,
1327 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
1328 IWineD3DGeometryShader **shader, IUnknown *parent,
1329 const struct wined3d_parent_ops *parent_ops)
1330{
1331 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1332 struct wined3d_geometryshader *object;
1333 HRESULT hr;
1334
1335 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1336 if (!object)
1337 {
1338 ERR("Failed to allocate shader memory.\n");
1339 return E_OUTOFMEMORY;
1340 }
1341
1342 hr = geometryshader_init(object, This, byte_code, output_signature, parent, parent_ops);
1343 if (FAILED(hr))
1344 {
1345 WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
1346 HeapFree(GetProcessHeap(), 0, object);
1347 return hr;
1348 }
1349
1350 TRACE("Created geometry shader %p.\n", object);
1351 *shader = (IWineD3DGeometryShader *)object;
1352
1353 return WINED3D_OK;
1354}
1355
1356static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1357 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1358 IWineD3DPixelShader **ppPixelShader, IUnknown *parent,
1359 const struct wined3d_parent_ops *parent_ops)
1360{
1361 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1362 IWineD3DPixelShaderImpl *object;
1363 HRESULT hr;
1364
1365 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1366 if (!object)
1367 {
1368 ERR("Failed to allocate shader memory.\n");
1369 return E_OUTOFMEMORY;
1370 }
1371
1372 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1373 if (FAILED(hr))
1374 {
1375 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1376 HeapFree(GetProcessHeap(), 0, object);
1377 return hr;
1378 }
1379
1380 TRACE("Created pixel shader %p.\n", object);
1381 *ppPixelShader = (IWineD3DPixelShader *)object;
1382
1383 return WINED3D_OK;
1384}
1385
1386static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1387 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1388{
1389 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1390 IWineD3DPaletteImpl *object;
1391 HRESULT hr;
1392
1393 TRACE("iface %p, flags %#x, entries %p, palette %p, parent %p.\n",
1394 iface, Flags, PalEnt, Palette, Parent);
1395
1396 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1397 if (!object)
1398 {
1399 ERR("Failed to allocate palette memory.\n");
1400 return E_OUTOFMEMORY;
1401 }
1402
1403 hr = wined3d_palette_init(object, This, Flags, PalEnt, Parent);
1404 if (FAILED(hr))
1405 {
1406 WARN("Failed to initialize palette, hr %#x.\n", hr);
1407 HeapFree(GetProcessHeap(), 0, object);
1408 return hr;
1409 }
1410
1411 TRACE("Created palette %p.\n", object);
1412 *Palette = (IWineD3DPalette *)object;
1413
1414 return WINED3D_OK;
1415}
1416
1417static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1418 HBITMAP hbm;
1419 BITMAP bm;
1420 HRESULT hr;
1421 HDC dcb = NULL, dcs = NULL;
1422 WINEDDCOLORKEY colorkey;
1423
1424 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1425 if(hbm)
1426 {
1427 GetObjectA(hbm, sizeof(BITMAP), &bm);
1428 dcb = CreateCompatibleDC(NULL);
1429 if(!dcb) goto out;
1430 SelectObject(dcb, hbm);
1431 }
1432 else
1433 {
1434 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1435 * couldn't be loaded
1436 */
1437 memset(&bm, 0, sizeof(bm));
1438 bm.bmWidth = 32;
1439 bm.bmHeight = 32;
1440 }
1441
1442#ifdef VBOX_WITH_WDDM
1443 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1444 FALSE, 0, &This->logo_surface, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL,
1445 NULL, &wined3d_null_parent_ops, NULL, NULL);
1446#else
1447 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1448 FALSE, 0, &This->logo_surface, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL,
1449 NULL, &wined3d_null_parent_ops);
1450#endif
1451 if(FAILED(hr)) {
1452 ERR("Wine logo requested, but failed to create surface\n");
1453 goto out;
1454 }
1455
1456 if(dcb) {
1457 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1458 if(FAILED(hr)) goto out;
1459 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1460 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1461
1462 colorkey.dwColorSpaceLowValue = 0;
1463 colorkey.dwColorSpaceHighValue = 0;
1464 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1465 } else {
1466 /* Fill the surface with a white color to show that wined3d is there */
1467 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1468 }
1469
1470out:
1471 if (dcb) DeleteDC(dcb);
1472 if (hbm) DeleteObject(hbm);
1473}
1474
1475/* Context activation is done by the caller. */
1476static void create_dummy_textures(IWineD3DDeviceImpl *This)
1477{
1478 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1479 unsigned int i;
1480 /* Under DirectX you can have texture stage operations even if no texture is
1481 bound, whereas opengl will only do texture operations when a valid texture is
1482 bound. We emulate this by creating dummy textures and binding them to each
1483 texture stage, but disable all stages by default. Hence if a stage is enabled
1484 then the default texture will kick in until replaced by a SetTexture call */
1485 ENTER_GL();
1486
1487 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1488 {
1489 /* The dummy texture does not have client storage backing */
1490 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1491 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1492 }
1493
1494 for (i = 0; i < gl_info->limits.textures; ++i)
1495 {
1496 GLubyte white = 255;
1497
1498 /* Make appropriate texture active */
1499 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1500 checkGLcall("glActiveTextureARB");
1501
1502 /* Generate an opengl texture name */
1503 glGenTextures(1, &This->dummyTextureName[i]);
1504 checkGLcall("glGenTextures");
1505 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1506
1507 /* Generate a dummy 2d texture (not using 1d because they cause many
1508 * DRI drivers fall back to sw) */
1509 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1510 checkGLcall("glBindTexture");
1511
1512 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1513 checkGLcall("glTexImage2D");
1514 }
1515
1516 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1517 {
1518 /* Reenable because if supported it is enabled by default */
1519 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1520 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1521 }
1522
1523 LEAVE_GL();
1524}
1525
1526/* Context activation is done by the caller. */
1527static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1528{
1529 ENTER_GL();
1530 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1531 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1532 LEAVE_GL();
1533
1534 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1535}
1536
1537static HRESULT WINAPI IWineD3DDeviceImpl_AcquireFocusWindow(IWineD3DDevice *iface, HWND window)
1538{
1539 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1540
1541 if (!wined3d_register_window(window, device))
1542 {
1543 ERR("Failed to register window %p.\n", window);
1544 return E_FAIL;
1545 }
1546
1547 device->focus_window = window;
1548 SetForegroundWindow(window);
1549
1550 return WINED3D_OK;
1551}
1552
1553static void WINAPI IWineD3DDeviceImpl_ReleaseFocusWindow(IWineD3DDevice *iface)
1554{
1555 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1556
1557 if (device->focus_window) wined3d_unregister_window(device->focus_window);
1558 device->focus_window = NULL;
1559}
1560
1561static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1562 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1563{
1564 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1565 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1566 IWineD3DSwapChainImpl *swapchain = NULL;
1567 struct wined3d_context *context;
1568 HRESULT hr;
1569 DWORD state;
1570 unsigned int i;
1571
1572 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1573
1574 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1575 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1576
1577 TRACE("(%p) : Creating stateblock\n", This);
1578 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1579 hr = IWineD3DDevice_CreateStateBlock(iface,
1580 WINED3DSBT_INIT,
1581 (IWineD3DStateBlock **)&This->stateBlock,
1582 NULL);
1583 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1584 WARN("Failed to create stateblock\n");
1585 goto err_out;
1586 }
1587 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1588 This->updateStateBlock = This->stateBlock;
1589 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1590
1591 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1592 sizeof(IWineD3DSurface *) * gl_info->limits.buffers);
1593 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1594 sizeof(GLenum) * gl_info->limits.buffers);
1595
1596 This->NumberOfPalettes = 1;
1597 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1598 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
1599 ERR("Out of memory!\n");
1600 hr = E_OUTOFMEMORY;
1601 goto err_out;
1602 }
1603 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1604 if(!This->palettes[0]) {
1605 ERR("Out of memory!\n");
1606 hr = E_OUTOFMEMORY;
1607 goto err_out;
1608 }
1609 for (i = 0; i < 256; ++i) {
1610 This->palettes[0][i].peRed = 0xFF;
1611 This->palettes[0][i].peGreen = 0xFF;
1612 This->palettes[0][i].peBlue = 0xFF;
1613 This->palettes[0][i].peFlags = 0xFF;
1614 }
1615 This->currentPalette = 0;
1616
1617 /* Initialize the texture unit mapping to a 1:1 mapping */
1618 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1619 {
1620 if (state < gl_info->limits.fragment_samplers)
1621 {
1622 This->texUnitMap[state] = state;
1623 This->rev_tex_unit_map[state] = state;
1624 } else {
1625 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1626 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1627 }
1628 }
1629
1630 /* Setup the implicit swapchain. This also initializes a context. */
1631 TRACE("Creating implicit swapchain\n");
1632 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1633 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1634 if (FAILED(hr))
1635 {
1636 WARN("Failed to create implicit swapchain\n");
1637 goto err_out;
1638 }
1639
1640 This->NumberOfSwapChains = 1;
1641 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1642 if(!This->swapchains) {
1643 ERR("Out of memory!\n");
1644 goto err_out;
1645 }
1646 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1647
1648 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1649 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1650 This->render_targets[0] = swapchain->backBuffer[0];
1651 }
1652 else {
1653 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1654 This->render_targets[0] = swapchain->frontBuffer;
1655 }
1656 IWineD3DSurface_AddRef(This->render_targets[0]);
1657
1658 /* Depth Stencil support */
1659 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
1660 if (NULL != This->stencilBufferTarget) {
1661 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1662 }
1663
1664 hr = This->shader_backend->shader_alloc_private(iface);
1665 if(FAILED(hr)) {
1666 TRACE("Shader private data couldn't be allocated\n");
1667 goto err_out;
1668 }
1669 hr = This->frag_pipe->alloc_private(iface);
1670 if(FAILED(hr)) {
1671 TRACE("Fragment pipeline private data couldn't be allocated\n");
1672 goto err_out;
1673 }
1674 hr = This->blitter->alloc_private(iface);
1675 if(FAILED(hr)) {
1676 TRACE("Blitter private data couldn't be allocated\n");
1677 goto err_out;
1678 }
1679
1680 /* Set up some starting GL setup */
1681
1682 /* Setup all the devices defaults */
1683 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1684
1685 context = context_acquire(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
1686
1687 create_dummy_textures(This);
1688
1689 ENTER_GL();
1690
1691 /* Initialize the current view state */
1692 This->view_ident = 1;
1693 This->contexts[0]->last_was_rhw = 0;
1694 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1695 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1696
1697 switch(wined3d_settings.offscreen_rendering_mode) {
1698 case ORM_FBO:
1699 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
1700 break;
1701
1702 case ORM_BACKBUFFER:
1703 {
1704 if (context_get_current()->aux_buffers > 0)
1705 {
1706 TRACE("Using auxilliary buffer for offscreen rendering\n");
1707 This->offscreenBuffer = GL_AUX0;
1708 } else {
1709 TRACE("Using back buffer for offscreen rendering\n");
1710 This->offscreenBuffer = GL_BACK;
1711 }
1712 }
1713 }
1714
1715 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1716 LEAVE_GL();
1717
1718 context_release(context);
1719
1720 /* Clear the screen */
1721 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1722 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1723 0x00, 1.0f, 0);
1724
1725 This->d3d_initialized = TRUE;
1726
1727 if(wined3d_settings.logo) {
1728 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
1729 }
1730 This->highest_dirty_ps_const = 0;
1731 This->highest_dirty_vs_const = 0;
1732 return WINED3D_OK;
1733
1734err_out:
1735 HeapFree(GetProcessHeap(), 0, This->render_targets);
1736 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1737 HeapFree(GetProcessHeap(), 0, This->swapchains);
1738 This->NumberOfSwapChains = 0;
1739 if(This->palettes) {
1740 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
1741 HeapFree(GetProcessHeap(), 0, This->palettes);
1742 }
1743 This->NumberOfPalettes = 0;
1744 if(swapchain) {
1745 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1746 }
1747 if(This->stateBlock) {
1748 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
1749 This->stateBlock = NULL;
1750 }
1751 if (This->blit_priv) {
1752 This->blitter->free_private(iface);
1753 }
1754 if (This->fragment_priv) {
1755 This->frag_pipe->free_private(iface);
1756 }
1757 if (This->shader_priv) {
1758 This->shader_backend->shader_free_private(iface);
1759 }
1760 return hr;
1761}
1762
1763static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
1764 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1765{
1766 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1767 IWineD3DSwapChainImpl *swapchain = NULL;
1768 HRESULT hr;
1769
1770 /* Setup the implicit swapchain */
1771 TRACE("Creating implicit swapchain\n");
1772 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1773 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1774 if (FAILED(hr))
1775 {
1776 WARN("Failed to create implicit swapchain\n");
1777 goto err_out;
1778 }
1779
1780 This->NumberOfSwapChains = 1;
1781 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1782 if(!This->swapchains) {
1783 ERR("Out of memory!\n");
1784 goto err_out;
1785 }
1786 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1787 return WINED3D_OK;
1788
1789err_out:
1790 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1791 return hr;
1792}
1793
1794static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
1795{
1796 IWineD3DResource_UnLoad(resource);
1797 IWineD3DResource_Release(resource);
1798 return WINED3D_OK;
1799}
1800
1801static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
1802 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
1803{
1804 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1805 const struct wined3d_gl_info *gl_info;
1806 struct wined3d_context *context;
1807 int sampler;
1808 UINT i;
1809 TRACE("(%p)\n", This);
1810
1811 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1812
1813 /* I don't think that the interface guarantees that the device is destroyed from the same thread
1814 * it was created. Thus make sure a context is active for the glDelete* calls
1815 */
1816 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
1817 gl_info = context->gl_info;
1818
1819 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
1820
1821 /* Unload resources */
1822 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
1823
1824 TRACE("Deleting high order patches\n");
1825 for(i = 0; i < PATCHMAP_SIZE; i++) {
1826 struct list *e1, *e2;
1827 struct WineD3DRectPatch *patch;
1828 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
1829 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
1830 IWineD3DDevice_DeletePatch(iface, patch->Handle);
1831 }
1832 }
1833
1834 /* Delete the mouse cursor texture */
1835 if(This->cursorTexture) {
1836 ENTER_GL();
1837 glDeleteTextures(1, &This->cursorTexture);
1838 LEAVE_GL();
1839 This->cursorTexture = 0;
1840 }
1841
1842 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
1843 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1844 }
1845 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
1846 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
1847 }
1848
1849 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
1850 * private data, it might contain opengl pointers
1851 */
1852 if(This->depth_blt_texture) {
1853 ENTER_GL();
1854 glDeleteTextures(1, &This->depth_blt_texture);
1855 LEAVE_GL();
1856 This->depth_blt_texture = 0;
1857 }
1858 if (This->depth_blt_rb) {
1859 ENTER_GL();
1860 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
1861 LEAVE_GL();
1862 This->depth_blt_rb = 0;
1863 This->depth_blt_rb_w = 0;
1864 This->depth_blt_rb_h = 0;
1865 }
1866
1867 /* Release the update stateblock */
1868 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
1869 if(This->updateStateBlock != This->stateBlock)
1870 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1871 }
1872 This->updateStateBlock = NULL;
1873
1874 { /* because were not doing proper internal refcounts releasing the primary state block
1875 causes recursion with the extra checks in ResourceReleased, to avoid this we have
1876 to set this->stateBlock = NULL; first */
1877 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
1878 This->stateBlock = NULL;
1879
1880 /* Release the stateblock */
1881 if(IWineD3DStateBlock_Release(stateBlock) > 0){
1882 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1883 }
1884 }
1885
1886 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
1887 This->blitter->free_private(iface);
1888 This->frag_pipe->free_private(iface);
1889 This->shader_backend->shader_free_private(iface);
1890
1891 /* Release the buffers (with sanity checks)*/
1892 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1893 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1894 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
1895 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
1896 }
1897 This->stencilBufferTarget = NULL;
1898
1899 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1900 IWineD3DSurface_Release(This->render_targets[0]);
1901
1902 TRACE("Setting rendertarget to NULL\n");
1903 This->render_targets[0] = NULL;
1904
1905 if (This->auto_depth_stencil_buffer) {
1906 if (IWineD3DSurface_Release(This->auto_depth_stencil_buffer) > 0)
1907 {
1908 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
1909 }
1910 This->auto_depth_stencil_buffer = NULL;
1911 }
1912
1913 context_release(context);
1914
1915 for(i=0; i < This->NumberOfSwapChains; i++) {
1916 TRACE("Releasing the implicit swapchain %d\n", i);
1917 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1918 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1919 }
1920 }
1921
1922 HeapFree(GetProcessHeap(), 0, This->swapchains);
1923 This->swapchains = NULL;
1924 This->NumberOfSwapChains = 0;
1925
1926 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
1927 HeapFree(GetProcessHeap(), 0, This->palettes);
1928 This->palettes = NULL;
1929 This->NumberOfPalettes = 0;
1930
1931 HeapFree(GetProcessHeap(), 0, This->render_targets);
1932 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1933 This->render_targets = NULL;
1934 This->draw_buffers = NULL;
1935
1936 This->d3d_initialized = FALSE;
1937
1938 return WINED3D_OK;
1939}
1940
1941static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1942 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1943 unsigned int i;
1944
1945 for(i=0; i < This->NumberOfSwapChains; i++) {
1946 TRACE("Releasing the implicit swapchain %d\n", i);
1947 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1948 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1949 }
1950 }
1951
1952 HeapFree(GetProcessHeap(), 0, This->swapchains);
1953 This->swapchains = NULL;
1954 This->NumberOfSwapChains = 0;
1955 return WINED3D_OK;
1956}
1957
1958/* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
1959 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
1960 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
1961 *
1962 * There is no way to deactivate thread safety once it is enabled.
1963 */
1964static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
1965 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1966
1967 /*For now just store the flag(needed in case of ddraw) */
1968 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
1969}
1970
1971static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
1972 const WINED3DDISPLAYMODE* pMode) {
1973 DEVMODEW devmode;
1974 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1975 const struct wined3d_format_desc *format_desc = getFormatDescEntry(pMode->Format, &This->adapter->gl_info);
1976 LONG ret;
1977 RECT clip_rc;
1978
1979 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
1980
1981 /* Resize the screen even without a window:
1982 * The app could have unset it with SetCooperativeLevel, but not called
1983 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
1984 * but we don't have any hwnd
1985 */
1986
1987 memset(&devmode, 0, sizeof(devmode));
1988 devmode.dmSize = sizeof(devmode);
1989 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1990 devmode.dmBitsPerPel = format_desc->byte_count * 8;
1991 devmode.dmPelsWidth = pMode->Width;
1992 devmode.dmPelsHeight = pMode->Height;
1993
1994 devmode.dmDisplayFrequency = pMode->RefreshRate;
1995 if (pMode->RefreshRate != 0) {
1996 devmode.dmFields |= DM_DISPLAYFREQUENCY;
1997 }
1998
1999 /* Only change the mode if necessary */
2000 if( (This->ddraw_width == pMode->Width) &&
2001 (This->ddraw_height == pMode->Height) &&
2002 (This->ddraw_format == pMode->Format) &&
2003 (pMode->RefreshRate == 0) ) {
2004 return WINED3D_OK;
2005 }
2006
2007 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2008 if (ret != DISP_CHANGE_SUCCESSFUL) {
2009 if(devmode.dmDisplayFrequency != 0) {
2010 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2011 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2012 devmode.dmDisplayFrequency = 0;
2013 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2014 }
2015 if(ret != DISP_CHANGE_SUCCESSFUL) {
2016 return WINED3DERR_NOTAVAILABLE;
2017 }
2018 }
2019
2020 /* Store the new values */
2021 This->ddraw_width = pMode->Width;
2022 This->ddraw_height = pMode->Height;
2023 This->ddraw_format = pMode->Format;
2024
2025 /* And finally clip mouse to our screen */
2026 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2027 ClipCursor(&clip_rc);
2028
2029 return WINED3D_OK;
2030}
2031
2032static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2033 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2034 *ppD3D = This->wined3d;
2035 TRACE("Returning %p.\n", *ppD3D);
2036 IWineD3D_AddRef(*ppD3D);
2037 return WINED3D_OK;
2038}
2039
2040static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2041 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2042
2043 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2044 (This->adapter->TextureRam/(1024*1024)),
2045 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2046 /* return simulated texture memory left */
2047 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2048}
2049
2050/*****
2051 * Get / Set Stream Source
2052 *****/
2053static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2054 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2055{
2056 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2057 IWineD3DBuffer *oldSrc;
2058
2059 if (StreamNumber >= MAX_STREAMS) {
2060 WARN("Stream out of range %d\n", StreamNumber);
2061 return WINED3DERR_INVALIDCALL;
2062 } else if(OffsetInBytes & 0x3) {
2063 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2064 return WINED3DERR_INVALIDCALL;
2065 }
2066
2067 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2068 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2069
2070 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2071
2072 if(oldSrc == pStreamData &&
2073 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2074 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2075 TRACE("Application is setting the old values over, nothing to do\n");
2076 return WINED3D_OK;
2077 }
2078
2079 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2080 if (pStreamData) {
2081 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2082 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2083 }
2084
2085 /* Handle recording of state blocks */
2086 if (This->isRecordingState) {
2087 TRACE("Recording... not performing anything\n");
2088 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2089 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2090 return WINED3D_OK;
2091 }
2092
2093 if (pStreamData != NULL) {
2094 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2095 IWineD3DBuffer_AddRef(pStreamData);
2096 }
2097 if (oldSrc != NULL) {
2098 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2099 IWineD3DBuffer_Release(oldSrc);
2100 }
2101
2102 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2103
2104 return WINED3D_OK;
2105}
2106
2107static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2108 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2109{
2110 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2111
2112 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2113 This->stateBlock->streamSource[StreamNumber],
2114 This->stateBlock->streamOffset[StreamNumber],
2115 This->stateBlock->streamStride[StreamNumber]);
2116
2117 if (StreamNumber >= MAX_STREAMS) {
2118 WARN("Stream out of range %d\n", StreamNumber);
2119 return WINED3DERR_INVALIDCALL;
2120 }
2121 *pStream = This->stateBlock->streamSource[StreamNumber];
2122 *pStride = This->stateBlock->streamStride[StreamNumber];
2123 if (pOffset) {
2124 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2125 }
2126
2127 if (*pStream != NULL) {
2128 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2129 }
2130 return WINED3D_OK;
2131}
2132
2133static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2134 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2135 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2136 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2137
2138 /* Verify input at least in d3d9 this is invalid*/
2139 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2140 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2141 return WINED3DERR_INVALIDCALL;
2142 }
2143 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2144 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2145 return WINED3DERR_INVALIDCALL;
2146 }
2147 if( Divider == 0 ){
2148 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2149 return WINED3DERR_INVALIDCALL;
2150 }
2151
2152 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2153 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2154
2155 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2156 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2157
2158 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2159 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2160 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2161 }
2162
2163 return WINED3D_OK;
2164}
2165
2166static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2167 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2168
2169 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2170 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2171
2172 TRACE("(%p) : returning %d\n", This, *Divider);
2173
2174 return WINED3D_OK;
2175}
2176
2177/*****
2178 * Get / Set & Multiply Transform
2179 *****/
2180static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2181 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2182
2183 /* Most of this routine, comments included copied from ddraw tree initially: */
2184 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2185
2186 /* Handle recording of state blocks */
2187 if (This->isRecordingState) {
2188 TRACE("Recording... not performing anything\n");
2189 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2190 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2191 return WINED3D_OK;
2192 }
2193
2194 /*
2195 * If the new matrix is the same as the current one,
2196 * we cut off any further processing. this seems to be a reasonable
2197 * optimization because as was noticed, some apps (warcraft3 for example)
2198 * tend towards setting the same matrix repeatedly for some reason.
2199 *
2200 * From here on we assume that the new matrix is different, wherever it matters.
2201 */
2202 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2203 TRACE("The app is setting the same matrix over again\n");
2204 return WINED3D_OK;
2205 } else {
2206 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2207 }
2208
2209 /*
2210 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2211 where ViewMat = Camera space, WorldMat = world space.
2212
2213 In OpenGL, camera and world space is combined into GL_MODELVIEW
2214 matrix. The Projection matrix stay projection matrix.
2215 */
2216
2217 /* Capture the times we can just ignore the change for now */
2218 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2219 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2220 /* Handled by the state manager */
2221 }
2222
2223 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2224 return WINED3D_OK;
2225
2226}
2227static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2228 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2229 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2230 *pMatrix = This->stateBlock->transforms[State];
2231 return WINED3D_OK;
2232}
2233
2234static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2235 const WINED3DMATRIX *mat = NULL;
2236 WINED3DMATRIX temp;
2237
2238 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2239 * below means it will be recorded in a state block change, but it
2240 * works regardless where it is recorded.
2241 * If this is found to be wrong, change to StateBlock.
2242 */
2243 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2244 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2245
2246 if (State <= HIGHEST_TRANSFORMSTATE)
2247 {
2248 mat = &This->updateStateBlock->transforms[State];
2249 } else {
2250 FIXME("Unhandled transform state!!\n");
2251 }
2252
2253 multiply_matrix(&temp, mat, pMatrix);
2254
2255 /* Apply change via set transform - will reapply to eg. lights this way */
2256 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2257}
2258
2259/*****
2260 * Get / Set Light
2261 *****/
2262/* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2263 you can reference any indexes you want as long as that number max are enabled at any
2264 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2265 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2266 but when recording, just build a chain pretty much of commands to be replayed. */
2267
2268static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2269 float rho;
2270 struct wined3d_light_info *object = NULL;
2271 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2272 struct list *e;
2273
2274 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2275 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2276
2277 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2278 * the gl driver.
2279 */
2280 if(!pLight) {
2281 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2282 return WINED3DERR_INVALIDCALL;
2283 }
2284
2285 switch(pLight->Type) {
2286 case WINED3DLIGHT_POINT:
2287 case WINED3DLIGHT_SPOT:
2288 case WINED3DLIGHT_PARALLELPOINT:
2289 case WINED3DLIGHT_GLSPOT:
2290 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2291 * most wanted
2292 */
2293 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2294 {
2295 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2296 return WINED3DERR_INVALIDCALL;
2297 }
2298 break;
2299
2300 case WINED3DLIGHT_DIRECTIONAL:
2301 /* Ignores attenuation */
2302 break;
2303
2304 default:
2305 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2306 return WINED3DERR_INVALIDCALL;
2307 }
2308
2309 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2310 {
2311 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2312 if(object->OriginalIndex == Index) break;
2313 object = NULL;
2314 }
2315
2316 if(!object) {
2317 TRACE("Adding new light\n");
2318 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2319 if(!object) {
2320 ERR("Out of memory error when allocating a light\n");
2321 return E_OUTOFMEMORY;
2322 }
2323 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2324 object->glIndex = -1;
2325 object->OriginalIndex = Index;
2326 }
2327
2328 /* Initialize the object */
2329 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,
2330 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2331 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2332 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2333 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2334 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2335 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2336
2337 /* Save away the information */
2338 object->OriginalParms = *pLight;
2339
2340 switch (pLight->Type) {
2341 case WINED3DLIGHT_POINT:
2342 /* Position */
2343 object->lightPosn[0] = pLight->Position.x;
2344 object->lightPosn[1] = pLight->Position.y;
2345 object->lightPosn[2] = pLight->Position.z;
2346 object->lightPosn[3] = 1.0f;
2347 object->cutoff = 180.0f;
2348 /* FIXME: Range */
2349 break;
2350
2351 case WINED3DLIGHT_DIRECTIONAL:
2352 /* Direction */
2353 object->lightPosn[0] = -pLight->Direction.x;
2354 object->lightPosn[1] = -pLight->Direction.y;
2355 object->lightPosn[2] = -pLight->Direction.z;
2356 object->lightPosn[3] = 0.0f;
2357 object->exponent = 0.0f;
2358 object->cutoff = 180.0f;
2359 break;
2360
2361 case WINED3DLIGHT_SPOT:
2362 /* Position */
2363 object->lightPosn[0] = pLight->Position.x;
2364 object->lightPosn[1] = pLight->Position.y;
2365 object->lightPosn[2] = pLight->Position.z;
2366 object->lightPosn[3] = 1.0f;
2367
2368 /* Direction */
2369 object->lightDirn[0] = pLight->Direction.x;
2370 object->lightDirn[1] = pLight->Direction.y;
2371 object->lightDirn[2] = pLight->Direction.z;
2372 object->lightDirn[3] = 1.0f;
2373
2374 /*
2375 * opengl-ish and d3d-ish spot lights use too different models for the
2376 * light "intensity" as a function of the angle towards the main light direction,
2377 * so we only can approximate very roughly.
2378 * however spot lights are rather rarely used in games (if ever used at all).
2379 * furthermore if still used, probably nobody pays attention to such details.
2380 */
2381 if (pLight->Falloff == 0) {
2382 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2383 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2384 * will always be 1.0 for both of them, and we don't have to care for the
2385 * rest of the rather complex calculation
2386 */
2387 object->exponent = 0.0f;
2388 } else {
2389 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2390 if (rho < 0.0001f) rho = 0.0001f;
2391 object->exponent = -0.3f/log(cos(rho/2));
2392 }
2393 if (object->exponent > 128.0f)
2394 {
2395 object->exponent = 128.0f;
2396 }
2397 object->cutoff = pLight->Phi*90/M_PI;
2398
2399 /* FIXME: Range */
2400 break;
2401
2402 default:
2403 FIXME("Unrecognized light type %d\n", pLight->Type);
2404 }
2405
2406 /* Update the live definitions if the light is currently assigned a glIndex */
2407 if (object->glIndex != -1 && !This->isRecordingState) {
2408 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2409 }
2410 return WINED3D_OK;
2411}
2412
2413static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2414{
2415 struct wined3d_light_info *lightInfo = NULL;
2416 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2417 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2418 struct list *e;
2419 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2420
2421 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2422 {
2423 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2424 if(lightInfo->OriginalIndex == Index) break;
2425 lightInfo = NULL;
2426 }
2427
2428 if (lightInfo == NULL) {
2429 TRACE("Light information requested but light not defined\n");
2430 return WINED3DERR_INVALIDCALL;
2431 }
2432
2433 *pLight = lightInfo->OriginalParms;
2434 return WINED3D_OK;
2435}
2436
2437/*****
2438 * Get / Set Light Enable
2439 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2440 *****/
2441static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2442{
2443 struct wined3d_light_info *lightInfo = NULL;
2444 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2445 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2446 struct list *e;
2447 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2448
2449 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2450 {
2451 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2452 if(lightInfo->OriginalIndex == Index) break;
2453 lightInfo = NULL;
2454 }
2455 TRACE("Found light: %p\n", lightInfo);
2456
2457 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2458 if (lightInfo == NULL) {
2459
2460 TRACE("Light enabled requested but light not defined, so defining one!\n");
2461 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2462
2463 /* Search for it again! Should be fairly quick as near head of list */
2464 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2465 {
2466 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2467 if(lightInfo->OriginalIndex == Index) break;
2468 lightInfo = NULL;
2469 }
2470 if (lightInfo == NULL) {
2471 FIXME("Adding default lights has failed dismally\n");
2472 return WINED3DERR_INVALIDCALL;
2473 }
2474 }
2475
2476 if(!Enable) {
2477 if(lightInfo->glIndex != -1) {
2478 if(!This->isRecordingState) {
2479 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2480 }
2481
2482 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2483 lightInfo->glIndex = -1;
2484 } else {
2485 TRACE("Light already disabled, nothing to do\n");
2486 }
2487 lightInfo->enabled = FALSE;
2488 } else {
2489 lightInfo->enabled = TRUE;
2490 if (lightInfo->glIndex != -1) {
2491 /* nop */
2492 TRACE("Nothing to do as light was enabled\n");
2493 } else {
2494 int i;
2495 /* Find a free gl light */
2496 for(i = 0; i < This->maxConcurrentLights; i++) {
2497 if(This->updateStateBlock->activeLights[i] == NULL) {
2498 This->updateStateBlock->activeLights[i] = lightInfo;
2499 lightInfo->glIndex = i;
2500 break;
2501 }
2502 }
2503 if(lightInfo->glIndex == -1) {
2504 /* Our tests show that Windows returns D3D_OK in this situation, even with
2505 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2506 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2507 * as well for those lights.
2508 *
2509 * TODO: Test how this affects rendering
2510 */
2511 WARN("Too many concurrently active lights\n");
2512 return WINED3D_OK;
2513 }
2514
2515 /* i == lightInfo->glIndex */
2516 if(!This->isRecordingState) {
2517 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2518 }
2519 }
2520 }
2521
2522 return WINED3D_OK;
2523}
2524
2525static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2526{
2527 struct wined3d_light_info *lightInfo = NULL;
2528 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2529 struct list *e;
2530 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2531 TRACE("(%p) : for idx(%d)\n", This, Index);
2532
2533 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2534 {
2535 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2536 if(lightInfo->OriginalIndex == Index) break;
2537 lightInfo = NULL;
2538 }
2539
2540 if (lightInfo == NULL) {
2541 TRACE("Light enabled state requested but light not defined\n");
2542 return WINED3DERR_INVALIDCALL;
2543 }
2544 /* true is 128 according to SetLightEnable */
2545 *pEnable = lightInfo->enabled ? 128 : 0;
2546 return WINED3D_OK;
2547}
2548
2549/*****
2550 * Get / Set Clip Planes
2551 *****/
2552static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2553 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2554 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2555
2556 /* Validate Index */
2557 if (Index >= This->adapter->gl_info.limits.clipplanes)
2558 {
2559 TRACE("Application has requested clipplane this device doesn't support\n");
2560 return WINED3DERR_INVALIDCALL;
2561 }
2562
2563 This->updateStateBlock->changed.clipplane |= 1 << Index;
2564
2565 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2566 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2567 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2568 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2569 TRACE("Application is setting old values over, nothing to do\n");
2570 return WINED3D_OK;
2571 }
2572
2573 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2574 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2575 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2576 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2577
2578 /* Handle recording of state blocks */
2579 if (This->isRecordingState) {
2580 TRACE("Recording... not performing anything\n");
2581 return WINED3D_OK;
2582 }
2583
2584 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2585
2586 return WINED3D_OK;
2587}
2588
2589static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2590 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2591 TRACE("(%p) : for idx %d\n", This, Index);
2592
2593 /* Validate Index */
2594 if (Index >= This->adapter->gl_info.limits.clipplanes)
2595 {
2596 TRACE("Application has requested clipplane this device doesn't support\n");
2597 return WINED3DERR_INVALIDCALL;
2598 }
2599
2600 pPlane[0] = This->stateBlock->clipplane[Index][0];
2601 pPlane[1] = This->stateBlock->clipplane[Index][1];
2602 pPlane[2] = This->stateBlock->clipplane[Index][2];
2603 pPlane[3] = This->stateBlock->clipplane[Index][3];
2604 return WINED3D_OK;
2605}
2606
2607/*****
2608 * Get / Set Clip Plane Status
2609 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2610 *****/
2611static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2612 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2613 FIXME("(%p) : stub\n", This);
2614 if (NULL == pClipStatus) {
2615 return WINED3DERR_INVALIDCALL;
2616 }
2617 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2618 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2619 return WINED3D_OK;
2620}
2621
2622static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2623 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2624 FIXME("(%p) : stub\n", This);
2625 if (NULL == pClipStatus) {
2626 return WINED3DERR_INVALIDCALL;
2627 }
2628 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2629 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2630 return WINED3D_OK;
2631}
2632
2633/*****
2634 * Get / Set Material
2635 *****/
2636static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2637 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2638
2639 This->updateStateBlock->changed.material = TRUE;
2640 This->updateStateBlock->material = *pMaterial;
2641
2642 /* Handle recording of state blocks */
2643 if (This->isRecordingState) {
2644 TRACE("Recording... not performing anything\n");
2645 return WINED3D_OK;
2646 }
2647
2648 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2649 return WINED3D_OK;
2650}
2651
2652static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2653 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2654 *pMaterial = This->updateStateBlock->material;
2655 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2656 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2657 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2658 pMaterial->Ambient.b, pMaterial->Ambient.a);
2659 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2660 pMaterial->Specular.b, pMaterial->Specular.a);
2661 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2662 pMaterial->Emissive.b, pMaterial->Emissive.a);
2663 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2664
2665 return WINED3D_OK;
2666}
2667
2668/*****
2669 * Get / Set Indices
2670 *****/
2671static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
2672 IWineD3DBuffer *pIndexData, WINED3DFORMAT fmt)
2673{
2674 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2675 IWineD3DBuffer *oldIdxs;
2676
2677 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2678 oldIdxs = This->updateStateBlock->pIndexData;
2679
2680 This->updateStateBlock->changed.indices = TRUE;
2681 This->updateStateBlock->pIndexData = pIndexData;
2682 This->updateStateBlock->IndexFmt = fmt;
2683
2684 /* Handle recording of state blocks */
2685 if (This->isRecordingState) {
2686 TRACE("Recording... not performing anything\n");
2687 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
2688 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2689 return WINED3D_OK;
2690 }
2691
2692 if(oldIdxs != pIndexData) {
2693 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2694 if(pIndexData) {
2695 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2696 IWineD3DBuffer_AddRef(pIndexData);
2697 }
2698 if(oldIdxs) {
2699 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2700 IWineD3DBuffer_Release(oldIdxs);
2701 }
2702 }
2703
2704 return WINED3D_OK;
2705}
2706
2707static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
2708{
2709 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2710
2711 *ppIndexData = This->stateBlock->pIndexData;
2712
2713 /* up ref count on ppindexdata */
2714 if (*ppIndexData) {
2715 IWineD3DBuffer_AddRef(*ppIndexData);
2716 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2717 }else{
2718 TRACE("(%p) No index data set\n", This);
2719 }
2720 TRACE("Returning %p\n", *ppIndexData);
2721
2722 return WINED3D_OK;
2723}
2724
2725/* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2726static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2727 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2728 TRACE("(%p)->(%d)\n", This, BaseIndex);
2729
2730 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2731 TRACE("Application is setting the old value over, nothing to do\n");
2732 return WINED3D_OK;
2733 }
2734
2735 This->updateStateBlock->baseVertexIndex = BaseIndex;
2736
2737 if (This->isRecordingState) {
2738 TRACE("Recording... not performing anything\n");
2739 return WINED3D_OK;
2740 }
2741 /* The base vertex index affects the stream sources */
2742 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2743 return WINED3D_OK;
2744}
2745
2746static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2747 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2748 TRACE("(%p) : base_index %p\n", This, base_index);
2749
2750 *base_index = This->stateBlock->baseVertexIndex;
2751
2752 TRACE("Returning %u\n", *base_index);
2753
2754 return WINED3D_OK;
2755}
2756
2757/*****
2758 * Get / Set Viewports
2759 *****/
2760static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2761 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2762
2763 TRACE("(%p)\n", This);
2764 This->updateStateBlock->changed.viewport = TRUE;
2765 This->updateStateBlock->viewport = *pViewport;
2766
2767 /* Handle recording of state blocks */
2768 if (This->isRecordingState) {
2769 TRACE("Recording... not performing anything\n");
2770 return WINED3D_OK;
2771 }
2772
2773 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2774 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2775
2776 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2777 return WINED3D_OK;
2778
2779}
2780
2781static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2782 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2783 TRACE("(%p)\n", This);
2784 *pViewport = This->stateBlock->viewport;
2785 return WINED3D_OK;
2786}
2787
2788/*****
2789 * Get / Set Render States
2790 * TODO: Verify against dx9 definitions
2791 *****/
2792static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2793
2794 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2795 DWORD oldValue = This->stateBlock->renderState[State];
2796
2797 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2798
2799 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
2800 This->updateStateBlock->renderState[State] = Value;
2801
2802 /* Handle recording of state blocks */
2803 if (This->isRecordingState) {
2804 TRACE("Recording... not performing anything\n");
2805 return WINED3D_OK;
2806 }
2807
2808 /* Compared here and not before the assignment to allow proper stateblock recording */
2809 if(Value == oldValue) {
2810 TRACE("Application is setting the old value over, nothing to do\n");
2811 } else {
2812 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2813 }
2814
2815 return WINED3D_OK;
2816}
2817
2818static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2819 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2820 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2821 *pValue = This->stateBlock->renderState[State];
2822 return WINED3D_OK;
2823}
2824
2825/*****
2826 * Get / Set Sampler States
2827 * TODO: Verify against dx9 definitions
2828 *****/
2829
2830static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2831 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2832 DWORD oldValue;
2833
2834 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
2835 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
2836
2837 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2838 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2839 }
2840
2841 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2842 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2843 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2844 }
2845 /**
2846 * SetSampler is designed to allow for more than the standard up to 8 textures
2847 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2848 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2849 *
2850 * http://developer.nvidia.com/object/General_FAQ.html#t6
2851 *
2852 * There are two new settings for GForce
2853 * the sampler one:
2854 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2855 * and the texture one:
2856 * GL_MAX_TEXTURE_COORDS_ARB.
2857 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2858 ******************/
2859
2860 oldValue = This->stateBlock->samplerState[Sampler][Type];
2861 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2862 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
2863
2864 /* Handle recording of state blocks */
2865 if (This->isRecordingState) {
2866 TRACE("Recording... not performing anything\n");
2867 return WINED3D_OK;
2868 }
2869
2870 if(oldValue == Value) {
2871 TRACE("Application is setting the old value over, nothing to do\n");
2872 return WINED3D_OK;
2873 }
2874
2875 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2876
2877 return WINED3D_OK;
2878}
2879
2880static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2881 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2882
2883 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
2884 This, Sampler, debug_d3dsamplerstate(Type), Type);
2885
2886 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2887 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2888 }
2889
2890 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2891 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2892 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2893 }
2894 *Value = This->stateBlock->samplerState[Sampler][Type];
2895 TRACE("(%p) : Returning %#x\n", This, *Value);
2896
2897 return WINED3D_OK;
2898}
2899
2900static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2901 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2902
2903 This->updateStateBlock->changed.scissorRect = TRUE;
2904 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2905 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2906 return WINED3D_OK;
2907 }
2908 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2909
2910 if(This->isRecordingState) {
2911 TRACE("Recording... not performing anything\n");
2912 return WINED3D_OK;
2913 }
2914
2915 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2916
2917 return WINED3D_OK;
2918}
2919
2920static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2921 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2922
2923 *pRect = This->updateStateBlock->scissorRect;
2924 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2925 return WINED3D_OK;
2926}
2927
2928static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2929 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2930 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2931
2932 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2933
2934 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
2935 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
2936
2937 This->updateStateBlock->vertexDecl = pDecl;
2938 This->updateStateBlock->changed.vertexDecl = TRUE;
2939
2940 if (This->isRecordingState) {
2941 TRACE("Recording... not performing anything\n");
2942 return WINED3D_OK;
2943 } else if(pDecl == oldDecl) {
2944 /* Checked after the assignment to allow proper stateblock recording */
2945 TRACE("Application is setting the old declaration over, nothing to do\n");
2946 return WINED3D_OK;
2947 }
2948
2949 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2950 return WINED3D_OK;
2951}
2952
2953static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
2954 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2955
2956 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
2957
2958 *ppDecl = This->stateBlock->vertexDecl;
2959 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
2960 return WINED3D_OK;
2961}
2962
2963static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
2964 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2965 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
2966
2967 This->updateStateBlock->vertexShader = pShader;
2968 This->updateStateBlock->changed.vertexShader = TRUE;
2969
2970 if (This->isRecordingState) {
2971 if(pShader) IWineD3DVertexShader_AddRef(pShader);
2972 if(oldShader) IWineD3DVertexShader_Release(oldShader);
2973 TRACE("Recording... not performing anything\n");
2974 return WINED3D_OK;
2975 } else if(oldShader == pShader) {
2976 /* Checked here to allow proper stateblock recording */
2977 TRACE("App is setting the old shader over, nothing to do\n");
2978 return WINED3D_OK;
2979 }
2980
2981 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
2982 if(pShader) IWineD3DVertexShader_AddRef(pShader);
2983 if(oldShader) IWineD3DVertexShader_Release(oldShader);
2984
2985 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
2986
2987 return WINED3D_OK;
2988}
2989
2990static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
2991 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2992
2993 if (NULL == ppShader) {
2994 return WINED3DERR_INVALIDCALL;
2995 }
2996 *ppShader = This->stateBlock->vertexShader;
2997 if( NULL != *ppShader)
2998 IWineD3DVertexShader_AddRef(*ppShader);
2999
3000 TRACE("(%p) : returning %p\n", This, *ppShader);
3001 return WINED3D_OK;
3002}
3003
3004static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3005 IWineD3DDevice *iface,
3006 UINT start,
3007 CONST BOOL *srcData,
3008 UINT count) {
3009
3010 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3011 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3012
3013 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3014 iface, srcData, start, count);
3015
3016 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3017
3018 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3019 for (i = 0; i < cnt; i++)
3020 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3021
3022 for (i = start; i < cnt + start; ++i) {
3023 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3024 }
3025
3026 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3027
3028 return WINED3D_OK;
3029}
3030
3031static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3032 IWineD3DDevice *iface,
3033 UINT start,
3034 BOOL *dstData,
3035 UINT count) {
3036
3037 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3038 int cnt = min(count, MAX_CONST_B - start);
3039
3040 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3041 iface, dstData, start, count);
3042
3043 if (dstData == NULL || cnt < 0)
3044 return WINED3DERR_INVALIDCALL;
3045
3046 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3047 return WINED3D_OK;
3048}
3049
3050static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3051 IWineD3DDevice *iface,
3052 UINT start,
3053 CONST int *srcData,
3054 UINT count) {
3055
3056 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3057 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3058
3059 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3060 iface, srcData, start, count);
3061
3062 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3063
3064 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3065 for (i = 0; i < cnt; i++)
3066 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3067 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3068
3069 for (i = start; i < cnt + start; ++i) {
3070 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3071 }
3072
3073 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3074
3075 return WINED3D_OK;
3076}
3077
3078static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3079 IWineD3DDevice *iface,
3080 UINT start,
3081 int *dstData,
3082 UINT count) {
3083
3084 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3085 int cnt = min(count, MAX_CONST_I - start);
3086
3087 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3088 iface, dstData, start, count);
3089
3090 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= 0)
3091 return WINED3DERR_INVALIDCALL;
3092
3093 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3094 return WINED3D_OK;
3095}
3096
3097static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3098 IWineD3DDevice *iface,
3099 UINT start,
3100 CONST float *srcData,
3101 UINT count) {
3102
3103 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3104 UINT i;
3105
3106 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3107 iface, srcData, start, count);
3108
3109 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3110 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3111 return WINED3DERR_INVALIDCALL;
3112
3113 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3114 if(TRACE_ON(d3d)) {
3115 for (i = 0; i < count; i++)
3116 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3117 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3118 }
3119
3120 if (!This->isRecordingState)
3121 {
3122 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3123 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3124 }
3125
3126 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3127 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3128
3129 return WINED3D_OK;
3130}
3131
3132static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3133 IWineD3DDevice *iface,
3134 UINT start,
3135 float *dstData,
3136 UINT count) {
3137
3138 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3139 int cnt = min(count, This->d3d_vshader_constantF - start);
3140
3141 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3142 iface, dstData, start, count);
3143
3144 if (dstData == NULL || cnt < 0)
3145 return WINED3DERR_INVALIDCALL;
3146
3147 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3148 return WINED3D_OK;
3149}
3150
3151static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3152 DWORD i;
3153 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3154 {
3155 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3156 }
3157}
3158
3159static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3160{
3161 DWORD i = This->rev_tex_unit_map[unit];
3162 DWORD j = This->texUnitMap[stage];
3163
3164 This->texUnitMap[stage] = unit;
3165 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3166 {
3167 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3168 }
3169
3170 This->rev_tex_unit_map[unit] = stage;
3171 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3172 {
3173 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3174 }
3175}
3176
3177static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3178 int i;
3179
3180 This->fixed_function_usage_map = 0;
3181 for (i = 0; i < MAX_TEXTURES; ++i) {
3182 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3183 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3184 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3185 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3186 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3187 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3188 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3189 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3190
3191 if (color_op == WINED3DTOP_DISABLE) {
3192 /* Not used, and disable higher stages */
3193 break;
3194 }
3195
3196 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3197 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3198 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3199 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3200 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3201 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3202 This->fixed_function_usage_map |= (1 << i);
3203 }
3204
3205 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3206 This->fixed_function_usage_map |= (1 << (i + 1));
3207 }
3208 }
3209}
3210
3211static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3212{
3213 unsigned int i, tex;
3214 WORD ffu_map;
3215
3216 device_update_fixed_function_usage_map(This);
3217 ffu_map = This->fixed_function_usage_map;
3218
3219 if (This->max_ffp_textures == gl_info->limits.texture_stages
3220 || This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures)
3221 {
3222 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3223 {
3224 if (!(ffu_map & 1)) continue;
3225
3226 if (This->texUnitMap[i] != i) {
3227 device_map_stage(This, i, i);
3228 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3229 markTextureStagesDirty(This, i);
3230 }
3231 }
3232 return;
3233 }
3234
3235 /* Now work out the mapping */
3236 tex = 0;
3237 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3238 {
3239 if (!(ffu_map & 1)) continue;
3240
3241 if (This->texUnitMap[i] != tex) {
3242 device_map_stage(This, i, tex);
3243 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3244 markTextureStagesDirty(This, i);
3245 }
3246
3247 ++tex;
3248 }
3249}
3250
3251static void device_map_psamplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3252{
3253 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3254 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3255 unsigned int i;
3256
3257 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3258 if (sampler_type[i] && This->texUnitMap[i] != i)
3259 {
3260 device_map_stage(This, i, i);
3261 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3262 if (i < gl_info->limits.texture_stages)
3263 {
3264 markTextureStagesDirty(This, i);
3265 }
3266 }
3267 }
3268}
3269
3270static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3271 const DWORD *vshader_sampler_tokens, DWORD unit)
3272{
3273 DWORD current_mapping = This->rev_tex_unit_map[unit];
3274
3275 /* Not currently used */
3276 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3277
3278 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3279 /* Used by a fragment sampler */
3280
3281 if (!pshader_sampler_tokens) {
3282 /* No pixel shader, check fixed function */
3283 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3284 }
3285
3286 /* Pixel shader, check the shader's sampler map */
3287 return !pshader_sampler_tokens[current_mapping];
3288 }
3289
3290 /* Used by a vertex sampler */
3291 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3292}
3293
3294static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps, const struct wined3d_gl_info *gl_info)
3295{
3296 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3297 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3298 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3299 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
3300 int i;
3301
3302 if (ps) {
3303 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3304
3305 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3306 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3307 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3308 }
3309
3310 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3311 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3312 if (vshader_sampler_type[i])
3313 {
3314 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3315 {
3316 /* Already mapped somewhere */
3317 continue;
3318 }
3319
3320 while (start >= 0) {
3321 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3322 {
3323 device_map_stage(This, vsampler_idx, start);
3324 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3325
3326 --start;
3327 break;
3328 }
3329
3330 --start;
3331 }
3332 }
3333 }
3334}
3335
3336void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This)
3337{
3338 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3339 BOOL vs = use_vs(This->stateBlock);
3340 BOOL ps = use_ps(This->stateBlock);
3341 /*
3342 * Rules are:
3343 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3344 * that would be really messy and require shader recompilation
3345 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3346 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3347 */
3348 if (ps) device_map_psamplers(This, gl_info);
3349 else device_map_fixed_function_samplers(This, gl_info);
3350
3351 if (vs) device_map_vsamplers(This, ps, gl_info);
3352}
3353
3354static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3355 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3356 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3357 This->updateStateBlock->pixelShader = pShader;
3358 This->updateStateBlock->changed.pixelShader = TRUE;
3359
3360 /* Handle recording of state blocks */
3361 if (This->isRecordingState) {
3362 TRACE("Recording... not performing anything\n");
3363 }
3364
3365 if (This->isRecordingState) {
3366 TRACE("Recording... not performing anything\n");
3367 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3368 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3369 return WINED3D_OK;
3370 }
3371
3372 if(pShader == oldShader) {
3373 TRACE("App is setting the old pixel shader over, nothing to do\n");
3374 return WINED3D_OK;
3375 }
3376
3377 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3378 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3379
3380 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3381 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3382
3383 return WINED3D_OK;
3384}
3385
3386static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3387 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3388
3389 if (NULL == ppShader) {
3390 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3391 return WINED3DERR_INVALIDCALL;
3392 }
3393
3394 *ppShader = This->stateBlock->pixelShader;
3395 if (NULL != *ppShader) {
3396 IWineD3DPixelShader_AddRef(*ppShader);
3397 }
3398 TRACE("(%p) : returning %p\n", This, *ppShader);
3399 return WINED3D_OK;
3400}
3401
3402static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3403 IWineD3DDevice *iface,
3404 UINT start,
3405 CONST BOOL *srcData,
3406 UINT count) {
3407
3408 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3409 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3410
3411 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3412 iface, srcData, start, count);
3413
3414 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3415
3416 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3417 for (i = 0; i < cnt; i++)
3418 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3419
3420 for (i = start; i < cnt + start; ++i) {
3421 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3422 }
3423
3424 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3425
3426 return WINED3D_OK;
3427}
3428
3429static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3430 IWineD3DDevice *iface,
3431 UINT start,
3432 BOOL *dstData,
3433 UINT count) {
3434
3435 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3436 int cnt = min(count, MAX_CONST_B - start);
3437
3438 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3439 iface, dstData, start, count);
3440
3441 if (dstData == NULL || cnt < 0)
3442 return WINED3DERR_INVALIDCALL;
3443
3444 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3445 return WINED3D_OK;
3446}
3447
3448static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3449 IWineD3DDevice *iface,
3450 UINT start,
3451 CONST int *srcData,
3452 UINT count) {
3453
3454 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3455 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3456
3457 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3458 iface, srcData, start, count);
3459
3460 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3461
3462 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3463 for (i = 0; i < cnt; i++)
3464 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3465 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3466
3467 for (i = start; i < cnt + start; ++i) {
3468 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3469 }
3470
3471 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3472
3473 return WINED3D_OK;
3474}
3475
3476static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3477 IWineD3DDevice *iface,
3478 UINT start,
3479 int *dstData,
3480 UINT count) {
3481
3482 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3483 int cnt = min(count, MAX_CONST_I - start);
3484
3485 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3486 iface, dstData, start, count);
3487
3488 if (dstData == NULL || cnt < 0)
3489 return WINED3DERR_INVALIDCALL;
3490
3491 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3492 return WINED3D_OK;
3493}
3494
3495static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3496 IWineD3DDevice *iface,
3497 UINT start,
3498 CONST float *srcData,
3499 UINT count) {
3500
3501 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3502 UINT i;
3503
3504 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3505 iface, srcData, start, count);
3506
3507 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3508 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3509 return WINED3DERR_INVALIDCALL;
3510
3511 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3512 if(TRACE_ON(d3d)) {
3513 for (i = 0; i < count; i++)
3514 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3515 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3516 }
3517
3518 if (!This->isRecordingState)
3519 {
3520 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3521 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3522 }
3523
3524 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3525 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3526
3527 return WINED3D_OK;
3528}
3529
3530static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3531 IWineD3DDevice *iface,
3532 UINT start,
3533 float *dstData,
3534 UINT count) {
3535
3536 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3537 int cnt = min(count, This->d3d_pshader_constantF - start);
3538
3539 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3540 iface, dstData, start, count);
3541
3542 if (dstData == NULL || cnt < 0)
3543 return WINED3DERR_INVALIDCALL;
3544
3545 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3546 return WINED3D_OK;
3547}
3548
3549/* Context activation is done by the caller. */
3550#define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3551static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3552 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3553 DWORD DestFVF)
3554{
3555 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3556 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3557 unsigned int i;
3558 WINED3DVIEWPORT vp;
3559 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3560 BOOL doClip;
3561 DWORD numTextures;
3562
3563 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3564 {
3565 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3566 }
3567
3568 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3569 {
3570 ERR("Source has no position mask\n");
3571 return WINED3DERR_INVALIDCALL;
3572 }
3573
3574 /* We might access VBOs from this code, so hold the lock */
3575 ENTER_GL();
3576
3577 if (dest->resource.allocatedMemory == NULL) {
3578 buffer_get_sysmem(dest);
3579 }
3580
3581 /* Get a pointer into the destination vbo(create one if none exists) and
3582 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3583 */
3584 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3585 {
3586 dest->flags |= WINED3D_BUFFER_CREATEBO;
3587 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3588 }
3589
3590 if (dest->buffer_object)
3591 {
3592 unsigned char extrabytes = 0;
3593 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3594 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3595 * this may write 4 extra bytes beyond the area that should be written
3596 */
3597 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3598 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3599 if(!dest_conv_addr) {
3600 ERR("Out of memory\n");
3601 /* Continue without storing converted vertices */
3602 }
3603 dest_conv = dest_conv_addr;
3604 }
3605
3606 /* Should I clip?
3607 * a) WINED3DRS_CLIPPING is enabled
3608 * b) WINED3DVOP_CLIP is passed
3609 */
3610 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3611 static BOOL warned = FALSE;
3612 /*
3613 * The clipping code is not quite correct. Some things need
3614 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3615 * so disable clipping for now.
3616 * (The graphics in Half-Life are broken, and my processvertices
3617 * test crashes with IDirect3DDevice3)
3618 doClip = TRUE;
3619 */
3620 doClip = FALSE;
3621 if(!warned) {
3622 warned = TRUE;
3623 FIXME("Clipping is broken and disabled for now\n");
3624 }
3625 } else doClip = FALSE;
3626 dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3627
3628 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3629 WINED3DTS_VIEW,
3630 &view_mat);
3631 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3632 WINED3DTS_PROJECTION,
3633 &proj_mat);
3634 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3635 WINED3DTS_WORLDMATRIX(0),
3636 &world_mat);
3637
3638 TRACE("View mat:\n");
3639 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);
3640 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);
3641 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);
3642 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);
3643
3644 TRACE("Proj mat:\n");
3645 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);
3646 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);
3647 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);
3648 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);
3649
3650 TRACE("World mat:\n");
3651 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);
3652 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);
3653 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);
3654 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);
3655
3656 /* Get the viewport */
3657 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3658 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3659 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3660
3661 multiply_matrix(&mat,&view_mat,&world_mat);
3662 multiply_matrix(&mat,&proj_mat,&mat);
3663
3664 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3665
3666 for (i = 0; i < dwCount; i+= 1) {
3667 unsigned int tex_index;
3668
3669 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3670 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3671 /* The position first */
3672 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3673 const float *p = (const float *)(element->data + i * element->stride);
3674 float x, y, z, rhw;
3675 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3676
3677 /* Multiplication with world, view and projection matrix */
3678 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);
3679 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);
3680 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);
3681 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);
3682
3683 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3684
3685 /* WARNING: The following things are taken from d3d7 and were not yet checked
3686 * against d3d8 or d3d9!
3687 */
3688
3689 /* Clipping conditions: From msdn
3690 *
3691 * A vertex is clipped if it does not match the following requirements
3692 * -rhw < x <= rhw
3693 * -rhw < y <= rhw
3694 * 0 < z <= rhw
3695 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3696 *
3697 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3698 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3699 *
3700 */
3701
3702 if( !doClip ||
3703 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3704 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3705 ( rhw > eps ) ) ) {
3706
3707 /* "Normal" viewport transformation (not clipped)
3708 * 1) The values are divided by rhw
3709 * 2) The y axis is negative, so multiply it with -1
3710 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3711 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3712 * 4) Multiply x with Width/2 and add Width/2
3713 * 5) The same for the height
3714 * 6) Add the viewpoint X and Y to the 2D coordinates and
3715 * The minimum Z value to z
3716 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3717 *
3718 * Well, basically it's simply a linear transformation into viewport
3719 * coordinates
3720 */
3721
3722 x /= rhw;
3723 y /= rhw;
3724 z /= rhw;
3725
3726 y *= -1;
3727
3728 x *= vp.Width / 2;
3729 y *= vp.Height / 2;
3730 z *= vp.MaxZ - vp.MinZ;
3731
3732 x += vp.Width / 2 + vp.X;
3733 y += vp.Height / 2 + vp.Y;
3734 z += vp.MinZ;
3735
3736 rhw = 1 / rhw;
3737 } else {
3738 /* That vertex got clipped
3739 * Contrary to OpenGL it is not dropped completely, it just
3740 * undergoes a different calculation.
3741 */
3742 TRACE("Vertex got clipped\n");
3743 x += rhw;
3744 y += rhw;
3745
3746 x /= 2;
3747 y /= 2;
3748
3749 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3750 * outside of the main vertex buffer memory. That needs some more
3751 * investigation...
3752 */
3753 }
3754
3755 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3756
3757
3758 ( (float *) dest_ptr)[0] = x;
3759 ( (float *) dest_ptr)[1] = y;
3760 ( (float *) dest_ptr)[2] = z;
3761 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3762
3763 dest_ptr += 3 * sizeof(float);
3764
3765 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3766 dest_ptr += sizeof(float);
3767 }
3768
3769 if(dest_conv) {
3770 float w = 1 / rhw;
3771 ( (float *) dest_conv)[0] = x * w;
3772 ( (float *) dest_conv)[1] = y * w;
3773 ( (float *) dest_conv)[2] = z * w;
3774 ( (float *) dest_conv)[3] = w;
3775
3776 dest_conv += 3 * sizeof(float);
3777
3778 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3779 dest_conv += sizeof(float);
3780 }
3781 }
3782 }
3783 if (DestFVF & WINED3DFVF_PSIZE) {
3784 dest_ptr += sizeof(DWORD);
3785 if(dest_conv) dest_conv += sizeof(DWORD);
3786 }
3787 if (DestFVF & WINED3DFVF_NORMAL) {
3788 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
3789 const float *normal = (const float *)(element->data + i * element->stride);
3790 /* AFAIK this should go into the lighting information */
3791 FIXME("Didn't expect the destination to have a normal\n");
3792 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3793 if(dest_conv) {
3794 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3795 }
3796 }
3797
3798 if (DestFVF & WINED3DFVF_DIFFUSE) {
3799 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
3800 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
3801 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
3802 {
3803 static BOOL warned = FALSE;
3804
3805 if(!warned) {
3806 ERR("No diffuse color in source, but destination has one\n");
3807 warned = TRUE;
3808 }
3809
3810 *( (DWORD *) dest_ptr) = 0xffffffff;
3811 dest_ptr += sizeof(DWORD);
3812
3813 if(dest_conv) {
3814 *( (DWORD *) dest_conv) = 0xffffffff;
3815 dest_conv += sizeof(DWORD);
3816 }
3817 }
3818 else {
3819 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3820 if(dest_conv) {
3821 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3822 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3823 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3824 dest_conv += sizeof(DWORD);
3825 }
3826 }
3827 }
3828
3829 if (DestFVF & WINED3DFVF_SPECULAR)
3830 {
3831 /* What's the color value in the feedback buffer? */
3832 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
3833 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
3834 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
3835 {
3836 static BOOL warned = FALSE;
3837
3838 if(!warned) {
3839 ERR("No specular color in source, but destination has one\n");
3840 warned = TRUE;
3841 }
3842
3843 *( (DWORD *) dest_ptr) = 0xFF000000;
3844 dest_ptr += sizeof(DWORD);
3845
3846 if(dest_conv) {
3847 *( (DWORD *) dest_conv) = 0xFF000000;
3848 dest_conv += sizeof(DWORD);
3849 }
3850 }
3851 else {
3852 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3853 if(dest_conv) {
3854 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3855 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3856 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3857 dest_conv += sizeof(DWORD);
3858 }
3859 }
3860 }
3861
3862 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3863 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
3864 const float *tex_coord = (const float *)(element->data + i * element->stride);
3865 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
3866 {
3867 ERR("No source texture, but destination requests one\n");
3868 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3869 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3870 }
3871 else {
3872 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3873 if(dest_conv) {
3874 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3875 }
3876 }
3877 }
3878 }
3879
3880 if(dest_conv) {
3881 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
3882 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3883 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3884 dwCount * get_flexible_vertex_size(DestFVF),
3885 dest_conv_addr));
3886 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3887 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3888 }
3889
3890 LEAVE_GL();
3891
3892 return WINED3D_OK;
3893}
3894#undef copy_and_next
3895
3896static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
3897 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
3898 DWORD DestFVF)
3899{
3900 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3901 struct wined3d_stream_info stream_info;
3902 struct wined3d_context *context;
3903 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
3904 HRESULT hr;
3905
3906 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3907
3908 if(pVertexDecl) {
3909 ERR("Output vertex declaration not implemented yet\n");
3910 }
3911
3912 /* Need any context to write to the vbo. */
3913 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
3914
3915 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
3916 * control the streamIsUP flag, thus restore it afterwards.
3917 */
3918 This->stateBlock->streamIsUP = FALSE;
3919 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
3920 This->stateBlock->streamIsUP = streamWasUP;
3921
3922 if(vbo || SrcStartIndex) {
3923 unsigned int i;
3924 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
3925 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
3926 *
3927 * Also get the start index in, but only loop over all elements if there's something to add at all.
3928 */
3929 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
3930 {
3931 struct wined3d_stream_info_element *e;
3932
3933 if (!(stream_info.use_map & (1 << i))) continue;
3934
3935 e = &stream_info.elements[i];
3936 if (e->buffer_object)
3937 {
3938 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
3939 e->buffer_object = 0;
3940 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
3941 ENTER_GL();
3942 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
3943 vb->buffer_object = 0;
3944 LEAVE_GL();
3945 }
3946 if (e->data) e->data += e->stride * SrcStartIndex;
3947 }
3948 }
3949
3950 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
3951 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
3952
3953 context_release(context);
3954
3955 return hr;
3956}
3957
3958/*****
3959 * Get / Set Texture Stage States
3960 * TODO: Verify against dx9 definitions
3961 *****/
3962static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3963 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3964 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3965 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3966
3967 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3968
3969 if (Stage >= gl_info->limits.texture_stages)
3970 {
3971 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
3972 Stage, gl_info->limits.texture_stages - 1);
3973 return WINED3D_OK;
3974 }
3975
3976 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
3977 This->updateStateBlock->textureState[Stage][Type] = Value;
3978
3979 if (This->isRecordingState) {
3980 TRACE("Recording... not performing anything\n");
3981 return WINED3D_OK;
3982 }
3983
3984 /* Checked after the assignments to allow proper stateblock recording */
3985 if(oldValue == Value) {
3986 TRACE("App is setting the old value over, nothing to do\n");
3987 return WINED3D_OK;
3988 }
3989
3990 if(Stage > This->stateBlock->lowest_disabled_stage &&
3991 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3992 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3993 * Changes in other states are important on disabled stages too
3994 */
3995 return WINED3D_OK;
3996 }
3997
3998 if(Type == WINED3DTSS_COLOROP) {
3999 unsigned int i;
4000
4001 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4002 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4003 * they have to be disabled
4004 *
4005 * The current stage is dirtified below.
4006 */
4007 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4008 TRACE("Additionally dirtifying stage %u\n", i);
4009 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4010 }
4011 This->stateBlock->lowest_disabled_stage = Stage;
4012 TRACE("New lowest disabled: %u\n", Stage);
4013 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4014 /* Previously disabled stage enabled. Stages above it may need enabling
4015 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4016 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4017 *
4018 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4019 */
4020
4021 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
4022 {
4023 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4024 break;
4025 }
4026 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4027 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4028 }
4029 This->stateBlock->lowest_disabled_stage = i;
4030 TRACE("New lowest disabled: %u\n", i);
4031 }
4032 }
4033
4034 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4035
4036 return WINED3D_OK;
4037}
4038
4039static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4040 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4041 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4042 *pValue = This->updateStateBlock->textureState[Stage][Type];
4043 return WINED3D_OK;
4044}
4045
4046/*****
4047 * Get / Set Texture
4048 *****/
4049static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4050 DWORD stage, IWineD3DBaseTexture *texture)
4051{
4052 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4053 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4054 IWineD3DBaseTexture *prev;
4055
4056 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4057
4058 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4059 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4060
4061 /* Windows accepts overflowing this array... we do not. */
4062 if (stage >= sizeof(This->stateBlock->textures) / sizeof(*This->stateBlock->textures))
4063 {
4064 WARN("Ignoring invalid stage %u.\n", stage);
4065 return WINED3D_OK;
4066 }
4067
4068 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4069 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4070 {
4071 WARN("Rejecting attempt to set scratch texture.\n");
4072 return WINED3DERR_INVALIDCALL;
4073 }
4074
4075 This->updateStateBlock->changed.textures |= 1 << stage;
4076
4077 prev = This->updateStateBlock->textures[stage];
4078 TRACE("Previous texture %p.\n", prev);
4079
4080 if (texture == prev)
4081 {
4082 TRACE("App is setting the same texture again, nothing to do.\n");
4083 return WINED3D_OK;
4084 }
4085
4086 TRACE("Setting new texture to %p.\n", texture);
4087 This->updateStateBlock->textures[stage] = texture;
4088
4089 if (This->isRecordingState)
4090 {
4091 TRACE("Recording... not performing anything\n");
4092
4093 if (texture) IWineD3DBaseTexture_AddRef(texture);
4094 if (prev) IWineD3DBaseTexture_Release(prev);
4095
4096 return WINED3D_OK;
4097 }
4098
4099 if (texture)
4100 {
4101 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4102 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4103 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(texture);
4104
4105 IWineD3DBaseTexture_AddRef(texture);
4106
4107 if (!prev || dimensions != IWineD3DBaseTexture_GetTextureDimensions(prev))
4108 {
4109 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4110 }
4111
4112 if (!prev && stage < gl_info->limits.texture_stages)
4113 {
4114 /* The source arguments for color and alpha ops have different
4115 * meanings when a NULL texture is bound, so the COLOROP and
4116 * ALPHAOP have to be dirtified. */
4117 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4118 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4119 }
4120
4121 if (bind_count == 1) t->baseTexture.sampler = stage;
4122 }
4123
4124 if (prev)
4125 {
4126 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4127 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4128
4129 IWineD3DBaseTexture_Release(prev);
4130
4131 if (!texture && stage < gl_info->limits.texture_stages)
4132 {
4133 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4134 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4135 }
4136
4137 if (bind_count && t->baseTexture.sampler == stage)
4138 {
4139 unsigned int i;
4140
4141 /* Search for other stages the texture is bound to. Shouldn't
4142 * happen if applications bind textures to a single stage only. */
4143 TRACE("Searching for other stages the texture is bound to.\n");
4144 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4145 {
4146 if (This->updateStateBlock->textures[i] == prev)
4147 {
4148 TRACE("Texture is also bound to stage %u.\n", i);
4149 t->baseTexture.sampler = i;
4150 break;
4151 }
4152 }
4153 }
4154 }
4155
4156 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4157
4158 return WINED3D_OK;
4159}
4160
4161static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4162 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4163
4164 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4165
4166 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4167 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4168 }
4169
4170 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4171 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4172 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4173 }
4174
4175 *ppTexture=This->stateBlock->textures[Stage];
4176 if (*ppTexture)
4177 IWineD3DBaseTexture_AddRef(*ppTexture);
4178
4179 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4180
4181 return WINED3D_OK;
4182}
4183
4184/*****
4185 * Get Back Buffer
4186 *****/
4187static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4188 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4189{
4190 IWineD3DSwapChain *swapchain;
4191 HRESULT hr;
4192
4193 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4194 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4195
4196 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4197 if (FAILED(hr))
4198 {
4199 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4200 return hr;
4201 }
4202
4203 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4204 IWineD3DSwapChain_Release(swapchain);
4205 if (FAILED(hr))
4206 {
4207 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4208 return hr;
4209 }
4210
4211 return WINED3D_OK;
4212}
4213
4214static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4215 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4216 WARN("(%p) : stub, calling idirect3d for now\n", This);
4217 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
4218}
4219
4220static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4221 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4222 IWineD3DSwapChain *swapChain;
4223 HRESULT hr;
4224
4225 if(iSwapChain > 0) {
4226 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4227 if (hr == WINED3D_OK) {
4228 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4229 IWineD3DSwapChain_Release(swapChain);
4230 } else {
4231 FIXME("(%p) Error getting display mode\n", This);
4232 }
4233 } else {
4234 /* Don't read the real display mode,
4235 but return the stored mode instead. X11 can't change the color
4236 depth, and some apps are pretty angry if they SetDisplayMode from
4237 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4238
4239 Also don't relay to the swapchain because with ddraw it's possible
4240 that there isn't a swapchain at all */
4241 pMode->Width = This->ddraw_width;
4242 pMode->Height = This->ddraw_height;
4243 pMode->Format = This->ddraw_format;
4244 pMode->RefreshRate = 0;
4245 hr = WINED3D_OK;
4246 }
4247
4248 return hr;
4249}
4250
4251/*****
4252 * Stateblock related functions
4253 *****/
4254
4255static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4256 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4257 IWineD3DStateBlock *stateblock;
4258 HRESULT hr;
4259
4260 TRACE("(%p)\n", This);
4261
4262 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4263
4264 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4265 if (FAILED(hr)) return hr;
4266
4267 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4268 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4269 This->isRecordingState = TRUE;
4270
4271 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4272
4273 return WINED3D_OK;
4274}
4275
4276static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4277 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4278 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4279
4280 if (!This->isRecordingState) {
4281 WARN("(%p) not recording! returning error\n", This);
4282 *ppStateBlock = NULL;
4283 return WINED3DERR_INVALIDCALL;
4284 }
4285
4286 stateblock_init_contained_states(object);
4287
4288 *ppStateBlock = (IWineD3DStateBlock*) object;
4289 This->isRecordingState = FALSE;
4290 This->updateStateBlock = This->stateBlock;
4291 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4292 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4293 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4294 return WINED3D_OK;
4295}
4296
4297/*****
4298 * Scene related functions
4299 *****/
4300static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4301 /* At the moment we have no need for any functionality at the beginning
4302 of a scene */
4303 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4304 TRACE("(%p)\n", This);
4305
4306 if(This->inScene) {
4307 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4308 return WINED3DERR_INVALIDCALL;
4309 }
4310 This->inScene = TRUE;
4311 return WINED3D_OK;
4312}
4313
4314static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4315{
4316 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4317 struct wined3d_context *context;
4318
4319 TRACE("(%p)\n", This);
4320
4321 if(!This->inScene) {
4322 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4323 return WINED3DERR_INVALIDCALL;
4324 }
4325
4326 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
4327 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4328 wglFlush();
4329 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4330 * fails. */
4331 context_release(context);
4332
4333 This->inScene = FALSE;
4334 return WINED3D_OK;
4335}
4336
4337static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4338 const RECT *pSourceRect, const RECT *pDestRect,
4339 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4340{
4341 IWineD3DSwapChain *swapChain = NULL;
4342 int i;
4343 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4344
4345 TRACE("iface %p.\n", iface);
4346
4347 for(i = 0 ; i < swapchains ; i ++) {
4348
4349 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4350 TRACE("presentinng chain %d, %p\n", i, swapChain);
4351 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4352 IWineD3DSwapChain_Release(swapChain);
4353 }
4354
4355 return WINED3D_OK;
4356}
4357
4358static BOOL is_full_clear(IWineD3DSurfaceImpl *target, const WINED3DVIEWPORT *viewport,
4359 const RECT *scissor_rect, const WINED3DRECT *clear_rect)
4360{
4361 /* partial viewport*/
4362 if (viewport->X != 0 || viewport->Y != 0
4363 || viewport->Width < target->currentDesc.Width
4364 || viewport->Height < target->currentDesc.Height)
4365 return FALSE;
4366
4367 /* partial scissor rect */
4368 if (scissor_rect && (scissor_rect->left > 0 || scissor_rect->top > 0
4369 || scissor_rect->right < target->currentDesc.Width
4370 || scissor_rect->bottom < target->currentDesc.Height))
4371 return FALSE;
4372
4373 /* partial clear rect */
4374 if (clear_rect && (clear_rect->x1 > 0 || clear_rect->y1 > 0
4375 || clear_rect->x2 < target->currentDesc.Width
4376 || clear_rect->y2 < target->currentDesc.Height))
4377 return FALSE;
4378
4379 return TRUE;
4380}
4381
4382/* Not called from the VTable (internal subroutine) */
4383HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4384 const WINED3DRECT *pRects, DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil)
4385{
4386 IWineD3DStateBlockImpl *stateblock = This->stateBlock;
4387 const RECT *scissor_rect = stateblock->renderState[WINED3DRS_SCISSORTESTENABLE] ? &stateblock->scissorRect : NULL;
4388 const WINED3DRECT *clear_rect = (Count > 0 && pRects) ? pRects : NULL;
4389 const WINED3DVIEWPORT *vp = &stateblock->viewport;
4390 GLbitfield glMask = 0;
4391 unsigned int i;
4392 WINED3DRECT curRect;
4393 RECT vp_rect;
4394 UINT drawable_width, drawable_height;
4395 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4396 struct wined3d_context *context;
4397
4398 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4399 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4400 * for the cleared parts, and the untouched parts.
4401 *
4402 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4403 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4404 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4405 * checking all this if the dest surface is in the drawable anyway.
4406 */
4407 if (Flags & WINED3DCLEAR_TARGET && !(target->Flags & SFLAG_INDRAWABLE))
4408 {
4409 if (!is_full_clear(target, vp, scissor_rect, clear_rect))
4410 IWineD3DSurface_LoadLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, NULL);
4411 }
4412
4413 context = context_acquire(This, (IWineD3DSurface *)target, CTXUSAGE_CLEAR);
4414 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
4415 {
4416 if (!surface_is_offscreen((IWineD3DSurface *)target))
4417 {
4418 TRACE("Surface %p is onscreen\n", target);
4419
4420 ENTER_GL();
4421 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
4422 context_set_draw_buffer(context, surface_get_gl_buffer((IWineD3DSurface *)target));
4423 LEAVE_GL();
4424 }
4425 else
4426 {
4427 TRACE("Surface %p is offscreen\n", target);
4428
4429 ENTER_GL();
4430 context_bind_fbo(context, GL_FRAMEBUFFER, &context->dst_fbo);
4431 context_attach_surface_fbo(context, GL_FRAMEBUFFER, 0, target);
4432 context_attach_depth_stencil_fbo(context, GL_FRAMEBUFFER, depth_stencil, TRUE);
4433 LEAVE_GL();
4434 }
4435 }
4436
4437 if (!context->valid)
4438 {
4439 context_release(context);
4440 WARN("Invalid context, skipping clear.\n");
4441 return WINED3D_OK;
4442 }
4443
4444 target->get_drawable_size(context, &drawable_width, &drawable_height);
4445
4446 ENTER_GL();
4447
4448 /* Only set the values up once, as they are not changing */
4449 if (Flags & WINED3DCLEAR_STENCIL)
4450 {
4451 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
4452 {
4453 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
4454 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_TWOSIDEDSTENCILMODE));
4455 }
4456 glStencilMask(~0U);
4457 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
4458 glClearStencil(Stencil);
4459 checkGLcall("glClearStencil");
4460 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4461 }
4462
4463 if (Flags & WINED3DCLEAR_ZBUFFER)
4464 {
4465 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4466 if (!(depth_stencil->Flags & location) && !is_full_clear(depth_stencil, vp, scissor_rect, clear_rect))
4467 surface_load_ds_location(This->stencilBufferTarget, context, location);
4468
4469 glDepthMask(GL_TRUE);
4470 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4471 glClearDepth(Z);
4472 checkGLcall("glClearDepth");
4473 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4474 }
4475
4476 if (Flags & WINED3DCLEAR_TARGET)
4477 {
4478 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4479 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
4480 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
4481 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
4482 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
4483 glClearColor(D3DCOLOR_R(Color), D3DCOLOR_G(Color), D3DCOLOR_B(Color), D3DCOLOR_A(Color));
4484 checkGLcall("glClearColor");
4485 glMask = glMask | GL_COLOR_BUFFER_BIT;
4486 }
4487
4488 vp_rect.left = vp->X;
4489 vp_rect.top = vp->Y;
4490 vp_rect.right = vp->X + vp->Width;
4491 vp_rect.bottom = vp->Y + vp->Height;
4492 if (!(Count > 0 && pRects)) {
4493 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4494 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4495 }
4496 if (context->render_offscreen)
4497 {
4498 glScissor(vp_rect.left, vp_rect.top,
4499 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4500 } else {
4501 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
4502 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4503 }
4504 checkGLcall("glScissor");
4505 glClear(glMask);
4506 checkGLcall("glClear");
4507 } else {
4508 /* Now process each rect in turn */
4509 for (i = 0; i < Count; i++) {
4510 /* Note gl uses lower left, width/height */
4511 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
4512 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4513 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
4514 }
4515 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
4516 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
4517 curRect.x1, (target->currentDesc.Height - curRect.y2),
4518 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4519
4520 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4521 * The rectangle is not cleared, no error is returned, but further rectanlges are
4522 * still cleared if they are valid
4523 */
4524 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
4525 TRACE("Rectangle with negative dimensions, ignoring\n");
4526 continue;
4527 }
4528
4529 if (context->render_offscreen)
4530 {
4531 glScissor(curRect.x1, curRect.y1,
4532 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4533 } else {
4534 glScissor(curRect.x1, drawable_height - curRect.y2,
4535 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4536 }
4537 checkGLcall("glScissor");
4538
4539 glClear(glMask);
4540 checkGLcall("glClear");
4541 }
4542 }
4543
4544 if (Flags & WINED3DCLEAR_TARGET)
4545 {
4546 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, TRUE);
4547 }
4548 if (Flags & WINED3DCLEAR_ZBUFFER) {
4549 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
4550 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4551 surface_modify_ds_location(This->stencilBufferTarget, location);
4552 }
4553
4554 LEAVE_GL();
4555
4556 if (wined3d_settings.strict_draw_ordering || ((target->Flags & SFLAG_SWAPCHAIN)
4557 && ((IWineD3DSwapChainImpl *)target->container)->frontBuffer == (IWineD3DSurface *)target))
4558 wglFlush(); /* Flush to ensure ordering across contexts. */
4559
4560 context_release(context);
4561
4562 return WINED3D_OK;
4563}
4564
4565static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4566 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4567 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4568 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4569
4570 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4571 Count, pRects, Flags, Color, Z, Stencil);
4572
4573 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4574 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4575 /* TODO: What about depth stencil buffers without stencil bits? */
4576 return WINED3DERR_INVALIDCALL;
4577 }
4578
4579 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
4580}
4581
4582/*****
4583 * Drawing functions
4584 *****/
4585
4586static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4587 WINED3DPRIMITIVETYPE primitive_type)
4588{
4589 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4590
4591 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4592
4593 This->updateStateBlock->changed.primitive_type = TRUE;
4594 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4595}
4596
4597static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4598 WINED3DPRIMITIVETYPE *primitive_type)
4599{
4600 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4601
4602 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4603
4604 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
4605
4606 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4607}
4608
4609static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4610{
4611 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4612
4613 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4614
4615 if(!This->stateBlock->vertexDecl) {
4616 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4617 return WINED3DERR_INVALIDCALL;
4618 }
4619
4620 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4621 if(This->stateBlock->streamIsUP) {
4622 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4623 This->stateBlock->streamIsUP = FALSE;
4624 }
4625
4626 if(This->stateBlock->loadBaseVertexIndex != 0) {
4627 This->stateBlock->loadBaseVertexIndex = 0;
4628 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4629 }
4630 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4631 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4632 return WINED3D_OK;
4633}
4634
4635static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4636{
4637 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4638 UINT idxStride = 2;
4639 IWineD3DBuffer *pIB;
4640 GLuint vbo;
4641
4642 pIB = This->stateBlock->pIndexData;
4643 if (!pIB) {
4644 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4645 * without an index buffer set. (The first time at least...)
4646 * D3D8 simply dies, but I doubt it can do much harm to return
4647 * D3DERR_INVALIDCALL there as well. */
4648 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4649 return WINED3DERR_INVALIDCALL;
4650 }
4651
4652 if(!This->stateBlock->vertexDecl) {
4653 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4654 return WINED3DERR_INVALIDCALL;
4655 }
4656
4657 if(This->stateBlock->streamIsUP) {
4658 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4659 This->stateBlock->streamIsUP = FALSE;
4660 }
4661 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
4662
4663 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4664
4665 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
4666 idxStride = 2;
4667 } else {
4668 idxStride = 4;
4669 }
4670
4671 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4672 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4673 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4674 }
4675
4676 drawPrimitive(iface, index_count, startIndex, idxStride,
4677 vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
4678
4679 return WINED3D_OK;
4680}
4681
4682static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4683 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4684{
4685 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4686 IWineD3DBuffer *vb;
4687
4688 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4689 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4690
4691 if(!This->stateBlock->vertexDecl) {
4692 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4693 return WINED3DERR_INVALIDCALL;
4694 }
4695
4696 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4697 vb = This->stateBlock->streamSource[0];
4698 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4699 if (vb) IWineD3DBuffer_Release(vb);
4700 This->stateBlock->streamOffset[0] = 0;
4701 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4702 This->stateBlock->streamIsUP = TRUE;
4703 This->stateBlock->loadBaseVertexIndex = 0;
4704
4705 /* TODO: Only mark dirty if drawing from a different UP address */
4706 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4707
4708 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4709
4710 /* MSDN specifies stream zero settings must be set to NULL */
4711 This->stateBlock->streamStride[0] = 0;
4712 This->stateBlock->streamSource[0] = NULL;
4713
4714 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4715 * the new stream sources or use UP drawing again
4716 */
4717 return WINED3D_OK;
4718}
4719
4720static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4721 UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
4722 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4723{
4724 int idxStride;
4725 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4726 IWineD3DBuffer *vb;
4727 IWineD3DBuffer *ib;
4728
4729 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4730 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4731
4732 if(!This->stateBlock->vertexDecl) {
4733 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4734 return WINED3DERR_INVALIDCALL;
4735 }
4736
4737 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4738 idxStride = 2;
4739 } else {
4740 idxStride = 4;
4741 }
4742
4743 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4744 vb = This->stateBlock->streamSource[0];
4745 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4746 if (vb) IWineD3DBuffer_Release(vb);
4747 This->stateBlock->streamIsUP = TRUE;
4748 This->stateBlock->streamOffset[0] = 0;
4749 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4750
4751 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4752 This->stateBlock->baseVertexIndex = 0;
4753 This->stateBlock->loadBaseVertexIndex = 0;
4754 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4755 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4756 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4757
4758 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4759
4760 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4761 This->stateBlock->streamSource[0] = NULL;
4762 This->stateBlock->streamStride[0] = 0;
4763 ib = This->stateBlock->pIndexData;
4764 if(ib) {
4765 IWineD3DBuffer_Release(ib);
4766 This->stateBlock->pIndexData = NULL;
4767 }
4768 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4769 * SetStreamSource to specify a vertex buffer
4770 */
4771
4772 return WINED3D_OK;
4773}
4774
4775static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4776 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4777{
4778 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4779
4780 /* Mark the state dirty until we have nicer tracking
4781 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4782 * that value.
4783 */
4784 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4785 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4786 This->stateBlock->baseVertexIndex = 0;
4787 This->up_strided = DrawPrimStrideData;
4788 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4789 This->up_strided = NULL;
4790 return WINED3D_OK;
4791}
4792
4793static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4794 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4795 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
4796{
4797 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4798 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4799
4800 /* Mark the state dirty until we have nicer tracking
4801 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4802 * that value.
4803 */
4804 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4805 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4806 This->stateBlock->streamIsUP = TRUE;
4807 This->stateBlock->baseVertexIndex = 0;
4808 This->up_strided = DrawPrimStrideData;
4809 drawPrimitive(iface, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4810 This->up_strided = NULL;
4811 return WINED3D_OK;
4812}
4813
4814/* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4815static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
4816 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
4817{
4818 WINED3DLOCKED_BOX src;
4819 WINED3DLOCKED_BOX dst;
4820 HRESULT hr;
4821
4822 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
4823 iface, pSourceVolume, pDestinationVolume);
4824
4825 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4826 * dirtification to improve loading performance.
4827 */
4828 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4829 if(FAILED(hr)) return hr;
4830 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4831 if(FAILED(hr)) {
4832 IWineD3DVolume_UnlockBox(pSourceVolume);
4833 return hr;
4834 }
4835
4836 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
4837
4838 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
4839 if(FAILED(hr)) {
4840 IWineD3DVolume_UnlockBox(pSourceVolume);
4841 } else {
4842 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
4843 }
4844 return hr;
4845}
4846
4847static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
4848 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
4849{
4850 unsigned int level_count, i;
4851 WINED3DRESOURCETYPE type;
4852 HRESULT hr;
4853
4854 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
4855
4856 /* Verify that the source and destination textures are non-NULL. */
4857 if (!src_texture || !dst_texture)
4858 {
4859 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4860 return WINED3DERR_INVALIDCALL;
4861 }
4862
4863 if (src_texture == dst_texture)
4864 {
4865 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4866 return WINED3DERR_INVALIDCALL;
4867 }
4868
4869 /* Verify that the source and destination textures are the same type. */
4870 type = IWineD3DBaseTexture_GetType(src_texture);
4871 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
4872 {
4873 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4874 return WINED3DERR_INVALIDCALL;
4875 }
4876
4877 /* Check that both textures have the identical numbers of levels. */
4878 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
4879 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
4880 {
4881 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4882 return WINED3DERR_INVALIDCALL;
4883 }
4884
4885 /* Make sure that the destination texture is loaded. */
4886 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
4887
4888 /* Update every surface level of the texture. */
4889 switch (type)
4890 {
4891 case WINED3DRTYPE_TEXTURE:
4892 {
4893 IWineD3DSurface *src_surface;
4894 IWineD3DSurface *dst_surface;
4895
4896 for (i = 0; i < level_count; ++i)
4897 {
4898 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
4899 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
4900 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4901 IWineD3DSurface_Release(dst_surface);
4902 IWineD3DSurface_Release(src_surface);
4903 if (FAILED(hr))
4904 {
4905 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4906 return hr;
4907 }
4908 }
4909 break;
4910 }
4911
4912 case WINED3DRTYPE_CUBETEXTURE:
4913 {
4914 IWineD3DSurface *src_surface;
4915 IWineD3DSurface *dst_surface;
4916 WINED3DCUBEMAP_FACES face;
4917
4918 for (i = 0; i < level_count; ++i)
4919 {
4920 /* Update each cube face. */
4921 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
4922 {
4923 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
4924 face, i, &src_surface);
4925 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4926 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
4927 face, i, &dst_surface);
4928 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4929 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4930 IWineD3DSurface_Release(dst_surface);
4931 IWineD3DSurface_Release(src_surface);
4932 if (FAILED(hr))
4933 {
4934 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4935 return hr;
4936 }
4937 }
4938 }
4939 break;
4940 }
4941
4942 case WINED3DRTYPE_VOLUMETEXTURE:
4943 {
4944 IWineD3DVolume *src_volume;
4945 IWineD3DVolume *dst_volume;
4946
4947 for (i = 0; i < level_count; ++i)
4948 {
4949 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
4950 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
4951 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
4952 IWineD3DVolume_Release(dst_volume);
4953 IWineD3DVolume_Release(src_volume);
4954 if (FAILED(hr))
4955 {
4956 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
4957 return hr;
4958 }
4959 }
4960 break;
4961 }
4962
4963 default:
4964 FIXME("Unsupported texture type %#x.\n", type);
4965 return WINED3DERR_INVALIDCALL;
4966 }
4967
4968 return WINED3D_OK;
4969}
4970
4971static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4972 IWineD3DSwapChain *swapChain;
4973 HRESULT hr;
4974 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4975 if(hr == WINED3D_OK) {
4976 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4977 IWineD3DSwapChain_Release(swapChain);
4978 }
4979 return hr;
4980}
4981
4982static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4983 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4984 IWineD3DBaseTextureImpl *texture;
4985 DWORD i;
4986
4987 TRACE("(%p) : %p\n", This, pNumPasses);
4988
4989 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4990 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
4991 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4992 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4993 }
4994 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
4995 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4996 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4997 }
4998
4999 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5000 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5001
5002 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5003 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5004 return E_FAIL;
5005 }
5006 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5007 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5008 return E_FAIL;
5009 }
5010 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5011 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5012 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5013 return E_FAIL;
5014 }
5015 }
5016
5017 /* return a sensible default */
5018 *pNumPasses = 1;
5019
5020 TRACE("returning D3D_OK\n");
5021 return WINED3D_OK;
5022}
5023
5024static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5025{
5026 int i;
5027
5028 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5029 {
5030 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5031 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8_UINT
5032 || texture->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM))
5033 {
5034 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5035 }
5036 }
5037}
5038
5039static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5040 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5041 int j;
5042 UINT NewSize;
5043 PALETTEENTRY **palettes;
5044
5045 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5046
5047 if (PaletteNumber >= MAX_PALETTES) {
5048 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5049 return WINED3DERR_INVALIDCALL;
5050 }
5051
5052 if (PaletteNumber >= This->NumberOfPalettes) {
5053 NewSize = This->NumberOfPalettes;
5054 do {
5055 NewSize *= 2;
5056 } while(PaletteNumber >= NewSize);
5057 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5058 if (!palettes) {
5059 ERR("Out of memory!\n");
5060 return E_OUTOFMEMORY;
5061 }
5062 This->palettes = palettes;
5063 This->NumberOfPalettes = NewSize;
5064 }
5065
5066 if (!This->palettes[PaletteNumber]) {
5067 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5068 if (!This->palettes[PaletteNumber]) {
5069 ERR("Out of memory!\n");
5070 return E_OUTOFMEMORY;
5071 }
5072 }
5073
5074 for (j = 0; j < 256; ++j) {
5075 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5076 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5077 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5078 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5079 }
5080 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5081 TRACE("(%p) : returning\n", This);
5082 return WINED3D_OK;
5083}
5084
5085static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5086 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5087 int j;
5088 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5089 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5090 /* What happens in such situation isn't documented; Native seems to silently abort
5091 on such conditions. Return Invalid Call. */
5092 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5093 return WINED3DERR_INVALIDCALL;
5094 }
5095 for (j = 0; j < 256; ++j) {
5096 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5097 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5098 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5099 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5100 }
5101 TRACE("(%p) : returning\n", This);
5102 return WINED3D_OK;
5103}
5104
5105static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5106 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5107 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5108 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5109 (tested with reference rasterizer). Return Invalid Call. */
5110 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5111 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5112 return WINED3DERR_INVALIDCALL;
5113 }
5114 /*TODO: stateblocks */
5115 if (This->currentPalette != PaletteNumber) {
5116 This->currentPalette = PaletteNumber;
5117 dirtify_p8_texture_samplers(This);
5118 }
5119 TRACE("(%p) : returning\n", This);
5120 return WINED3D_OK;
5121}
5122
5123static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5124 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5125 if (PaletteNumber == NULL) {
5126 WARN("(%p) : returning Invalid Call\n", This);
5127 return WINED3DERR_INVALIDCALL;
5128 }
5129 /*TODO: stateblocks */
5130 *PaletteNumber = This->currentPalette;
5131 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5132 return WINED3D_OK;
5133}
5134
5135static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5136 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5137 static BOOL warned;
5138 if (!warned)
5139 {
5140 FIXME("(%p) : stub\n", This);
5141 warned = TRUE;
5142 }
5143
5144 This->softwareVertexProcessing = bSoftware;
5145 return WINED3D_OK;
5146}
5147
5148
5149static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5150 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5151 static BOOL warned;
5152 if (!warned)
5153 {
5154 FIXME("(%p) : stub\n", This);
5155 warned = TRUE;
5156 }
5157 return This->softwareVertexProcessing;
5158}
5159
5160static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5161 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5162{
5163 IWineD3DSwapChain *swapchain;
5164 HRESULT hr;
5165
5166 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5167 iface, swapchain_idx, raster_status);
5168
5169 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5170 if (FAILED(hr))
5171 {
5172 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5173 return hr;
5174 }
5175
5176 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5177 IWineD3DSwapChain_Release(swapchain);
5178 if (FAILED(hr))
5179 {
5180 WARN("Failed to get raster status, hr %#x.\n", hr);
5181 return hr;
5182 }
5183
5184 return WINED3D_OK;
5185}
5186
5187static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5188{
5189 static BOOL warned;
5190 if(nSegments != 0.0f) {
5191 if (!warned)
5192 {
5193 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5194 warned = TRUE;
5195 }
5196 }
5197 return WINED3D_OK;
5198}
5199
5200static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5201{
5202 static BOOL warned;
5203 if (!warned)
5204 {
5205 FIXME("iface %p stub!\n", iface);
5206 warned = TRUE;
5207 }
5208 return 0.0f;
5209}
5210
5211static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface,
5212 IWineD3DSurface *src_surface, const RECT *src_rect,
5213 IWineD3DSurface *dst_surface, const POINT *dst_point)
5214{
5215 IWineD3DSurfaceImpl *src_impl = (IWineD3DSurfaceImpl *)src_surface;
5216 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)dst_surface;
5217 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5218 const struct wined3d_format_desc *src_format;
5219 const struct wined3d_format_desc *dst_format;
5220 struct wined3d_context *context;
5221 const unsigned char *data;
5222 UINT update_w, update_h;
5223 CONVERT_TYPES convert;
5224 UINT src_w, src_h;
5225 UINT dst_x, dst_y;
5226 DWORD sampler;
5227 struct wined3d_format_desc dummy_desc;
5228
5229 TRACE("iface %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s",
5230 iface, src_surface, wine_dbgstr_rect(src_rect),
5231 dst_surface, wine_dbgstr_point(dst_point));
5232
5233 if (src_impl->resource.pool != WINED3DPOOL_SYSTEMMEM || dst_impl->resource.pool != WINED3DPOOL_DEFAULT)
5234 {
5235 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
5236 src_surface, dst_surface);
5237 return WINED3DERR_INVALIDCALL;
5238 }
5239
5240 src_format = src_impl->resource.format_desc;
5241 dst_format = dst_impl->resource.format_desc;
5242
5243 if (src_format->format != dst_format->format)
5244 {
5245 WARN("Source and destination surfaces should have the same format.\n");
5246 return WINED3DERR_INVALIDCALL;
5247 }
5248
5249 dst_x = dst_point ? dst_point->x : 0;
5250 dst_y = dst_point ? dst_point->y : 0;
5251
5252 /* This call loads the OpenGL surface directly, instead of copying the
5253 * surface to the destination's sysmem copy. If surface conversion is
5254 * needed, use BltFast instead to copy in sysmem and use regular surface
5255 * loading. */
5256 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &dummy_desc, &convert);
5257 if (convert != NO_CONVERSION)
5258 return IWineD3DSurface_BltFast(dst_surface, dst_x, dst_y, src_surface, src_rect, 0);
5259
5260 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5261
5262 ENTER_GL();
5263 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5264 checkGLcall("glActiveTextureARB");
5265 LEAVE_GL();
5266
5267 /* Make sure the surface is loaded and up to date */
5268 surface_internal_preload(dst_surface, SRGB_RGB);
5269 IWineD3DSurface_BindTexture(dst_surface, FALSE);
5270
5271 src_w = src_impl->currentDesc.Width;
5272 src_h = src_impl->currentDesc.Height;
5273 update_w = src_rect ? src_rect->right - src_rect->left : src_w;
5274 update_h = src_rect ? src_rect->bottom - src_rect->top : src_h;
5275
5276 data = IWineD3DSurface_GetData(src_surface);
5277 if (!data) ERR("Source surface has no allocated memory, but should be a sysmem surface.\n");
5278
5279 ENTER_GL();
5280
5281 if (dst_format->Flags & WINED3DFMT_FLAG_COMPRESSED)
5282 {
5283 UINT row_length = (update_w / src_format->block_width) * src_format->block_byte_count;
5284 UINT row_count = update_h / src_format->block_height;
5285 UINT src_pitch = IWineD3DSurface_GetPitch(src_surface);
5286
5287 if (src_rect)
5288 {
5289 data += (src_rect->top / src_format->block_height) * src_pitch;
5290 data += (src_rect->left / src_format->block_width) * src_format->block_byte_count;
5291 }
5292
5293 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
5294 "format %#x, image_size %#x, data %p.\n", dst_impl->texture_target, dst_impl->texture_level,
5295 dst_x, dst_y, update_w, update_h, dst_format->glFormat, row_count * row_length, data);
5296
5297 if (row_length == src_pitch)
5298 {
5299 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5300 dst_x, dst_y, update_w, update_h, dst_format->glInternal, row_count * row_length, data));
5301 }
5302 else
5303 {
5304 UINT row, y;
5305
5306 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
5307 * can't use the unpack row length like below. */
5308 for (row = 0, y = dst_y; row < row_count; ++row)
5309 {
5310 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5311 dst_x, y, update_w, src_format->block_height, dst_format->glInternal, row_length, data));
5312 y += src_format->block_height;
5313 data += src_pitch;
5314 }
5315 }
5316 checkGLcall("glCompressedTexSubImage2DARB");
5317 }
5318 else
5319 {
5320 if (src_rect)
5321 {
5322 data += src_rect->top * src_w * src_format->byte_count;
5323 data += src_rect->left * src_format->byte_count;
5324 }
5325
5326 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, data %p.\n",
5327 dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5328 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5329
5330 glPixelStorei(GL_UNPACK_ROW_LENGTH, src_w);
5331 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5332 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5333 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
5334 checkGLcall("glTexSubImage2D");
5335 }
5336
5337 LEAVE_GL();
5338 context_release(context);
5339
5340 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INTEXTURE, TRUE);
5341 sampler = This->rev_tex_unit_map[0];
5342 if (sampler != WINED3D_UNMAPPED_STAGE)
5343 {
5344 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5345 }
5346
5347 return WINED3D_OK;
5348}
5349
5350static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5351 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5352 struct WineD3DRectPatch *patch;
5353 GLenum old_primitive_type;
5354 unsigned int i;
5355 struct list *e;
5356 BOOL found;
5357 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5358
5359 if(!(Handle || pRectPatchInfo)) {
5360 /* TODO: Write a test for the return value, thus the FIXME */
5361 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5362 return WINED3DERR_INVALIDCALL;
5363 }
5364
5365 if(Handle) {
5366 i = PATCHMAP_HASHFUNC(Handle);
5367 found = FALSE;
5368 LIST_FOR_EACH(e, &This->patches[i]) {
5369 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5370 if(patch->Handle == Handle) {
5371 found = TRUE;
5372 break;
5373 }
5374 }
5375
5376 if(!found) {
5377 TRACE("Patch does not exist. Creating a new one\n");
5378 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5379 patch->Handle = Handle;
5380 list_add_head(&This->patches[i], &patch->entry);
5381 } else {
5382 TRACE("Found existing patch %p\n", patch);
5383 }
5384 } else {
5385 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5386 * attributes we have to tesselate, read back, and draw. This needs a patch
5387 * management structure instance. Create one.
5388 *
5389 * A possible improvement is to check if a vertex shader is used, and if not directly
5390 * draw the patch.
5391 */
5392 FIXME("Drawing an uncached patch. This is slow\n");
5393 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5394 }
5395
5396 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5397 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5398 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5399 HRESULT hr;
5400 TRACE("Tesselation density or patch info changed, retesselating\n");
5401
5402 if(pRectPatchInfo) {
5403 patch->RectPatchInfo = *pRectPatchInfo;
5404 }
5405 patch->numSegs[0] = pNumSegs[0];
5406 patch->numSegs[1] = pNumSegs[1];
5407 patch->numSegs[2] = pNumSegs[2];
5408 patch->numSegs[3] = pNumSegs[3];
5409
5410 hr = tesselate_rectpatch(This, patch);
5411 if(FAILED(hr)) {
5412 WARN("Patch tesselation failed\n");
5413
5414 /* Do not release the handle to store the params of the patch */
5415 if(!Handle) {
5416 HeapFree(GetProcessHeap(), 0, patch);
5417 }
5418 return hr;
5419 }
5420 }
5421
5422 This->currentPatch = patch;
5423 old_primitive_type = This->stateBlock->gl_primitive_type;
5424 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5425 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5426 This->stateBlock->gl_primitive_type = old_primitive_type;
5427 This->currentPatch = NULL;
5428
5429 /* Destroy uncached patches */
5430 if(!Handle) {
5431 HeapFree(GetProcessHeap(), 0, patch->mem);
5432 HeapFree(GetProcessHeap(), 0, patch);
5433 }
5434 return WINED3D_OK;
5435}
5436
5437static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5438 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5439{
5440 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5441 iface, handle, segment_count, patch_info);
5442
5443 return WINED3D_OK;
5444}
5445
5446static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5447 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5448 int i;
5449 struct WineD3DRectPatch *patch;
5450 struct list *e;
5451 TRACE("(%p) Handle(%d)\n", This, Handle);
5452
5453 i = PATCHMAP_HASHFUNC(Handle);
5454 LIST_FOR_EACH(e, &This->patches[i]) {
5455 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5456 if(patch->Handle == Handle) {
5457 TRACE("Deleting patch %p\n", patch);
5458 list_remove(&patch->entry);
5459 HeapFree(GetProcessHeap(), 0, patch->mem);
5460 HeapFree(GetProcessHeap(), 0, patch);
5461 return WINED3D_OK;
5462 }
5463 }
5464
5465 /* TODO: Write a test for the return value */
5466 FIXME("Attempt to destroy nonexistent patch\n");
5467 return WINED3DERR_INVALIDCALL;
5468}
5469
5470static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
5471 const WINED3DRECT *rect, const float color[4])
5472{
5473 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5474 struct wined3d_context *context;
5475
5476 if (rect) IWineD3DSurface_LoadLocation(surface, SFLAG_INDRAWABLE, NULL);
5477 IWineD3DSurface_ModifyLocation(surface, SFLAG_INDRAWABLE, TRUE);
5478
5479 if (!surface_is_offscreen(surface))
5480 {
5481 TRACE("Surface %p is onscreen\n", surface);
5482
5483 context = context_acquire(This, surface, CTXUSAGE_RESOURCELOAD);
5484 ENTER_GL();
5485 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
5486 context_set_draw_buffer(context, surface_get_gl_buffer(surface));
5487 }
5488 else
5489 {
5490 TRACE("Surface %p is offscreen\n", surface);
5491
5492 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5493 ENTER_GL();
5494 context_bind_fbo(context, GL_FRAMEBUFFER, &context->dst_fbo);
5495 context_attach_surface_fbo(context, GL_FRAMEBUFFER, 0, (IWineD3DSurfaceImpl *)surface);
5496 context_attach_depth_stencil_fbo(context, GL_FRAMEBUFFER, NULL, FALSE);
5497 }
5498
5499 if (rect) {
5500 glEnable(GL_SCISSOR_TEST);
5501 if(surface_is_offscreen(surface)) {
5502 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5503 } else {
5504 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5505 rect->x2 - rect->x1, rect->y2 - rect->y1);
5506 }
5507 checkGLcall("glScissor");
5508 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5509 } else {
5510 glDisable(GL_SCISSOR_TEST);
5511 }
5512 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5513
5514 glDisable(GL_BLEND);
5515 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
5516
5517 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5518 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5519 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
5520 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
5521 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
5522
5523 glClearColor(color[0], color[1], color[2], color[3]);
5524 glClear(GL_COLOR_BUFFER_BIT);
5525 checkGLcall("glClear");
5526
5527 LEAVE_GL();
5528
5529 if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
5530
5531 context_release(context);
5532}
5533
5534static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5535 IWineD3DSurface *pSurface, const WINED3DRECT *pRect, WINED3DCOLOR color)
5536{
5537 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5538 WINEDDBLTFX BltFx;
5539
5540 TRACE("iface %p, surface %p, rect %p, color 0x%08x.\n", iface, pSurface, pRect, color);
5541
5542 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5543 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5544 return WINED3DERR_INVALIDCALL;
5545 }
5546
5547 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5548 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
5549 color_fill_fbo(iface, pSurface, pRect, c);
5550 return WINED3D_OK;
5551 } else {
5552 /* Just forward this to the DirectDraw blitting engine */
5553 memset(&BltFx, 0, sizeof(BltFx));
5554 BltFx.dwSize = sizeof(BltFx);
5555 BltFx.u5.dwFillColor = color_convert_argb_to_fmt(color, surface->resource.format_desc->format);
5556 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
5557 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5558 }
5559}
5560
5561static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5562 IWineD3DRendertargetView *rendertarget_view, const float color[4])
5563{
5564 IWineD3DResource *resource;
5565 IWineD3DSurface *surface;
5566 HRESULT hr;
5567
5568 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5569 if (FAILED(hr))
5570 {
5571 ERR("Failed to get resource, hr %#x\n", hr);
5572 return;
5573 }
5574
5575 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5576 {
5577 FIXME("Only supported on surface resources\n");
5578 IWineD3DResource_Release(resource);
5579 return;
5580 }
5581
5582 surface = (IWineD3DSurface *)resource;
5583
5584 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
5585 {
5586 color_fill_fbo(iface, surface, NULL, color);
5587 }
5588 else
5589 {
5590 WINEDDBLTFX BltFx;
5591 WINED3DCOLOR c;
5592
5593 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
5594
5595 c = ((DWORD)(color[2] * 255.0f));
5596 c |= ((DWORD)(color[1] * 255.0f)) << 8;
5597 c |= ((DWORD)(color[0] * 255.0f)) << 16;
5598 c |= ((DWORD)(color[3] * 255.0f)) << 24;
5599
5600 /* Just forward this to the DirectDraw blitting engine */
5601 memset(&BltFx, 0, sizeof(BltFx));
5602 BltFx.dwSize = sizeof(BltFx);
5603 BltFx.u5.dwFillColor = color_convert_argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
5604 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5605 if (FAILED(hr))
5606 {
5607 ERR("Blt failed, hr %#x\n", hr);
5608 }
5609 }
5610
5611 IWineD3DResource_Release(resource);
5612}
5613
5614/* rendertarget and depth stencil functions */
5615static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5616 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5617
5618 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5619 {
5620 ERR("(%p) : Only %d render targets are supported.\n",
5621 This, This->adapter->gl_info.limits.buffers);
5622 return WINED3DERR_INVALIDCALL;
5623 }
5624
5625 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5626 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5627 /* Note inc ref on returned surface */
5628 if(*ppRenderTarget != NULL)
5629 IWineD3DSurface_AddRef(*ppRenderTarget);
5630 return WINED3D_OK;
5631}
5632
5633static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface,
5634 IWineD3DSurface *front, IWineD3DSurface *back)
5635{
5636 IWineD3DSurfaceImpl *front_impl = (IWineD3DSurfaceImpl *)front;
5637 IWineD3DSurfaceImpl *back_impl = (IWineD3DSurfaceImpl *)back;
5638 IWineD3DSwapChainImpl *swapchain;
5639 HRESULT hr;
5640
5641 TRACE("iface %p, front %p, back %p.\n", iface, front, back);
5642
5643 if (FAILED(hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **)&swapchain)))
5644 {
5645 ERR("Failed to get the swapchain, hr %#x.\n", hr);
5646 return hr;
5647 }
5648
5649 if (front_impl && !(front_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5650 {
5651 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5652 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5653 return WINED3DERR_INVALIDCALL;
5654 }
5655
5656 if (back_impl)
5657 {
5658 if (!(back_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5659 {
5660 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5661 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5662 return WINED3DERR_INVALIDCALL;
5663 }
5664
5665 if (!swapchain->backBuffer)
5666 {
5667 swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*swapchain->backBuffer));
5668 if (!swapchain->backBuffer)
5669 {
5670 ERR("Failed to allocate back buffer array memory.\n");
5671 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5672 return E_OUTOFMEMORY;
5673 }
5674 }
5675 }
5676
5677 if (swapchain->frontBuffer != front)
5678 {
5679 TRACE("Changing the front buffer from %p to %p.\n", swapchain->frontBuffer, front);
5680
5681 if (swapchain->frontBuffer)
5682 {
5683 IWineD3DSurface_SetContainer(swapchain->frontBuffer, NULL);
5684 ((IWineD3DSurfaceImpl *)swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
5685 }
5686 swapchain->frontBuffer = front;
5687
5688 if (front)
5689 {
5690 IWineD3DSurface_SetContainer(front, (IWineD3DBase *)swapchain);
5691 front_impl->Flags |= SFLAG_SWAPCHAIN;
5692 }
5693 }
5694
5695 if (swapchain->backBuffer[0] != back)
5696 {
5697 TRACE("Changing the back buffer from %p to %p.\n", swapchain->backBuffer[0], back);
5698
5699 if (swapchain->backBuffer[0])
5700 {
5701 IWineD3DSurface_SetContainer(swapchain->backBuffer[0], NULL);
5702 ((IWineD3DSurfaceImpl *)swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
5703 }
5704 swapchain->backBuffer[0] = back;
5705
5706 if (back)
5707 {
5708 swapchain->presentParms.BackBufferWidth = back_impl->currentDesc.Width;
5709 swapchain->presentParms.BackBufferHeight = back_impl->currentDesc.Height;
5710 swapchain->presentParms.BackBufferFormat = back_impl->resource.format_desc->format;
5711 swapchain->presentParms.BackBufferCount = 1;
5712
5713 IWineD3DSurface_SetContainer(back, (IWineD3DBase *)swapchain);
5714 back_impl->Flags |= SFLAG_SWAPCHAIN;
5715 }
5716 else
5717 {
5718 swapchain->presentParms.BackBufferCount = 0;
5719 HeapFree(GetProcessHeap(), 0, swapchain->backBuffer);
5720 swapchain->backBuffer = NULL;
5721 }
5722 }
5723
5724 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5725 return WINED3D_OK;
5726}
5727
5728static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5729 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5730 *ppZStencilSurface = This->stencilBufferTarget;
5731 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5732
5733 if(*ppZStencilSurface != NULL) {
5734 /* Note inc ref on returned surface */
5735 IWineD3DSurface_AddRef(*ppZStencilSurface);
5736 return WINED3D_OK;
5737 } else {
5738 return WINED3DERR_NOTFOUND;
5739 }
5740}
5741
5742void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, const RECT *src_rect_in,
5743 IWineD3DSurface *dst_surface, const RECT *dst_rect_in, const WINED3DTEXTUREFILTERTYPE filter)
5744{
5745 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5746 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5747 const struct wined3d_gl_info *gl_info;
5748 struct wined3d_context *context;
5749 GLenum gl_filter;
5750 POINT offset = {0, 0};
5751 RECT src_rect, dst_rect;
5752
5753 TRACE("(%p) : src_surface %p, src_rect_in %p, dst_surface %p, dst_rect_in %p, filter %s (0x%08x)\n",
5754 This, src_surface, src_rect_in, dst_surface, dst_rect_in, debug_d3dtexturefiltertype(filter), filter);
5755 TRACE("src_rect_in %s\n", wine_dbgstr_rect(src_rect_in));
5756 TRACE("dst_rect_in %s\n", wine_dbgstr_rect(dst_rect_in));
5757
5758 src_rect = *src_rect_in;
5759 dst_rect = *dst_rect_in;
5760
5761 switch (filter) {
5762 case WINED3DTEXF_LINEAR:
5763 gl_filter = GL_LINEAR;
5764 break;
5765
5766 default:
5767 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5768 case WINED3DTEXF_NONE:
5769 case WINED3DTEXF_POINT:
5770 gl_filter = GL_NEAREST;
5771 break;
5772 }
5773
5774 /* Make sure the drawables are up-to-date. Note that loading the
5775 * destination surface isn't strictly required if we overwrite the
5776 * entire surface. */
5777 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
5778 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
5779
5780 if (!surface_is_offscreen(src_surface)) context = context_acquire(This, src_surface, CTXUSAGE_RESOURCELOAD);
5781 else if (!surface_is_offscreen(dst_surface)) context = context_acquire(This, dst_surface, CTXUSAGE_RESOURCELOAD);
5782 else context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5783
5784 if (!context->valid)
5785 {
5786 context_release(context);
5787 WARN("Invalid context, skipping blit.\n");
5788 return;
5789 }
5790
5791 gl_info = context->gl_info;
5792
5793 if (!surface_is_offscreen(src_surface))
5794 {
5795 GLenum buffer = surface_get_gl_buffer(src_surface);
5796
5797 TRACE("Source surface %p is onscreen\n", src_surface);
5798
5799 if(buffer == GL_FRONT) {
5800 RECT windowsize;
5801 UINT h;
5802
5803 ClientToScreen(context->win_handle, &offset);
5804 GetClientRect(context->win_handle, &windowsize);
5805 h = windowsize.bottom - windowsize.top;
5806#ifdef DEBUG_leo
5807 if (offset.x!=0 || offset.y!=0 || h!=((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height)
5808 {
5809 DebugBreak();
5810 }
5811#endif
5812 src_rect.left -= offset.x; src_rect.right -=offset.x;
5813 src_rect.top = offset.y + h - src_rect.top;
5814 src_rect.bottom = offset.y + h - src_rect.bottom;
5815 } else {
5816 src_rect.top = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect.top;
5817 src_rect.bottom = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect.bottom;
5818 }
5819
5820 ENTER_GL();
5821 context_bind_fbo(context, GL_READ_FRAMEBUFFER, NULL);
5822 glReadBuffer(buffer);
5823 checkGLcall("glReadBuffer()");
5824 } else {
5825 TRACE("Source surface %p is offscreen\n", src_surface);
5826 ENTER_GL();
5827 context_bind_fbo(context, GL_READ_FRAMEBUFFER, &context->src_fbo);
5828 context_attach_surface_fbo(context, GL_READ_FRAMEBUFFER, 0, (IWineD3DSurfaceImpl *)src_surface);
5829 glReadBuffer(GL_COLOR_ATTACHMENT0);
5830 checkGLcall("glReadBuffer()");
5831 context_attach_depth_stencil_fbo(context, GL_READ_FRAMEBUFFER, NULL, FALSE);
5832 }
5833 LEAVE_GL();
5834
5835 /* Attach dst surface to dst fbo */
5836 if (!surface_is_offscreen(dst_surface))
5837 {
5838 GLenum buffer = surface_get_gl_buffer(dst_surface);
5839
5840 TRACE("Destination surface %p is onscreen\n", dst_surface);
5841
5842 if(buffer == GL_FRONT) {
5843 RECT windowsize;
5844 UINT h;
5845 ClientToScreen(context->win_handle, &offset);
5846 GetClientRect(context->win_handle, &windowsize);
5847 h = windowsize.bottom - windowsize.top;
5848#ifdef DEBUG_leo
5849 if (offset.x!=0 || offset.y!=0 || h!=((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height)
5850 {
5851 DebugBreak();
5852 }
5853#endif
5854 dst_rect.left -= offset.x; dst_rect.right -=offset.x;
5855 dst_rect.top = offset.y + h - dst_rect.top;
5856 dst_rect.bottom = offset.y + h - dst_rect.bottom;
5857 } else {
5858 /* Screen coords = window coords, surface height = window height */
5859 dst_rect.top = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect.top;
5860 dst_rect.bottom = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect.bottom;
5861 }
5862
5863 ENTER_GL();
5864 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, NULL);
5865 context_set_draw_buffer(context, buffer);
5866 }
5867 else
5868 {
5869 TRACE("Destination surface %p is offscreen\n", dst_surface);
5870
5871 ENTER_GL();
5872 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, &context->dst_fbo);
5873 context_attach_surface_fbo(context, GL_DRAW_FRAMEBUFFER, 0, (IWineD3DSurfaceImpl *)dst_surface);
5874 context_set_draw_buffer(context, GL_COLOR_ATTACHMENT0);
5875 context_attach_depth_stencil_fbo(context, GL_DRAW_FRAMEBUFFER, NULL, FALSE);
5876 }
5877 glDisable(GL_SCISSOR_TEST);
5878 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5879
5880 gl_info->fbo_ops.glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom,
5881 dst_rect.left, dst_rect.top, dst_rect.right, dst_rect.bottom, mask, gl_filter);
5882 checkGLcall("glBlitFramebuffer()");
5883
5884 LEAVE_GL();
5885
5886 if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
5887
5888 context_release(context);
5889
5890 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
5891}
5892
5893static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget,
5894 BOOL set_viewport) {
5895 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5896
5897 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5898
5899 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5900 {
5901 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
5902 This, RenderTargetIndex, This->adapter->gl_info.limits.buffers);
5903 return WINED3DERR_INVALIDCALL;
5904 }
5905
5906 /* MSDN says that null disables the render target
5907 but a device must always be associated with a render target
5908 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5909 */
5910 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5911 FIXME("Trying to set render target 0 to NULL\n");
5912 return WINED3DERR_INVALIDCALL;
5913 }
5914 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5915 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);
5916 return WINED3DERR_INVALIDCALL;
5917 }
5918
5919 /* If we are trying to set what we already have, don't bother */
5920 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5921 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5922 return WINED3D_OK;
5923 }
5924 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5925 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5926 This->render_targets[RenderTargetIndex] = pRenderTarget;
5927
5928 /* Render target 0 is special */
5929 if(RenderTargetIndex == 0 && set_viewport) {
5930 /* Finally, reset the viewport and scissor rect as the MSDN states.
5931 * Tests show that stateblock recording is ignored, the change goes
5932 * directly into the primary stateblock.
5933 */
5934 This->stateBlock->viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5935 This->stateBlock->viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5936 This->stateBlock->viewport.X = 0;
5937 This->stateBlock->viewport.Y = 0;
5938 This->stateBlock->viewport.MaxZ = 1.0f;
5939 This->stateBlock->viewport.MinZ = 0.0f;
5940 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
5941
5942 This->stateBlock->scissorRect.top = 0;
5943 This->stateBlock->scissorRect.left = 0;
5944 This->stateBlock->scissorRect.right = This->stateBlock->viewport.Width;
5945 This->stateBlock->scissorRect.bottom = This->stateBlock->viewport.Height;
5946 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5947 }
5948 return WINED3D_OK;
5949}
5950
5951static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5952 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5953 HRESULT hr = WINED3D_OK;
5954 IWineD3DSurface *tmp;
5955
5956 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
5957
5958 if (pNewZStencil == This->stencilBufferTarget) {
5959 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5960 } else {
5961 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
5962 * depending on the renter target implementation being used.
5963 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5964 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5965 * stencil buffer and incur an extra memory overhead
5966 ******************************************************/
5967
5968 if (This->stencilBufferTarget) {
5969 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5970 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
5971 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
5972 } else {
5973 struct wined3d_context *context = context_acquire(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5974 surface_load_ds_location(This->stencilBufferTarget, context, SFLAG_DS_OFFSCREEN);
5975 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
5976 context_release(context);
5977 }
5978 }
5979
5980 tmp = This->stencilBufferTarget;
5981 This->stencilBufferTarget = pNewZStencil;
5982 /* should we be calling the parent or the wined3d surface? */
5983 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5984 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5985 hr = WINED3D_OK;
5986
5987 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
5988 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5989 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5990 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5991 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5992 }
5993 }
5994
5995 return hr;
5996}
5997
5998static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5999 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6000 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6001 /* TODO: the use of Impl is deprecated. */
6002 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6003 WINED3DLOCKED_RECT lockedRect;
6004
6005 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6006
6007 /* some basic validation checks */
6008 if(This->cursorTexture) {
6009 struct wined3d_context *context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6010 ENTER_GL();
6011 glDeleteTextures(1, &This->cursorTexture);
6012 LEAVE_GL();
6013 context_release(context);
6014 This->cursorTexture = 0;
6015 }
6016
6017 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6018 This->haveHardwareCursor = TRUE;
6019 else
6020 This->haveHardwareCursor = FALSE;
6021
6022 if(pCursorBitmap) {
6023 WINED3DLOCKED_RECT rect;
6024
6025 /* MSDN: Cursor must be A8R8G8B8 */
6026 if (pSur->resource.format_desc->format != WINED3DFMT_B8G8R8A8_UNORM)
6027 {
6028 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6029 return WINED3DERR_INVALIDCALL;
6030 }
6031
6032 /* MSDN: Cursor must be smaller than the display mode */
6033 if(pSur->currentDesc.Width > This->ddraw_width ||
6034 pSur->currentDesc.Height > This->ddraw_height) {
6035 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);
6036 return WINED3DERR_INVALIDCALL;
6037 }
6038
6039 if (!This->haveHardwareCursor) {
6040 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6041
6042 /* Do not store the surface's pointer because the application may
6043 * release it after setting the cursor image. Windows doesn't
6044 * addref the set surface, so we can't do this either without
6045 * creating circular refcount dependencies. Copy out the gl texture
6046 * instead.
6047 */
6048 This->cursorWidth = pSur->currentDesc.Width;
6049 This->cursorHeight = pSur->currentDesc.Height;
6050 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6051 {
6052 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
6053 const struct wined3d_format_desc *format_desc = getFormatDescEntry(WINED3DFMT_B8G8R8A8_UNORM, gl_info);
6054 struct wined3d_context *context;
6055 char *mem, *bits = rect.pBits;
6056 GLint intfmt = format_desc->glInternal;
6057 GLint format = format_desc->glFormat;
6058 GLint type = format_desc->glType;
6059 INT height = This->cursorHeight;
6060 INT width = This->cursorWidth;
6061 INT bpp = format_desc->byte_count;
6062 DWORD sampler;
6063 INT i;
6064
6065 /* Reformat the texture memory (pitch and width can be
6066 * different) */
6067 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6068 for(i = 0; i < height; i++)
6069 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6070 IWineD3DSurface_UnlockRect(pCursorBitmap);
6071
6072 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6073
6074 ENTER_GL();
6075
6076 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6077 {
6078 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6079 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6080 }
6081
6082 /* Make sure that a proper texture unit is selected */
6083 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6084 checkGLcall("glActiveTextureARB");
6085 sampler = This->rev_tex_unit_map[0];
6086 if (sampler != WINED3D_UNMAPPED_STAGE)
6087 {
6088 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6089 }
6090 /* Create a new cursor texture */
6091 glGenTextures(1, &This->cursorTexture);
6092 checkGLcall("glGenTextures");
6093 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6094 checkGLcall("glBindTexture");
6095 /* Copy the bitmap memory into the cursor texture */
6096 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6097 HeapFree(GetProcessHeap(), 0, mem);
6098 checkGLcall("glTexImage2D");
6099
6100 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6101 {
6102 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6103 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6104 }
6105
6106 LEAVE_GL();
6107
6108 context_release(context);
6109 }
6110 else
6111 {
6112 FIXME("A cursor texture was not returned.\n");
6113 This->cursorTexture = 0;
6114 }
6115 }
6116 else
6117 {
6118 /* Draw a hardware cursor */
6119 ICONINFO cursorInfo;
6120 HCURSOR cursor;
6121 /* Create and clear maskBits because it is not needed for
6122 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6123 * chunks. */
6124 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6125 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6126 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6127 WINED3DLOCK_NO_DIRTY_UPDATE |
6128 WINED3DLOCK_READONLY
6129 );
6130 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6131 pSur->currentDesc.Height);
6132
6133 cursorInfo.fIcon = FALSE;
6134 cursorInfo.xHotspot = XHotSpot;
6135 cursorInfo.yHotspot = YHotSpot;
6136 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6137 1, 1, maskBits);
6138 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6139 1, 32, lockedRect.pBits);
6140 IWineD3DSurface_UnlockRect(pCursorBitmap);
6141 /* Create our cursor and clean up. */
6142 cursor = CreateIconIndirect(&cursorInfo);
6143 SetCursor(cursor);
6144 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6145 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6146 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6147 This->hardwareCursor = cursor;
6148 HeapFree(GetProcessHeap(), 0, maskBits);
6149 }
6150 }
6151
6152 This->xHotSpot = XHotSpot;
6153 This->yHotSpot = YHotSpot;
6154 return WINED3D_OK;
6155}
6156
6157static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6158 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6159 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6160
6161 This->xScreenSpace = XScreenSpace;
6162 This->yScreenSpace = YScreenSpace;
6163
6164 return;
6165
6166}
6167
6168static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6169 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6170 BOOL oldVisible = This->bCursorVisible;
6171 POINT pt;
6172
6173 TRACE("(%p) : visible(%d)\n", This, bShow);
6174
6175 /*
6176 * When ShowCursor is first called it should make the cursor appear at the OS's last
6177 * known cursor position. Because of this, some applications just repetitively call
6178 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6179 */
6180 GetCursorPos(&pt);
6181 This->xScreenSpace = pt.x;
6182 This->yScreenSpace = pt.y;
6183
6184 if (This->haveHardwareCursor) {
6185 This->bCursorVisible = bShow;
6186 if (bShow)
6187 SetCursor(This->hardwareCursor);
6188 else
6189 SetCursor(NULL);
6190 }
6191 else
6192 {
6193 if (This->cursorTexture)
6194 This->bCursorVisible = bShow;
6195 }
6196
6197 return oldVisible;
6198}
6199
6200static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6201 TRACE("checking resource %p for eviction\n", resource);
6202 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6203 TRACE("Evicting %p\n", resource);
6204 IWineD3DResource_UnLoad(resource);
6205 }
6206 IWineD3DResource_Release(resource);
6207 return S_OK;
6208}
6209
6210static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6211{
6212 TRACE("iface %p.\n", iface);
6213
6214 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6215 return WINED3D_OK;
6216}
6217
6218static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6219{
6220 IWineD3DDeviceImpl *device = surface->resource.device;
6221 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6222
6223 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6224 if(surface->Flags & SFLAG_DIBSECTION) {
6225 /* Release the DC */
6226 SelectObject(surface->hDC, surface->dib.holdbitmap);
6227 DeleteDC(surface->hDC);
6228 /* Release the DIB section */
6229 DeleteObject(surface->dib.DIBsection);
6230 surface->dib.bitmap_data = NULL;
6231 surface->resource.allocatedMemory = NULL;
6232 surface->Flags &= ~SFLAG_DIBSECTION;
6233 }
6234 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6235 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6236 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6237 || gl_info->supported[WINE_NORMALIZED_TEXRECT])
6238 {
6239 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6240 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6241 } else {
6242 surface->pow2Width = surface->pow2Height = 1;
6243 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6244 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6245 }
6246
6247 if (surface->texture_name)
6248 {
6249 struct wined3d_context *context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
6250 ENTER_GL();
6251 glDeleteTextures(1, &surface->texture_name);
6252 LEAVE_GL();
6253 context_release(context);
6254 surface->texture_name = 0;
6255 surface->Flags &= ~SFLAG_CLIENT;
6256 }
6257 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6258 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6259 surface->Flags |= SFLAG_NONPOW2;
6260 } else {
6261 surface->Flags &= ~SFLAG_NONPOW2;
6262 }
6263 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6264 surface->resource.allocatedMemory = NULL;
6265 surface->resource.heapMemory = NULL;
6266 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6267
6268 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6269 * to a FBO */
6270 if(!surface_init_sysmem((IWineD3DSurface *) surface))
6271 {
6272 return E_OUTOFMEMORY;
6273 }
6274 return WINED3D_OK;
6275}
6276
6277static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6278 TRACE("Unloading resource %p\n", resource);
6279 IWineD3DResource_UnLoad(resource);
6280 IWineD3DResource_Release(resource);
6281 return S_OK;
6282}
6283
6284static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6285{
6286 UINT i, count;
6287 WINED3DDISPLAYMODE m;
6288 HRESULT hr;
6289
6290 /* All Windowed modes are supported, as is leaving the current mode */
6291 if(pp->Windowed) return TRUE;
6292 if(!pp->BackBufferWidth) return TRUE;
6293 if(!pp->BackBufferHeight) return TRUE;
6294
6295 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6296 for(i = 0; i < count; i++) {
6297 memset(&m, 0, sizeof(m));
6298 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6299 if(FAILED(hr)) {
6300 ERR("EnumAdapterModes failed\n");
6301 }
6302 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6303 /* Mode found, it is supported */
6304 return TRUE;
6305 }
6306 }
6307 /* Mode not found -> not supported */
6308 return FALSE;
6309}
6310
6311static void delete_opengl_contexts(IWineD3DDevice *iface
6312#ifndef VBOX_WITH_WDDM
6313 , IWineD3DSwapChainImpl *swapchain
6314#endif
6315 )
6316{
6317 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6318 const struct wined3d_gl_info *gl_info;
6319 struct wined3d_context *context;
6320 IWineD3DBaseShaderImpl *shader;
6321
6322 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6323 gl_info = context->gl_info;
6324
6325 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6326 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6327 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6328 }
6329
6330 ENTER_GL();
6331 if(This->depth_blt_texture) {
6332 glDeleteTextures(1, &This->depth_blt_texture);
6333 This->depth_blt_texture = 0;
6334 }
6335 if (This->depth_blt_rb) {
6336 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6337 This->depth_blt_rb = 0;
6338 This->depth_blt_rb_w = 0;
6339 This->depth_blt_rb_h = 0;
6340 }
6341 LEAVE_GL();
6342
6343 This->blitter->free_private(iface);
6344 This->frag_pipe->free_private(iface);
6345 This->shader_backend->shader_free_private(iface);
6346 destroy_dummy_textures(This, gl_info);
6347
6348 context_release(context);
6349
6350 while (This->numContexts)
6351 {
6352 context_destroy(This, This->contexts[0]);
6353 }
6354#ifndef VBOX_WITH_WDDM
6355 HeapFree(GetProcessHeap(), 0, swapchain->context);
6356 swapchain->context = NULL;
6357 swapchain->num_contexts = 0;
6358#endif
6359}
6360
6361static HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6362{
6363 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6364 struct wined3d_context *context;
6365 HRESULT hr;
6366 IWineD3DSurfaceImpl *target;
6367
6368#ifndef VBOX_WITH_WDDM
6369 /* Recreate the primary swapchain's context */
6370 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6371 if (!swapchain->context)
6372 {
6373 ERR("Failed to allocate memory for swapchain context array.\n");
6374 return E_OUTOFMEMORY;
6375 }
6376#endif
6377
6378 target = (IWineD3DSurfaceImpl *)(swapchain->backBuffer ? swapchain->backBuffer[0] : swapchain->frontBuffer);
6379 if (!(context = context_create(swapchain, target, swapchain->ds_format)))
6380 {
6381 WARN("Failed to create context.\n");
6382#ifndef VBOX_WITH_WDDM
6383 HeapFree(GetProcessHeap(), 0, swapchain->context);
6384#endif
6385 return E_FAIL;
6386 }
6387
6388#ifndef VBOX_WITH_WDDM
6389 swapchain->context[0] = context;
6390 swapchain->num_contexts = 1;
6391#endif
6392 create_dummy_textures(This);
6393 context_release(context);
6394
6395 hr = This->shader_backend->shader_alloc_private(iface);
6396 if (FAILED(hr))
6397 {
6398 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6399 goto err;
6400 }
6401
6402 hr = This->frag_pipe->alloc_private(iface);
6403 if (FAILED(hr))
6404 {
6405 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6406 This->shader_backend->shader_free_private(iface);
6407 goto err;
6408 }
6409
6410 hr = This->blitter->alloc_private(iface);
6411 if (FAILED(hr))
6412 {
6413 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6414 This->frag_pipe->free_private(iface);
6415 This->shader_backend->shader_free_private(iface);
6416 goto err;
6417 }
6418
6419 return WINED3D_OK;
6420
6421err:
6422 context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6423 destroy_dummy_textures(This, context->gl_info);
6424 context_release(context);
6425 context_destroy(This, context);
6426#ifndef VBOX_WITH_WDDM
6427 HeapFree(GetProcessHeap(), 0, swapchain->context);
6428 swapchain->num_contexts = 0;
6429#endif
6430 return hr;
6431}
6432
6433static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6434 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6435 IWineD3DSwapChainImpl *swapchain;
6436 HRESULT hr;
6437 BOOL DisplayModeChanged = FALSE;
6438 WINED3DDISPLAYMODE mode;
6439 TRACE("(%p)\n", This);
6440
6441#ifdef VBOX_WITH_WDDM
6442 /* todo: implement multi-swapchain handlling!!! */
6443 Assert(0);
6444#endif
6445
6446 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6447 if(FAILED(hr)) {
6448 ERR("Failed to get the first implicit swapchain\n");
6449 return hr;
6450 }
6451
6452 if(!is_display_mode_supported(This, pPresentationParameters)) {
6453 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6454 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6455 pPresentationParameters->BackBufferHeight);
6456 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6457 return WINED3DERR_INVALIDCALL;
6458 }
6459
6460 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6461 * on an existing gl context, so there's no real need for recreation.
6462 *
6463 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6464 *
6465 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6466 */
6467 TRACE("New params:\n");
6468 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6469 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6470 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6471 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6472 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6473 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6474 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6475 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6476 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6477 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6478 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6479 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6480 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6481
6482 /* No special treatment of these parameters. Just store them */
6483 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6484 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6485 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6486 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6487
6488 /* What to do about these? */
6489 if(pPresentationParameters->BackBufferCount != 0 &&
6490 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6491 ERR("Cannot change the back buffer count yet\n");
6492 }
6493 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6494 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6495 ERR("Cannot change the back buffer format yet\n");
6496 }
6497 if(pPresentationParameters->hDeviceWindow != NULL &&
6498 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6499 ERR("Cannot change the device window yet\n");
6500 }
6501 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
6502 HRESULT hrc;
6503
6504 TRACE("Creating the depth stencil buffer\n");
6505
6506 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6507 This->parent,
6508 pPresentationParameters->BackBufferWidth,
6509 pPresentationParameters->BackBufferHeight,
6510 pPresentationParameters->AutoDepthStencilFormat,
6511 pPresentationParameters->MultiSampleType,
6512 pPresentationParameters->MultiSampleQuality,
6513 FALSE,
6514 &This->auto_depth_stencil_buffer);
6515
6516 if (FAILED(hrc)) {
6517 ERR("Failed to create the depth stencil buffer\n");
6518 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6519 return WINED3DERR_INVALIDCALL;
6520 }
6521 }
6522
6523 /* Reset the depth stencil */
6524 if (pPresentationParameters->EnableAutoDepthStencil)
6525 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
6526 else
6527 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6528
6529 TRACE("Resetting stateblock\n");
6530 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6531 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6532
6533 delete_opengl_contexts(iface
6534#ifndef VBOX_WITH_WDDM
6535 , swapchain
6536#endif
6537 );
6538
6539 if(pPresentationParameters->Windowed) {
6540 mode.Width = swapchain->orig_width;
6541 mode.Height = swapchain->orig_height;
6542 mode.RefreshRate = 0;
6543 mode.Format = swapchain->presentParms.BackBufferFormat;
6544 } else {
6545 mode.Width = pPresentationParameters->BackBufferWidth;
6546 mode.Height = pPresentationParameters->BackBufferHeight;
6547 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6548 mode.Format = swapchain->presentParms.BackBufferFormat;
6549 }
6550
6551 /* Should Width == 800 && Height == 0 set 800x600? */
6552 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6553 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6554 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6555 {
6556 UINT i;
6557
6558 if(!pPresentationParameters->Windowed) {
6559 DisplayModeChanged = TRUE;
6560 }
6561 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6562 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6563
6564 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6565 if(FAILED(hr))
6566 {
6567 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6568 return hr;
6569 }
6570
6571 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6572 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6573 if(FAILED(hr))
6574 {
6575 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6576 return hr;
6577 }
6578 }
6579 if(This->auto_depth_stencil_buffer) {
6580 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
6581 if(FAILED(hr))
6582 {
6583 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6584 return hr;
6585 }
6586 }
6587 }
6588
6589 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
6590 || DisplayModeChanged)
6591 {
6592 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6593
6594 if (!pPresentationParameters->Windowed)
6595 {
6596 if(swapchain->presentParms.Windowed) {
6597 /* switch from windowed to fs */
6598 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6599 pPresentationParameters->BackBufferHeight);
6600 } else {
6601 /* Fullscreen -> fullscreen mode change */
6602 MoveWindow(swapchain->device_window, 0, 0,
6603 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6604 TRUE);
6605 }
6606 }
6607 else if (!swapchain->presentParms.Windowed)
6608 {
6609 /* Fullscreen -> windowed switch */
6610 swapchain_restore_fullscreen_window(swapchain);
6611 }
6612 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6613 } else if(!pPresentationParameters->Windowed) {
6614 DWORD style = This->style, exStyle = This->exStyle;
6615 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6616 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6617 * Reset to clear up their mess. Guild Wars also loses the device during that.
6618 */
6619 This->style = 0;
6620 This->exStyle = 0;
6621 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6622 pPresentationParameters->BackBufferHeight);
6623 This->style = style;
6624 This->exStyle = exStyle;
6625 }
6626
6627 /* Note: No parent needed for initial internal stateblock */
6628 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
6629 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6630 else TRACE("Created stateblock %p\n", This->stateBlock);
6631 This->updateStateBlock = This->stateBlock;
6632 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6633
6634 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
6635 if(FAILED(hr)) {
6636 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6637 }
6638
6639 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6640 {
6641 RECT client_rect;
6642 GetClientRect(swapchain->win_handle, &client_rect);
6643
6644 if(!swapchain->presentParms.BackBufferCount)
6645 {
6646 TRACE("Single buffered rendering\n");
6647 swapchain->render_to_fbo = FALSE;
6648 }
6649 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6650 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6651 {
6652 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6653 swapchain->presentParms.BackBufferWidth,
6654 swapchain->presentParms.BackBufferHeight,
6655 client_rect.right, client_rect.bottom);
6656 swapchain->render_to_fbo = TRUE;
6657 }
6658 else
6659 {
6660 TRACE("Rendering directly to GL_BACK\n");
6661 swapchain->render_to_fbo = FALSE;
6662 }
6663 }
6664
6665 hr = create_primary_opengl_context(iface, swapchain);
6666 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6667
6668 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6669 * first use
6670 */
6671 return hr;
6672}
6673
6674static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6675{
6676 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6677
6678 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6679
6680 return WINED3D_OK;
6681}
6682
6683
6684static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6685 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6686 TRACE("(%p) : pParameters %p\n", This, pParameters);
6687
6688 *pParameters = This->createParms;
6689 return WINED3D_OK;
6690}
6691
6692static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6693 IWineD3DSwapChain *swapchain;
6694
6695 TRACE("Relaying to swapchain\n");
6696
6697 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6698 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6699 IWineD3DSwapChain_Release(swapchain);
6700 }
6701}
6702
6703static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6704 IWineD3DSwapChain *swapchain;
6705
6706 TRACE("Relaying to swapchain\n");
6707
6708 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6709 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6710 IWineD3DSwapChain_Release(swapchain);
6711 }
6712}
6713
6714
6715/** ********************************************************
6716* Notification functions
6717** ********************************************************/
6718/** This function must be called in the release of a resource when ref == 0,
6719* the contents of resource must still be correct,
6720* any handles to other resource held by the caller must be closed
6721* (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6722 *****************************************************/
6723void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6724{
6725 TRACE("(%p) : Adding resource %p\n", This, resource);
6726
6727 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6728}
6729
6730static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6731{
6732 TRACE("(%p) : Removing resource %p\n", This, resource);
6733
6734 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6735}
6736
6737void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6738{
6739 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6740 int counter;
6741
6742 TRACE("(%p) : resource %p\n", This, resource);
6743
6744 context_resource_released((IWineD3DDevice *)This, resource, type);
6745
6746 switch (type) {
6747 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6748 case WINED3DRTYPE_SURFACE: {
6749 unsigned int i;
6750
6751 if (This->d3d_initialized)
6752 {
6753 for (i = 0; i < This->adapter->gl_info.limits.buffers; ++i)
6754 {
6755 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
6756 This->render_targets[i] = NULL;
6757 }
6758 }
6759 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
6760 This->stencilBufferTarget = NULL;
6761 }
6762 }
6763
6764 break;
6765 }
6766 case WINED3DRTYPE_TEXTURE:
6767 case WINED3DRTYPE_CUBETEXTURE:
6768 case WINED3DRTYPE_VOLUMETEXTURE:
6769 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6770 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6771 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6772 This->stateBlock->textures[counter] = NULL;
6773 }
6774 if (This->updateStateBlock != This->stateBlock ){
6775 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6776 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6777 This->updateStateBlock->textures[counter] = NULL;
6778 }
6779 }
6780 }
6781 break;
6782 case WINED3DRTYPE_VOLUME:
6783 /* TODO: nothing really? */
6784 break;
6785 case WINED3DRTYPE_BUFFER:
6786 {
6787 int streamNumber;
6788 TRACE("Cleaning up stream pointers\n");
6789
6790 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6791 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6792 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6793 */
6794 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6795 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6796 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6797 This->updateStateBlock->streamSource[streamNumber] = 0;
6798 /* Set changed flag? */
6799 }
6800 }
6801 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) */
6802 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6803 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6804 This->stateBlock->streamSource[streamNumber] = 0;
6805 }
6806 }
6807 }
6808
6809 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6810 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6811 This->updateStateBlock->pIndexData = NULL;
6812 }
6813 }
6814 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6815 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6816 This->stateBlock->pIndexData = NULL;
6817 }
6818 }
6819 }
6820 break;
6821
6822 default:
6823 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6824 break;
6825 }
6826
6827
6828 /* Remove the resource from the resourceStore */
6829 device_resource_remove(This, resource);
6830
6831 TRACE("Resource released\n");
6832
6833}
6834
6835static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6836 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6837 IWineD3DResourceImpl *resource, *cursor;
6838 HRESULT ret;
6839 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6840
6841 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6842 TRACE("enumerating resource %p\n", resource);
6843 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6844 ret = pCallback((IWineD3DResource *) resource, pData);
6845 if(ret == S_FALSE) {
6846 TRACE("Canceling enumeration\n");
6847 break;
6848 }
6849 }
6850 return WINED3D_OK;
6851}
6852
6853static HRESULT WINAPI IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice *iface, HDC dc, IWineD3DSurface **surface)
6854{
6855 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6856 IWineD3DResourceImpl *resource;
6857
6858 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
6859 {
6860 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
6861 if (type == WINED3DRTYPE_SURFACE)
6862 {
6863 if (((IWineD3DSurfaceImpl *)resource)->hDC == dc)
6864 {
6865 TRACE("Found surface %p for dc %p.\n", resource, dc);
6866 *surface = (IWineD3DSurface *)resource;
6867 return WINED3D_OK;
6868 }
6869 }
6870 }
6871
6872 return WINED3DERR_INVALIDCALL;
6873}
6874
6875#ifdef VBOX_WITH_WDDM
6876static HRESULT WINAPI IWineD3DDeviceImpl_Flush(IWineD3DDevice *iface)
6877{
6878 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6879 struct wined3d_context *context;
6880 int i;
6881 for (i = 0; i < This->numContexts; ++i)
6882 {
6883 context = This->contexts[i];
6884 if (context_acquire_context(context, NULL, CTXUSAGE_RESOURCELOAD, TRUE))
6885 {
6886 Assert(context->valid);
6887 wglFlush();
6888 context_release(context);
6889 }
6890 else
6891 {
6892 WARN("Invalid context, skipping flush.\n");
6893 }
6894 }
6895 return WINED3D_OK;
6896}
6897
6898static HRESULT WINAPI IWineD3DDeviceImpl_AddSwapChain(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain)
6899{
6900 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6901 VOID *pvNewBuf = HeapReAlloc(GetProcessHeap(), 0, This->swapchains, (This->NumberOfSwapChains + 1) * sizeof(IWineD3DSwapChain *));
6902 if(!pvNewBuf) {
6903 ERR("Out of memory!\n");
6904 return E_OUTOFMEMORY;
6905 }
6906 This->swapchains = (IWineD3DSwapChain *)pvNewBuf;
6907 This->swapchains[This->NumberOfSwapChains] = swapchain;
6908 ++This->NumberOfSwapChains;
6909 return WINED3D_OK;
6910}
6911
6912static HRESULT WINAPI IWineD3DDeviceImpl_RemoveSwapChain(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain)
6913{
6914 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6915 int i;
6916 for (i = 0; i < This->NumberOfSwapChains; ++i)
6917 {
6918 if (This->swapchains[i] == swapchain)
6919 {
6920 break;
6921 }
6922 }
6923
6924 if (i == This->NumberOfSwapChains)
6925 {
6926 WARN("swapchain 0x%p is not part of device 0x%p\n", swapchain, iface);
6927 return E_INVALIDARG;
6928 }
6929
6930 --This->NumberOfSwapChains;
6931 if (This->NumberOfSwapChains)
6932 {
6933 IWineD3DSwapChain **pvNewBuf = (IWineD3DSwapChain **)HeapAlloc(GetProcessHeap(), 0, (This->NumberOfSwapChains) * sizeof(IWineD3DSwapChain *));
6934 if(!pvNewBuf) {
6935 ERR("Out of memory!\n");
6936 return E_OUTOFMEMORY;
6937 }
6938 if (i) {
6939 memcpy (pvNewBuf, This->swapchains, i*sizeof(IWineD3DSwapChain *));
6940 }
6941 if (i < This->NumberOfSwapChains) {
6942 memcpy (pvNewBuf + i, This->swapchains +i+1, (This->NumberOfSwapChains - i)*sizeof(IWineD3DSwapChain *));
6943 }
6944
6945 This->swapchains = (IWineD3DSwapChain *)pvNewBuf;
6946 }
6947 else
6948 {
6949 while (This->numContexts)
6950 {
6951 context_destroy(This, This->contexts[0]);
6952 }
6953 }
6954 return WINED3D_OK;
6955}
6956#endif
6957
6958/**********************************************************
6959 * IWineD3DDevice VTbl follows
6960 **********************************************************/
6961
6962static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6963{
6964 /*** IUnknown methods ***/
6965 IWineD3DDeviceImpl_QueryInterface,
6966 IWineD3DDeviceImpl_AddRef,
6967 IWineD3DDeviceImpl_Release,
6968 /*** IWineD3DDevice methods ***/
6969 IWineD3DDeviceImpl_GetParent,
6970 /*** Creation methods**/
6971 IWineD3DDeviceImpl_CreateBuffer,
6972 IWineD3DDeviceImpl_CreateVertexBuffer,
6973 IWineD3DDeviceImpl_CreateIndexBuffer,
6974 IWineD3DDeviceImpl_CreateStateBlock,
6975 IWineD3DDeviceImpl_CreateSurface,
6976 IWineD3DDeviceImpl_CreateRendertargetView,
6977 IWineD3DDeviceImpl_CreateTexture,
6978 IWineD3DDeviceImpl_CreateVolumeTexture,
6979 IWineD3DDeviceImpl_CreateVolume,
6980 IWineD3DDeviceImpl_CreateCubeTexture,
6981 IWineD3DDeviceImpl_CreateQuery,
6982 IWineD3DDeviceImpl_CreateSwapChain,
6983 IWineD3DDeviceImpl_CreateVertexDeclaration,
6984 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6985 IWineD3DDeviceImpl_CreateVertexShader,
6986 IWineD3DDeviceImpl_CreateGeometryShader,
6987 IWineD3DDeviceImpl_CreatePixelShader,
6988 IWineD3DDeviceImpl_CreatePalette,
6989 /*** Odd functions **/
6990 IWineD3DDeviceImpl_Init3D,
6991 IWineD3DDeviceImpl_InitGDI,
6992 IWineD3DDeviceImpl_Uninit3D,
6993 IWineD3DDeviceImpl_UninitGDI,
6994 IWineD3DDeviceImpl_SetMultithreaded,
6995 IWineD3DDeviceImpl_EvictManagedResources,
6996 IWineD3DDeviceImpl_GetAvailableTextureMem,
6997 IWineD3DDeviceImpl_GetBackBuffer,
6998 IWineD3DDeviceImpl_GetCreationParameters,
6999 IWineD3DDeviceImpl_GetDeviceCaps,
7000 IWineD3DDeviceImpl_GetDirect3D,
7001 IWineD3DDeviceImpl_GetDisplayMode,
7002 IWineD3DDeviceImpl_SetDisplayMode,
7003 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7004 IWineD3DDeviceImpl_GetRasterStatus,
7005 IWineD3DDeviceImpl_GetSwapChain,
7006 IWineD3DDeviceImpl_Reset,
7007 IWineD3DDeviceImpl_SetDialogBoxMode,
7008 IWineD3DDeviceImpl_SetCursorProperties,
7009 IWineD3DDeviceImpl_SetCursorPosition,
7010 IWineD3DDeviceImpl_ShowCursor,
7011 /*** Getters and setters **/
7012 IWineD3DDeviceImpl_SetClipPlane,
7013 IWineD3DDeviceImpl_GetClipPlane,
7014 IWineD3DDeviceImpl_SetClipStatus,
7015 IWineD3DDeviceImpl_GetClipStatus,
7016 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7017 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7018 IWineD3DDeviceImpl_SetDepthStencilSurface,
7019 IWineD3DDeviceImpl_GetDepthStencilSurface,
7020 IWineD3DDeviceImpl_SetGammaRamp,
7021 IWineD3DDeviceImpl_GetGammaRamp,
7022 IWineD3DDeviceImpl_SetIndexBuffer,
7023 IWineD3DDeviceImpl_GetIndexBuffer,
7024 IWineD3DDeviceImpl_SetBaseVertexIndex,
7025 IWineD3DDeviceImpl_GetBaseVertexIndex,
7026 IWineD3DDeviceImpl_SetLight,
7027 IWineD3DDeviceImpl_GetLight,
7028 IWineD3DDeviceImpl_SetLightEnable,
7029 IWineD3DDeviceImpl_GetLightEnable,
7030 IWineD3DDeviceImpl_SetMaterial,
7031 IWineD3DDeviceImpl_GetMaterial,
7032 IWineD3DDeviceImpl_SetNPatchMode,
7033 IWineD3DDeviceImpl_GetNPatchMode,
7034 IWineD3DDeviceImpl_SetPaletteEntries,
7035 IWineD3DDeviceImpl_GetPaletteEntries,
7036 IWineD3DDeviceImpl_SetPixelShader,
7037 IWineD3DDeviceImpl_GetPixelShader,
7038 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7039 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7040 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7041 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7042 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7043 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7044 IWineD3DDeviceImpl_SetRenderState,
7045 IWineD3DDeviceImpl_GetRenderState,
7046 IWineD3DDeviceImpl_SetRenderTarget,
7047 IWineD3DDeviceImpl_GetRenderTarget,
7048 IWineD3DDeviceImpl_SetFrontBackBuffers,
7049 IWineD3DDeviceImpl_SetSamplerState,
7050 IWineD3DDeviceImpl_GetSamplerState,
7051 IWineD3DDeviceImpl_SetScissorRect,
7052 IWineD3DDeviceImpl_GetScissorRect,
7053 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7054 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7055 IWineD3DDeviceImpl_SetStreamSource,
7056 IWineD3DDeviceImpl_GetStreamSource,
7057 IWineD3DDeviceImpl_SetStreamSourceFreq,
7058 IWineD3DDeviceImpl_GetStreamSourceFreq,
7059 IWineD3DDeviceImpl_SetTexture,
7060 IWineD3DDeviceImpl_GetTexture,
7061 IWineD3DDeviceImpl_SetTextureStageState,
7062 IWineD3DDeviceImpl_GetTextureStageState,
7063 IWineD3DDeviceImpl_SetTransform,
7064 IWineD3DDeviceImpl_GetTransform,
7065 IWineD3DDeviceImpl_SetVertexDeclaration,
7066 IWineD3DDeviceImpl_GetVertexDeclaration,
7067 IWineD3DDeviceImpl_SetVertexShader,
7068 IWineD3DDeviceImpl_GetVertexShader,
7069 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7070 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7071 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7072 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7073 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7074 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7075 IWineD3DDeviceImpl_SetViewport,
7076 IWineD3DDeviceImpl_GetViewport,
7077 IWineD3DDeviceImpl_MultiplyTransform,
7078 IWineD3DDeviceImpl_ValidateDevice,
7079 IWineD3DDeviceImpl_ProcessVertices,
7080 /*** State block ***/
7081 IWineD3DDeviceImpl_BeginStateBlock,
7082 IWineD3DDeviceImpl_EndStateBlock,
7083 /*** Scene management ***/
7084 IWineD3DDeviceImpl_BeginScene,
7085 IWineD3DDeviceImpl_EndScene,
7086 IWineD3DDeviceImpl_Present,
7087 IWineD3DDeviceImpl_Clear,
7088 IWineD3DDeviceImpl_ClearRendertargetView,
7089 /*** Drawing ***/
7090 IWineD3DDeviceImpl_SetPrimitiveType,
7091 IWineD3DDeviceImpl_GetPrimitiveType,
7092 IWineD3DDeviceImpl_DrawPrimitive,
7093 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7094 IWineD3DDeviceImpl_DrawPrimitiveUP,
7095 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7096 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7097 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7098 IWineD3DDeviceImpl_DrawRectPatch,
7099 IWineD3DDeviceImpl_DrawTriPatch,
7100 IWineD3DDeviceImpl_DeletePatch,
7101 IWineD3DDeviceImpl_ColorFill,
7102 IWineD3DDeviceImpl_UpdateTexture,
7103 IWineD3DDeviceImpl_UpdateSurface,
7104 IWineD3DDeviceImpl_GetFrontBufferData,
7105 /*** object tracking ***/
7106 IWineD3DDeviceImpl_EnumResources,
7107 IWineD3DDeviceImpl_GetSurfaceFromDC,
7108 IWineD3DDeviceImpl_AcquireFocusWindow,
7109 IWineD3DDeviceImpl_ReleaseFocusWindow,
7110#ifdef VBOX_WITH_WDDM
7111 /* VBox WDDM extensions */
7112 IWineD3DDeviceImpl_Flush,
7113 IWineD3DDeviceImpl_AddSwapChain,
7114 IWineD3DDeviceImpl_RemoveSwapChain,
7115#endif
7116};
7117
7118HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
7119 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
7120 IUnknown *parent, IWineD3DDeviceParent *device_parent)
7121{
7122 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
7123 const struct fragment_pipeline *fragment_pipeline;
7124 struct shader_caps shader_caps;
7125 struct fragment_caps ffp_caps;
7126 WINED3DDISPLAYMODE mode;
7127 unsigned int i;
7128 HRESULT hr;
7129
7130 device->lpVtbl = &IWineD3DDevice_Vtbl;
7131 device->ref = 1;
7132 device->wined3d = (IWineD3D *)wined3d;
7133 IWineD3D_AddRef(device->wined3d);
7134 device->adapter = wined3d->adapter_count ? adapter : NULL;
7135 device->parent = parent;
7136 device->device_parent = device_parent;
7137 list_init(&device->resources);
7138 list_init(&device->shaders);
7139
7140 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
7141 device->posFixup[0] = 1.0f; /* This is needed to get the x coord unmodified through a MAD. */
7142
7143 /* Get the initial screen setup for ddraw. */
7144 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
7145 if (FAILED(hr))
7146 {
7147 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
7148 IWineD3D_Release(device->wined3d);
7149 return hr;
7150 }
7151 device->ddraw_width = mode.Width;
7152 device->ddraw_height = mode.Height;
7153 device->ddraw_format = mode.Format;
7154
7155 /* Save the creation parameters. */
7156 device->createParms.AdapterOrdinal = adapter_idx;
7157 device->createParms.DeviceType = device_type;
7158 device->createParms.hFocusWindow = focus_window;
7159 device->createParms.BehaviorFlags = flags;
7160
7161 device->devType = device_type;
7162 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
7163
7164 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
7165 device->shader_backend = adapter->shader_backend;
7166
7167 memset(&shader_caps, 0, sizeof(shader_caps));
7168 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
7169 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
7170 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
7171 device->vs_clipping = shader_caps.VSClipping;
7172
7173 memset(&ffp_caps, 0, sizeof(ffp_caps));
7174 fragment_pipeline = adapter->fragment_pipe;
7175 device->frag_pipe = fragment_pipeline;
7176 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
7177 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
7178
7179 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
7180 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
7181 if (FAILED(hr))
7182 {
7183 ERR("Failed to compile state table, hr %#x.\n", hr);
7184 IWineD3D_Release(device->wined3d);
7185 return hr;
7186 }
7187
7188 device->blitter = adapter->blitter;
7189
7190 return WINED3D_OK;
7191}
7192
7193
7194void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7195 DWORD rep = This->StateTable[state].representative;
7196 struct wined3d_context *context;
7197 DWORD idx;
7198 BYTE shift;
7199 UINT i;
7200
7201 for(i = 0; i < This->numContexts; i++) {
7202 context = This->contexts[i];
7203 if(isStateDirty(context, rep)) continue;
7204
7205 context->dirtyArray[context->numDirtyEntries++] = rep;
7206 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
7207 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
7208 context->isStateDirty[idx] |= (1 << shift);
7209 }
7210}
7211
7212void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7213{
7214 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->current_rt;
7215 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7216 *width = surface->pow2Width;
7217 *height = surface->pow2Height;
7218}
7219
7220void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7221{
7222#ifdef VBOX_WITH_WDDM
7223 IWineD3DSwapChainImpl *swapchain = context->currentSwapchain;
7224#else
7225 IWineD3DSwapChainImpl *swapchain = context->swapchain;
7226#endif
7227 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7228 * current context's drawable, which is the size of the back buffer of the swapchain
7229 * the active context belongs to. */
7230 *width = swapchain->presentParms.BackBufferWidth;
7231 *height = swapchain->presentParms.BackBufferHeight;
7232}
7233
7234LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window,
7235 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
7236{
7237 if (device->filter_messages)
7238 {
7239 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
7240 window, message, wparam, lparam);
7241 return DefWindowProcW(window, message, wparam, lparam);
7242 }
7243
7244 if (message == WM_DESTROY)
7245 {
7246 TRACE("unregister window %p.\n", window);
7247 wined3d_unregister_window(window);
7248
7249 if (device->focus_window == window) device->focus_window = NULL;
7250 else ERR("Window %p is not the focus window for device %p.\n", window, device);
7251 }
7252
7253 return CallWindowProcW(proc, window, message, wparam, lparam);
7254}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette