VirtualBox

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

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

wddm/3d: make wine handle gl window create/destroy

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

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