VirtualBox

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

最後變更 在這個檔案從37608是 35650,由 vboxsync 提交於 14 年 前

wddm/3d: cube texture support fixes + some cleanup & refactoring

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

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