VirtualBox

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

Last change on this file since 42971 was 42971, checked in by vboxsync, 12 years ago

wddm/3d: fix app crashes on shut down

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