VirtualBox

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

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

wined3d: profiling; export flushToHost and Finish commands

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