VirtualBox

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

Last change on this file since 42700 was 42516, checked in by vboxsync, 13 years ago

wine/wddm: shader cache destroy fix

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