VirtualBox

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

Last change on this file since 28475 was 28475, checked in by vboxsync, 15 years ago

crOpenGL: update to wine 1.1.43

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

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