VirtualBox

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

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

wddm/3d: volume texture func impl; fixes & cleanup

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