wined3d: Figure out the index size inside drawPrimitive().
[wine] / dlls / wined3d / device.c
1 /*
2  * Copyright 2002 Lionel Ulmer
3  * Copyright 2002-2005 Jason Edmeades
4  * Copyright 2003-2004 Raphael Junqueira
5  * Copyright 2004 Christian Costa
6  * Copyright 2005 Oliver Stieber
7  * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
8  * Copyright 2006-2008 Henri Verbeet
9  * Copyright 2007 Andrew Riedi
10  * Copyright 2009-2011 Henri Verbeet for CodeWeavers
11  *
12  * This library is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Lesser General Public
14  * License as published by the Free Software Foundation; either
15  * version 2.1 of the License, or (at your option) any later version.
16  *
17  * This library is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * Lesser General Public License for more details.
21  *
22  * You should have received a copy of the GNU Lesser General Public
23  * License along with this library; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25  */
26
27 #include "config.h"
28 #include <stdio.h>
29 #ifdef HAVE_FLOAT_H
30 # include <float.h>
31 #endif
32 #include "wined3d_private.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
35
36 /* Define the default light parameters as specified by MSDN. */
37 const struct wined3d_light WINED3D_default_light =
38 {
39     WINED3D_LIGHT_DIRECTIONAL,  /* Type */
40     { 1.0f, 1.0f, 1.0f, 0.0f }, /* Diffuse r,g,b,a */
41     { 0.0f, 0.0f, 0.0f, 0.0f }, /* Specular r,g,b,a */
42     { 0.0f, 0.0f, 0.0f, 0.0f }, /* Ambient r,g,b,a, */
43     { 0.0f, 0.0f, 0.0f },       /* Position x,y,z */
44     { 0.0f, 0.0f, 1.0f },       /* Direction x,y,z */
45     0.0f,                       /* Range */
46     0.0f,                       /* Falloff */
47     0.0f, 0.0f, 0.0f,           /* Attenuation 0,1,2 */
48     0.0f,                       /* Theta */
49     0.0f                        /* Phi */
50 };
51
52 /**********************************************************
53  * Global variable / Constants follow
54  **********************************************************/
55 const float identity[] =
56 {
57     1.0f, 0.0f, 0.0f, 0.0f,
58     0.0f, 1.0f, 0.0f, 0.0f,
59     0.0f, 0.0f, 1.0f, 0.0f,
60     0.0f, 0.0f, 0.0f, 1.0f,
61 };  /* When needed for comparisons */
62
63 /* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these
64  * actually have the same values in GL and D3D. */
65 static GLenum gl_primitive_type_from_d3d(enum wined3d_primitive_type primitive_type)
66 {
67     switch(primitive_type)
68     {
69         case WINED3D_PT_POINTLIST:
70             return GL_POINTS;
71
72         case WINED3D_PT_LINELIST:
73             return GL_LINES;
74
75         case WINED3D_PT_LINESTRIP:
76             return GL_LINE_STRIP;
77
78         case WINED3D_PT_TRIANGLELIST:
79             return GL_TRIANGLES;
80
81         case WINED3D_PT_TRIANGLESTRIP:
82             return GL_TRIANGLE_STRIP;
83
84         case WINED3D_PT_TRIANGLEFAN:
85             return GL_TRIANGLE_FAN;
86
87         case WINED3D_PT_LINELIST_ADJ:
88             return GL_LINES_ADJACENCY_ARB;
89
90         case WINED3D_PT_LINESTRIP_ADJ:
91             return GL_LINE_STRIP_ADJACENCY_ARB;
92
93         case WINED3D_PT_TRIANGLELIST_ADJ:
94             return GL_TRIANGLES_ADJACENCY_ARB;
95
96         case WINED3D_PT_TRIANGLESTRIP_ADJ:
97             return GL_TRIANGLE_STRIP_ADJACENCY_ARB;
98
99         default:
100             FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
101             return GL_NONE;
102     }
103 }
104
105 static enum wined3d_primitive_type d3d_primitive_type_from_gl(GLenum primitive_type)
106 {
107     switch(primitive_type)
108     {
109         case GL_POINTS:
110             return WINED3D_PT_POINTLIST;
111
112         case GL_LINES:
113             return WINED3D_PT_LINELIST;
114
115         case GL_LINE_STRIP:
116             return WINED3D_PT_LINESTRIP;
117
118         case GL_TRIANGLES:
119             return WINED3D_PT_TRIANGLELIST;
120
121         case GL_TRIANGLE_STRIP:
122             return WINED3D_PT_TRIANGLESTRIP;
123
124         case GL_TRIANGLE_FAN:
125             return WINED3D_PT_TRIANGLEFAN;
126
127         case GL_LINES_ADJACENCY_ARB:
128             return WINED3D_PT_LINELIST_ADJ;
129
130         case GL_LINE_STRIP_ADJACENCY_ARB:
131             return WINED3D_PT_LINESTRIP_ADJ;
132
133         case GL_TRIANGLES_ADJACENCY_ARB:
134             return WINED3D_PT_TRIANGLELIST_ADJ;
135
136         case GL_TRIANGLE_STRIP_ADJACENCY_ARB:
137             return WINED3D_PT_TRIANGLESTRIP_ADJ;
138
139         default:
140             FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
141             return WINED3D_PT_UNDEFINED;
142     }
143 }
144
145 static BOOL fixed_get_input(BYTE usage, BYTE usage_idx, unsigned int *regnum)
146 {
147     if ((usage == WINED3D_DECL_USAGE_POSITION || usage == WINED3D_DECL_USAGE_POSITIONT) && !usage_idx)
148         *regnum = WINED3D_FFP_POSITION;
149     else if (usage == WINED3D_DECL_USAGE_BLEND_WEIGHT && !usage_idx)
150         *regnum = WINED3D_FFP_BLENDWEIGHT;
151     else if (usage == WINED3D_DECL_USAGE_BLEND_INDICES && !usage_idx)
152         *regnum = WINED3D_FFP_BLENDINDICES;
153     else if (usage == WINED3D_DECL_USAGE_NORMAL && !usage_idx)
154         *regnum = WINED3D_FFP_NORMAL;
155     else if (usage == WINED3D_DECL_USAGE_PSIZE && !usage_idx)
156         *regnum = WINED3D_FFP_PSIZE;
157     else if (usage == WINED3D_DECL_USAGE_COLOR && !usage_idx)
158         *regnum = WINED3D_FFP_DIFFUSE;
159     else if (usage == WINED3D_DECL_USAGE_COLOR && usage_idx == 1)
160         *regnum = WINED3D_FFP_SPECULAR;
161     else if (usage == WINED3D_DECL_USAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
162         *regnum = WINED3D_FFP_TEXCOORD0 + usage_idx;
163     else
164     {
165         FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage), usage_idx);
166         *regnum = ~0U;
167         return FALSE;
168     }
169
170     return TRUE;
171 }
172
173 /* Context activation is done by the caller. */
174 void device_stream_info_from_declaration(struct wined3d_device *device, struct wined3d_stream_info *stream_info)
175 {
176     const struct wined3d_state *state = &device->stateBlock->state;
177     /* We need to deal with frequency data! */
178     struct wined3d_vertex_declaration *declaration = state->vertex_declaration;
179     BOOL use_vshader;
180     unsigned int i;
181
182     stream_info->use_map = 0;
183     stream_info->swizzle_map = 0;
184
185     /* Check for transformed vertices, disable vertex shader if present. */
186     stream_info->position_transformed = declaration->position_transformed;
187     use_vshader = state->vertex_shader && !declaration->position_transformed;
188
189     /* Translate the declaration into strided data. */
190     for (i = 0; i < declaration->element_count; ++i)
191     {
192         const struct wined3d_vertex_declaration_element *element = &declaration->elements[i];
193         const struct wined3d_stream_state *stream = &state->streams[element->input_slot];
194         struct wined3d_buffer *buffer = stream->buffer;
195         struct wined3d_bo_address data;
196         BOOL stride_used;
197         unsigned int idx;
198         DWORD stride;
199
200         TRACE("%p Element %p (%u of %u)\n", declaration->elements,
201                 element, i + 1, declaration->element_count);
202
203         if (!buffer) continue;
204
205         data.buffer_object = 0;
206         data.addr = NULL;
207
208         stride = stream->stride;
209         if (state->user_stream)
210         {
211             TRACE("Stream %u is UP, %p\n", element->input_slot, buffer);
212             data.buffer_object = 0;
213             data.addr = (BYTE *)buffer;
214         }
215         else
216         {
217             TRACE("Stream %u isn't UP, %p\n", element->input_slot, buffer);
218             buffer_get_memory(buffer, &device->adapter->gl_info, &data);
219
220             /* Can't use vbo's if the base vertex index is negative. OpenGL doesn't accept negative offsets
221              * (or rather offsets bigger than the vbo, because the pointer is unsigned), so use system memory
222              * sources. In most sane cases the pointer - offset will still be > 0, otherwise it will wrap
223              * around to some big value. Hope that with the indices, the driver wraps it back internally. If
224              * not, drawStridedSlow is needed, including a vertex buffer path. */
225             if (state->load_base_vertex_index < 0)
226             {
227                 WARN("load_base_vertex_index is < 0 (%d), not using VBOs.\n",
228                         state->load_base_vertex_index);
229                 data.buffer_object = 0;
230                 data.addr = buffer_get_sysmem(buffer, &device->adapter->gl_info);
231                 if ((UINT_PTR)data.addr < -state->load_base_vertex_index * stride)
232                 {
233                     FIXME("System memory vertex data load offset is negative!\n");
234                 }
235             }
236         }
237         data.addr += element->offset;
238
239         TRACE("offset %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx);
240
241         if (use_vshader)
242         {
243             if (element->output_slot == ~0U)
244             {
245                 /* TODO: Assuming vertexdeclarations are usually used with the
246                  * same or a similar shader, it might be worth it to store the
247                  * last used output slot and try that one first. */
248                 stride_used = vshader_get_input(state->vertex_shader,
249                         element->usage, element->usage_idx, &idx);
250             }
251             else
252             {
253                 idx = element->output_slot;
254                 stride_used = TRUE;
255             }
256         }
257         else
258         {
259             if (!element->ffp_valid)
260             {
261                 WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
262                         debug_d3dformat(element->format->id), debug_d3ddeclusage(element->usage));
263                 stride_used = FALSE;
264             }
265             else
266             {
267                 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
268             }
269         }
270
271         if (stride_used)
272         {
273             TRACE("Load %s array %u [usage %s, usage_idx %u, "
274                     "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
275                     use_vshader ? "shader": "fixed function", idx,
276                     debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot,
277                     element->offset, stride, debug_d3dformat(element->format->id), data.buffer_object);
278
279             data.addr += stream->offset;
280
281             stream_info->elements[idx].format = element->format;
282             stream_info->elements[idx].data = data;
283             stream_info->elements[idx].stride = stride;
284             stream_info->elements[idx].stream_idx = element->input_slot;
285
286             if (!device->adapter->gl_info.supported[ARB_VERTEX_ARRAY_BGRA]
287                     && element->format->id == WINED3DFMT_B8G8R8A8_UNORM)
288             {
289                 stream_info->swizzle_map |= 1 << idx;
290             }
291             stream_info->use_map |= 1 << idx;
292         }
293     }
294
295     device->num_buffer_queries = 0;
296     if (!state->user_stream)
297     {
298         WORD map = stream_info->use_map;
299         stream_info->all_vbo = 1;
300
301         /* PreLoad all the vertex buffers. */
302         for (i = 0; map; map >>= 1, ++i)
303         {
304             struct wined3d_stream_info_element *element;
305             struct wined3d_buffer *buffer;
306
307             if (!(map & 1)) continue;
308
309             element = &stream_info->elements[i];
310             buffer = state->streams[element->stream_idx].buffer;
311             wined3d_buffer_preload(buffer);
312
313             /* If the preload dropped the buffer object, update the stream info. */
314             if (buffer->buffer_object != element->data.buffer_object)
315             {
316                 element->data.buffer_object = 0;
317                 element->data.addr = buffer_get_sysmem(buffer, &device->adapter->gl_info)
318                         + (ptrdiff_t)element->data.addr;
319             }
320
321             if (!buffer->buffer_object)
322                 stream_info->all_vbo = 0;
323
324             if (buffer->query)
325                 device->buffer_queries[device->num_buffer_queries++] = buffer->query;
326         }
327     }
328     else
329     {
330         stream_info->all_vbo = 0;
331     }
332 }
333
334 static void stream_info_element_from_strided(const struct wined3d_gl_info *gl_info,
335         const struct wined3d_strided_element *strided, struct wined3d_stream_info_element *e)
336 {
337     e->data.addr = strided->data;
338     e->data.buffer_object = 0;
339     e->format = wined3d_get_format(gl_info, strided->format);
340     e->stride = strided->stride;
341     e->stream_idx = 0;
342 }
343
344 static void device_stream_info_from_strided(const struct wined3d_gl_info *gl_info,
345         const struct wined3d_strided_data *strided, struct wined3d_stream_info *stream_info)
346 {
347     unsigned int i;
348
349     memset(stream_info, 0, sizeof(*stream_info));
350
351     if (strided->position.data)
352         stream_info_element_from_strided(gl_info, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
353     if (strided->normal.data)
354         stream_info_element_from_strided(gl_info, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
355     if (strided->diffuse.data)
356         stream_info_element_from_strided(gl_info, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
357     if (strided->specular.data)
358         stream_info_element_from_strided(gl_info, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);
359
360     for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
361     {
362         if (strided->tex_coords[i].data)
363             stream_info_element_from_strided(gl_info, &strided->tex_coords[i],
364                     &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
365     }
366
367     stream_info->position_transformed = strided->position_transformed;
368
369     for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
370     {
371         if (!stream_info->elements[i].format) continue;
372
373         if (!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
374                 && stream_info->elements[i].format->id == WINED3DFMT_B8G8R8A8_UNORM)
375         {
376             stream_info->swizzle_map |= 1 << i;
377         }
378         stream_info->use_map |= 1 << i;
379     }
380 }
381
382 static void device_trace_strided_stream_info(const struct wined3d_stream_info *stream_info)
383 {
384     TRACE("Strided Data:\n");
385     TRACE_STRIDED(stream_info, WINED3D_FFP_POSITION);
386     TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDWEIGHT);
387     TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDINDICES);
388     TRACE_STRIDED(stream_info, WINED3D_FFP_NORMAL);
389     TRACE_STRIDED(stream_info, WINED3D_FFP_PSIZE);
390     TRACE_STRIDED(stream_info, WINED3D_FFP_DIFFUSE);
391     TRACE_STRIDED(stream_info, WINED3D_FFP_SPECULAR);
392     TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD0);
393     TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD1);
394     TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD2);
395     TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD3);
396     TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD4);
397     TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD5);
398     TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD6);
399     TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD7);
400 }
401
402 /* Context activation is done by the caller. */
403 void device_update_stream_info(struct wined3d_device *device, const struct wined3d_gl_info *gl_info)
404 {
405     struct wined3d_stream_info *stream_info = &device->strided_streams;
406     const struct wined3d_state *state = &device->stateBlock->state;
407
408     if (device->up_strided)
409     {
410         /* Note: this is a ddraw fixed-function code path. */
411         TRACE("=============================== Strided Input ================================\n");
412         device_stream_info_from_strided(gl_info, device->up_strided, stream_info);
413         if (TRACE_ON(d3d)) device_trace_strided_stream_info(stream_info);
414     }
415     else
416     {
417         TRACE("============================= Vertex Declaration =============================\n");
418         device_stream_info_from_declaration(device, stream_info);
419     }
420
421     if (state->vertex_shader && !stream_info->position_transformed)
422     {
423         if (state->vertex_declaration->half_float_conv_needed && !stream_info->all_vbo)
424         {
425             TRACE("Using drawStridedSlow with vertex shaders for FLOAT16 conversion.\n");
426             device->useDrawStridedSlow = TRUE;
427         }
428         else
429         {
430             device->useDrawStridedSlow = FALSE;
431         }
432     }
433     else
434     {
435         WORD slow_mask = (1 << WINED3D_FFP_PSIZE);
436         slow_mask |= -!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
437                 & ((1 << WINED3D_FFP_DIFFUSE) | (1 << WINED3D_FFP_SPECULAR));
438
439         if ((stream_info->position_transformed || (stream_info->use_map & slow_mask)) && !stream_info->all_vbo)
440         {
441             device->useDrawStridedSlow = TRUE;
442         }
443         else
444         {
445             device->useDrawStridedSlow = FALSE;
446         }
447     }
448 }
449
450 static void device_preload_texture(const struct wined3d_state *state, unsigned int idx)
451 {
452     struct wined3d_texture *texture;
453     enum WINED3DSRGB srgb;
454
455     if (!(texture = state->textures[idx])) return;
456     srgb = state->sampler_states[idx][WINED3D_SAMP_SRGB_TEXTURE] ? SRGB_SRGB : SRGB_RGB;
457     texture->texture_ops->texture_preload(texture, srgb);
458 }
459
460 void device_preload_textures(const struct wined3d_device *device)
461 {
462     const struct wined3d_state *state = &device->stateBlock->state;
463     unsigned int i;
464
465     if (use_vs(state))
466     {
467         for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i)
468         {
469             if (state->vertex_shader->reg_maps.sampler_type[i])
470                 device_preload_texture(state, MAX_FRAGMENT_SAMPLERS + i);
471         }
472     }
473
474     if (use_ps(state))
475     {
476         for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i)
477         {
478             if (state->pixel_shader->reg_maps.sampler_type[i])
479                 device_preload_texture(state, i);
480         }
481     }
482     else
483     {
484         WORD ffu_map = device->fixed_function_usage_map;
485
486         for (i = 0; ffu_map; ffu_map >>= 1, ++i)
487         {
488             if (ffu_map & 1)
489                 device_preload_texture(state, i);
490         }
491     }
492 }
493
494 BOOL device_context_add(struct wined3d_device *device, struct wined3d_context *context)
495 {
496     struct wined3d_context **new_array;
497
498     TRACE("Adding context %p.\n", context);
499
500     if (!device->contexts) new_array = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_array));
501     else new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts,
502             sizeof(*new_array) * (device->context_count + 1));
503
504     if (!new_array)
505     {
506         ERR("Failed to grow the context array.\n");
507         return FALSE;
508     }
509
510     new_array[device->context_count++] = context;
511     device->contexts = new_array;
512     return TRUE;
513 }
514
515 void device_context_remove(struct wined3d_device *device, struct wined3d_context *context)
516 {
517     struct wined3d_context **new_array;
518     BOOL found = FALSE;
519     UINT i;
520
521     TRACE("Removing context %p.\n", context);
522
523     for (i = 0; i < device->context_count; ++i)
524     {
525         if (device->contexts[i] == context)
526         {
527             found = TRUE;
528             break;
529         }
530     }
531
532     if (!found)
533     {
534         ERR("Context %p doesn't exist in context array.\n", context);
535         return;
536     }
537
538     if (!--device->context_count)
539     {
540         HeapFree(GetProcessHeap(), 0, device->contexts);
541         device->contexts = NULL;
542         return;
543     }
544
545     memmove(&device->contexts[i], &device->contexts[i + 1], (device->context_count - i) * sizeof(*device->contexts));
546     new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, device->context_count * sizeof(*device->contexts));
547     if (!new_array)
548     {
549         ERR("Failed to shrink context array. Oh well.\n");
550         return;
551     }
552
553     device->contexts = new_array;
554 }
555
556 /* Do not call while under the GL lock. */
557 void device_switch_onscreen_ds(struct wined3d_device *device,
558         struct wined3d_context *context, struct wined3d_surface *depth_stencil)
559 {
560     if (device->onscreen_depth_stencil)
561     {
562         surface_load_ds_location(device->onscreen_depth_stencil, context, SFLAG_INTEXTURE);
563
564         surface_modify_ds_location(device->onscreen_depth_stencil, SFLAG_INTEXTURE,
565                 device->onscreen_depth_stencil->ds_current_size.cx,
566                 device->onscreen_depth_stencil->ds_current_size.cy);
567         wined3d_surface_decref(device->onscreen_depth_stencil);
568     }
569     device->onscreen_depth_stencil = depth_stencil;
570     wined3d_surface_incref(device->onscreen_depth_stencil);
571 }
572
573 static BOOL is_full_clear(const struct wined3d_surface *target, const RECT *draw_rect, const RECT *clear_rect)
574 {
575     /* partial draw rect */
576     if (draw_rect->left || draw_rect->top
577             || draw_rect->right < target->resource.width
578             || draw_rect->bottom < target->resource.height)
579         return FALSE;
580
581     /* partial clear rect */
582     if (clear_rect && (clear_rect->left > 0 || clear_rect->top > 0
583             || clear_rect->right < target->resource.width
584             || clear_rect->bottom < target->resource.height))
585         return FALSE;
586
587     return TRUE;
588 }
589
590 static void prepare_ds_clear(struct wined3d_surface *ds, struct wined3d_context *context,
591         DWORD location, const RECT *draw_rect, UINT rect_count, const RECT *clear_rect, RECT *out_rect)
592 {
593     RECT current_rect, r;
594
595     if (ds->flags & location)
596         SetRect(&current_rect, 0, 0,
597                 ds->ds_current_size.cx,
598                 ds->ds_current_size.cy);
599     else
600         SetRectEmpty(&current_rect);
601
602     IntersectRect(&r, draw_rect, &current_rect);
603     if (EqualRect(&r, draw_rect))
604     {
605         /* current_rect âŠ‡ draw_rect, modify only. */
606         SetRect(out_rect, 0, 0, ds->ds_current_size.cx, ds->ds_current_size.cy);
607         return;
608     }
609
610     if (EqualRect(&r, &current_rect))
611     {
612         /* draw_rect âŠ‡ current_rect, test if we're doing a full clear. */
613
614         if (!clear_rect)
615         {
616             /* Full clear, modify only. */
617             *out_rect = *draw_rect;
618             return;
619         }
620
621         IntersectRect(&r, draw_rect, clear_rect);
622         if (EqualRect(&r, draw_rect))
623         {
624             /* clear_rect âŠ‡ draw_rect, modify only. */
625             *out_rect = *draw_rect;
626             return;
627         }
628     }
629
630     /* Full load. */
631     surface_load_ds_location(ds, context, location);
632     SetRect(out_rect, 0, 0, ds->ds_current_size.cx, ds->ds_current_size.cy);
633 }
634
635 /* Do not call while under the GL lock. */
636 void device_clear_render_targets(struct wined3d_device *device, UINT rt_count, const struct wined3d_fb_state *fb,
637         UINT rect_count, const RECT *rects, const RECT *draw_rect, DWORD flags, const struct wined3d_color *color,
638         float depth, DWORD stencil)
639 {
640     const RECT *clear_rect = (rect_count > 0 && rects) ? (const RECT *)rects : NULL;
641     struct wined3d_surface *target = rt_count ? fb->render_targets[0] : NULL;
642     UINT drawable_width, drawable_height;
643     struct wined3d_context *context;
644     GLbitfield clear_mask = 0;
645     BOOL render_offscreen;
646     unsigned int i;
647     RECT ds_rect;
648
649     /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
650      * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
651      * for the cleared parts, and the untouched parts.
652      *
653      * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
654      * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
655      * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
656      * checking all this if the dest surface is in the drawable anyway. */
657     if (flags & WINED3DCLEAR_TARGET && !is_full_clear(target, draw_rect, clear_rect))
658     {
659         for (i = 0; i < rt_count; ++i)
660         {
661             struct wined3d_surface *rt = fb->render_targets[i];
662             if (rt)
663                 surface_load_location(rt, rt->draw_binding, NULL);
664         }
665     }
666
667     context = context_acquire(device, target);
668     if (!context->valid)
669     {
670         context_release(context);
671         WARN("Invalid context, skipping clear.\n");
672         return;
673     }
674
675     if (target)
676     {
677         render_offscreen = context->render_offscreen;
678         target->get_drawable_size(context, &drawable_width, &drawable_height);
679     }
680     else
681     {
682         render_offscreen = TRUE;
683         drawable_width = fb->depth_stencil->pow2Width;
684         drawable_height = fb->depth_stencil->pow2Height;
685     }
686
687     if (flags & WINED3DCLEAR_ZBUFFER)
688     {
689         DWORD location = render_offscreen ? fb->depth_stencil->draw_binding : SFLAG_INDRAWABLE;
690
691         if (!render_offscreen && fb->depth_stencil != device->onscreen_depth_stencil)
692             device_switch_onscreen_ds(device, context, fb->depth_stencil);
693         prepare_ds_clear(fb->depth_stencil, context, location,
694                 draw_rect, rect_count, clear_rect, &ds_rect);
695     }
696
697     if (!context_apply_clear_state(context, device, rt_count, fb))
698     {
699         context_release(context);
700         WARN("Failed to apply clear state, skipping clear.\n");
701         return;
702     }
703
704     ENTER_GL();
705
706     /* Only set the values up once, as they are not changing. */
707     if (flags & WINED3DCLEAR_STENCIL)
708     {
709         if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
710         {
711             glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
712             context_invalidate_state(context, STATE_RENDER(WINED3D_RS_TWOSIDEDSTENCILMODE));
713         }
714         glStencilMask(~0U);
715         context_invalidate_state(context, STATE_RENDER(WINED3D_RS_STENCILWRITEMASK));
716         glClearStencil(stencil);
717         checkGLcall("glClearStencil");
718         clear_mask = clear_mask | GL_STENCIL_BUFFER_BIT;
719     }
720
721     if (flags & WINED3DCLEAR_ZBUFFER)
722     {
723         DWORD location = render_offscreen ? fb->depth_stencil->draw_binding : SFLAG_INDRAWABLE;
724
725         surface_modify_ds_location(fb->depth_stencil, location, ds_rect.right, ds_rect.bottom);
726
727         glDepthMask(GL_TRUE);
728         context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ZWRITEENABLE));
729         glClearDepth(depth);
730         checkGLcall("glClearDepth");
731         clear_mask = clear_mask | GL_DEPTH_BUFFER_BIT;
732     }
733
734     if (flags & WINED3DCLEAR_TARGET)
735     {
736         for (i = 0; i < rt_count; ++i)
737         {
738             struct wined3d_surface *rt = fb->render_targets[i];
739
740             if (rt)
741                 surface_modify_location(rt, rt->draw_binding, TRUE);
742         }
743
744         glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
745         context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE));
746         context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE1));
747         context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE2));
748         context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE3));
749         glClearColor(color->r, color->g, color->b, color->a);
750         checkGLcall("glClearColor");
751         clear_mask = clear_mask | GL_COLOR_BUFFER_BIT;
752     }
753
754     if (!clear_rect)
755     {
756         if (render_offscreen)
757         {
758             glScissor(draw_rect->left, draw_rect->top,
759                     draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
760         }
761         else
762         {
763             glScissor(draw_rect->left, drawable_height - draw_rect->bottom,
764                         draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
765         }
766         checkGLcall("glScissor");
767         glClear(clear_mask);
768         checkGLcall("glClear");
769     }
770     else
771     {
772         RECT current_rect;
773
774         /* Now process each rect in turn. */
775         for (i = 0; i < rect_count; ++i)
776         {
777             /* Note that GL uses lower left, width/height. */
778             IntersectRect(&current_rect, draw_rect, &clear_rect[i]);
779
780             TRACE("clear_rect[%u] %s, current_rect %s.\n", i,
781                     wine_dbgstr_rect(&clear_rect[i]),
782                     wine_dbgstr_rect(&current_rect));
783
784             /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
785              * The rectangle is not cleared, no error is returned, but further rectangles are
786              * still cleared if they are valid. */
787             if (current_rect.left > current_rect.right || current_rect.top > current_rect.bottom)
788             {
789                 TRACE("Rectangle with negative dimensions, ignoring.\n");
790                 continue;
791             }
792
793             if (render_offscreen)
794             {
795                 glScissor(current_rect.left, current_rect.top,
796                         current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
797             }
798             else
799             {
800                 glScissor(current_rect.left, drawable_height - current_rect.bottom,
801                           current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
802             }
803             checkGLcall("glScissor");
804
805             glClear(clear_mask);
806             checkGLcall("glClear");
807         }
808     }
809
810     LEAVE_GL();
811
812     if (wined3d_settings.strict_draw_ordering || (flags & WINED3DCLEAR_TARGET
813             && target->container.type == WINED3D_CONTAINER_SWAPCHAIN
814             && target->container.u.swapchain->front_buffer == target))
815         wglFlush(); /* Flush to ensure ordering across contexts. */
816
817     context_release(context);
818 }
819
820 ULONG CDECL wined3d_device_incref(struct wined3d_device *device)
821 {
822     ULONG refcount = InterlockedIncrement(&device->ref);
823
824     TRACE("%p increasing refcount to %u.\n", device, refcount);
825
826     return refcount;
827 }
828
829 ULONG CDECL wined3d_device_decref(struct wined3d_device *device)
830 {
831     ULONG refcount = InterlockedDecrement(&device->ref);
832
833     TRACE("%p decreasing refcount to %u.\n", device, refcount);
834
835     if (!refcount)
836     {
837         struct wined3d_stateblock *stateblock;
838         UINT i;
839
840         if (wined3d_stateblock_decref(device->updateStateBlock)
841                 && device->updateStateBlock != device->stateBlock)
842             FIXME("Something's still holding the update stateblock.\n");
843         device->updateStateBlock = NULL;
844
845         stateblock = device->stateBlock;
846         device->stateBlock = NULL;
847         if (wined3d_stateblock_decref(stateblock))
848             FIXME("Something's still holding the stateblock.\n");
849
850         for (i = 0; i < sizeof(device->multistate_funcs) / sizeof(device->multistate_funcs[0]); ++i)
851         {
852             HeapFree(GetProcessHeap(), 0, device->multistate_funcs[i]);
853             device->multistate_funcs[i] = NULL;
854         }
855
856         if (!list_empty(&device->resources))
857         {
858             struct wined3d_resource *resource;
859
860             FIXME("Device released with resources still bound, acceptable but unexpected.\n");
861
862             LIST_FOR_EACH_ENTRY(resource, &device->resources, struct wined3d_resource, resource_list_entry)
863             {
864                 FIXME("Leftover resource %p with type %s (%#x).\n",
865                         resource, debug_d3dresourcetype(resource->type), resource->type);
866             }
867         }
868
869         if (device->contexts)
870             ERR("Context array not freed!\n");
871         if (device->hardwareCursor)
872             DestroyCursor(device->hardwareCursor);
873         device->hardwareCursor = 0;
874
875         wined3d_decref(device->wined3d);
876         device->wined3d = NULL;
877         HeapFree(GetProcessHeap(), 0, device);
878         TRACE("Freed device %p.\n", device);
879     }
880
881     return refcount;
882 }
883
884 UINT CDECL wined3d_device_get_swapchain_count(const struct wined3d_device *device)
885 {
886     TRACE("device %p.\n", device);
887
888     return device->swapchain_count;
889 }
890
891 HRESULT CDECL wined3d_device_get_swapchain(const struct wined3d_device *device,
892         UINT swapchain_idx, struct wined3d_swapchain **swapchain)
893 {
894     TRACE("device %p, swapchain_idx %u, swapchain %p.\n",
895             device, swapchain_idx, swapchain);
896
897     if (swapchain_idx >= device->swapchain_count)
898     {
899         WARN("swapchain_idx %u >= swapchain_count %u.\n",
900                 swapchain_idx, device->swapchain_count);
901         *swapchain = NULL;
902
903         return WINED3DERR_INVALIDCALL;
904     }
905
906     *swapchain = device->swapchains[swapchain_idx];
907     wined3d_swapchain_incref(*swapchain);
908     TRACE("Returning %p.\n", *swapchain);
909
910     return WINED3D_OK;
911 }
912
913 static void device_load_logo(struct wined3d_device *device, const char *filename)
914 {
915     struct wined3d_color_key color_key;
916     HBITMAP hbm;
917     BITMAP bm;
918     HRESULT hr;
919     HDC dcb = NULL, dcs = NULL;
920
921     hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
922     if(hbm)
923     {
924         GetObjectA(hbm, sizeof(BITMAP), &bm);
925         dcb = CreateCompatibleDC(NULL);
926         if(!dcb) goto out;
927         SelectObject(dcb, hbm);
928     }
929     else
930     {
931         /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
932          * couldn't be loaded
933          */
934         memset(&bm, 0, sizeof(bm));
935         bm.bmWidth = 32;
936         bm.bmHeight = 32;
937     }
938
939     hr = wined3d_surface_create(device, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, 0, 0,
940             WINED3D_POOL_DEFAULT, WINED3D_MULTISAMPLE_NONE, 0, WINED3D_SURFACE_TYPE_OPENGL, WINED3D_SURFACE_MAPPABLE,
941             NULL, &wined3d_null_parent_ops, &device->logo_surface);
942     if (FAILED(hr))
943     {
944         ERR("Wine logo requested, but failed to create surface, hr %#x.\n", hr);
945         goto out;
946     }
947
948     if (dcb)
949     {
950         if (FAILED(hr = wined3d_surface_getdc(device->logo_surface, &dcs)))
951             goto out;
952         BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
953         wined3d_surface_releasedc(device->logo_surface, dcs);
954
955         color_key.color_space_low_value = 0;
956         color_key.color_space_high_value = 0;
957         wined3d_surface_set_color_key(device->logo_surface, WINEDDCKEY_SRCBLT, &color_key);
958     }
959     else
960     {
961         const struct wined3d_color c = {1.0f, 1.0f, 1.0f, 1.0f};
962         /* Fill the surface with a white color to show that wined3d is there */
963         wined3d_device_color_fill(device, device->logo_surface, NULL, &c);
964     }
965
966 out:
967     if (dcb) DeleteDC(dcb);
968     if (hbm) DeleteObject(hbm);
969 }
970
971 /* Context activation is done by the caller. */
972 static void create_dummy_textures(struct wined3d_device *device, struct wined3d_context *context)
973 {
974     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
975     unsigned int i, j, count;
976     /* Under DirectX you can sample even if no texture is bound, whereas
977      * OpenGL will only allow that when a valid texture is bound.
978      * We emulate this by creating dummy textures and binding them
979      * to each texture stage when the currently set D3D texture is NULL. */
980     ENTER_GL();
981
982     if (gl_info->supported[APPLE_CLIENT_STORAGE])
983     {
984         /* The dummy texture does not have client storage backing */
985         glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
986         checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
987     }
988
989     count = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers);
990     for (i = 0; i < count; ++i)
991     {
992         DWORD color = 0x000000ff;
993
994         /* Make appropriate texture active */
995         context_active_texture(context, gl_info, i);
996
997         glGenTextures(1, &device->dummy_texture_2d[i]);
998         checkGLcall("glGenTextures");
999         TRACE("Dummy 2D texture %u given name %u.\n", i, device->dummy_texture_2d[i]);
1000
1001         glBindTexture(GL_TEXTURE_2D, device->dummy_texture_2d[i]);
1002         checkGLcall("glBindTexture");
1003
1004         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, &color);
1005         checkGLcall("glTexImage2D");
1006
1007         if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
1008         {
1009             glGenTextures(1, &device->dummy_texture_rect[i]);
1010             checkGLcall("glGenTextures");
1011             TRACE("Dummy rectangle texture %u given name %u.\n", i, device->dummy_texture_rect[i]);
1012
1013             glBindTexture(GL_TEXTURE_RECTANGLE_ARB, device->dummy_texture_rect[i]);
1014             checkGLcall("glBindTexture");
1015
1016             glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, &color);
1017             checkGLcall("glTexImage2D");
1018         }
1019
1020         if (gl_info->supported[EXT_TEXTURE3D])
1021         {
1022             glGenTextures(1, &device->dummy_texture_3d[i]);
1023             checkGLcall("glGenTextures");
1024             TRACE("Dummy 3D texture %u given name %u.\n", i, device->dummy_texture_3d[i]);
1025
1026             glBindTexture(GL_TEXTURE_3D, device->dummy_texture_3d[i]);
1027             checkGLcall("glBindTexture");
1028
1029             GL_EXTCALL(glTexImage3DEXT(GL_TEXTURE_3D, 0, GL_RGBA8, 1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, &color));
1030             checkGLcall("glTexImage3D");
1031         }
1032
1033         if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
1034         {
1035             glGenTextures(1, &device->dummy_texture_cube[i]);
1036             checkGLcall("glGenTextures");
1037             TRACE("Dummy cube texture %u given name %u.\n", i, device->dummy_texture_cube[i]);
1038
1039             glBindTexture(GL_TEXTURE_CUBE_MAP, device->dummy_texture_cube[i]);
1040             checkGLcall("glBindTexture");
1041
1042             for (j = GL_TEXTURE_CUBE_MAP_POSITIVE_X; j <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; ++j)
1043             {
1044                 glTexImage2D(j, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, &color);
1045                 checkGLcall("glTexImage2D");
1046             }
1047         }
1048     }
1049
1050     if (gl_info->supported[APPLE_CLIENT_STORAGE])
1051     {
1052         /* Reenable because if supported it is enabled by default */
1053         glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1054         checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1055     }
1056
1057     LEAVE_GL();
1058 }
1059
1060 /* Context activation is done by the caller. */
1061 static void destroy_dummy_textures(struct wined3d_device *device, const struct wined3d_gl_info *gl_info)
1062 {
1063     unsigned int count = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers);
1064
1065     ENTER_GL();
1066     if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
1067     {
1068         glDeleteTextures(count, device->dummy_texture_cube);
1069         checkGLcall("glDeleteTextures(count, device->dummy_texture_cube)");
1070     }
1071
1072     if (gl_info->supported[EXT_TEXTURE3D])
1073     {
1074         glDeleteTextures(count, device->dummy_texture_3d);
1075         checkGLcall("glDeleteTextures(count, device->dummy_texture_3d)");
1076     }
1077
1078     if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
1079     {
1080         glDeleteTextures(count, device->dummy_texture_rect);
1081         checkGLcall("glDeleteTextures(count, device->dummy_texture_rect)");
1082     }
1083
1084     glDeleteTextures(count, device->dummy_texture_2d);
1085     checkGLcall("glDeleteTextures(count, device->dummy_texture_2d)");
1086     LEAVE_GL();
1087
1088     memset(device->dummy_texture_cube, 0, gl_info->limits.textures * sizeof(*device->dummy_texture_cube));
1089     memset(device->dummy_texture_3d, 0, gl_info->limits.textures * sizeof(*device->dummy_texture_3d));
1090     memset(device->dummy_texture_rect, 0, gl_info->limits.textures * sizeof(*device->dummy_texture_rect));
1091     memset(device->dummy_texture_2d, 0, gl_info->limits.textures * sizeof(*device->dummy_texture_2d));
1092 }
1093
1094 static LONG fullscreen_style(LONG style)
1095 {
1096     /* Make sure the window is managed, otherwise we won't get keyboard input. */
1097     style |= WS_POPUP | WS_SYSMENU;
1098     style &= ~(WS_CAPTION | WS_THICKFRAME);
1099
1100     return style;
1101 }
1102
1103 static LONG fullscreen_exstyle(LONG exstyle)
1104 {
1105     /* Filter out window decorations. */
1106     exstyle &= ~(WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE);
1107
1108     return exstyle;
1109 }
1110
1111 void CDECL wined3d_device_setup_fullscreen_window(struct wined3d_device *device, HWND window, UINT w, UINT h)
1112 {
1113     BOOL filter_messages;
1114     LONG style, exstyle;
1115
1116     TRACE("Setting up window %p for fullscreen mode.\n", window);
1117
1118     if (device->style || device->exStyle)
1119     {
1120         ERR("Changing the window style for window %p, but another style (%08x, %08x) is already stored.\n",
1121                 window, device->style, device->exStyle);
1122     }
1123
1124     device->style = GetWindowLongW(window, GWL_STYLE);
1125     device->exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1126
1127     style = fullscreen_style(device->style);
1128     exstyle = fullscreen_exstyle(device->exStyle);
1129
1130     TRACE("Old style was %08x, %08x, setting to %08x, %08x.\n",
1131             device->style, device->exStyle, style, exstyle);
1132
1133     filter_messages = device->filter_messages;
1134     device->filter_messages = TRUE;
1135
1136     SetWindowLongW(window, GWL_STYLE, style);
1137     SetWindowLongW(window, GWL_EXSTYLE, exstyle);
1138     SetWindowPos(window, HWND_TOP, 0, 0, w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOACTIVATE);
1139
1140     device->filter_messages = filter_messages;
1141 }
1142
1143 void CDECL wined3d_device_restore_fullscreen_window(struct wined3d_device *device, HWND window)
1144 {
1145     BOOL filter_messages;
1146     LONG style, exstyle;
1147
1148     if (!device->style && !device->exStyle) return;
1149
1150     TRACE("Restoring window style of window %p to %08x, %08x.\n",
1151             window, device->style, device->exStyle);
1152
1153     style = GetWindowLongW(window, GWL_STYLE);
1154     exstyle = GetWindowLongW(window, GWL_EXSTYLE);
1155
1156     filter_messages = device->filter_messages;
1157     device->filter_messages = TRUE;
1158
1159     /* Only restore the style if the application didn't modify it during the
1160      * fullscreen phase. Some applications change it before calling Reset()
1161      * when switching between windowed and fullscreen modes (HL2), some
1162      * depend on the original style (Eve Online). */
1163     if (style == fullscreen_style(device->style) && exstyle == fullscreen_exstyle(device->exStyle))
1164     {
1165         SetWindowLongW(window, GWL_STYLE, device->style);
1166         SetWindowLongW(window, GWL_EXSTYLE, device->exStyle);
1167     }
1168     SetWindowPos(window, 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
1169
1170     device->filter_messages = filter_messages;
1171
1172     /* Delete the old values. */
1173     device->style = 0;
1174     device->exStyle = 0;
1175 }
1176
1177 HRESULT CDECL wined3d_device_acquire_focus_window(struct wined3d_device *device, HWND window)
1178 {
1179     TRACE("device %p, window %p.\n", device, window);
1180
1181     if (!wined3d_register_window(window, device))
1182     {
1183         ERR("Failed to register window %p.\n", window);
1184         return E_FAIL;
1185     }
1186
1187     InterlockedExchangePointer((void **)&device->focus_window, window);
1188     SetWindowPos(window, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
1189
1190     return WINED3D_OK;
1191 }
1192
1193 void CDECL wined3d_device_release_focus_window(struct wined3d_device *device)
1194 {
1195     TRACE("device %p.\n", device);
1196
1197     if (device->focus_window) wined3d_unregister_window(device->focus_window);
1198     InterlockedExchangePointer((void **)&device->focus_window, NULL);
1199 }
1200
1201 HRESULT CDECL wined3d_device_init_3d(struct wined3d_device *device,
1202         struct wined3d_swapchain_desc *swapchain_desc)
1203 {
1204     static const struct wined3d_color black = {0.0f, 0.0f, 0.0f, 0.0f};
1205     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1206     struct wined3d_swapchain *swapchain = NULL;
1207     struct wined3d_context *context;
1208     HRESULT hr;
1209     DWORD state;
1210     unsigned int i;
1211
1212     TRACE("device %p, swapchain_desc %p.\n", device, swapchain_desc);
1213
1214     if (device->d3d_initialized)
1215         return WINED3DERR_INVALIDCALL;
1216     if (!device->adapter->opengl)
1217         return WINED3DERR_INVALIDCALL;
1218
1219     device->valid_rt_mask = 0;
1220     for (i = 0; i < gl_info->limits.buffers; ++i)
1221         device->valid_rt_mask |= (1 << i);
1222     device->fb.render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1223             sizeof(*device->fb.render_targets) * gl_info->limits.buffers);
1224
1225     /* Initialize the texture unit mapping to a 1:1 mapping */
1226     for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1227     {
1228         if (state < gl_info->limits.fragment_samplers)
1229         {
1230             device->texUnitMap[state] = state;
1231             device->rev_tex_unit_map[state] = state;
1232         }
1233         else
1234         {
1235             device->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1236             device->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1237         }
1238     }
1239
1240     /* Setup the implicit swapchain. This also initializes a context. */
1241     TRACE("Creating implicit swapchain\n");
1242     hr = device->device_parent->ops->create_swapchain(device->device_parent,
1243             swapchain_desc, &swapchain);
1244     if (FAILED(hr))
1245     {
1246         WARN("Failed to create implicit swapchain\n");
1247         goto err_out;
1248     }
1249
1250     device->swapchain_count = 1;
1251     device->swapchains = HeapAlloc(GetProcessHeap(), 0, device->swapchain_count * sizeof(*device->swapchains));
1252     if (!device->swapchains)
1253     {
1254         ERR("Out of memory!\n");
1255         goto err_out;
1256     }
1257     device->swapchains[0] = swapchain;
1258
1259     if (swapchain->back_buffers && swapchain->back_buffers[0])
1260     {
1261         TRACE("Setting rendertarget to %p.\n", swapchain->back_buffers);
1262         device->fb.render_targets[0] = swapchain->back_buffers[0];
1263     }
1264     else
1265     {
1266         TRACE("Setting rendertarget to %p.\n", swapchain->front_buffer);
1267         device->fb.render_targets[0] = swapchain->front_buffer;
1268     }
1269     wined3d_surface_incref(device->fb.render_targets[0]);
1270
1271     /* Depth Stencil support */
1272     device->fb.depth_stencil = device->auto_depth_stencil;
1273     if (device->fb.depth_stencil)
1274         wined3d_surface_incref(device->fb.depth_stencil);
1275
1276     hr = device->shader_backend->shader_alloc_private(device);
1277     if (FAILED(hr))
1278     {
1279         TRACE("Shader private data couldn't be allocated\n");
1280         goto err_out;
1281     }
1282     hr = device->frag_pipe->alloc_private(device);
1283     if (FAILED(hr))
1284     {
1285         TRACE("Fragment pipeline private data couldn't be allocated\n");
1286         goto err_out;
1287     }
1288     hr = device->blitter->alloc_private(device);
1289     if (FAILED(hr))
1290     {
1291         TRACE("Blitter private data couldn't be allocated\n");
1292         goto err_out;
1293     }
1294
1295     /* Set up some starting GL setup */
1296
1297     /* Setup all the devices defaults */
1298     stateblock_init_default_state(device->stateBlock);
1299
1300     context = context_acquire(device, swapchain->front_buffer);
1301
1302     create_dummy_textures(device, context);
1303
1304     ENTER_GL();
1305
1306     /* Initialize the current view state */
1307     device->view_ident = 1;
1308     device->contexts[0]->last_was_rhw = 0;
1309
1310     switch (wined3d_settings.offscreen_rendering_mode)
1311     {
1312         case ORM_FBO:
1313             device->offscreenBuffer = GL_COLOR_ATTACHMENT0;
1314             break;
1315
1316         case ORM_BACKBUFFER:
1317         {
1318             if (context_get_current()->aux_buffers > 0)
1319             {
1320                 TRACE("Using auxiliary buffer for offscreen rendering\n");
1321                 device->offscreenBuffer = GL_AUX0;
1322             }
1323             else
1324             {
1325                 TRACE("Using back buffer for offscreen rendering\n");
1326                 device->offscreenBuffer = GL_BACK;
1327             }
1328         }
1329     }
1330
1331     TRACE("All defaults now set up, leaving 3D init.\n");
1332     LEAVE_GL();
1333
1334     context_release(context);
1335
1336     /* Clear the screen */
1337     wined3d_device_clear(device, 0, NULL, WINED3DCLEAR_TARGET
1338             | (swapchain_desc->enable_auto_depth_stencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0),
1339             &black, 1.0f, 0);
1340
1341     device->d3d_initialized = TRUE;
1342
1343     if (wined3d_settings.logo)
1344         device_load_logo(device, wined3d_settings.logo);
1345     return WINED3D_OK;
1346
1347 err_out:
1348     HeapFree(GetProcessHeap(), 0, device->fb.render_targets);
1349     HeapFree(GetProcessHeap(), 0, device->swapchains);
1350     device->swapchain_count = 0;
1351     if (swapchain)
1352         wined3d_swapchain_decref(swapchain);
1353     if (device->blit_priv)
1354         device->blitter->free_private(device);
1355     if (device->fragment_priv)
1356         device->frag_pipe->free_private(device);
1357     if (device->shader_priv)
1358         device->shader_backend->shader_free_private(device);
1359
1360     return hr;
1361 }
1362
1363 HRESULT CDECL wined3d_device_init_gdi(struct wined3d_device *device,
1364         struct wined3d_swapchain_desc *swapchain_desc)
1365 {
1366     struct wined3d_swapchain *swapchain = NULL;
1367     HRESULT hr;
1368
1369     TRACE("device %p, swapchain_desc %p.\n", device, swapchain_desc);
1370
1371     /* Setup the implicit swapchain */
1372     TRACE("Creating implicit swapchain\n");
1373     hr = device->device_parent->ops->create_swapchain(device->device_parent,
1374             swapchain_desc, &swapchain);
1375     if (FAILED(hr))
1376     {
1377         WARN("Failed to create implicit swapchain\n");
1378         goto err_out;
1379     }
1380
1381     device->swapchain_count = 1;
1382     device->swapchains = HeapAlloc(GetProcessHeap(), 0, device->swapchain_count * sizeof(*device->swapchains));
1383     if (!device->swapchains)
1384     {
1385         ERR("Out of memory!\n");
1386         goto err_out;
1387     }
1388     device->swapchains[0] = swapchain;
1389     return WINED3D_OK;
1390
1391 err_out:
1392     wined3d_swapchain_decref(swapchain);
1393     return hr;
1394 }
1395
1396 HRESULT CDECL wined3d_device_uninit_3d(struct wined3d_device *device)
1397 {
1398     struct wined3d_resource *resource, *cursor;
1399     const struct wined3d_gl_info *gl_info;
1400     struct wined3d_context *context;
1401     struct wined3d_surface *surface;
1402     UINT i;
1403
1404     TRACE("device %p.\n", device);
1405
1406     if (!device->d3d_initialized)
1407         return WINED3DERR_INVALIDCALL;
1408
1409     /* Force making the context current again, to verify it is still valid
1410      * (workaround for broken drivers) */
1411     context_set_current(NULL);
1412     /* I don't think that the interface guarantees that the device is destroyed from the same thread
1413      * it was created. Thus make sure a context is active for the glDelete* calls
1414      */
1415     context = context_acquire(device, NULL);
1416     gl_info = context->gl_info;
1417
1418     if (device->logo_surface)
1419         wined3d_surface_decref(device->logo_surface);
1420
1421     stateblock_unbind_resources(device->stateBlock);
1422
1423     /* Unload resources */
1424     LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &device->resources, struct wined3d_resource, resource_list_entry)
1425     {
1426         TRACE("Unloading resource %p.\n", resource);
1427
1428         resource->resource_ops->resource_unload(resource);
1429     }
1430
1431     TRACE("Deleting high order patches\n");
1432     for (i = 0; i < PATCHMAP_SIZE; ++i)
1433     {
1434         struct wined3d_rect_patch *patch;
1435         struct list *e1, *e2;
1436
1437         LIST_FOR_EACH_SAFE(e1, e2, &device->patches[i])
1438         {
1439             patch = LIST_ENTRY(e1, struct wined3d_rect_patch, entry);
1440             wined3d_device_delete_patch(device, patch->Handle);
1441         }
1442     }
1443
1444     /* Delete the mouse cursor texture */
1445     if (device->cursorTexture)
1446     {
1447         ENTER_GL();
1448         glDeleteTextures(1, &device->cursorTexture);
1449         LEAVE_GL();
1450         device->cursorTexture = 0;
1451     }
1452
1453     /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
1454      * private data, it might contain opengl pointers
1455      */
1456     if (device->depth_blt_texture)
1457     {
1458         ENTER_GL();
1459         glDeleteTextures(1, &device->depth_blt_texture);
1460         LEAVE_GL();
1461         device->depth_blt_texture = 0;
1462     }
1463
1464     /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
1465     device->blitter->free_private(device);
1466     device->frag_pipe->free_private(device);
1467     device->shader_backend->shader_free_private(device);
1468
1469     /* Release the buffers (with sanity checks)*/
1470     if (device->onscreen_depth_stencil)
1471     {
1472         surface = device->onscreen_depth_stencil;
1473         device->onscreen_depth_stencil = NULL;
1474         wined3d_surface_decref(surface);
1475     }
1476
1477     if (device->fb.depth_stencil)
1478     {
1479         surface = device->fb.depth_stencil;
1480
1481         TRACE("Releasing depth/stencil buffer %p.\n", surface);
1482
1483         device->fb.depth_stencil = NULL;
1484         wined3d_surface_decref(surface);
1485     }
1486
1487     if (device->auto_depth_stencil)
1488     {
1489         surface = device->auto_depth_stencil;
1490         device->auto_depth_stencil = NULL;
1491         if (wined3d_surface_decref(surface))
1492             FIXME("Something's still holding the auto depth stencil buffer (%p).\n", surface);
1493     }
1494
1495     for (i = 1; i < gl_info->limits.buffers; ++i)
1496     {
1497         wined3d_device_set_render_target(device, i, NULL, FALSE);
1498     }
1499
1500     surface = device->fb.render_targets[0];
1501     TRACE("Setting rendertarget 0 to NULL\n");
1502     device->fb.render_targets[0] = NULL;
1503     TRACE("Releasing the render target at %p\n", surface);
1504     wined3d_surface_decref(surface);
1505
1506     context_release(context);
1507
1508     for (i = 0; i < device->swapchain_count; ++i)
1509     {
1510         TRACE("Releasing the implicit swapchain %u.\n", i);
1511         if (wined3d_swapchain_decref(device->swapchains[i]))
1512             FIXME("Something's still holding the implicit swapchain.\n");
1513     }
1514
1515     HeapFree(GetProcessHeap(), 0, device->swapchains);
1516     device->swapchains = NULL;
1517     device->swapchain_count = 0;
1518
1519     HeapFree(GetProcessHeap(), 0, device->fb.render_targets);
1520     device->fb.render_targets = NULL;
1521
1522     device->d3d_initialized = FALSE;
1523
1524     return WINED3D_OK;
1525 }
1526
1527 HRESULT CDECL wined3d_device_uninit_gdi(struct wined3d_device *device)
1528 {
1529     unsigned int i;
1530
1531     for (i = 0; i < device->swapchain_count; ++i)
1532     {
1533         TRACE("Releasing the implicit swapchain %u.\n", i);
1534         if (wined3d_swapchain_decref(device->swapchains[i]))
1535             FIXME("Something's still holding the implicit swapchain.\n");
1536     }
1537
1538     HeapFree(GetProcessHeap(), 0, device->swapchains);
1539     device->swapchains = NULL;
1540     device->swapchain_count = 0;
1541     return WINED3D_OK;
1542 }
1543
1544 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
1545  * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
1546  * CreateDevice if D3DCREATE_MULTITHREADED is passed.
1547  *
1548  * There is no way to deactivate thread safety once it is enabled.
1549  */
1550 void CDECL wined3d_device_set_multithreaded(struct wined3d_device *device)
1551 {
1552     TRACE("device %p.\n", device);
1553
1554     /* For now just store the flag (needed in case of ddraw). */
1555     device->create_parms.flags |= WINED3DCREATE_MULTITHREADED;
1556 }
1557
1558 HRESULT CDECL wined3d_device_set_display_mode(struct wined3d_device *device,
1559         UINT swapchain_idx, const struct wined3d_display_mode *mode)
1560 {
1561     struct wined3d_adapter *adapter = device->adapter;
1562     const struct wined3d_format *format = wined3d_get_format(&adapter->gl_info, mode->format_id);
1563     DEVMODEW devmode;
1564     LONG ret;
1565     RECT clip_rc;
1566
1567     TRACE("device %p, swapchain_idx %u, mode %p (%ux%u@%u %s).\n", device, swapchain_idx, mode,
1568             mode->width, mode->height, mode->refresh_rate, debug_d3dformat(mode->format_id));
1569
1570     /* Resize the screen even without a window:
1571      * The app could have unset it with SetCooperativeLevel, but not called
1572      * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
1573      * but we don't have any hwnd
1574      */
1575
1576     memset(&devmode, 0, sizeof(devmode));
1577     devmode.dmSize = sizeof(devmode);
1578     devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1579     devmode.dmBitsPerPel = format->byte_count * CHAR_BIT;
1580     devmode.dmPelsWidth = mode->width;
1581     devmode.dmPelsHeight = mode->height;
1582
1583     devmode.dmDisplayFrequency = mode->refresh_rate;
1584     if (mode->refresh_rate)
1585         devmode.dmFields |= DM_DISPLAYFREQUENCY;
1586
1587     /* Only change the mode if necessary */
1588     if (adapter->screen_size.cx == mode->width && adapter->screen_size.cy == mode->height
1589             && adapter->screen_format == mode->format_id && !mode->refresh_rate)
1590         return WINED3D_OK;
1591
1592     ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
1593     if (ret != DISP_CHANGE_SUCCESSFUL)
1594     {
1595         if (devmode.dmDisplayFrequency)
1596         {
1597             WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
1598             devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
1599             devmode.dmDisplayFrequency = 0;
1600             ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
1601         }
1602         if(ret != DISP_CHANGE_SUCCESSFUL) {
1603             return WINED3DERR_NOTAVAILABLE;
1604         }
1605     }
1606
1607     /* Store the new values */
1608     adapter->screen_size.cx = mode->width;
1609     adapter->screen_size.cy = mode->height;
1610     adapter->screen_format = mode->format_id;
1611
1612     /* And finally clip mouse to our screen */
1613     SetRect(&clip_rc, 0, 0, mode->width, mode->height);
1614     ClipCursor(&clip_rc);
1615
1616     return WINED3D_OK;
1617 }
1618
1619 HRESULT CDECL wined3d_device_get_wined3d(const struct wined3d_device *device, struct wined3d **wined3d)
1620 {
1621     TRACE("device %p, wined3d %p.\n", device, wined3d);
1622
1623     *wined3d = device->wined3d;
1624     wined3d_incref(*wined3d);
1625
1626     TRACE("Returning %p.\n", *wined3d);
1627
1628     return WINED3D_OK;
1629 }
1630
1631 UINT CDECL wined3d_device_get_available_texture_mem(const struct wined3d_device *device)
1632 {
1633     TRACE("device %p.\n", device);
1634
1635     TRACE("Emulating %d MB, returning %d MB left.\n",
1636             device->adapter->TextureRam / (1024 * 1024),
1637             (device->adapter->TextureRam - device->adapter->UsedTextureRam) / (1024 * 1024));
1638
1639     return device->adapter->TextureRam - device->adapter->UsedTextureRam;
1640 }
1641
1642 HRESULT CDECL wined3d_device_set_stream_source(struct wined3d_device *device, UINT stream_idx,
1643         struct wined3d_buffer *buffer, UINT offset, UINT stride)
1644 {
1645     struct wined3d_stream_state *stream;
1646     struct wined3d_buffer *prev_buffer;
1647
1648     TRACE("device %p, stream_idx %u, buffer %p, offset %u, stride %u.\n",
1649             device, stream_idx, buffer, offset, stride);
1650
1651     if (stream_idx >= MAX_STREAMS)
1652     {
1653         WARN("Stream index %u out of range.\n", stream_idx);
1654         return WINED3DERR_INVALIDCALL;
1655     }
1656     else if (offset & 0x3)
1657     {
1658         WARN("Offset %u is not 4 byte aligned.\n", offset);
1659         return WINED3DERR_INVALIDCALL;
1660     }
1661
1662     stream = &device->updateStateBlock->state.streams[stream_idx];
1663     prev_buffer = stream->buffer;
1664
1665     device->updateStateBlock->changed.streamSource |= 1 << stream_idx;
1666
1667     if (prev_buffer == buffer
1668             && stream->stride == stride
1669             && stream->offset == offset)
1670     {
1671        TRACE("Application is setting the old values over, nothing to do.\n");
1672        return WINED3D_OK;
1673     }
1674
1675     stream->buffer = buffer;
1676     if (buffer)
1677     {
1678         stream->stride = stride;
1679         stream->offset = offset;
1680     }
1681
1682     /* Handle recording of state blocks. */
1683     if (device->isRecordingState)
1684     {
1685         TRACE("Recording... not performing anything.\n");
1686         if (buffer)
1687             wined3d_buffer_incref(buffer);
1688         if (prev_buffer)
1689             wined3d_buffer_decref(prev_buffer);
1690         return WINED3D_OK;
1691     }
1692
1693     if (buffer)
1694     {
1695         InterlockedIncrement(&buffer->resource.bind_count);
1696         wined3d_buffer_incref(buffer);
1697     }
1698     if (prev_buffer)
1699     {
1700         InterlockedDecrement(&prev_buffer->resource.bind_count);
1701         wined3d_buffer_decref(prev_buffer);
1702     }
1703
1704     device_invalidate_state(device, STATE_STREAMSRC);
1705
1706     return WINED3D_OK;
1707 }
1708
1709 HRESULT CDECL wined3d_device_get_stream_source(const struct wined3d_device *device,
1710         UINT stream_idx, struct wined3d_buffer **buffer, UINT *offset, UINT *stride)
1711 {
1712     struct wined3d_stream_state *stream;
1713
1714     TRACE("device %p, stream_idx %u, buffer %p, offset %p, stride %p.\n",
1715             device, stream_idx, buffer, offset, stride);
1716
1717     if (stream_idx >= MAX_STREAMS)
1718     {
1719         WARN("Stream index %u out of range.\n", stream_idx);
1720         return WINED3DERR_INVALIDCALL;
1721     }
1722
1723     stream = &device->stateBlock->state.streams[stream_idx];
1724     *buffer = stream->buffer;
1725     if (*buffer)
1726         wined3d_buffer_incref(*buffer);
1727     if (offset)
1728         *offset = stream->offset;
1729     *stride = stream->stride;
1730
1731     return WINED3D_OK;
1732 }
1733
1734 HRESULT CDECL wined3d_device_set_stream_source_freq(struct wined3d_device *device, UINT stream_idx, UINT divider)
1735 {
1736     struct wined3d_stream_state *stream;
1737     UINT old_flags, old_freq;
1738
1739     TRACE("device %p, stream_idx %u, divider %#x.\n", device, stream_idx, divider);
1740
1741     /* Verify input. At least in d3d9 this is invalid. */
1742     if ((divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (divider & WINED3DSTREAMSOURCE_INDEXEDDATA))
1743     {
1744         WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL.\n");
1745         return WINED3DERR_INVALIDCALL;
1746     }
1747     if ((divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && !stream_idx)
1748     {
1749         WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL.\n");
1750         return WINED3DERR_INVALIDCALL;
1751     }
1752     if (!divider)
1753     {
1754         WARN("Divider is 0, returning D3DERR_INVALIDCALL.\n");
1755         return WINED3DERR_INVALIDCALL;
1756     }
1757
1758     stream = &device->updateStateBlock->state.streams[stream_idx];
1759     old_flags = stream->flags;
1760     old_freq = stream->frequency;
1761
1762     stream->flags = divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA);
1763     stream->frequency = divider & 0x7fffff;
1764
1765     device->updateStateBlock->changed.streamFreq |= 1 << stream_idx;
1766
1767     if (stream->frequency != old_freq || stream->flags != old_flags)
1768         device_invalidate_state(device, STATE_STREAMSRC);
1769
1770     return WINED3D_OK;
1771 }
1772
1773 HRESULT CDECL wined3d_device_get_stream_source_freq(const struct wined3d_device *device,
1774         UINT stream_idx, UINT *divider)
1775 {
1776     struct wined3d_stream_state *stream;
1777
1778     TRACE("device %p, stream_idx %u, divider %p.\n", device, stream_idx, divider);
1779
1780     stream = &device->updateStateBlock->state.streams[stream_idx];
1781     *divider = stream->flags | stream->frequency;
1782
1783     TRACE("Returning %#x.\n", *divider);
1784
1785     return WINED3D_OK;
1786 }
1787
1788 HRESULT CDECL wined3d_device_set_transform(struct wined3d_device *device,
1789         enum wined3d_transform_state d3dts, const struct wined3d_matrix *matrix)
1790 {
1791     TRACE("device %p, state %s, matrix %p.\n",
1792             device, debug_d3dtstype(d3dts), matrix);
1793
1794     /* Handle recording of state blocks. */
1795     if (device->isRecordingState)
1796     {
1797         TRACE("Recording... not performing anything.\n");
1798         device->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
1799         device->updateStateBlock->state.transforms[d3dts] = *matrix;
1800         return WINED3D_OK;
1801     }
1802
1803     /* If the new matrix is the same as the current one,
1804      * we cut off any further processing. this seems to be a reasonable
1805      * optimization because as was noticed, some apps (warcraft3 for example)
1806      * tend towards setting the same matrix repeatedly for some reason.
1807      *
1808      * From here on we assume that the new matrix is different, wherever it matters. */
1809     if (!memcmp(&device->stateBlock->state.transforms[d3dts].u.m[0][0], matrix, sizeof(*matrix)))
1810     {
1811         TRACE("The application is setting the same matrix over again.\n");
1812         return WINED3D_OK;
1813     }
1814
1815     conv_mat(matrix, &device->stateBlock->state.transforms[d3dts].u.m[0][0]);
1816
1817     /* ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
1818      * where ViewMat = Camera space, WorldMat = world space.
1819      *
1820      * In OpenGL, camera and world space is combined into GL_MODELVIEW
1821      * matrix.  The Projection matrix stay projection matrix. */
1822
1823     if (d3dts == WINED3D_TS_VIEW)
1824         device->view_ident = !memcmp(matrix, identity, 16 * sizeof(float));
1825
1826     if (d3dts < WINED3D_TS_WORLD_MATRIX(device->adapter->gl_info.limits.blends))
1827         device_invalidate_state(device, STATE_TRANSFORM(d3dts));
1828
1829     return WINED3D_OK;
1830
1831 }
1832
1833 HRESULT CDECL wined3d_device_get_transform(const struct wined3d_device *device,
1834         enum wined3d_transform_state state, struct wined3d_matrix *matrix)
1835 {
1836     TRACE("device %p, state %s, matrix %p.\n", device, debug_d3dtstype(state), matrix);
1837
1838     *matrix = device->stateBlock->state.transforms[state];
1839
1840     return WINED3D_OK;
1841 }
1842
1843 HRESULT CDECL wined3d_device_multiply_transform(struct wined3d_device *device,
1844         enum wined3d_transform_state state, const struct wined3d_matrix *matrix)
1845 {
1846     const struct wined3d_matrix *mat = NULL;
1847     struct wined3d_matrix temp;
1848
1849     TRACE("device %p, state %s, matrix %p.\n", device, debug_d3dtstype(state), matrix);
1850
1851     /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
1852      * below means it will be recorded in a state block change, but it
1853      * works regardless where it is recorded.
1854      * If this is found to be wrong, change to StateBlock. */
1855     if (state > HIGHEST_TRANSFORMSTATE)
1856     {
1857         WARN("Unhandled transform state %#x.\n", state);
1858         return WINED3D_OK;
1859     }
1860
1861     mat = &device->updateStateBlock->state.transforms[state];
1862     multiply_matrix(&temp, mat, matrix);
1863
1864     /* Apply change via set transform - will reapply to eg. lights this way. */
1865     return wined3d_device_set_transform(device, state, &temp);
1866 }
1867
1868 /* Note lights are real special cases. Although the device caps state only
1869  * e.g. 8 are supported, you can reference any indexes you want as long as
1870  * that number max are enabled at any one point in time. Therefore since the
1871  * indices can be anything, we need a hashmap of them. However, this causes
1872  * stateblock problems. When capturing the state block, I duplicate the
1873  * hashmap, but when recording, just build a chain pretty much of commands to
1874  * be replayed. */
1875 HRESULT CDECL wined3d_device_set_light(struct wined3d_device *device,
1876         UINT light_idx, const struct wined3d_light *light)
1877 {
1878     UINT hash_idx = LIGHTMAP_HASHFUNC(light_idx);
1879     struct wined3d_light_info *object = NULL;
1880     struct list *e;
1881     float rho;
1882
1883     TRACE("device %p, light_idx %u, light %p.\n", device, light_idx, light);
1884
1885     /* Check the parameter range. Need for speed most wanted sets junk lights
1886      * which confuse the GL driver. */
1887     if (!light)
1888         return WINED3DERR_INVALIDCALL;
1889
1890     switch (light->type)
1891     {
1892         case WINED3D_LIGHT_POINT:
1893         case WINED3D_LIGHT_SPOT:
1894         case WINED3D_LIGHT_PARALLELPOINT:
1895         case WINED3D_LIGHT_GLSPOT:
1896             /* Incorrect attenuation values can cause the gl driver to crash.
1897              * Happens with Need for speed most wanted. */
1898             if (light->attenuation0 < 0.0f || light->attenuation1 < 0.0f || light->attenuation2 < 0.0f)
1899             {
1900                 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL.\n");
1901                 return WINED3DERR_INVALIDCALL;
1902             }
1903             break;
1904
1905         case WINED3D_LIGHT_DIRECTIONAL:
1906             /* Ignores attenuation */
1907             break;
1908
1909         default:
1910         WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
1911         return WINED3DERR_INVALIDCALL;
1912     }
1913
1914     LIST_FOR_EACH(e, &device->updateStateBlock->state.light_map[hash_idx])
1915     {
1916         object = LIST_ENTRY(e, struct wined3d_light_info, entry);
1917         if (object->OriginalIndex == light_idx)
1918             break;
1919         object = NULL;
1920     }
1921
1922     if (!object)
1923     {
1924         TRACE("Adding new light\n");
1925         object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1926         if (!object)
1927         {
1928             ERR("Out of memory error when allocating a light\n");
1929             return E_OUTOFMEMORY;
1930         }
1931         list_add_head(&device->updateStateBlock->state.light_map[hash_idx], &object->entry);
1932         object->glIndex = -1;
1933         object->OriginalIndex = light_idx;
1934     }
1935
1936     /* Initialize the object. */
1937     TRACE("Light %d setting to type %d, Diffuse(%f,%f,%f,%f), Specular(%f,%f,%f,%f), Ambient(%f,%f,%f,%f)\n",
1938             light_idx, light->type,
1939             light->diffuse.r, light->diffuse.g, light->diffuse.b, light->diffuse.a,
1940             light->specular.r, light->specular.g, light->specular.b, light->specular.a,
1941             light->ambient.r, light->ambient.g, light->ambient.b, light->ambient.a);
1942     TRACE("... Pos(%f,%f,%f), Dir(%f,%f,%f)\n", light->position.x, light->position.y, light->position.z,
1943             light->direction.x, light->direction.y, light->direction.z);
1944     TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n",
1945             light->range, light->falloff, light->theta, light->phi);
1946
1947     /* Save away the information. */
1948     object->OriginalParms = *light;
1949
1950     switch (light->type)
1951     {
1952         case WINED3D_LIGHT_POINT:
1953             /* Position */
1954             object->lightPosn[0] = light->position.x;
1955             object->lightPosn[1] = light->position.y;
1956             object->lightPosn[2] = light->position.z;
1957             object->lightPosn[3] = 1.0f;
1958             object->cutoff = 180.0f;
1959             /* FIXME: Range */
1960             break;
1961
1962         case WINED3D_LIGHT_DIRECTIONAL:
1963             /* Direction */
1964             object->lightPosn[0] = -light->direction.x;
1965             object->lightPosn[1] = -light->direction.y;
1966             object->lightPosn[2] = -light->direction.z;
1967             object->lightPosn[3] = 0.0f;
1968             object->exponent = 0.0f;
1969             object->cutoff = 180.0f;
1970             break;
1971
1972         case WINED3D_LIGHT_SPOT:
1973             /* Position */
1974             object->lightPosn[0] = light->position.x;
1975             object->lightPosn[1] = light->position.y;
1976             object->lightPosn[2] = light->position.z;
1977             object->lightPosn[3] = 1.0f;
1978
1979             /* Direction */
1980             object->lightDirn[0] = light->direction.x;
1981             object->lightDirn[1] = light->direction.y;
1982             object->lightDirn[2] = light->direction.z;
1983             object->lightDirn[3] = 1.0f;
1984
1985             /* opengl-ish and d3d-ish spot lights use too different models
1986              * for the light "intensity" as a function of the angle towards
1987              * the main light direction, so we only can approximate very
1988              * roughly. However, spot lights are rather rarely used in games
1989              * (if ever used at all). Furthermore if still used, probably
1990              * nobody pays attention to such details. */
1991             if (!light->falloff)
1992             {
1993                 /* Falloff = 0 is easy, because d3d's and opengl's spot light
1994                  * equations have the falloff resp. exponent parameter as an
1995                  * exponent, so the spot light lighting will always be 1.0 for
1996                  * both of them, and we don't have to care for the rest of the
1997                  * rather complex calculation. */
1998                 object->exponent = 0.0f;
1999             }
2000             else
2001             {
2002                 rho = light->theta + (light->phi - light->theta) / (2 * light->falloff);
2003                 if (rho < 0.0001f)
2004                     rho = 0.0001f;
2005                 object->exponent = -0.3f / logf(cosf(rho / 2));
2006             }
2007
2008             if (object->exponent > 128.0f)
2009                 object->exponent = 128.0f;
2010
2011             object->cutoff = (float)(light->phi * 90 / M_PI);
2012             /* FIXME: Range */
2013             break;
2014
2015         default:
2016             FIXME("Unrecognized light type %#x.\n", light->type);
2017     }
2018
2019     /* Update the live definitions if the light is currently assigned a glIndex. */
2020     if (object->glIndex != -1 && !device->isRecordingState)
2021         device_invalidate_state(device, STATE_ACTIVELIGHT(object->glIndex));
2022
2023     return WINED3D_OK;
2024 }
2025
2026 HRESULT CDECL wined3d_device_get_light(const struct wined3d_device *device,
2027         UINT light_idx, struct wined3d_light *light)
2028 {
2029     UINT hash_idx = LIGHTMAP_HASHFUNC(light_idx);
2030     struct wined3d_light_info *light_info = NULL;
2031     struct list *e;
2032
2033     TRACE("device %p, light_idx %u, light %p.\n", device, light_idx, light);
2034
2035     LIST_FOR_EACH(e, &device->stateBlock->state.light_map[hash_idx])
2036     {
2037         light_info = LIST_ENTRY(e, struct wined3d_light_info, entry);
2038         if (light_info->OriginalIndex == light_idx)
2039             break;
2040         light_info = NULL;
2041     }
2042
2043     if (!light_info)
2044     {
2045         TRACE("Light information requested but light not defined\n");
2046         return WINED3DERR_INVALIDCALL;
2047     }
2048
2049     *light = light_info->OriginalParms;
2050     return WINED3D_OK;
2051 }
2052
2053 HRESULT CDECL wined3d_device_set_light_enable(struct wined3d_device *device, UINT light_idx, BOOL enable)
2054 {
2055     UINT hash_idx = LIGHTMAP_HASHFUNC(light_idx);
2056     struct wined3d_light_info *light_info = NULL;
2057     struct list *e;
2058
2059     TRACE("device %p, light_idx %u, enable %#x.\n", device, light_idx, enable);
2060
2061     LIST_FOR_EACH(e, &device->updateStateBlock->state.light_map[hash_idx])
2062     {
2063         light_info = LIST_ENTRY(e, struct wined3d_light_info, entry);
2064         if (light_info->OriginalIndex == light_idx)
2065             break;
2066         light_info = NULL;
2067     }
2068     TRACE("Found light %p.\n", light_info);
2069
2070     /* Special case - enabling an undefined light creates one with a strict set of parameters. */
2071     if (!light_info)
2072     {
2073         TRACE("Light enabled requested but light not defined, so defining one!\n");
2074         wined3d_device_set_light(device, light_idx, &WINED3D_default_light);
2075
2076         /* Search for it again! Should be fairly quick as near head of list. */
2077         LIST_FOR_EACH(e, &device->updateStateBlock->state.light_map[hash_idx])
2078         {
2079             light_info = LIST_ENTRY(e, struct wined3d_light_info, entry);
2080             if (light_info->OriginalIndex == light_idx)
2081                 break;
2082             light_info = NULL;
2083         }
2084         if (!light_info)
2085         {
2086             FIXME("Adding default lights has failed dismally\n");
2087             return WINED3DERR_INVALIDCALL;
2088         }
2089     }
2090
2091     if (!enable)
2092     {
2093         if (light_info->glIndex != -1)
2094         {
2095             if (!device->isRecordingState)
2096                 device_invalidate_state(device, STATE_ACTIVELIGHT(light_info->glIndex));
2097
2098             device->updateStateBlock->state.lights[light_info->glIndex] = NULL;
2099             light_info->glIndex = -1;
2100         }
2101         else
2102         {
2103             TRACE("Light already disabled, nothing to do\n");
2104         }
2105         light_info->enabled = FALSE;
2106     }
2107     else
2108     {
2109         light_info->enabled = TRUE;
2110         if (light_info->glIndex != -1)
2111         {
2112             TRACE("Nothing to do as light was enabled\n");
2113         }
2114         else
2115         {
2116             unsigned int i;
2117             const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
2118             /* Find a free GL light. */
2119             for (i = 0; i < gl_info->limits.lights; ++i)
2120             {
2121                 if (!device->updateStateBlock->state.lights[i])
2122                 {
2123                     device->updateStateBlock->state.lights[i] = light_info;
2124                     light_info->glIndex = i;
2125                     break;
2126                 }
2127             }
2128             if (light_info->glIndex == -1)
2129             {
2130                 /* Our tests show that Windows returns D3D_OK in this situation, even with
2131                  * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2132                  * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2133                  * as well for those lights.
2134                  *
2135                  * TODO: Test how this affects rendering. */
2136                 WARN("Too many concurrently active lights\n");
2137                 return WINED3D_OK;
2138             }
2139
2140             /* i == light_info->glIndex */
2141             if (!device->isRecordingState)
2142                 device_invalidate_state(device, STATE_ACTIVELIGHT(i));
2143         }
2144     }
2145
2146     return WINED3D_OK;
2147 }
2148
2149 HRESULT CDECL wined3d_device_get_light_enable(const struct wined3d_device *device, UINT light_idx, BOOL *enable)
2150 {
2151     UINT hash_idx = LIGHTMAP_HASHFUNC(light_idx);
2152     struct wined3d_light_info *light_info = NULL;
2153     struct list *e;
2154
2155     TRACE("device %p, light_idx %u, enable %p.\n", device, light_idx, enable);
2156
2157     LIST_FOR_EACH(e, &device->stateBlock->state.light_map[hash_idx])
2158     {
2159         light_info = LIST_ENTRY(e, struct wined3d_light_info, entry);
2160         if (light_info->OriginalIndex == light_idx)
2161             break;
2162         light_info = NULL;
2163     }
2164
2165     if (!light_info)
2166     {
2167         TRACE("Light enabled state requested but light not defined.\n");
2168         return WINED3DERR_INVALIDCALL;
2169     }
2170     /* true is 128 according to SetLightEnable */
2171     *enable = light_info->enabled ? 128 : 0;
2172     return WINED3D_OK;
2173 }
2174
2175 HRESULT CDECL wined3d_device_set_clip_plane(struct wined3d_device *device, UINT plane_idx, const float *plane)
2176 {
2177     TRACE("device %p, plane_idx %u, plane %p.\n", device, plane_idx, plane);
2178
2179     /* Validate plane_idx. */
2180     if (plane_idx >= device->adapter->gl_info.limits.clipplanes)
2181     {
2182         TRACE("Application has requested clipplane this device doesn't support.\n");
2183         return WINED3DERR_INVALIDCALL;
2184     }
2185
2186     device->updateStateBlock->changed.clipplane |= 1 << plane_idx;
2187
2188     if (device->updateStateBlock->state.clip_planes[plane_idx][0] == plane[0]
2189             && device->updateStateBlock->state.clip_planes[plane_idx][1] == plane[1]
2190             && device->updateStateBlock->state.clip_planes[plane_idx][2] == plane[2]
2191             && device->updateStateBlock->state.clip_planes[plane_idx][3] == plane[3])
2192     {
2193         TRACE("Application is setting old values over, nothing to do.\n");
2194         return WINED3D_OK;
2195     }
2196
2197     device->updateStateBlock->state.clip_planes[plane_idx][0] = plane[0];
2198     device->updateStateBlock->state.clip_planes[plane_idx][1] = plane[1];
2199     device->updateStateBlock->state.clip_planes[plane_idx][2] = plane[2];
2200     device->updateStateBlock->state.clip_planes[plane_idx][3] = plane[3];
2201
2202     /* Handle recording of state blocks. */
2203     if (device->isRecordingState)
2204     {
2205         TRACE("Recording... not performing anything.\n");
2206         return WINED3D_OK;
2207     }
2208
2209     device_invalidate_state(device, STATE_CLIPPLANE(plane_idx));
2210
2211     return WINED3D_OK;
2212 }
2213
2214 HRESULT CDECL wined3d_device_get_clip_plane(const struct wined3d_device *device, UINT plane_idx, float *plane)
2215 {
2216     TRACE("device %p, plane_idx %u, plane %p.\n", device, plane_idx, plane);
2217
2218     /* Validate plane_idx. */
2219     if (plane_idx >= device->adapter->gl_info.limits.clipplanes)
2220     {
2221         TRACE("Application has requested clipplane this device doesn't support.\n");
2222         return WINED3DERR_INVALIDCALL;
2223     }
2224
2225     plane[0] = (float)device->stateBlock->state.clip_planes[plane_idx][0];
2226     plane[1] = (float)device->stateBlock->state.clip_planes[plane_idx][1];
2227     plane[2] = (float)device->stateBlock->state.clip_planes[plane_idx][2];
2228     plane[3] = (float)device->stateBlock->state.clip_planes[plane_idx][3];
2229
2230     return WINED3D_OK;
2231 }
2232
2233 HRESULT CDECL wined3d_device_set_clip_status(struct wined3d_device *device,
2234         const struct wined3d_clip_status *clip_status)
2235 {
2236     FIXME("device %p, clip_status %p stub!\n", device, clip_status);
2237
2238     if (!clip_status)
2239         return WINED3DERR_INVALIDCALL;
2240
2241     return WINED3D_OK;
2242 }
2243
2244 HRESULT CDECL wined3d_device_get_clip_status(const struct wined3d_device *device,
2245         struct wined3d_clip_status *clip_status)
2246 {
2247     FIXME("device %p, clip_status %p stub!\n", device, clip_status);
2248
2249     if (!clip_status)
2250         return WINED3DERR_INVALIDCALL;
2251
2252     return WINED3D_OK;
2253 }
2254
2255 HRESULT CDECL wined3d_device_set_material(struct wined3d_device *device, const struct wined3d_material *material)
2256 {
2257     TRACE("device %p, material %p.\n", device, material);
2258
2259     device->updateStateBlock->changed.material = TRUE;
2260     device->updateStateBlock->state.material = *material;
2261
2262     /* Handle recording of state blocks */
2263     if (device->isRecordingState)
2264     {
2265         TRACE("Recording... not performing anything.\n");
2266         return WINED3D_OK;
2267     }
2268
2269     device_invalidate_state(device, STATE_MATERIAL);
2270
2271     return WINED3D_OK;
2272 }
2273
2274 HRESULT CDECL wined3d_device_get_material(const struct wined3d_device *device, struct wined3d_material *material)
2275 {
2276     TRACE("device %p, material %p.\n", device, material);
2277
2278     *material = device->updateStateBlock->state.material;
2279
2280     TRACE("diffuse {%.8e, %.8e, %.8e, %.8e}\n",
2281             material->diffuse.r, material->diffuse.g,
2282             material->diffuse.b, material->diffuse.a);
2283     TRACE("ambient {%.8e, %.8e, %.8e, %.8e}\n",
2284             material->ambient.r, material->ambient.g,
2285             material->ambient.b, material->ambient.a);
2286     TRACE("specular {%.8e, %.8e, %.8e, %.8e}\n",
2287             material->specular.r, material->specular.g,
2288             material->specular.b, material->specular.a);
2289     TRACE("emissive {%.8e, %.8e, %.8e, %.8e}\n",
2290             material->emissive.r, material->emissive.g,
2291             material->emissive.b, material->emissive.a);
2292     TRACE("power %.8e.\n", material->power);
2293
2294     return WINED3D_OK;
2295 }
2296
2297 HRESULT CDECL wined3d_device_set_index_buffer(struct wined3d_device *device,
2298         struct wined3d_buffer *buffer, enum wined3d_format_id format_id)
2299 {
2300     struct wined3d_buffer *prev_buffer;
2301
2302     TRACE("device %p, buffer %p, format %s.\n",
2303             device, buffer, debug_d3dformat(format_id));
2304
2305     prev_buffer = device->updateStateBlock->state.index_buffer;
2306
2307     device->updateStateBlock->changed.indices = TRUE;
2308     device->updateStateBlock->state.index_buffer = buffer;
2309     device->updateStateBlock->state.index_format = format_id;
2310
2311     /* Handle recording of state blocks. */
2312     if (device->isRecordingState)
2313     {
2314         TRACE("Recording... not performing anything.\n");
2315         if (buffer)
2316             wined3d_buffer_incref(buffer);
2317         if (prev_buffer)
2318             wined3d_buffer_decref(prev_buffer);
2319         return WINED3D_OK;
2320     }
2321
2322     if (prev_buffer != buffer)
2323     {
2324         device_invalidate_state(device, STATE_INDEXBUFFER);
2325         if (buffer)
2326         {
2327             InterlockedIncrement(&buffer->resource.bind_count);
2328             wined3d_buffer_incref(buffer);
2329         }
2330         if (prev_buffer)
2331         {
2332             InterlockedDecrement(&prev_buffer->resource.bind_count);
2333             wined3d_buffer_decref(prev_buffer);
2334         }
2335     }
2336
2337     return WINED3D_OK;
2338 }
2339
2340 HRESULT CDECL wined3d_device_get_index_buffer(const struct wined3d_device *device, struct wined3d_buffer **buffer)
2341 {
2342     TRACE("device %p, buffer %p.\n", device, buffer);
2343
2344     *buffer = device->stateBlock->state.index_buffer;
2345
2346     if (*buffer)
2347         wined3d_buffer_incref(*buffer);
2348
2349     TRACE("Returning %p.\n", *buffer);
2350
2351     return WINED3D_OK;
2352 }
2353
2354 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2355 HRESULT CDECL wined3d_device_set_base_vertex_index(struct wined3d_device *device, INT base_index)
2356 {
2357     TRACE("device %p, base_index %d.\n", device, base_index);
2358
2359     if (device->updateStateBlock->state.base_vertex_index == base_index)
2360     {
2361         TRACE("Application is setting the old value over, nothing to do\n");
2362         return WINED3D_OK;
2363     }
2364
2365     device->updateStateBlock->state.base_vertex_index = base_index;
2366
2367     if (device->isRecordingState)
2368     {
2369         TRACE("Recording... not performing anything\n");
2370         return WINED3D_OK;
2371     }
2372     return WINED3D_OK;
2373 }
2374
2375 INT CDECL wined3d_device_get_base_vertex_index(const struct wined3d_device *device)
2376 {
2377     TRACE("device %p.\n", device);
2378
2379     return device->stateBlock->state.base_vertex_index;
2380 }
2381
2382 HRESULT CDECL wined3d_device_set_viewport(struct wined3d_device *device, const struct wined3d_viewport *viewport)
2383 {
2384     TRACE("device %p, viewport %p.\n", device, viewport);
2385     TRACE("x %u, y %u, w %u, h %u, min_z %.8e, max_z %.8e.\n",
2386           viewport->x, viewport->y, viewport->width, viewport->height, viewport->min_z, viewport->max_z);
2387
2388     device->updateStateBlock->changed.viewport = TRUE;
2389     device->updateStateBlock->state.viewport = *viewport;
2390
2391     /* Handle recording of state blocks */
2392     if (device->isRecordingState)
2393     {
2394         TRACE("Recording... not performing anything\n");
2395         return WINED3D_OK;
2396     }
2397
2398     device_invalidate_state(device, STATE_VIEWPORT);
2399
2400     return WINED3D_OK;
2401 }
2402
2403 HRESULT CDECL wined3d_device_get_viewport(const struct wined3d_device *device, struct wined3d_viewport *viewport)
2404 {
2405     TRACE("device %p, viewport %p.\n", device, viewport);
2406
2407     *viewport = device->stateBlock->state.viewport;
2408
2409     return WINED3D_OK;
2410 }
2411
2412 HRESULT CDECL wined3d_device_set_render_state(struct wined3d_device *device,
2413         enum wined3d_render_state state, DWORD value)
2414 {
2415     DWORD old_value = device->stateBlock->state.render_states[state];
2416
2417     TRACE("device %p, state %s (%#x), value %#x.\n", device, debug_d3drenderstate(state), state, value);
2418
2419     device->updateStateBlock->changed.renderState[state >> 5] |= 1 << (state & 0x1f);
2420     device->updateStateBlock->state.render_states[state] = value;
2421
2422     /* Handle recording of state blocks. */
2423     if (device->isRecordingState)
2424     {
2425         TRACE("Recording... not performing anything.\n");
2426         return WINED3D_OK;
2427     }
2428
2429     /* Compared here and not before the assignment to allow proper stateblock recording. */
2430     if (value == old_value)
2431         TRACE("Application is setting the old value over, nothing to do.\n");
2432     else
2433         device_invalidate_state(device, STATE_RENDER(state));
2434
2435     return WINED3D_OK;
2436 }
2437
2438 HRESULT CDECL wined3d_device_get_render_state(const struct wined3d_device *device,
2439         enum wined3d_render_state state, DWORD *value)
2440 {
2441     TRACE("device %p, state %s (%#x), value %p.\n", device, debug_d3drenderstate(state), state, value);
2442
2443     *value = device->stateBlock->state.render_states[state];
2444
2445     return WINED3D_OK;
2446 }
2447
2448 HRESULT CDECL wined3d_device_set_sampler_state(struct wined3d_device *device,
2449         UINT sampler_idx, enum wined3d_sampler_state state, DWORD value)
2450 {
2451     DWORD old_value;
2452
2453     TRACE("device %p, sampler_idx %u, state %s, value %#x.\n",
2454             device, sampler_idx, debug_d3dsamplerstate(state), value);
2455
2456     if (sampler_idx >= WINED3DVERTEXTEXTURESAMPLER0 && sampler_idx <= WINED3DVERTEXTEXTURESAMPLER3)
2457         sampler_idx -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2458
2459     if (sampler_idx >= sizeof(device->stateBlock->state.sampler_states)
2460             / sizeof(*device->stateBlock->state.sampler_states))
2461     {
2462         WARN("Invalid sampler %u.\n", sampler_idx);
2463         return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2464     }
2465
2466     old_value = device->stateBlock->state.sampler_states[sampler_idx][state];
2467     device->updateStateBlock->state.sampler_states[sampler_idx][state] = value;
2468     device->updateStateBlock->changed.samplerState[sampler_idx] |= 1 << state;
2469
2470     /* Handle recording of state blocks. */
2471     if (device->isRecordingState)
2472     {
2473         TRACE("Recording... not performing anything.\n");
2474         return WINED3D_OK;
2475     }
2476
2477     if (old_value == value)
2478     {
2479         TRACE("Application is setting the old value over, nothing to do.\n");
2480         return WINED3D_OK;
2481     }
2482
2483     device_invalidate_state(device, STATE_SAMPLER(sampler_idx));
2484
2485     return WINED3D_OK;
2486 }
2487
2488 HRESULT CDECL wined3d_device_get_sampler_state(const struct wined3d_device *device,
2489         UINT sampler_idx, enum wined3d_sampler_state state, DWORD *value)
2490 {
2491     TRACE("device %p, sampler_idx %u, state %s, value %p.\n",
2492             device, sampler_idx, debug_d3dsamplerstate(state), value);
2493
2494     if (sampler_idx >= WINED3DVERTEXTEXTURESAMPLER0 && sampler_idx <= WINED3DVERTEXTEXTURESAMPLER3)
2495         sampler_idx -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2496
2497     if (sampler_idx >= sizeof(device->stateBlock->state.sampler_states)
2498             / sizeof(*device->stateBlock->state.sampler_states))
2499     {
2500         WARN("Invalid sampler %u.\n", sampler_idx);
2501         return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2502     }
2503
2504     *value = device->stateBlock->state.sampler_states[sampler_idx][state];
2505     TRACE("Returning %#x.\n", *value);
2506
2507     return WINED3D_OK;
2508 }
2509
2510 HRESULT CDECL wined3d_device_set_scissor_rect(struct wined3d_device *device, const RECT *rect)
2511 {
2512     TRACE("device %p, rect %s.\n", device, wine_dbgstr_rect(rect));
2513
2514     device->updateStateBlock->changed.scissorRect = TRUE;
2515     if (EqualRect(&device->updateStateBlock->state.scissor_rect, rect))
2516     {
2517         TRACE("App is setting the old scissor rectangle over, nothing to do.\n");
2518         return WINED3D_OK;
2519     }
2520     CopyRect(&device->updateStateBlock->state.scissor_rect, rect);
2521
2522     if (device->isRecordingState)
2523     {
2524         TRACE("Recording... not performing anything.\n");
2525         return WINED3D_OK;
2526     }
2527
2528     device_invalidate_state(device, STATE_SCISSORRECT);
2529
2530     return WINED3D_OK;
2531 }
2532
2533 HRESULT CDECL wined3d_device_get_scissor_rect(const struct wined3d_device *device, RECT *rect)
2534 {
2535     TRACE("device %p, rect %p.\n", device, rect);
2536
2537     *rect = device->updateStateBlock->state.scissor_rect;
2538     TRACE("Returning rect %s.\n", wine_dbgstr_rect(rect));
2539
2540     return WINED3D_OK;
2541 }
2542
2543 HRESULT CDECL wined3d_device_set_vertex_declaration(struct wined3d_device *device,
2544         struct wined3d_vertex_declaration *declaration)
2545 {
2546     struct wined3d_vertex_declaration *prev = device->updateStateBlock->state.vertex_declaration;
2547
2548     TRACE("device %p, declaration %p.\n", device, declaration);
2549
2550     if (declaration)
2551         wined3d_vertex_declaration_incref(declaration);
2552     if (prev)
2553         wined3d_vertex_declaration_decref(prev);
2554
2555     device->updateStateBlock->state.vertex_declaration = declaration;
2556     device->updateStateBlock->changed.vertexDecl = TRUE;
2557
2558     if (device->isRecordingState)
2559     {
2560         TRACE("Recording... not performing anything.\n");
2561         return WINED3D_OK;
2562     }
2563     else if (declaration == prev)
2564     {
2565         /* Checked after the assignment to allow proper stateblock recording. */
2566         TRACE("Application is setting the old declaration over, nothing to do.\n");
2567         return WINED3D_OK;
2568     }
2569
2570     device_invalidate_state(device, STATE_VDECL);
2571     return WINED3D_OK;
2572 }
2573
2574 HRESULT CDECL wined3d_device_get_vertex_declaration(const struct wined3d_device *device,
2575         struct wined3d_vertex_declaration **declaration)
2576 {
2577     TRACE("device %p, declaration %p.\n", device, declaration);
2578
2579     *declaration = device->stateBlock->state.vertex_declaration;
2580     if (*declaration)
2581         wined3d_vertex_declaration_incref(*declaration);
2582
2583     return WINED3D_OK;
2584 }
2585
2586 HRESULT CDECL wined3d_device_set_vertex_shader(struct wined3d_device *device, struct wined3d_shader *shader)
2587 {
2588     struct wined3d_shader *prev = device->updateStateBlock->state.vertex_shader;
2589
2590     TRACE("device %p, shader %p.\n", device, shader);
2591
2592     device->updateStateBlock->state.vertex_shader = shader;
2593     device->updateStateBlock->changed.vertexShader = TRUE;
2594
2595     if (device->isRecordingState)
2596     {
2597         if (shader)
2598             wined3d_shader_incref(shader);
2599         if (prev)
2600             wined3d_shader_decref(prev);
2601         TRACE("Recording... not performing anything.\n");
2602         return WINED3D_OK;
2603     }
2604
2605     if (shader == prev)
2606     {
2607         TRACE("Application is setting the old shader over, nothing to do.\n");
2608         return WINED3D_OK;
2609     }
2610
2611     if (shader)
2612         wined3d_shader_incref(shader);
2613     if (prev)
2614         wined3d_shader_decref(prev);
2615
2616     device_invalidate_state(device, STATE_VSHADER);
2617
2618     return WINED3D_OK;
2619 }
2620
2621 struct wined3d_shader * CDECL wined3d_device_get_vertex_shader(const struct wined3d_device *device)
2622 {
2623     struct wined3d_shader *shader;
2624
2625     TRACE("device %p.\n", device);
2626
2627     shader = device->stateBlock->state.vertex_shader;
2628     if (shader)
2629         wined3d_shader_incref(shader);
2630
2631     TRACE("Returning %p.\n", shader);
2632     return shader;
2633 }
2634
2635 HRESULT CDECL wined3d_device_set_vs_consts_b(struct wined3d_device *device,
2636         UINT start_register, const BOOL *constants, UINT bool_count)
2637 {
2638     UINT count = min(bool_count, MAX_CONST_B - start_register);
2639     UINT i;
2640
2641     TRACE("device %p, start_register %u, constants %p, bool_count %u.\n",
2642             device, start_register, constants, bool_count);
2643
2644     if (!constants || start_register >= MAX_CONST_B)
2645         return WINED3DERR_INVALIDCALL;
2646
2647     memcpy(&device->updateStateBlock->state.vs_consts_b[start_register], constants, count * sizeof(BOOL));
2648     for (i = 0; i < count; ++i)
2649         TRACE("Set BOOL constant %u to %s.\n", start_register + i, constants[i] ? "true" : "false");
2650
2651     for (i = start_register; i < count + start_register; ++i)
2652         device->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
2653
2654     if (!device->isRecordingState)
2655         device_invalidate_state(device, STATE_VERTEXSHADERCONSTANT);
2656
2657     return WINED3D_OK;
2658 }
2659
2660 HRESULT CDECL wined3d_device_get_vs_consts_b(const struct wined3d_device *device,
2661         UINT start_register, BOOL *constants, UINT bool_count)
2662 {
2663     UINT count = min(bool_count, MAX_CONST_B - start_register);
2664
2665     TRACE("device %p, start_register %u, constants %p, bool_count %u.\n",
2666             device, start_register, constants, bool_count);
2667
2668     if (!constants || start_register >= MAX_CONST_B)
2669         return WINED3DERR_INVALIDCALL;
2670
2671     memcpy(constants, &device->stateBlock->state.vs_consts_b[start_register], count * sizeof(BOOL));
2672
2673     return WINED3D_OK;
2674 }
2675
2676 HRESULT CDECL wined3d_device_set_vs_consts_i(struct wined3d_device *device,
2677         UINT start_register, const int *constants, UINT vector4i_count)
2678 {
2679     UINT count = min(vector4i_count, MAX_CONST_I - start_register);
2680     UINT i;
2681
2682     TRACE("device %p, start_register %u, constants %p, vector4i_count %u.\n",
2683             device, start_register, constants, vector4i_count);
2684
2685     if (!constants || start_register >= MAX_CONST_I)
2686         return WINED3DERR_INVALIDCALL;
2687
2688     memcpy(&device->updateStateBlock->state.vs_consts_i[start_register * 4], constants, count * sizeof(int) * 4);
2689     for (i = 0; i < count; ++i)
2690         TRACE("Set INT constant %u to {%d, %d, %d, %d}.\n", start_register + i,
2691                 constants[i * 4], constants[i * 4 + 1],
2692                 constants[i * 4 + 2], constants[i * 4 + 3]);
2693
2694     for (i = start_register; i < count + start_register; ++i)
2695         device->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
2696
2697     if (!device->isRecordingState)
2698         device_invalidate_state(device, STATE_VERTEXSHADERCONSTANT);
2699
2700     return WINED3D_OK;
2701 }
2702
2703 HRESULT CDECL wined3d_device_get_vs_consts_i(const struct wined3d_device *device,
2704         UINT start_register, int *constants, UINT vector4i_count)
2705 {
2706     UINT count = min(vector4i_count, MAX_CONST_I - start_register);
2707
2708     TRACE("device %p, start_register %u, constants %p, vector4i_count %u.\n",
2709             device, start_register, constants, vector4i_count);
2710
2711     if (!constants || start_register >= MAX_CONST_I)
2712         return WINED3DERR_INVALIDCALL;
2713
2714     memcpy(constants, &device->stateBlock->state.vs_consts_i[start_register * 4], count * sizeof(int) * 4);
2715     return WINED3D_OK;
2716 }
2717
2718 HRESULT CDECL wined3d_device_set_vs_consts_f(struct wined3d_device *device,
2719         UINT start_register, const float *constants, UINT vector4f_count)
2720 {
2721     UINT i;
2722
2723     TRACE("device %p, start_register %u, constants %p, vector4f_count %u.\n",
2724             device, start_register, constants, vector4f_count);
2725
2726     /* Specifically test start_register > limit to catch MAX_UINT overflows
2727      * when adding start_register + vector4f_count. */
2728     if (!constants
2729             || start_register + vector4f_count > device->d3d_vshader_constantF
2730             || start_register > device->d3d_vshader_constantF)
2731         return WINED3DERR_INVALIDCALL;
2732
2733     memcpy(&device->updateStateBlock->state.vs_consts_f[start_register * 4],
2734             constants, vector4f_count * sizeof(float) * 4);
2735     if (TRACE_ON(d3d))
2736     {
2737         for (i = 0; i < vector4f_count; ++i)
2738             TRACE("Set FLOAT constant %u to {%.8e, %.8e, %.8e, %.8e}.\n", start_register + i,
2739                     constants[i * 4], constants[i * 4 + 1],
2740                     constants[i * 4 + 2], constants[i * 4 + 3]);
2741     }
2742
2743     if (!device->isRecordingState)
2744     {
2745         device->shader_backend->shader_update_float_vertex_constants(device, start_register, vector4f_count);
2746         device_invalidate_state(device, STATE_VERTEXSHADERCONSTANT);
2747     }
2748
2749     memset(device->updateStateBlock->changed.vertexShaderConstantsF + start_register, 1,
2750             sizeof(*device->updateStateBlock->changed.vertexShaderConstantsF) * vector4f_count);
2751
2752     return WINED3D_OK;
2753 }
2754
2755 HRESULT CDECL wined3d_device_get_vs_consts_f(const struct wined3d_device *device,
2756         UINT start_register, float *constants, UINT vector4f_count)
2757 {
2758     int count = min(vector4f_count, device->d3d_vshader_constantF - start_register);
2759
2760     TRACE("device %p, start_register %u, constants %p, vector4f_count %u.\n",
2761             device, start_register, constants, vector4f_count);
2762
2763     if (!constants || count < 0)
2764         return WINED3DERR_INVALIDCALL;
2765
2766     memcpy(constants, &device->stateBlock->state.vs_consts_f[start_register * 4], count * sizeof(float) * 4);
2767
2768     return WINED3D_OK;
2769 }
2770
2771 static void device_invalidate_texture_stage(const struct wined3d_device *device, DWORD stage)
2772 {
2773     DWORD i;
2774
2775     for (i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
2776     {
2777         device_invalidate_state(device, STATE_TEXTURESTAGE(stage, i));
2778     }
2779 }
2780
2781 static void device_map_stage(struct wined3d_device *device, DWORD stage, DWORD unit)
2782 {
2783     DWORD i = device->rev_tex_unit_map[unit];
2784     DWORD j = device->texUnitMap[stage];
2785
2786     device->texUnitMap[stage] = unit;
2787     if (i != WINED3D_UNMAPPED_STAGE && i != stage)
2788         device->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
2789
2790     device->rev_tex_unit_map[unit] = stage;
2791     if (j != WINED3D_UNMAPPED_STAGE && j != unit)
2792         device->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
2793 }
2794
2795 static void device_update_fixed_function_usage_map(struct wined3d_device *device)
2796 {
2797     UINT i;
2798
2799     device->fixed_function_usage_map = 0;
2800     for (i = 0; i < MAX_TEXTURES; ++i)
2801     {
2802         const struct wined3d_state *state = &device->stateBlock->state;
2803         enum wined3d_texture_op color_op = state->texture_states[i][WINED3D_TSS_COLOR_OP];
2804         enum wined3d_texture_op alpha_op = state->texture_states[i][WINED3D_TSS_ALPHA_OP];
2805         DWORD color_arg1 = state->texture_states[i][WINED3D_TSS_COLOR_ARG1] & WINED3DTA_SELECTMASK;
2806         DWORD color_arg2 = state->texture_states[i][WINED3D_TSS_COLOR_ARG2] & WINED3DTA_SELECTMASK;
2807         DWORD color_arg3 = state->texture_states[i][WINED3D_TSS_COLOR_ARG0] & WINED3DTA_SELECTMASK;
2808         DWORD alpha_arg1 = state->texture_states[i][WINED3D_TSS_ALPHA_ARG1] & WINED3DTA_SELECTMASK;
2809         DWORD alpha_arg2 = state->texture_states[i][WINED3D_TSS_ALPHA_ARG2] & WINED3DTA_SELECTMASK;
2810         DWORD alpha_arg3 = state->texture_states[i][WINED3D_TSS_ALPHA_ARG0] & WINED3DTA_SELECTMASK;
2811
2812         /* Not used, and disable higher stages. */
2813         if (color_op == WINED3D_TOP_DISABLE)
2814             break;
2815
2816         if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3D_TOP_SELECT_ARG2)
2817                 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3D_TOP_SELECT_ARG1)
2818                 || ((color_arg3 == WINED3DTA_TEXTURE)
2819                     && (color_op == WINED3D_TOP_MULTIPLY_ADD || color_op == WINED3D_TOP_LERP))
2820                 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3D_TOP_SELECT_ARG2)
2821                 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3D_TOP_SELECT_ARG1)
2822                 || ((alpha_arg3 == WINED3DTA_TEXTURE)
2823                     && (alpha_op == WINED3D_TOP_MULTIPLY_ADD || alpha_op == WINED3D_TOP_LERP)))
2824             device->fixed_function_usage_map |= (1 << i);
2825
2826         if ((color_op == WINED3D_TOP_BUMPENVMAP || color_op == WINED3D_TOP_BUMPENVMAP_LUMINANCE)
2827                 && i < MAX_TEXTURES - 1)
2828             device->fixed_function_usage_map |= (1 << (i + 1));
2829     }
2830 }
2831
2832 static void device_map_fixed_function_samplers(struct wined3d_device *device, const struct wined3d_gl_info *gl_info)
2833 {
2834     unsigned int i, tex;
2835     WORD ffu_map;
2836
2837     device_update_fixed_function_usage_map(device);
2838     ffu_map = device->fixed_function_usage_map;
2839
2840     if (device->max_ffp_textures == gl_info->limits.texture_stages
2841             || device->stateBlock->state.lowest_disabled_stage <= device->max_ffp_textures)
2842     {
2843         for (i = 0; ffu_map; ffu_map >>= 1, ++i)
2844         {
2845             if (!(ffu_map & 1)) continue;
2846
2847             if (device->texUnitMap[i] != i)
2848             {
2849                 device_map_stage(device, i, i);
2850                 device_invalidate_state(device, STATE_SAMPLER(i));
2851                 device_invalidate_texture_stage(device, i);
2852             }
2853         }
2854         return;
2855     }
2856
2857     /* Now work out the mapping */
2858     tex = 0;
2859     for (i = 0; ffu_map; ffu_map >>= 1, ++i)
2860     {
2861         if (!(ffu_map & 1)) continue;
2862
2863         if (device->texUnitMap[i] != tex)
2864         {
2865             device_map_stage(device, i, tex);
2866             device_invalidate_state(device, STATE_SAMPLER(i));
2867             device_invalidate_texture_stage(device, i);
2868         }
2869
2870         ++tex;
2871     }
2872 }
2873
2874 static void device_map_psamplers(struct wined3d_device *device, const struct wined3d_gl_info *gl_info)
2875 {
2876     const enum wined3d_sampler_texture_type *sampler_type =
2877             device->stateBlock->state.pixel_shader->reg_maps.sampler_type;
2878     unsigned int i;
2879
2880     for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i)
2881     {
2882         if (sampler_type[i] && device->texUnitMap[i] != i)
2883         {
2884             device_map_stage(device, i, i);
2885             device_invalidate_state(device, STATE_SAMPLER(i));
2886             if (i < gl_info->limits.texture_stages)
2887                 device_invalidate_texture_stage(device, i);
2888         }
2889     }
2890 }
2891
2892 static BOOL device_unit_free_for_vs(const struct wined3d_device *device,
2893         const enum wined3d_sampler_texture_type *pshader_sampler_tokens,
2894         const enum wined3d_sampler_texture_type *vshader_sampler_tokens, DWORD unit)
2895 {
2896     DWORD current_mapping = device->rev_tex_unit_map[unit];
2897
2898     /* Not currently used */
2899     if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
2900
2901     if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
2902         /* Used by a fragment sampler */
2903
2904         if (!pshader_sampler_tokens) {
2905             /* No pixel shader, check fixed function */
2906             return current_mapping >= MAX_TEXTURES || !(device->fixed_function_usage_map & (1 << current_mapping));
2907         }
2908
2909         /* Pixel shader, check the shader's sampler map */
2910         return !pshader_sampler_tokens[current_mapping];
2911     }
2912
2913     /* Used by a vertex sampler */
2914     return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
2915 }
2916
2917 static void device_map_vsamplers(struct wined3d_device *device, BOOL ps, const struct wined3d_gl_info *gl_info)
2918 {
2919     const enum wined3d_sampler_texture_type *vshader_sampler_type =
2920             device->stateBlock->state.vertex_shader->reg_maps.sampler_type;
2921     const enum wined3d_sampler_texture_type *pshader_sampler_type = NULL;
2922     int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
2923     int i;
2924
2925     if (ps)
2926     {
2927         /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
2928          * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
2929         pshader_sampler_type = device->stateBlock->state.pixel_shader->reg_maps.sampler_type;
2930     }
2931
2932     for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
2933         DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
2934         if (vshader_sampler_type[i])
2935         {
2936             if (device->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
2937             {
2938                 /* Already mapped somewhere */
2939                 continue;
2940             }
2941
2942             while (start >= 0)
2943             {
2944                 if (device_unit_free_for_vs(device, pshader_sampler_type, vshader_sampler_type, start))
2945                 {
2946                     device_map_stage(device, vsampler_idx, start);
2947                     device_invalidate_state(device, STATE_SAMPLER(vsampler_idx));
2948
2949                     --start;
2950                     break;
2951                 }
2952
2953                 --start;
2954             }
2955         }
2956     }
2957 }
2958
2959 void device_update_tex_unit_map(struct wined3d_device *device)
2960 {
2961     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
2962     const struct wined3d_state *state = &device->stateBlock->state;
2963     BOOL vs = use_vs(state);
2964     BOOL ps = use_ps(state);
2965     /*
2966      * Rules are:
2967      * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
2968      * that would be really messy and require shader recompilation
2969      * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
2970      * to be reset. Because of that try to work with a 1:1 mapping as much as possible
2971      */
2972     if (ps)
2973         device_map_psamplers(device, gl_info);
2974     else
2975         device_map_fixed_function_samplers(device, gl_info);
2976
2977     if (vs)
2978         device_map_vsamplers(device, ps, gl_info);
2979 }
2980
2981 HRESULT CDECL wined3d_device_set_pixel_shader(struct wined3d_device *device, struct wined3d_shader *shader)
2982 {
2983     struct wined3d_shader *prev = device->updateStateBlock->state.pixel_shader;
2984
2985     TRACE("device %p, shader %p.\n", device, shader);
2986
2987     device->updateStateBlock->state.pixel_shader = shader;
2988     device->updateStateBlock->changed.pixelShader = TRUE;
2989
2990     if (device->isRecordingState)
2991     {
2992         if (shader)
2993             wined3d_shader_incref(shader);
2994         if (prev)
2995             wined3d_shader_decref(prev);
2996         TRACE("Recording... not performing anything.\n");
2997         return WINED3D_OK;
2998     }
2999
3000     if (shader == prev)
3001     {
3002         TRACE("Application is setting the old shader over, nothing to do.\n");
3003         return WINED3D_OK;
3004     }
3005
3006     if (shader)
3007         wined3d_shader_incref(shader);
3008     if (prev)
3009         wined3d_shader_decref(prev);
3010
3011     device_invalidate_state(device, STATE_PIXELSHADER);
3012
3013     return WINED3D_OK;
3014 }
3015
3016 struct wined3d_shader * CDECL wined3d_device_get_pixel_shader(const struct wined3d_device *device)
3017 {
3018     struct wined3d_shader *shader;
3019
3020     TRACE("device %p.\n", device);
3021
3022     shader = device->stateBlock->state.pixel_shader;
3023     if (shader)
3024         wined3d_shader_incref(shader);
3025
3026     TRACE("Returning %p.\n", shader);
3027     return shader;
3028 }
3029
3030 HRESULT CDECL wined3d_device_set_ps_consts_b(struct wined3d_device *device,
3031         UINT start_register, const BOOL *constants, UINT bool_count)
3032 {
3033     UINT count = min(bool_count, MAX_CONST_B - start_register);
3034     UINT i;
3035
3036     TRACE("device %p, start_register %u, constants %p, bool_count %u.\n",
3037             device, start_register, constants, bool_count);
3038
3039     if (!constants || start_register >= MAX_CONST_B)
3040         return WINED3DERR_INVALIDCALL;
3041
3042     memcpy(&device->updateStateBlock->state.ps_consts_b[start_register], constants, count * sizeof(BOOL));
3043     for (i = 0; i < count; ++i)
3044         TRACE("Set BOOL constant %u to %s.\n", start_register + i, constants[i] ? "true" : "false");
3045
3046     for (i = start_register; i < count + start_register; ++i)
3047         device->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3048
3049     if (!device->isRecordingState)
3050         device_invalidate_state(device, STATE_PIXELSHADERCONSTANT);
3051
3052     return WINED3D_OK;
3053 }
3054
3055 HRESULT CDECL wined3d_device_get_ps_consts_b(const struct wined3d_device *device,
3056         UINT start_register, BOOL *constants, UINT bool_count)
3057 {
3058     UINT count = min(bool_count, MAX_CONST_B - start_register);
3059
3060     TRACE("device %p, start_register %u, constants %p, bool_count %u.\n",
3061             device, start_register, constants, bool_count);
3062
3063     if (!constants || start_register >= MAX_CONST_B)
3064         return WINED3DERR_INVALIDCALL;
3065
3066     memcpy(constants, &device->stateBlock->state.ps_consts_b[start_register], count * sizeof(BOOL));
3067
3068     return WINED3D_OK;
3069 }
3070
3071 HRESULT CDECL wined3d_device_set_ps_consts_i(struct wined3d_device *device,
3072         UINT start_register, const int *constants, UINT vector4i_count)
3073 {
3074     UINT count = min(vector4i_count, MAX_CONST_I - start_register);
3075     UINT i;
3076
3077     TRACE("device %p, start_register %u, constants %p, vector4i_count %u.\n",
3078             device, start_register, constants, vector4i_count);
3079
3080     if (!constants || start_register >= MAX_CONST_I)
3081         return WINED3DERR_INVALIDCALL;
3082
3083     memcpy(&device->updateStateBlock->state.ps_consts_i[start_register * 4], constants, count * sizeof(int) * 4);
3084     for (i = 0; i < count; ++i)
3085         TRACE("Set INT constant %u to {%d, %d, %d, %d}.\n", start_register + i,
3086                 constants[i * 4], constants[i * 4 + 1],
3087                 constants[i * 4 + 2], constants[i * 4 + 3]);
3088
3089     for (i = start_register; i < count + start_register; ++i)
3090         device->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3091
3092     if (!device->isRecordingState)
3093         device_invalidate_state(device, STATE_PIXELSHADERCONSTANT);
3094
3095     return WINED3D_OK;
3096 }
3097
3098 HRESULT CDECL wined3d_device_get_ps_consts_i(const struct wined3d_device *device,
3099         UINT start_register, int *constants, UINT vector4i_count)
3100 {
3101     UINT count = min(vector4i_count, MAX_CONST_I - start_register);
3102
3103     TRACE("device %p, start_register %u, constants %p, vector4i_count %u.\n",
3104             device, start_register, constants, vector4i_count);
3105
3106     if (!constants || start_register >= MAX_CONST_I)
3107         return WINED3DERR_INVALIDCALL;
3108
3109     memcpy(constants, &device->stateBlock->state.ps_consts_i[start_register * 4], count * sizeof(int) * 4);
3110
3111     return WINED3D_OK;
3112 }
3113
3114 HRESULT CDECL wined3d_device_set_ps_consts_f(struct wined3d_device *device,
3115         UINT start_register, const float *constants, UINT vector4f_count)
3116 {
3117     UINT i;
3118
3119     TRACE("device %p, start_register %u, constants %p, vector4f_count %u.\n",
3120             device, start_register, constants, vector4f_count);
3121
3122     /* Specifically test start_register > limit to catch MAX_UINT overflows
3123      * when adding start_register + vector4f_count. */
3124     if (!constants
3125             || start_register + vector4f_count > device->d3d_pshader_constantF
3126             || start_register > device->d3d_pshader_constantF)
3127         return WINED3DERR_INVALIDCALL;
3128
3129     memcpy(&device->updateStateBlock->state.ps_consts_f[start_register * 4],
3130             constants, vector4f_count * sizeof(float) * 4);
3131     if (TRACE_ON(d3d))
3132     {
3133         for (i = 0; i < vector4f_count; ++i)
3134             TRACE("Set FLOAT constant %u to {%.8e, %.8e, %.8e, %.8e}.\n", start_register + i,
3135                     constants[i * 4], constants[i * 4 + 1],
3136                     constants[i * 4 + 2], constants[i * 4 + 3]);
3137     }
3138
3139     if (!device->isRecordingState)
3140     {
3141         device->shader_backend->shader_update_float_pixel_constants(device, start_register, vector4f_count);
3142         device_invalidate_state(device, STATE_PIXELSHADERCONSTANT);
3143     }
3144
3145     memset(device->updateStateBlock->changed.pixelShaderConstantsF + start_register, 1,
3146             sizeof(*device->updateStateBlock->changed.pixelShaderConstantsF) * vector4f_count);
3147
3148     return WINED3D_OK;
3149 }
3150
3151 HRESULT CDECL wined3d_device_get_ps_consts_f(const struct wined3d_device *device,
3152         UINT start_register, float *constants, UINT vector4f_count)
3153 {
3154     int count = min(vector4f_count, device->d3d_pshader_constantF - start_register);
3155
3156     TRACE("device %p, start_register %u, constants %p, vector4f_count %u.\n",
3157             device, start_register, constants, vector4f_count);
3158
3159     if (!constants || count < 0)
3160         return WINED3DERR_INVALIDCALL;
3161
3162     memcpy(constants, &device->stateBlock->state.ps_consts_f[start_register * 4], count * sizeof(float) * 4);
3163
3164     return WINED3D_OK;
3165 }
3166
3167 /* Context activation is done by the caller. */
3168 /* Do not call while under the GL lock. */
3169 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3170 static HRESULT process_vertices_strided(const struct wined3d_device *device, DWORD dwDestIndex, DWORD dwCount,
3171         const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD flags,
3172         DWORD DestFVF)
3173 {
3174     struct wined3d_matrix mat, proj_mat, view_mat, world_mat;
3175     struct wined3d_viewport vp;
3176     UINT vertex_size;
3177     unsigned int i;
3178     BYTE *dest_ptr;
3179     BOOL doClip;
3180     DWORD numTextures;
3181     HRESULT hr;
3182
3183     if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3184     {
3185         WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3186     }
3187
3188     if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3189     {
3190         ERR("Source has no position mask\n");
3191         return WINED3DERR_INVALIDCALL;
3192     }
3193
3194     if (device->stateBlock->state.render_states[WINED3D_RS_CLIPPING])
3195     {
3196         static BOOL warned = FALSE;
3197         /*
3198          * The clipping code is not quite correct. Some things need
3199          * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3200          * so disable clipping for now.
3201          * (The graphics in Half-Life are broken, and my processvertices
3202          *  test crashes with IDirect3DDevice3)
3203         doClip = TRUE;
3204          */
3205         doClip = FALSE;
3206         if(!warned) {
3207            warned = TRUE;
3208            FIXME("Clipping is broken and disabled for now\n");
3209         }
3210     }
3211     else
3212         doClip = FALSE;
3213
3214     vertex_size = get_flexible_vertex_size(DestFVF);
3215     if (FAILED(hr = wined3d_buffer_map(dest, dwDestIndex * vertex_size, dwCount * vertex_size, &dest_ptr, 0)))
3216     {
3217         WARN("Failed to map buffer, hr %#x.\n", hr);
3218         return hr;
3219     }
3220
3221     wined3d_device_get_transform(device, WINED3D_TS_VIEW, &view_mat);
3222     wined3d_device_get_transform(device, WINED3D_TS_PROJECTION, &proj_mat);
3223     wined3d_device_get_transform(device, WINED3D_TS_WORLD_MATRIX(0), &world_mat);
3224
3225     TRACE("View mat:\n");
3226     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);
3227     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);
3228     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);
3229     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);
3230
3231     TRACE("Proj mat:\n");
3232     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);
3233     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);
3234     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);
3235     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);
3236
3237     TRACE("World mat:\n");
3238     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);
3239     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);
3240     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);
3241     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);
3242
3243     /* Get the viewport */
3244     wined3d_device_get_viewport(device, &vp);
3245     TRACE("viewport  x %u, y %u, width %u, height %u, min_z %.8e, max_z %.8e.\n",
3246           vp.x, vp.y, vp.width, vp.height, vp.min_z, vp.max_z);
3247
3248     multiply_matrix(&mat,&view_mat,&world_mat);
3249     multiply_matrix(&mat,&proj_mat,&mat);
3250
3251     numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3252
3253     for (i = 0; i < dwCount; i+= 1) {
3254         unsigned int tex_index;
3255
3256         if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3257              ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3258             /* The position first */
3259             const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3260             const float *p = (const float *)(element->data.addr + i * element->stride);
3261             float x, y, z, rhw;
3262             TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3263
3264             /* Multiplication with world, view and projection matrix */
3265             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);
3266             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);
3267             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);
3268             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);
3269
3270             TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3271
3272             /* WARNING: The following things are taken from d3d7 and were not yet checked
3273              * against d3d8 or d3d9!
3274              */
3275
3276             /* Clipping conditions: From msdn
3277              *
3278              * A vertex is clipped if it does not match the following requirements
3279              * -rhw < x <= rhw
3280              * -rhw < y <= rhw
3281              *    0 < z <= rhw
3282              *    0 < rhw ( Not in d3d7, but tested in d3d7)
3283              *
3284              * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3285              * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3286              *
3287              */
3288
3289             if( !doClip ||
3290                 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3291                   (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3292                   ( rhw > eps ) ) ) {
3293
3294                 /* "Normal" viewport transformation (not clipped)
3295                  * 1) The values are divided by rhw
3296                  * 2) The y axis is negative, so multiply it with -1
3297                  * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3298                  *    -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3299                  * 4) Multiply x with Width/2 and add Width/2
3300                  * 5) The same for the height
3301                  * 6) Add the viewpoint X and Y to the 2D coordinates and
3302                  *    The minimum Z value to z
3303                  * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3304                  *
3305                  * Well, basically it's simply a linear transformation into viewport
3306                  * coordinates
3307                  */
3308
3309                 x /= rhw;
3310                 y /= rhw;
3311                 z /= rhw;
3312
3313                 y *= -1;
3314
3315                 x *= vp.width / 2;
3316                 y *= vp.height / 2;
3317                 z *= vp.max_z - vp.min_z;
3318
3319                 x += vp.width / 2 + vp.x;
3320                 y += vp.height / 2 + vp.y;
3321                 z += vp.min_z;
3322
3323                 rhw = 1 / rhw;
3324             } else {
3325                 /* That vertex got clipped
3326                  * Contrary to OpenGL it is not dropped completely, it just
3327                  * undergoes a different calculation.
3328                  */
3329                 TRACE("Vertex got clipped\n");
3330                 x += rhw;
3331                 y += rhw;
3332
3333                 x  /= 2;
3334                 y  /= 2;
3335
3336                 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3337                  * outside of the main vertex buffer memory. That needs some more
3338                  * investigation...
3339                  */
3340             }
3341
3342             TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3343
3344
3345             ( (float *) dest_ptr)[0] = x;
3346             ( (float *) dest_ptr)[1] = y;
3347             ( (float *) dest_ptr)[2] = z;
3348             ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3349
3350             dest_ptr += 3 * sizeof(float);
3351
3352             if ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW)
3353                 dest_ptr += sizeof(float);
3354         }
3355
3356         if (DestFVF & WINED3DFVF_PSIZE)
3357             dest_ptr += sizeof(DWORD);
3358
3359         if (DestFVF & WINED3DFVF_NORMAL)
3360         {
3361             const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
3362             const float *normal = (const float *)(element->data.addr + i * element->stride);
3363             /* AFAIK this should go into the lighting information */
3364             FIXME("Didn't expect the destination to have a normal\n");
3365             copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3366         }
3367
3368         if (DestFVF & WINED3DFVF_DIFFUSE)
3369         {
3370             const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
3371             const DWORD *color_d = (const DWORD *)(element->data.addr + i * element->stride);
3372             if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
3373             {
3374                 static BOOL warned = FALSE;
3375
3376                 if(!warned) {
3377                     ERR("No diffuse color in source, but destination has one\n");
3378                     warned = TRUE;
3379                 }
3380
3381                 *( (DWORD *) dest_ptr) = 0xffffffff;
3382                 dest_ptr += sizeof(DWORD);
3383             }
3384             else
3385             {
3386                 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3387             }
3388         }
3389
3390         if (DestFVF & WINED3DFVF_SPECULAR)
3391         {
3392             /* What's the color value in the feedback buffer? */
3393             const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
3394             const DWORD *color_s = (const DWORD *)(element->data.addr + i * element->stride);
3395             if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
3396             {
3397                 static BOOL warned = FALSE;
3398
3399                 if(!warned) {
3400                     ERR("No specular color in source, but destination has one\n");
3401                     warned = TRUE;
3402                 }
3403
3404                 *( (DWORD *) dest_ptr) = 0xFF000000;
3405                 dest_ptr += sizeof(DWORD);
3406             }
3407             else
3408             {
3409                 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3410             }
3411         }
3412
3413         for (tex_index = 0; tex_index < numTextures; ++tex_index)
3414         {
3415             const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
3416             const float *tex_coord = (const float *)(element->data.addr + i * element->stride);
3417             if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
3418             {
3419                 ERR("No source texture, but destination requests one\n");
3420                 dest_ptr += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3421             }
3422             else
3423             {
3424                 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3425             }
3426         }
3427     }
3428
3429     wined3d_buffer_unmap(dest);
3430
3431     return WINED3D_OK;
3432 }
3433 #undef copy_and_next
3434
3435 /* Do not call while under the GL lock. */
3436 HRESULT CDECL wined3d_device_process_vertices(struct wined3d_device *device,
3437         UINT src_start_idx, UINT dst_idx, UINT vertex_count, struct wined3d_buffer *dst_buffer,
3438         const struct wined3d_vertex_declaration *declaration, DWORD flags, DWORD dst_fvf)
3439 {
3440     struct wined3d_state *state = &device->stateBlock->state;
3441     struct wined3d_stream_info stream_info;
3442     const struct wined3d_gl_info *gl_info;
3443     BOOL streamWasUP = state->user_stream;
3444     struct wined3d_context *context;
3445     struct wined3d_shader *vs;
3446     unsigned int i;
3447     HRESULT hr;
3448
3449     TRACE("device %p, src_start_idx %u, dst_idx %u, vertex_count %u, "
3450             "dst_buffer %p, declaration %p, flags %#x, dst_fvf %#x.\n",
3451             device, src_start_idx, dst_idx, vertex_count,
3452             dst_buffer, declaration, flags, dst_fvf);
3453
3454     if (declaration)
3455         FIXME("Output vertex declaration not implemented yet.\n");
3456
3457     /* Need any context to write to the vbo. */
3458     context = context_acquire(device, NULL);
3459     gl_info = context->gl_info;
3460
3461     /* ProcessVertices reads from vertex buffers, which have to be assigned.
3462      * DrawPrimitive and DrawPrimitiveUP control the streamIsUP flag, thus
3463      * restore it afterwards. */
3464     vs = state->vertex_shader;
3465     state->vertex_shader = NULL;
3466     state->user_stream = FALSE;
3467     device_stream_info_from_declaration(device, &stream_info);
3468     state->user_stream = streamWasUP;
3469     state->vertex_shader = vs;
3470
3471     /* We can't convert FROM a VBO, and vertex buffers used to source into
3472      * process_vertices() are unlikely to ever be used for drawing. Release
3473      * VBOs in those buffers and fix up the stream_info structure.
3474      *
3475      * Also apply the start index. */
3476     for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
3477     {
3478         struct wined3d_stream_info_element *e;
3479
3480         if (!(stream_info.use_map & (1 << i)))
3481             continue;
3482
3483         e = &stream_info.elements[i];
3484         if (e->data.buffer_object)
3485         {
3486             struct wined3d_buffer *vb = state->streams[e->stream_idx].buffer;
3487             e->data.buffer_object = 0;
3488             e->data.addr = (BYTE *)((ULONG_PTR)e->data.addr + (ULONG_PTR)buffer_get_sysmem(vb, gl_info));
3489             ENTER_GL();
3490             GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
3491             vb->buffer_object = 0;
3492             LEAVE_GL();
3493         }
3494         if (e->data.addr)
3495             e->data.addr += e->stride * src_start_idx;
3496     }
3497
3498     hr = process_vertices_strided(device, dst_idx, vertex_count,
3499             &stream_info, dst_buffer, flags, dst_fvf);
3500
3501     context_release(context);
3502
3503     return hr;
3504 }
3505
3506 HRESULT CDECL wined3d_device_set_texture_stage_state(struct wined3d_device *device,
3507         UINT stage, enum wined3d_texture_stage_state state, DWORD value)
3508 {
3509     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
3510     DWORD old_value;
3511
3512     TRACE("device %p, stage %u, state %s, value %#x.\n",
3513             device, stage, debug_d3dtexturestate(state), value);
3514
3515     if (state > WINED3D_HIGHEST_TEXTURE_STATE)
3516     {
3517         WARN("Invalid state %#x passed.\n", state);
3518         return WINED3D_OK;
3519     }
3520
3521     if (stage >= gl_info->limits.texture_stages)
3522     {
3523         WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
3524                 stage, gl_info->limits.texture_stages - 1);
3525         return WINED3D_OK;
3526     }
3527
3528     old_value = device->updateStateBlock->state.texture_states[stage][state];
3529     device->updateStateBlock->changed.textureState[stage] |= 1 << state;
3530     device->updateStateBlock->state.texture_states[stage][state] = value;
3531
3532     if (device->isRecordingState)
3533     {
3534         TRACE("Recording... not performing anything.\n");
3535         return WINED3D_OK;
3536     }
3537
3538     /* Checked after the assignments to allow proper stateblock recording. */
3539     if (old_value == value)
3540     {
3541         TRACE("Application is setting the old value over, nothing to do.\n");
3542         return WINED3D_OK;
3543     }
3544
3545     if (stage > device->stateBlock->state.lowest_disabled_stage
3546             && device->StateTable[STATE_TEXTURESTAGE(0, state)].representative
3547             == STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP))
3548     {
3549         /* Colorop change above lowest disabled stage? That won't change
3550          * anything in the GL setup. Changes in other states are important on
3551          * disabled stages too. */
3552         return WINED3D_OK;
3553     }
3554
3555     if (state == WINED3D_TSS_COLOR_OP)
3556     {
3557         unsigned int i;
3558
3559         if (value == WINED3D_TOP_DISABLE && old_value != WINED3D_TOP_DISABLE)
3560         {
3561             /* Previously enabled stage disabled now. Make sure to dirtify
3562              * all enabled stages above stage, they have to be disabled.
3563              *
3564              * The current stage is dirtified below. */
3565             for (i = stage + 1; i < device->stateBlock->state.lowest_disabled_stage; ++i)
3566             {
3567                 TRACE("Additionally dirtifying stage %u.\n", i);
3568                 device_invalidate_state(device, STATE_TEXTURESTAGE(i, WINED3D_TSS_COLOR_OP));
3569             }
3570             device->stateBlock->state.lowest_disabled_stage = stage;
3571             TRACE("New lowest disabled: %u.\n", stage);
3572         }
3573         else if (value != WINED3D_TOP_DISABLE && old_value == WINED3D_TOP_DISABLE)
3574         {
3575             /* Previously disabled stage enabled. Stages above it may need
3576              * enabling. Stage must be lowest_disabled_stage here, if it's
3577              * bigger success is returned above, and stages below the lowest
3578              * disabled stage can't be enabled (because they are enabled
3579              * already).
3580              *
3581              * Again stage stage doesn't need to be dirtified here, it is
3582              * handled below. */
3583             for (i = stage + 1; i < gl_info->limits.texture_stages; ++i)
3584             {
3585                 if (device->updateStateBlock->state.texture_states[i][WINED3D_TSS_COLOR_OP] == WINED3D_TOP_DISABLE)
3586                     break;
3587                 TRACE("Additionally dirtifying stage %u due to enable.\n", i);
3588                 device_invalidate_state(device, STATE_TEXTURESTAGE(i, WINED3D_TSS_COLOR_OP));
3589             }
3590             device->stateBlock->state.lowest_disabled_stage = i;
3591             TRACE("New lowest disabled: %u.\n", i);
3592         }
3593     }
3594
3595     device_invalidate_state(device, STATE_TEXTURESTAGE(stage, state));
3596
3597     return WINED3D_OK;
3598 }
3599
3600 HRESULT CDECL wined3d_device_get_texture_stage_state(const struct wined3d_device *device,
3601         UINT stage, enum wined3d_texture_stage_state state, DWORD *value)
3602 {
3603     TRACE("device %p, stage %u, state %s, value %p.\n",
3604             device, stage, debug_d3dtexturestate(state), value);
3605
3606     if (state > WINED3D_HIGHEST_TEXTURE_STATE)
3607     {
3608         WARN("Invalid state %#x passed.\n", state);
3609         return WINED3D_OK;
3610     }
3611
3612     *value = device->updateStateBlock->state.texture_states[stage][state];
3613     TRACE("Returning %#x.\n", *value);
3614
3615     return WINED3D_OK;
3616 }
3617
3618 HRESULT CDECL wined3d_device_set_texture(struct wined3d_device *device,
3619         UINT stage, struct wined3d_texture *texture)
3620 {
3621     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
3622     struct wined3d_texture *prev;
3623
3624     TRACE("device %p, stage %u, texture %p.\n", device, stage, texture);
3625
3626     if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
3627         stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3628
3629     /* Windows accepts overflowing this array... we do not. */
3630     if (stage >= sizeof(device->stateBlock->state.textures) / sizeof(*device->stateBlock->state.textures))
3631     {
3632         WARN("Ignoring invalid stage %u.\n", stage);
3633         return WINED3D_OK;
3634     }
3635
3636     if (texture && texture->resource.pool == WINED3D_POOL_SCRATCH)
3637     {
3638         WARN("Rejecting attempt to set scratch texture.\n");
3639         return WINED3DERR_INVALIDCALL;
3640     }
3641
3642     device->updateStateBlock->changed.textures |= 1 << stage;
3643
3644     prev = device->updateStateBlock->state.textures[stage];
3645     TRACE("Previous texture %p.\n", prev);
3646
3647     if (texture == prev)
3648     {
3649         TRACE("App is setting the same texture again, nothing to do.\n");
3650         return WINED3D_OK;
3651     }
3652
3653     TRACE("Setting new texture to %p.\n", texture);
3654     device->updateStateBlock->state.textures[stage] = texture;
3655
3656     if (device->isRecordingState)
3657     {
3658         TRACE("Recording... not performing anything\n");
3659
3660         if (texture) wined3d_texture_incref(texture);
3661         if (prev) wined3d_texture_decref(prev);
3662
3663         return WINED3D_OK;
3664     }
3665
3666     if (texture)
3667     {
3668         LONG bind_count = InterlockedIncrement(&texture->resource.bind_count);
3669
3670         wined3d_texture_incref(texture);
3671
3672         if (!prev || texture->target != prev->target)
3673             device_invalidate_state(device, STATE_PIXELSHADER);
3674
3675         if (!prev && stage < gl_info->limits.texture_stages)
3676         {
3677             /* The source arguments for color and alpha ops have different
3678              * meanings when a NULL texture is bound, so the COLOR_OP and
3679              * ALPHA_OP have to be dirtified. */
3680             device_invalidate_state(device, STATE_TEXTURESTAGE(stage, WINED3D_TSS_COLOR_OP));
3681             device_invalidate_state(device, STATE_TEXTURESTAGE(stage, WINED3D_TSS_ALPHA_OP));
3682         }
3683
3684         if (bind_count == 1)
3685             texture->sampler = stage;
3686     }
3687
3688     if (prev)
3689     {
3690         LONG bind_count = InterlockedDecrement(&prev->resource.bind_count);
3691
3692         wined3d_texture_decref(prev);
3693
3694         if (!texture && stage < gl_info->limits.texture_stages)
3695         {
3696             device_invalidate_state(device, STATE_TEXTURESTAGE(stage, WINED3D_TSS_COLOR_OP));
3697             device_invalidate_state(device, STATE_TEXTURESTAGE(stage, WINED3D_TSS_ALPHA_OP));
3698         }
3699
3700         if (bind_count && prev->sampler == stage)
3701         {
3702             unsigned int i;
3703
3704             /* Search for other stages the texture is bound to. Shouldn't
3705              * happen if applications bind textures to a single stage only. */
3706             TRACE("Searching for other stages the texture is bound to.\n");
3707             for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
3708             {
3709                 if (device->updateStateBlock->state.textures[i] == prev)
3710                 {
3711                     TRACE("Texture is also bound to stage %u.\n", i);
3712                     prev->sampler = i;
3713                     break;
3714                 }
3715             }
3716         }
3717     }
3718
3719     device_invalidate_state(device, STATE_SAMPLER(stage));
3720
3721     return WINED3D_OK;
3722 }
3723
3724 HRESULT CDECL wined3d_device_get_texture(const struct wined3d_device *device,
3725         UINT stage, struct wined3d_texture **texture)
3726 {
3727     TRACE("device %p, stage %u, texture %p.\n", device, stage, texture);
3728
3729     if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
3730         stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3731
3732     if (stage >= sizeof(device->stateBlock->state.textures) / sizeof(*device->stateBlock->state.textures))
3733     {
3734         WARN("Ignoring invalid stage %u.\n", stage);
3735         return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3736     }
3737
3738     *texture = device->stateBlock->state.textures[stage];
3739     if (*texture)
3740         wined3d_texture_incref(*texture);
3741
3742     TRACE("Returning %p.\n", *texture);
3743
3744     return WINED3D_OK;
3745 }
3746
3747 HRESULT CDECL wined3d_device_get_back_buffer(const struct wined3d_device *device, UINT swapchain_idx,
3748         UINT backbuffer_idx, enum wined3d_backbuffer_type backbuffer_type, struct wined3d_surface **backbuffer)
3749 {
3750     struct wined3d_swapchain *swapchain;
3751     HRESULT hr;
3752
3753     TRACE("device %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
3754             device, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
3755
3756     hr = wined3d_device_get_swapchain(device, swapchain_idx, &swapchain);
3757     if (FAILED(hr))
3758     {
3759         WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
3760         return hr;
3761     }
3762
3763     hr = wined3d_swapchain_get_back_buffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
3764     wined3d_swapchain_decref(swapchain);
3765     if (FAILED(hr))
3766     {
3767         WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
3768         return hr;
3769     }
3770
3771     return WINED3D_OK;
3772 }
3773
3774 HRESULT CDECL wined3d_device_get_device_caps(const struct wined3d_device *device, WINED3DCAPS *caps)
3775 {
3776     TRACE("device %p, caps %p.\n", device, caps);
3777
3778     return wined3d_get_device_caps(device->wined3d, device->adapter->ordinal,
3779             device->create_parms.device_type, caps);
3780 }
3781
3782 HRESULT CDECL wined3d_device_get_display_mode(const struct wined3d_device *device,
3783         UINT swapchain_idx, struct wined3d_display_mode *mode)
3784 {
3785     struct wined3d_swapchain *swapchain;
3786     HRESULT hr;
3787
3788     TRACE("device %p, swapchain_idx %u, mode %p.\n", device, swapchain_idx, mode);
3789
3790     if (swapchain_idx)
3791     {
3792         hr = wined3d_device_get_swapchain(device, swapchain_idx, &swapchain);
3793         if (SUCCEEDED(hr))
3794         {
3795             hr = wined3d_swapchain_get_display_mode(swapchain, mode);
3796             wined3d_swapchain_decref(swapchain);
3797         }
3798     }
3799     else
3800     {
3801         const struct wined3d_adapter *adapter = device->adapter;
3802
3803         /* Don't read the real display mode, but return the stored mode
3804          * instead. X11 can't change the color depth, and some apps are
3805          * pretty angry if they SetDisplayMode from 24 to 16 bpp and find out
3806          * that GetDisplayMode still returns 24 bpp.
3807          *
3808          * Also don't relay to the swapchain because with ddraw it's possible
3809          * that there isn't a swapchain at all. */
3810         mode->width = adapter->screen_size.cx;
3811         mode->height = adapter->screen_size.cy;
3812         mode->format_id = adapter->screen_format;
3813         mode->refresh_rate = 0;
3814         hr = WINED3D_OK;
3815     }
3816
3817     return hr;
3818 }
3819
3820 HRESULT CDECL wined3d_device_begin_stateblock(struct wined3d_device *device)
3821 {
3822     struct wined3d_stateblock *stateblock;
3823     HRESULT hr;
3824
3825     TRACE("device %p.\n", device);
3826
3827     if (device->isRecordingState)
3828         return WINED3DERR_INVALIDCALL;
3829
3830     hr = wined3d_stateblock_create(device, WINED3D_SBT_RECORDED, &stateblock);
3831     if (FAILED(hr))
3832         return hr;
3833
3834     wined3d_stateblock_decref(device->updateStateBlock);
3835     device->updateStateBlock = stateblock;
3836     device->isRecordingState = TRUE;
3837
3838     TRACE("Recording stateblock %p.\n", stateblock);
3839
3840     return WINED3D_OK;
3841 }
3842
3843 HRESULT CDECL wined3d_device_end_stateblock(struct wined3d_device *device,
3844         struct wined3d_stateblock **stateblock)
3845 {
3846     struct wined3d_stateblock *object = device->updateStateBlock;
3847
3848     TRACE("device %p, stateblock %p.\n", device, stateblock);
3849
3850     if (!device->isRecordingState)
3851     {
3852         WARN("Not recording.\n");
3853         *stateblock = NULL;
3854         return WINED3DERR_INVALIDCALL;
3855     }
3856
3857     stateblock_init_contained_states(object);
3858
3859     *stateblock = object;
3860     device->isRecordingState = FALSE;
3861     device->updateStateBlock = device->stateBlock;
3862     wined3d_stateblock_incref(device->updateStateBlock);
3863
3864     TRACE("Returning stateblock %p.\n", *stateblock);
3865
3866     return WINED3D_OK;
3867 }
3868
3869 HRESULT CDECL wined3d_device_begin_scene(struct wined3d_device *device)
3870 {
3871     /* At the moment we have no need for any functionality at the beginning
3872      * of a scene. */
3873     TRACE("device %p.\n", device);
3874
3875     if (device->inScene)
3876     {
3877         WARN("Already in scene, returning WINED3DERR_INVALIDCALL.\n");
3878         return WINED3DERR_INVALIDCALL;
3879     }
3880     device->inScene = TRUE;
3881     return WINED3D_OK;
3882 }
3883
3884 HRESULT CDECL wined3d_device_end_scene(struct wined3d_device *device)
3885 {
3886     struct wined3d_context *context;
3887
3888     TRACE("device %p.\n", device);
3889
3890     if (!device->inScene)
3891     {
3892         WARN("Not in scene, returning WINED3DERR_INVALIDCALL.\n");
3893         return WINED3DERR_INVALIDCALL;
3894     }
3895
3896     context = context_acquire(device, NULL);
3897     /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
3898     wglFlush();
3899     /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
3900      * fails. */
3901     context_release(context);
3902
3903     device->inScene = FALSE;
3904     return WINED3D_OK;
3905 }
3906
3907 HRESULT CDECL wined3d_device_present(const struct wined3d_device *device, const RECT *src_rect,
3908         const RECT *dst_rect, HWND dst_window_override, const RGNDATA *dirty_region)
3909 {
3910     UINT i;
3911
3912     TRACE("device %p, src_rect %s, dst_rect %s, dst_window_override %p, dirty_region %p.\n",
3913             device, wine_dbgstr_rect(src_rect), wine_dbgstr_rect(dst_rect),
3914             dst_window_override, dirty_region);
3915
3916     for (i = 0; i < device->swapchain_count; ++i)
3917     {
3918         wined3d_swapchain_present(device->swapchains[i], src_rect,
3919                 dst_rect, dst_window_override, dirty_region, 0);
3920     }
3921
3922     return WINED3D_OK;
3923 }
3924
3925 /* Do not call while under the GL lock. */
3926 HRESULT CDECL wined3d_device_clear(struct wined3d_device *device, DWORD rect_count,
3927         const RECT *rects, DWORD flags, const struct wined3d_color *color, float depth, DWORD stencil)
3928 {
3929     RECT draw_rect;
3930
3931     TRACE("device %p, rect_count %u, rects %p, flags %#x, color {%.8e, %.8e, %.8e, %.8e}, depth %.8e, stencil %u.\n",
3932             device, rect_count, rects, flags, color->r, color->g, color->b, color->a, depth, stencil);
3933
3934     if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL))
3935     {
3936         struct wined3d_surface *ds = device->fb.depth_stencil;
3937         if (!ds)
3938         {
3939             WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
3940             /* TODO: What about depth stencil buffers without stencil bits? */
3941             return WINED3DERR_INVALIDCALL;
3942         }
3943         else if (flags & WINED3DCLEAR_TARGET)
3944         {
3945             if (ds->resource.width < device->fb.render_targets[0]->resource.width
3946                     || ds->resource.height < device->fb.render_targets[0]->resource.height)
3947             {
3948                 WARN("Silently ignoring depth and target clear with mismatching sizes\n");
3949                 return WINED3D_OK;
3950             }
3951         }
3952     }
3953
3954     wined3d_get_draw_rect(&device->stateBlock->state, &draw_rect);
3955     device_clear_render_targets(device, device->adapter->gl_info.limits.buffers,
3956             &device->fb, rect_count, rects, &draw_rect, flags, color, depth, stencil);
3957
3958     return WINED3D_OK;
3959 }
3960
3961 void CDECL wined3d_device_set_primitive_type(struct wined3d_device *device,
3962         enum wined3d_primitive_type primitive_type)
3963 {
3964     TRACE("device %p, primitive_type %s\n", device, debug_d3dprimitivetype(primitive_type));
3965
3966     device->updateStateBlock->changed.primitive_type = TRUE;
3967     device->updateStateBlock->state.gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
3968 }
3969
3970 void CDECL wined3d_device_get_primitive_type(const struct wined3d_device *device,
3971         enum wined3d_primitive_type *primitive_type)
3972 {
3973     TRACE("device %p, primitive_type %p\n", device, primitive_type);
3974
3975     *primitive_type = d3d_primitive_type_from_gl(device->stateBlock->state.gl_primitive_type);
3976
3977     TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
3978 }
3979
3980 HRESULT CDECL wined3d_device_draw_primitive(struct wined3d_device *device, UINT start_vertex, UINT vertex_count)
3981 {
3982     TRACE("device %p, start_vertex %u, vertex_count %u.\n", device, start_vertex, vertex_count);
3983
3984     if (!device->stateBlock->state.vertex_declaration)
3985     {
3986         WARN("Called without a valid vertex declaration set.\n");
3987         return WINED3DERR_INVALIDCALL;
3988     }
3989
3990     /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
3991     if (device->stateBlock->state.user_stream)
3992     {
3993         device_invalidate_state(device, STATE_INDEXBUFFER);
3994         device->stateBlock->state.user_stream = FALSE;
3995     }
3996
3997     if (device->stateBlock->state.load_base_vertex_index)
3998     {
3999         device->stateBlock->state.load_base_vertex_index = 0;
4000         device_invalidate_state(device, STATE_BASEVERTEXINDEX);
4001     }
4002
4003     /* Account for the loading offset due to index buffers. Instead of
4004      * reloading all sources correct it with the startvertex parameter. */
4005     drawPrimitive(device, vertex_count, start_vertex, FALSE, NULL);
4006     return WINED3D_OK;
4007 }
4008
4009 HRESULT CDECL wined3d_device_draw_indexed_primitive(struct wined3d_device *device, UINT start_idx, UINT index_count)
4010 {
4011     struct wined3d_buffer *index_buffer;
4012     GLuint vbo;
4013     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
4014
4015     TRACE("device %p, start_idx %u, index_count %u.\n", device, start_idx, index_count);
4016
4017     index_buffer = device->stateBlock->state.index_buffer;
4018     if (!index_buffer)
4019     {
4020         /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4021          * without an index buffer set. (The first time at least...)
4022          * D3D8 simply dies, but I doubt it can do much harm to return
4023          * D3DERR_INVALIDCALL there as well. */
4024         WARN("Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL.\n");
4025         return WINED3DERR_INVALIDCALL;
4026     }
4027
4028     if (!device->stateBlock->state.vertex_declaration)
4029     {
4030         WARN("Called without a valid vertex declaration set.\n");
4031         return WINED3DERR_INVALIDCALL;
4032     }
4033
4034     if (device->stateBlock->state.user_stream)
4035     {
4036         device_invalidate_state(device, STATE_INDEXBUFFER);
4037         device->stateBlock->state.user_stream = FALSE;
4038     }
4039     vbo = index_buffer->buffer_object;
4040
4041     if (!gl_info->supported[ARB_DRAW_ELEMENTS_BASE_VERTEX] &&
4042         device->stateBlock->state.load_base_vertex_index != device->stateBlock->state.base_vertex_index)
4043     {
4044         device->stateBlock->state.load_base_vertex_index = device->stateBlock->state.base_vertex_index;
4045         device_invalidate_state(device, STATE_BASEVERTEXINDEX);
4046     }
4047
4048     drawPrimitive(device, index_count, start_idx, TRUE,
4049             vbo ? NULL : index_buffer->resource.allocatedMemory);
4050
4051     return WINED3D_OK;
4052 }
4053
4054 HRESULT CDECL wined3d_device_draw_primitive_up(struct wined3d_device *device, UINT vertex_count,
4055         const void *stream_data, UINT stream_stride)
4056 {
4057     struct wined3d_stream_state *stream;
4058     struct wined3d_buffer *vb;
4059
4060     TRACE("device %p, vertex count %u, stream_data %p, stream_stride %u.\n",
4061             device, vertex_count, stream_data, stream_stride);
4062
4063     if (!device->stateBlock->state.vertex_declaration)
4064     {
4065         WARN("Called without a valid vertex declaration set.\n");
4066         return WINED3DERR_INVALIDCALL;
4067     }
4068
4069     /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4070     stream = &device->stateBlock->state.streams[0];
4071     vb = stream->buffer;
4072     stream->buffer = (struct wined3d_buffer *)stream_data;
4073     if (vb)
4074         wined3d_buffer_decref(vb);
4075     stream->offset = 0;
4076     stream->stride = stream_stride;
4077     device->stateBlock->state.user_stream = TRUE;
4078     if (device->stateBlock->state.load_base_vertex_index)
4079     {
4080         device->stateBlock->state.load_base_vertex_index = 0;
4081         device_invalidate_state(device, STATE_BASEVERTEXINDEX);
4082     }
4083
4084     /* TODO: Only mark dirty if drawing from a different UP address */
4085     device_invalidate_state(device, STATE_STREAMSRC);
4086
4087     drawPrimitive(device, vertex_count, 0, FALSE, NULL);
4088
4089     /* MSDN specifies stream zero settings must be set to NULL */
4090     stream->buffer = NULL;
4091     stream->stride = 0;
4092
4093     /* stream zero settings set to null at end, as per the msdn. No need to
4094      * mark dirty here, the app has to set the new stream sources or use UP
4095      * drawing again. */
4096     return WINED3D_OK;
4097 }
4098
4099 HRESULT CDECL wined3d_device_draw_indexed_primitive_up(struct wined3d_device *device,
4100         UINT index_count, const void *index_data, enum wined3d_format_id index_data_format_id,
4101         const void *stream_data, UINT stream_stride)
4102 {
4103     struct wined3d_stream_state *stream;
4104     struct wined3d_buffer *vb, *ib;
4105
4106     TRACE("device %p, index_count %u, index_data %p, index_data_format %s, stream_data %p, stream_stride %u.\n",
4107             device, index_count, index_data, debug_d3dformat(index_data_format_id), stream_data, stream_stride);
4108
4109     if (!device->stateBlock->state.vertex_declaration)
4110     {
4111         WARN("(%p) : Called without a valid vertex declaration set\n", device);
4112         return WINED3DERR_INVALIDCALL;
4113     }
4114
4115     stream = &device->stateBlock->state.streams[0];
4116     vb = stream->buffer;
4117     stream->buffer = (struct wined3d_buffer *)stream_data;
4118     if (vb)
4119         wined3d_buffer_decref(vb);
4120     stream->offset = 0;
4121     stream->stride = stream_stride;
4122     device->stateBlock->state.user_stream = TRUE;
4123     device->stateBlock->state.index_format = index_data_format_id;
4124
4125     /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4126     device->stateBlock->state.base_vertex_index = 0;
4127     if (device->stateBlock->state.load_base_vertex_index)
4128     {
4129         device->stateBlock->state.load_base_vertex_index = 0;
4130         device_invalidate_state(device, STATE_BASEVERTEXINDEX);
4131     }
4132     /* Invalidate the state until we have nicer tracking of the stream source pointers */
4133     device_invalidate_state(device, STATE_STREAMSRC);
4134     device_invalidate_state(device, STATE_INDEXBUFFER);
4135
4136     drawPrimitive(device, index_count, 0, TRUE, index_data);
4137
4138     /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4139     stream->buffer = NULL;
4140     stream->stride = 0;
4141     ib = device->stateBlock->state.index_buffer;
4142     if (ib)
4143     {
4144         wined3d_buffer_decref(ib);
4145         device->stateBlock->state.index_buffer = NULL;
4146     }
4147     /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4148      * SetStreamSource to specify a vertex buffer
4149      */
4150
4151     return WINED3D_OK;
4152 }
4153
4154 HRESULT CDECL wined3d_device_draw_primitive_strided(struct wined3d_device *device,
4155         UINT vertex_count, const struct wined3d_strided_data *strided_data)
4156 {
4157     /* Mark the state dirty until we have nicer tracking. It's fine to change
4158      * baseVertexIndex because that call is only called by ddraw which does
4159      * not need that value. */
4160     device_invalidate_state(device, STATE_VDECL);
4161     device_invalidate_state(device, STATE_STREAMSRC);
4162     device_invalidate_state(device, STATE_INDEXBUFFER);
4163
4164     device->stateBlock->state.base_vertex_index = 0;
4165     device->up_strided = strided_data;
4166     drawPrimitive(device, vertex_count, 0, FALSE, NULL);
4167     device->up_strided = NULL;
4168
4169     /* Invalidate the states again to make sure the values from the stateblock
4170      * are properly applied in the next regular draw. Note that the application-
4171      * provided strided data has ovwritten pretty much the entire vertex and
4172      * and index stream related states */
4173     device_invalidate_state(device, STATE_VDECL);
4174     device_invalidate_state(device, STATE_STREAMSRC);
4175     device_invalidate_state(device, STATE_INDEXBUFFER);
4176     return WINED3D_OK;
4177 }
4178
4179 HRESULT CDECL wined3d_device_draw_indexed_primitive_strided(struct wined3d_device *device,
4180         UINT index_count, const struct wined3d_strided_data *strided_data,
4181         UINT vertex_count, const void *index_data, enum wined3d_format_id index_data_format_id)
4182 {
4183     enum wined3d_format_id prev_idx_format;
4184
4185     /* Mark the state dirty until we have nicer tracking
4186      * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4187      * that value.
4188      */
4189     device_invalidate_state(device, STATE_VDECL);
4190     device_invalidate_state(device, STATE_STREAMSRC);
4191     device_invalidate_state(device, STATE_INDEXBUFFER);
4192
4193     prev_idx_format = device->stateBlock->state.index_format;
4194     device->stateBlock->state.index_format = index_data_format_id;
4195     device->stateBlock->state.user_stream = TRUE;
4196     device->stateBlock->state.base_vertex_index = 0;
4197     device->up_strided = strided_data;
4198     drawPrimitive(device, index_count, 0, TRUE, index_data);
4199     device->up_strided = NULL;
4200     device->stateBlock->state.index_format = prev_idx_format;
4201
4202     device_invalidate_state(device, STATE_VDECL);
4203     device_invalidate_state(device, STATE_STREAMSRC);
4204     device_invalidate_state(device, STATE_INDEXBUFFER);
4205     return WINED3D_OK;
4206 }
4207
4208 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4209 static HRESULT device_update_volume(struct wined3d_device *device,
4210         struct wined3d_volume *src_volume, struct wined3d_volume *dst_volume)
4211 {
4212     struct wined3d_map_desc src;
4213     struct wined3d_map_desc dst;
4214     HRESULT hr;
4215
4216     TRACE("device %p, src_volume %p, dst_volume %p.\n",
4217             device, src_volume, dst_volume);
4218
4219     /* TODO: Implement direct loading into the gl volume instead of using
4220      * memcpy and dirtification to improve loading performance. */
4221     hr = wined3d_volume_map(src_volume, &src, NULL, WINED3DLOCK_READONLY);
4222     if (FAILED(hr)) return hr;
4223     hr = wined3d_volume_map(dst_volume, &dst, NULL, WINED3DLOCK_DISCARD);
4224     if (FAILED(hr))
4225     {
4226         wined3d_volume_unmap(src_volume);
4227         return hr;
4228     }
4229
4230     memcpy(dst.data, src.data, dst_volume->resource.size);
4231
4232     hr = wined3d_volume_unmap(dst_volume);
4233     if (FAILED(hr))
4234         wined3d_volume_unmap(src_volume);
4235     else
4236         hr = wined3d_volume_unmap(src_volume);
4237
4238     return hr;
4239 }
4240
4241 HRESULT CDECL wined3d_device_update_texture(struct wined3d_device *device,
4242         struct wined3d_texture *src_texture, struct wined3d_texture *dst_texture)
4243 {
4244     enum wined3d_resource_type type;
4245     unsigned int level_count, i;
4246     HRESULT hr;
4247
4248     TRACE("device %p, src_texture %p, dst_texture %p.\n", device, src_texture, dst_texture);
4249
4250     /* Verify that the source and destination textures are non-NULL. */
4251     if (!src_texture || !dst_texture)
4252     {
4253         WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4254         return WINED3DERR_INVALIDCALL;
4255     }
4256
4257     if (src_texture == dst_texture)
4258     {
4259         WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4260         return WINED3DERR_INVALIDCALL;
4261     }
4262
4263     /* Verify that the source and destination textures are the same type. */
4264     type = src_texture->resource.type;
4265     if (dst_texture->resource.type != type)
4266     {
4267         WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4268         return WINED3DERR_INVALIDCALL;
4269     }
4270
4271     /* Check that both textures have the identical numbers of levels. */
4272     level_count = wined3d_texture_get_level_count(src_texture);
4273     if (wined3d_texture_get_level_count(dst_texture) != level_count)
4274     {
4275         WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4276         return WINED3DERR_INVALIDCALL;
4277     }
4278
4279     /* Make sure that the destination texture is loaded. */
4280     dst_texture->texture_ops->texture_preload(dst_texture, SRGB_RGB);
4281
4282     /* Update every surface level of the texture. */
4283     switch (type)
4284     {
4285         case WINED3D_RTYPE_TEXTURE:
4286         {
4287             struct wined3d_surface *src_surface;
4288             struct wined3d_surface *dst_surface;
4289
4290             for (i = 0; i < level_count; ++i)
4291             {
4292                 src_surface = surface_from_resource(wined3d_texture_get_sub_resource(src_texture, i));
4293                 dst_surface = surface_from_resource(wined3d_texture_get_sub_resource(dst_texture, i));
4294                 hr = wined3d_device_update_surface(device, src_surface, NULL, dst_surface, NULL);
4295                 if (FAILED(hr))
4296                 {
4297                     WARN("Failed to update surface, hr %#x.\n", hr);
4298                     return hr;
4299                 }
4300             }
4301             break;
4302         }
4303
4304         case WINED3D_RTYPE_CUBE_TEXTURE:
4305         {
4306             struct wined3d_surface *src_surface;
4307             struct wined3d_surface *dst_surface;
4308
4309             for (i = 0; i < level_count * 6; ++i)
4310             {
4311                 src_surface = surface_from_resource(wined3d_texture_get_sub_resource(src_texture, i));
4312                 dst_surface = surface_from_resource(wined3d_texture_get_sub_resource(dst_texture, i));
4313                 hr = wined3d_device_update_surface(device, src_surface, NULL, dst_surface, NULL);
4314                 if (FAILED(hr))
4315                 {
4316                     WARN("Failed to update surface, hr %#x.\n", hr);
4317                     return hr;
4318                 }
4319             }
4320             break;
4321         }
4322
4323         case WINED3D_RTYPE_VOLUME_TEXTURE:
4324         {
4325             for (i = 0; i < level_count; ++i)
4326             {
4327                 hr = device_update_volume(device,
4328                         volume_from_resource(wined3d_texture_get_sub_resource(src_texture, i)),
4329                         volume_from_resource(wined3d_texture_get_sub_resource(dst_texture, i)));
4330                 if (FAILED(hr))
4331                 {
4332                     WARN("Failed to update volume, hr %#x.\n", hr);
4333                     return hr;
4334                 }
4335             }
4336             break;
4337         }
4338
4339         default:
4340             FIXME("Unsupported texture type %#x.\n", type);
4341             return WINED3DERR_INVALIDCALL;
4342     }
4343
4344     return WINED3D_OK;
4345 }
4346
4347 HRESULT CDECL wined3d_device_get_front_buffer_data(const struct wined3d_device *device,
4348         UINT swapchain_idx, struct wined3d_surface *dst_surface)
4349 {
4350     struct wined3d_swapchain *swapchain;
4351     HRESULT hr;
4352
4353     TRACE("device %p, swapchain_idx %u, dst_surface %p.\n", device, swapchain_idx, dst_surface);
4354
4355     hr = wined3d_device_get_swapchain(device, swapchain_idx, &swapchain);
4356     if (FAILED(hr)) return hr;
4357
4358     hr = wined3d_swapchain_get_front_buffer_data(swapchain, dst_surface);
4359     wined3d_swapchain_decref(swapchain);
4360
4361     return hr;
4362 }
4363
4364 HRESULT CDECL wined3d_device_validate_device(const struct wined3d_device *device, DWORD *num_passes)
4365 {
4366     const struct wined3d_state *state = &device->stateBlock->state;
4367     struct wined3d_texture *texture;
4368     DWORD i;
4369
4370     TRACE("device %p, num_passes %p.\n", device, num_passes);
4371
4372     for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4373     {
4374         if (state->sampler_states[i][WINED3D_SAMP_MIN_FILTER] == WINED3D_TEXF_NONE)
4375         {
4376             WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4377             return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4378         }
4379         if (state->sampler_states[i][WINED3D_SAMP_MAG_FILTER] == WINED3D_TEXF_NONE)
4380         {
4381             WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4382             return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4383         }
4384
4385         texture = state->textures[i];
4386         if (!texture || texture->resource.format->flags & WINED3DFMT_FLAG_FILTERING) continue;
4387
4388         if (state->sampler_states[i][WINED3D_SAMP_MAG_FILTER] != WINED3D_TEXF_POINT)
4389         {
4390             WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
4391             return E_FAIL;
4392         }
4393         if (state->sampler_states[i][WINED3D_SAMP_MIN_FILTER] != WINED3D_TEXF_POINT)
4394         {
4395             WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
4396             return E_FAIL;
4397         }
4398         if (state->sampler_states[i][WINED3D_SAMP_MIP_FILTER] != WINED3D_TEXF_NONE
4399                 && state->sampler_states[i][WINED3D_SAMP_MIP_FILTER] != WINED3D_TEXF_POINT)
4400         {
4401             WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
4402             return E_FAIL;
4403         }
4404     }
4405
4406     if (state->render_states[WINED3D_RS_ZENABLE] || state->render_states[WINED3D_RS_ZWRITEENABLE]
4407             || state->render_states[WINED3D_RS_STENCILENABLE])
4408     {
4409         struct wined3d_surface *ds = device->fb.depth_stencil;
4410         struct wined3d_surface *target = device->fb.render_targets[0];
4411
4412         if(ds && target
4413                 && (ds->resource.width < target->resource.width || ds->resource.height < target->resource.height))
4414         {
4415             WARN("Depth stencil is smaller than the color buffer, returning D3DERR_CONFLICTINGRENDERSTATE\n");
4416             return WINED3DERR_CONFLICTINGRENDERSTATE;
4417         }
4418     }
4419
4420     /* return a sensible default */
4421     *num_passes = 1;
4422
4423     TRACE("returning D3D_OK\n");
4424     return WINED3D_OK;
4425 }
4426
4427 HRESULT CDECL wined3d_device_set_software_vertex_processing(struct wined3d_device *device, BOOL software)
4428 {
4429     static BOOL warned;
4430
4431     TRACE("device %p, software %#x.\n", device, software);
4432
4433     if (!warned)
4434     {
4435         FIXME("device %p, software %#x stub!\n", device, software);
4436         warned = TRUE;
4437     }
4438
4439     device->softwareVertexProcessing = software;
4440
4441     return WINED3D_OK;
4442 }
4443
4444 BOOL CDECL wined3d_device_get_software_vertex_processing(const struct wined3d_device *device)
4445 {
4446     static BOOL warned;
4447
4448     TRACE("device %p.\n", device);
4449
4450     if (!warned)
4451     {
4452         TRACE("device %p stub!\n", device);
4453         warned = TRUE;
4454     }
4455
4456     return device->softwareVertexProcessing;
4457 }
4458
4459 HRESULT CDECL wined3d_device_get_raster_status(const struct wined3d_device *device,
4460         UINT swapchain_idx, struct wined3d_raster_status *raster_status)
4461 {
4462     struct wined3d_swapchain *swapchain;
4463     HRESULT hr;
4464
4465     TRACE("device %p, swapchain_idx %u, raster_status %p.\n",
4466             device, swapchain_idx, raster_status);
4467
4468     hr = wined3d_device_get_swapchain(device, swapchain_idx, &swapchain);
4469     if (FAILED(hr))
4470     {
4471         WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4472         return hr;
4473     }
4474
4475     hr = wined3d_swapchain_get_raster_status(swapchain, raster_status);
4476     wined3d_swapchain_decref(swapchain);
4477     if (FAILED(hr))
4478     {
4479         WARN("Failed to get raster status, hr %#x.\n", hr);
4480         return hr;
4481     }
4482
4483     return WINED3D_OK;
4484 }
4485
4486 HRESULT CDECL wined3d_device_set_npatch_mode(struct wined3d_device *device, float segments)
4487 {
4488     static BOOL warned;
4489
4490     TRACE("device %p, segments %.8e.\n", device, segments);
4491
4492     if (segments != 0.0f)
4493     {
4494         if (!warned)
4495         {
4496             FIXME("device %p, segments %.8e stub!\n", device, segments);
4497             warned = TRUE;
4498         }
4499     }
4500
4501     return WINED3D_OK;
4502 }
4503
4504 float CDECL wined3d_device_get_npatch_mode(const struct wined3d_device *device)
4505 {
4506     static BOOL warned;
4507
4508     TRACE("device %p.\n", device);
4509
4510     if (!warned)
4511     {
4512         FIXME("device %p stub!\n", device);
4513         warned = TRUE;
4514     }
4515
4516     return 0.0f;
4517 }
4518
4519 HRESULT CDECL wined3d_device_update_surface(struct wined3d_device *device,
4520         struct wined3d_surface *src_surface, const RECT *src_rect,
4521         struct wined3d_surface *dst_surface, const POINT *dst_point)
4522 {
4523     TRACE("device %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s.\n",
4524             device, src_surface, wine_dbgstr_rect(src_rect),
4525             dst_surface, wine_dbgstr_point(dst_point));
4526
4527     if (src_surface->resource.pool != WINED3D_POOL_SYSTEM_MEM || dst_surface->resource.pool != WINED3D_POOL_DEFAULT)
4528     {
4529         WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
4530                 src_surface, dst_surface);
4531         return WINED3DERR_INVALIDCALL;
4532     }
4533
4534     return surface_upload_from_surface(dst_surface, dst_point, src_surface, src_rect);
4535 }
4536
4537 HRESULT CDECL wined3d_device_draw_rect_patch(struct wined3d_device *device, UINT handle,
4538         const float *num_segs, const struct wined3d_rect_patch_info *rect_patch_info)
4539 {
4540     struct wined3d_rect_patch *patch;
4541     GLenum old_primitive_type;
4542     unsigned int i;
4543     struct list *e;
4544     BOOL found;
4545
4546     TRACE("device %p, handle %#x, num_segs %p, rect_patch_info %p.\n",
4547             device, handle, num_segs, rect_patch_info);
4548
4549     if (!(handle || rect_patch_info))
4550     {
4551         /* TODO: Write a test for the return value, thus the FIXME */
4552         FIXME("Both handle and rect_patch_info are NULL.\n");
4553         return WINED3DERR_INVALIDCALL;
4554     }
4555
4556     if (handle)
4557     {
4558         i = PATCHMAP_HASHFUNC(handle);
4559         found = FALSE;
4560         LIST_FOR_EACH(e, &device->patches[i])
4561         {
4562             patch = LIST_ENTRY(e, struct wined3d_rect_patch, entry);
4563             if (patch->Handle == handle)
4564             {
4565                 found = TRUE;
4566                 break;
4567             }
4568         }
4569
4570         if (!found)
4571         {
4572             TRACE("Patch does not exist. Creating a new one\n");
4573             patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
4574             patch->Handle = handle;
4575             list_add_head(&device->patches[i], &patch->entry);
4576         } else {
4577             TRACE("Found existing patch %p\n", patch);
4578         }
4579     }
4580     else
4581     {
4582         /* Since opengl does not load tesselated vertex attributes into numbered vertex
4583          * attributes we have to tesselate, read back, and draw. This needs a patch
4584          * management structure instance. Create one.
4585          *
4586          * A possible improvement is to check if a vertex shader is used, and if not directly
4587          * draw the patch.
4588          */
4589         FIXME("Drawing an uncached patch. This is slow\n");
4590         patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
4591     }
4592
4593     if (num_segs[0] != patch->numSegs[0] || num_segs[1] != patch->numSegs[1]
4594             || num_segs[2] != patch->numSegs[2] || num_segs[3] != patch->numSegs[3]
4595             || (rect_patch_info && memcmp(rect_patch_info, &patch->rect_patch_info, sizeof(*rect_patch_info))))
4596     {
4597         HRESULT hr;
4598         TRACE("Tesselation density or patch info changed, retesselating\n");
4599
4600         if (rect_patch_info)
4601             patch->rect_patch_info = *rect_patch_info;
4602
4603         patch->numSegs[0] = num_segs[0];
4604         patch->numSegs[1] = num_segs[1];
4605         patch->numSegs[2] = num_segs[2];
4606         patch->numSegs[3] = num_segs[3];
4607
4608         hr = tesselate_rectpatch(device, patch);
4609         if (FAILED(hr))
4610         {
4611             WARN("Patch tesselation failed.\n");
4612
4613             /* Do not release the handle to store the params of the patch */
4614             if (!handle)
4615                 HeapFree(GetProcessHeap(), 0, patch);
4616
4617             return hr;
4618         }
4619     }
4620
4621     old_primitive_type = device->stateBlock->state.gl_primitive_type;
4622     device->stateBlock->state.gl_primitive_type = GL_TRIANGLES;
4623     wined3d_device_draw_primitive_strided(device, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
4624     device->stateBlock->state.gl_primitive_type = old_primitive_type;
4625
4626     /* Destroy uncached patches */
4627     if (!handle)
4628     {
4629         HeapFree(GetProcessHeap(), 0, patch->mem);
4630         HeapFree(GetProcessHeap(), 0, patch);
4631     }
4632     return WINED3D_OK;
4633 }
4634
4635 HRESULT CDECL wined3d_device_draw_tri_patch(struct wined3d_device *device, UINT handle,
4636         const float *segment_count, const struct wined3d_tri_patch_info *patch_info)
4637 {
4638     FIXME("device %p, handle %#x, segment_count %p, patch_info %p stub!\n",
4639             device, handle, segment_count, patch_info);
4640
4641     return WINED3D_OK;
4642 }
4643
4644 HRESULT CDECL wined3d_device_delete_patch(struct wined3d_device *device, UINT handle)
4645 {
4646     struct wined3d_rect_patch *patch;
4647     struct list *e;
4648     int i;
4649
4650     TRACE("device %p, handle %#x.\n", device, handle);
4651
4652     i = PATCHMAP_HASHFUNC(handle);
4653     LIST_FOR_EACH(e, &device->patches[i])
4654     {
4655         patch = LIST_ENTRY(e, struct wined3d_rect_patch, entry);
4656         if (patch->Handle == handle)
4657         {
4658             TRACE("Deleting patch %p\n", patch);
4659             list_remove(&patch->entry);
4660             HeapFree(GetProcessHeap(), 0, patch->mem);
4661             HeapFree(GetProcessHeap(), 0, patch);
4662             return WINED3D_OK;
4663         }
4664     }
4665
4666     /* TODO: Write a test for the return value */
4667     FIXME("Attempt to destroy nonexistent patch\n");
4668     return WINED3DERR_INVALIDCALL;
4669 }
4670
4671 /* Do not call while under the GL lock. */
4672 HRESULT CDECL wined3d_device_color_fill(struct wined3d_device *device,
4673         struct wined3d_surface *surface, const RECT *rect, const struct wined3d_color *color)
4674 {
4675     RECT r;
4676
4677     TRACE("device %p, surface %p, rect %s, color {%.8e, %.8e, %.8e, %.8e}.\n",
4678             device, surface, wine_dbgstr_rect(rect),
4679             color->r, color->g, color->b, color->a);
4680
4681     if (surface->resource.pool != WINED3D_POOL_DEFAULT && surface->resource.pool != WINED3D_POOL_SYSTEM_MEM)
4682     {
4683         WARN("Color-fill not allowed on %s surfaces.\n", debug_d3dpool(surface->resource.pool));
4684         return WINED3DERR_INVALIDCALL;
4685     }
4686
4687     if (!rect)
4688     {
4689         SetRect(&r, 0, 0, surface->resource.width, surface->resource.height);
4690         rect = &r;
4691     }
4692
4693     return surface_color_fill(surface, rect, color);
4694 }
4695
4696 /* Do not call while under the GL lock. */
4697 void CDECL wined3d_device_clear_rendertarget_view(struct wined3d_device *device,
4698         struct wined3d_rendertarget_view *rendertarget_view, const struct wined3d_color *color)
4699 {
4700     struct wined3d_resource *resource;
4701     HRESULT hr;
4702     RECT rect;
4703
4704     resource = rendertarget_view->resource;
4705     if (resource->type != WINED3D_RTYPE_SURFACE)
4706     {
4707         FIXME("Only supported on surface resources\n");
4708         return;
4709     }
4710
4711     SetRect(&rect, 0, 0, resource->width, resource->height);
4712     hr = surface_color_fill(surface_from_resource(resource), &rect, color);
4713     if (FAILED(hr)) ERR("Color fill failed, hr %#x.\n", hr);
4714 }
4715
4716 HRESULT CDECL wined3d_device_get_render_target(const struct wined3d_device *device,
4717         UINT render_target_idx, struct wined3d_surface **render_target)
4718 {
4719     TRACE("device %p, render_target_idx %u, render_target %p.\n",
4720             device, render_target_idx, render_target);
4721
4722     if (render_target_idx >= device->adapter->gl_info.limits.buffers)
4723     {
4724         WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
4725         return WINED3DERR_INVALIDCALL;
4726     }
4727
4728     *render_target = device->fb.render_targets[render_target_idx];
4729     TRACE("Returning render target %p.\n", *render_target);
4730
4731     if (!*render_target)
4732         return WINED3DERR_NOTFOUND;
4733
4734     wined3d_surface_incref(*render_target);
4735
4736     return WINED3D_OK;
4737 }
4738
4739 HRESULT CDECL wined3d_device_get_depth_stencil(const struct wined3d_device *device,
4740         struct wined3d_surface **depth_stencil)
4741 {
4742     TRACE("device %p, depth_stencil %p.\n", device, depth_stencil);
4743
4744     *depth_stencil = device->fb.depth_stencil;
4745     TRACE("Returning depth/stencil surface %p.\n", *depth_stencil);
4746
4747     if (!*depth_stencil)
4748         return WINED3DERR_NOTFOUND;
4749
4750     wined3d_surface_incref(*depth_stencil);
4751
4752     return WINED3D_OK;
4753 }
4754
4755 HRESULT CDECL wined3d_device_set_render_target(struct wined3d_device *device,
4756         UINT render_target_idx, struct wined3d_surface *render_target, BOOL set_viewport)
4757 {
4758     struct wined3d_surface *prev;
4759
4760     TRACE("device %p, render_target_idx %u, render_target %p, set_viewport %#x.\n",
4761             device, render_target_idx, render_target, set_viewport);
4762
4763     if (render_target_idx >= device->adapter->gl_info.limits.buffers)
4764     {
4765         WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
4766         return WINED3DERR_INVALIDCALL;
4767     }
4768
4769     prev = device->fb.render_targets[render_target_idx];
4770     if (render_target == prev)
4771     {
4772         TRACE("Trying to do a NOP SetRenderTarget operation.\n");
4773         return WINED3D_OK;
4774     }
4775
4776     /* Render target 0 can't be set to NULL. */
4777     if (!render_target && !render_target_idx)
4778     {
4779         WARN("Trying to set render target 0 to NULL.\n");
4780         return WINED3DERR_INVALIDCALL;
4781     }
4782
4783     if (render_target && !(render_target->resource.usage & WINED3DUSAGE_RENDERTARGET))
4784     {
4785         FIXME("Surface %p doesn't have render target usage.\n", render_target);
4786         return WINED3DERR_INVALIDCALL;
4787     }
4788
4789     if (render_target)
4790         wined3d_surface_incref(render_target);
4791     device->fb.render_targets[render_target_idx] = render_target;
4792     /* Release after the assignment, to prevent device_resource_released()
4793      * from seeing the surface as still in use. */
4794     if (prev)
4795         wined3d_surface_decref(prev);
4796
4797     /* Render target 0 is special. */
4798     if (!render_target_idx && set_viewport)
4799     {
4800         /* Set the viewport and scissor rectangles, if requested. Tests show
4801          * that stateblock recording is ignored, the change goes directly
4802          * into the primary stateblock. */
4803         device->stateBlock->state.viewport.height = device->fb.render_targets[0]->resource.height;
4804         device->stateBlock->state.viewport.width  = device->fb.render_targets[0]->resource.width;
4805         device->stateBlock->state.viewport.x      = 0;
4806         device->stateBlock->state.viewport.y      = 0;
4807         device->stateBlock->state.viewport.max_z  = 1.0f;
4808         device->stateBlock->state.viewport.min_z  = 0.0f;
4809         device_invalidate_state(device, STATE_VIEWPORT);
4810
4811         device->stateBlock->state.scissor_rect.top = 0;
4812         device->stateBlock->state.scissor_rect.left = 0;
4813         device->stateBlock->state.scissor_rect.right = device->stateBlock->state.viewport.width;
4814         device->stateBlock->state.scissor_rect.bottom = device->stateBlock->state.viewport.height;
4815         device_invalidate_state(device, STATE_SCISSORRECT);
4816     }
4817
4818     device_invalidate_state(device, STATE_FRAMEBUFFER);
4819
4820     return WINED3D_OK;
4821 }
4822
4823 HRESULT CDECL wined3d_device_set_depth_stencil(struct wined3d_device *device, struct wined3d_surface *depth_stencil)
4824 {
4825     struct wined3d_surface *prev = device->fb.depth_stencil;
4826
4827     TRACE("device %p, depth_stencil %p, old depth_stencil %p.\n",
4828             device, depth_stencil, prev);
4829
4830     if (prev == depth_stencil)
4831     {
4832         TRACE("Trying to do a NOP SetRenderTarget operation.\n");
4833         return WINED3D_OK;
4834     }
4835
4836     if (prev)
4837     {
4838         if (device->swapchains[0]->desc.flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
4839                 || prev->flags & SFLAG_DISCARD)
4840         {
4841             surface_modify_ds_location(prev, SFLAG_DISCARDED,
4842                     prev->resource.width, prev->resource.height);
4843             if (prev == device->onscreen_depth_stencil)
4844             {
4845                 wined3d_surface_decref(device->onscreen_depth_stencil);
4846                 device->onscreen_depth_stencil = NULL;
4847             }
4848         }
4849     }
4850
4851     device->fb.depth_stencil = depth_stencil;
4852     if (depth_stencil)
4853         wined3d_surface_incref(depth_stencil);
4854
4855     if (!prev != !depth_stencil)
4856     {
4857         /* Swapping NULL / non NULL depth stencil affects the depth and tests */
4858         device_invalidate_state(device, STATE_RENDER(WINED3D_RS_ZENABLE));
4859         device_invalidate_state(device, STATE_RENDER(WINED3D_RS_STENCILENABLE));
4860         device_invalidate_state(device, STATE_RENDER(WINED3D_RS_STENCILWRITEMASK));
4861         device_invalidate_state(device, STATE_RENDER(WINED3D_RS_DEPTHBIAS));
4862     }
4863     else if (prev && prev->resource.format->depth_size != depth_stencil->resource.format->depth_size)
4864     {
4865         device_invalidate_state(device, STATE_RENDER(WINED3D_RS_DEPTHBIAS));
4866     }
4867     if (prev)
4868         wined3d_surface_decref(prev);
4869
4870     device_invalidate_state(device, STATE_FRAMEBUFFER);
4871
4872     return WINED3D_OK;
4873 }
4874
4875 HRESULT CDECL wined3d_device_set_cursor_properties(struct wined3d_device *device,
4876         UINT x_hotspot, UINT y_hotspot, struct wined3d_surface *cursor_image)
4877 {
4878     TRACE("device %p, x_hotspot %u, y_hotspot %u, cursor_image %p.\n",
4879             device, x_hotspot, y_hotspot, cursor_image);
4880
4881     /* some basic validation checks */
4882     if (device->cursorTexture)
4883     {
4884         struct wined3d_context *context = context_acquire(device, NULL);
4885         ENTER_GL();
4886         glDeleteTextures(1, &device->cursorTexture);
4887         LEAVE_GL();
4888         context_release(context);
4889         device->cursorTexture = 0;
4890     }
4891
4892     if (cursor_image)
4893     {
4894         struct wined3d_map_desc map_desc;
4895
4896         /* MSDN: Cursor must be A8R8G8B8 */
4897         if (cursor_image->resource.format->id != WINED3DFMT_B8G8R8A8_UNORM)
4898         {
4899             WARN("surface %p has an invalid format.\n", cursor_image);
4900             return WINED3DERR_INVALIDCALL;
4901         }
4902
4903         /* MSDN: Cursor must be smaller than the display mode */
4904         if (cursor_image->resource.width > device->adapter->screen_size.cx
4905                 || cursor_image->resource.height > device->adapter->screen_size.cy)
4906         {
4907             WARN("Surface %p dimensions are %ux%u, but screen dimensions are %ux%u.\n",
4908                     cursor_image, cursor_image->resource.width, cursor_image->resource.height,
4909                     device->adapter->screen_size.cx, device->adapter->screen_size.cy);
4910             return WINED3DERR_INVALIDCALL;
4911         }
4912
4913         /* TODO: MSDN: Cursor sizes must be a power of 2 */
4914
4915         /* Do not store the surface's pointer because the application may
4916          * release it after setting the cursor image. Windows doesn't
4917          * addref the set surface, so we can't do this either without
4918          * creating circular refcount dependencies. Copy out the gl texture
4919          * instead. */
4920         device->cursorWidth = cursor_image->resource.width;
4921         device->cursorHeight = cursor_image->resource.height;
4922         if (SUCCEEDED(wined3d_surface_map(cursor_image, &map_desc, NULL, WINED3DLOCK_READONLY)))
4923         {
4924             const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
4925             const struct wined3d_format *format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM);
4926             struct wined3d_context *context;
4927             char *mem, *bits = map_desc.data;
4928             GLint intfmt = format->glInternal;
4929             GLint gl_format = format->glFormat;
4930             GLint type = format->glType;
4931             INT height = device->cursorHeight;
4932             INT width = device->cursorWidth;
4933             INT bpp = format->byte_count;
4934             INT i;
4935
4936             /* Reformat the texture memory (pitch and width can be
4937              * different) */
4938             mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
4939             for (i = 0; i < height; ++i)
4940                 memcpy(&mem[width * bpp * i], &bits[map_desc.row_pitch * i], width * bpp);
4941             wined3d_surface_unmap(cursor_image);
4942
4943             context = context_acquire(device, NULL);
4944
4945             ENTER_GL();
4946
4947             if (gl_info->supported[APPLE_CLIENT_STORAGE])
4948             {
4949                 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
4950                 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
4951             }
4952
4953             invalidate_active_texture(device, context);
4954             /* Create a new cursor texture */
4955             glGenTextures(1, &device->cursorTexture);
4956             checkGLcall("glGenTextures");
4957             context_bind_texture(context, GL_TEXTURE_2D, device->cursorTexture);
4958             /* Copy the bitmap memory into the cursor texture */
4959             glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, gl_format, type, mem);
4960             checkGLcall("glTexImage2D");
4961             HeapFree(GetProcessHeap(), 0, mem);
4962
4963             if (gl_info->supported[APPLE_CLIENT_STORAGE])
4964             {
4965                 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
4966                 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
4967             }
4968
4969             LEAVE_GL();
4970
4971             context_release(context);
4972         }
4973         else
4974         {
4975             FIXME("A cursor texture was not returned.\n");
4976             device->cursorTexture = 0;
4977         }
4978
4979         if (cursor_image->resource.width == 32 && cursor_image->resource.height == 32)
4980         {
4981             UINT mask_size = cursor_image->resource.width * cursor_image->resource.height / 8;
4982             ICONINFO cursorInfo;
4983             DWORD *maskBits;
4984             HCURSOR cursor;
4985
4986             /* 32-bit user32 cursors ignore the alpha channel if it's all
4987              * zeroes, and use the mask instead. Fill the mask with all ones
4988              * to ensure we still get a fully transparent cursor. */
4989             maskBits = HeapAlloc(GetProcessHeap(), 0, mask_size);
4990             memset(maskBits, 0xff, mask_size);
4991             wined3d_surface_map(cursor_image, &map_desc, NULL,
4992                     WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY);
4993             TRACE("width: %u height: %u.\n", cursor_image->resource.width, cursor_image->resource.height);
4994
4995             cursorInfo.fIcon = FALSE;
4996             cursorInfo.xHotspot = x_hotspot;
4997             cursorInfo.yHotspot = y_hotspot;
4998             cursorInfo.hbmMask = CreateBitmap(cursor_image->resource.width, cursor_image->resource.height,
4999                     1, 1, maskBits);
5000             cursorInfo.hbmColor = CreateBitmap(cursor_image->resource.width, cursor_image->resource.height,
5001                     1, 32, map_desc.data);
5002             wined3d_surface_unmap(cursor_image);
5003             /* Create our cursor and clean up. */
5004             cursor = CreateIconIndirect(&cursorInfo);
5005             if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
5006             if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
5007             if (device->hardwareCursor) DestroyCursor(device->hardwareCursor);
5008             device->hardwareCursor = cursor;
5009             if (device->bCursorVisible) SetCursor( cursor );
5010             HeapFree(GetProcessHeap(), 0, maskBits);
5011         }
5012     }
5013
5014     device->xHotSpot = x_hotspot;
5015     device->yHotSpot = y_hotspot;
5016     return WINED3D_OK;
5017 }
5018
5019 void CDECL wined3d_device_set_cursor_position(struct wined3d_device *device,
5020         int x_screen_space, int y_screen_space, DWORD flags)
5021 {
5022     TRACE("device %p, x %d, y %d, flags %#x.\n",
5023             device, x_screen_space, y_screen_space, flags);
5024
5025     device->xScreenSpace = x_screen_space;
5026     device->yScreenSpace = y_screen_space;
5027
5028     if (device->hardwareCursor)
5029     {
5030         POINT pt;
5031
5032         GetCursorPos( &pt );
5033         if (x_screen_space == pt.x && y_screen_space == pt.y)
5034             return;
5035         SetCursorPos( x_screen_space, y_screen_space );
5036
5037         /* Switch to the software cursor if position diverges from the hardware one. */
5038         GetCursorPos( &pt );
5039         if (x_screen_space != pt.x || y_screen_space != pt.y)
5040         {
5041             if (device->bCursorVisible) SetCursor( NULL );
5042             DestroyCursor( device->hardwareCursor );
5043             device->hardwareCursor = 0;
5044         }
5045     }
5046 }
5047
5048 BOOL CDECL wined3d_device_show_cursor(struct wined3d_device *device, BOOL show)
5049 {
5050     BOOL oldVisible = device->bCursorVisible;
5051
5052     TRACE("device %p, show %#x.\n", device, show);
5053
5054     /*
5055      * When ShowCursor is first called it should make the cursor appear at the OS's last
5056      * known cursor position.
5057      */
5058     if (show && !oldVisible)
5059     {
5060         POINT pt;
5061         GetCursorPos(&pt);
5062         device->xScreenSpace = pt.x;
5063         device->yScreenSpace = pt.y;
5064     }
5065
5066     if (device->hardwareCursor)
5067     {
5068         device->bCursorVisible = show;
5069         if (show)
5070             SetCursor(device->hardwareCursor);
5071         else
5072             SetCursor(NULL);
5073     }
5074     else
5075     {
5076         if (device->cursorTexture)
5077             device->bCursorVisible = show;
5078     }
5079
5080     return oldVisible;
5081 }
5082
5083 void CDECL wined3d_device_evict_managed_resources(struct wined3d_device *device)
5084 {
5085     struct wined3d_resource *resource, *cursor;
5086
5087     TRACE("device %p.\n", device);
5088
5089     LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &device->resources, struct wined3d_resource, resource_list_entry)
5090     {
5091         TRACE("Checking resource %p for eviction.\n", resource);
5092
5093         if (resource->pool == WINED3D_POOL_MANAGED)
5094         {
5095             TRACE("Evicting %p.\n", resource);
5096             resource->resource_ops->resource_unload(resource);
5097         }
5098     }
5099
5100     /* Invalidate stream sources, the buffer(s) may have been evicted. */
5101     device_invalidate_state(device, STATE_STREAMSRC);
5102 }
5103
5104 static BOOL is_display_mode_supported(const struct wined3d_device *device,
5105         const struct wined3d_swapchain_desc *swapchain_desc)
5106 {
5107     struct wined3d_display_mode m;
5108     UINT i, count;
5109     HRESULT hr;
5110
5111     /* All Windowed modes are supported, as is leaving the current mode */
5112     if (swapchain_desc->windowed)
5113         return TRUE;
5114     if (!swapchain_desc->backbuffer_width)
5115         return TRUE;
5116     if (!swapchain_desc->backbuffer_height)
5117         return TRUE;
5118
5119     count = wined3d_get_adapter_mode_count(device->wined3d, device->adapter->ordinal, WINED3DFMT_UNKNOWN);
5120     for (i = 0; i < count; ++i)
5121     {
5122         memset(&m, 0, sizeof(m));
5123         hr = wined3d_enum_adapter_modes(device->wined3d, device->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
5124         if (FAILED(hr))
5125             ERR("Failed to enumerate adapter mode.\n");
5126         if (m.width == swapchain_desc->backbuffer_width && m.height == swapchain_desc->backbuffer_height)
5127             /* Mode found, it is supported. */
5128             return TRUE;
5129     }
5130     /* Mode not found -> not supported */
5131     return FALSE;
5132 }
5133
5134 /* Do not call while under the GL lock. */
5135 static void delete_opengl_contexts(struct wined3d_device *device, struct wined3d_swapchain *swapchain)
5136 {
5137     struct wined3d_resource *resource, *cursor;
5138     const struct wined3d_gl_info *gl_info;
5139     struct wined3d_context *context;
5140     struct wined3d_shader *shader;
5141
5142     context = context_acquire(device, NULL);
5143     gl_info = context->gl_info;
5144
5145     LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &device->resources, struct wined3d_resource, resource_list_entry)
5146     {
5147         TRACE("Unloading resource %p.\n", resource);
5148
5149         resource->resource_ops->resource_unload(resource);
5150     }
5151
5152     LIST_FOR_EACH_ENTRY(shader, &device->shaders, struct wined3d_shader, shader_list_entry)
5153     {
5154         device->shader_backend->shader_destroy(shader);
5155     }
5156
5157     ENTER_GL();
5158     if (device->depth_blt_texture)
5159     {
5160         glDeleteTextures(1, &device->depth_blt_texture);
5161         device->depth_blt_texture = 0;
5162     }
5163     if (device->cursorTexture)
5164     {
5165         glDeleteTextures(1, &device->cursorTexture);
5166         device->cursorTexture = 0;
5167     }
5168     LEAVE_GL();
5169
5170     device->blitter->free_private(device);
5171     device->frag_pipe->free_private(device);
5172     device->shader_backend->shader_free_private(device);
5173     destroy_dummy_textures(device, gl_info);
5174
5175     context_release(context);
5176
5177     while (device->context_count)
5178     {
5179         swapchain_destroy_contexts(device->contexts[0]->swapchain);
5180     }
5181
5182     HeapFree(GetProcessHeap(), 0, swapchain->context);
5183     swapchain->context = NULL;
5184 }
5185
5186 /* Do not call while under the GL lock. */
5187 static HRESULT create_primary_opengl_context(struct wined3d_device *device, struct wined3d_swapchain *swapchain)
5188 {
5189     struct wined3d_context *context;
5190     struct wined3d_surface *target;
5191     HRESULT hr;
5192
5193     /* Recreate the primary swapchain's context */
5194     swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
5195     if (!swapchain->context)
5196     {
5197         ERR("Failed to allocate memory for swapchain context array.\n");
5198         return E_OUTOFMEMORY;
5199     }
5200
5201     target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer;
5202     if (!(context = context_create(swapchain, target, swapchain->ds_format)))
5203     {
5204         WARN("Failed to create context.\n");
5205         HeapFree(GetProcessHeap(), 0, swapchain->context);
5206         return E_FAIL;
5207     }
5208
5209     swapchain->context[0] = context;
5210     swapchain->num_contexts = 1;
5211     create_dummy_textures(device, context);
5212     context_release(context);
5213
5214     hr = device->shader_backend->shader_alloc_private(device);
5215     if (FAILED(hr))
5216     {
5217         ERR("Failed to allocate shader private data, hr %#x.\n", hr);
5218         goto err;
5219     }
5220
5221     hr = device->frag_pipe->alloc_private(device);
5222     if (FAILED(hr))
5223     {
5224         ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
5225         device->shader_backend->shader_free_private(device);
5226         goto err;
5227     }
5228
5229     hr = device->blitter->alloc_private(device);
5230     if (FAILED(hr))
5231     {
5232         ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
5233         device->frag_pipe->free_private(device);
5234         device->shader_backend->shader_free_private(device);
5235         goto err;
5236     }
5237
5238     return WINED3D_OK;
5239
5240 err:
5241     context_acquire(device, NULL);
5242     destroy_dummy_textures(device, context->gl_info);
5243     context_release(context);
5244     context_destroy(device, context);
5245     HeapFree(GetProcessHeap(), 0, swapchain->context);
5246     swapchain->num_contexts = 0;
5247     return hr;
5248 }
5249
5250 /* Do not call while under the GL lock. */
5251 HRESULT CDECL wined3d_device_reset(struct wined3d_device *device,
5252         const struct wined3d_swapchain_desc *swapchain_desc,
5253         wined3d_device_reset_cb callback)
5254 {
5255     struct wined3d_resource *resource, *cursor;
5256     struct wined3d_swapchain *swapchain;
5257     struct wined3d_display_mode mode;
5258     BOOL DisplayModeChanged = FALSE;
5259     BOOL update_desc = FALSE;
5260     HRESULT hr;
5261
5262     TRACE("device %p, swapchain_desc %p.\n", device, swapchain_desc);
5263
5264     stateblock_unbind_resources(device->stateBlock);
5265
5266     if (device->onscreen_depth_stencil)
5267     {
5268         wined3d_surface_decref(device->onscreen_depth_stencil);
5269         device->onscreen_depth_stencil = NULL;
5270     }
5271
5272     LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &device->resources, struct wined3d_resource, resource_list_entry)
5273     {
5274         TRACE("Enumerating resource %p.\n", resource);
5275         if (FAILED(hr = callback(resource)))
5276             return hr;
5277     }
5278
5279     hr = wined3d_device_get_swapchain(device, 0, &swapchain);
5280     if (FAILED(hr))
5281     {
5282         ERR("Failed to get the first implicit swapchain\n");
5283         return hr;
5284     }
5285
5286     if (!is_display_mode_supported(device, swapchain_desc))
5287     {
5288         WARN("Rejecting reset() call because the requested display mode is not supported.\n");
5289         WARN("Requested mode: %ux%u.\n",
5290                 swapchain_desc->backbuffer_width,
5291                 swapchain_desc->backbuffer_height);
5292         wined3d_swapchain_decref(swapchain);
5293         return WINED3DERR_INVALIDCALL;
5294     }
5295
5296     /* Is it necessary to recreate the gl context? Actually every setting can be changed
5297      * on an existing gl context, so there's no real need for recreation.
5298      *
5299      * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
5300      *
5301      * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
5302      */
5303     TRACE("New params:\n");
5304     TRACE("backbuffer_width %u\n", swapchain_desc->backbuffer_width);
5305     TRACE("backbuffer_height %u\n", swapchain_desc->backbuffer_height);
5306     TRACE("backbuffer_format %s\n", debug_d3dformat(swapchain_desc->backbuffer_format));
5307     TRACE("backbuffer_count %u\n", swapchain_desc->backbuffer_count);
5308     TRACE("multisample_type %#x\n", swapchain_desc->multisample_type);
5309     TRACE("multisample_quality %u\n", swapchain_desc->multisample_quality);
5310     TRACE("swap_effect %#x\n", swapchain_desc->swap_effect);
5311     TRACE("device_window %p\n", swapchain_desc->device_window);
5312     TRACE("windowed %#x\n", swapchain_desc->windowed);
5313     TRACE("enable_auto_depth_stencil %#x\n", swapchain_desc->enable_auto_depth_stencil);
5314     if (swapchain_desc->enable_auto_depth_stencil)
5315         TRACE("auto_depth_stencil_format %s\n", debug_d3dformat(swapchain_desc->auto_depth_stencil_format));
5316     TRACE("flags %#x\n", swapchain_desc->flags);
5317     TRACE("refresh_rate %u\n", swapchain_desc->refresh_rate);
5318     TRACE("swap_interval %u\n", swapchain_desc->swap_interval);
5319     TRACE("auto_restore_display_mode %#x\n", swapchain_desc->auto_restore_display_mode);
5320
5321     /* No special treatment of these parameters. Just store them */
5322     swapchain->desc.swap_effect = swapchain_desc->swap_effect;
5323     swapchain->desc.flags = swapchain_desc->flags;
5324     swapchain->desc.swap_interval = swapchain_desc->swap_interval;
5325     swapchain->desc.refresh_rate = swapchain_desc->refresh_rate;
5326
5327     /* What to do about these? */
5328     if (swapchain_desc->backbuffer_count
5329             && swapchain_desc->backbuffer_count != swapchain->desc.backbuffer_count)
5330         FIXME("Cannot change the back buffer count yet.\n");
5331
5332     if (swapchain_desc->device_window
5333             && swapchain_desc->device_window != swapchain->desc.device_window)
5334     {
5335         TRACE("Changing the device window from %p to %p.\n",
5336                 swapchain->desc.device_window, swapchain_desc->device_window);
5337         swapchain->desc.device_window = swapchain_desc->device_window;
5338         swapchain->device_window = swapchain_desc->device_window;
5339         wined3d_swapchain_set_window(swapchain, NULL);
5340     }
5341
5342     if (swapchain_desc->enable_auto_depth_stencil && !device->auto_depth_stencil)
5343     {
5344         HRESULT hrc;
5345
5346         TRACE("Creating the depth stencil buffer\n");
5347
5348         hrc = device->device_parent->ops->create_depth_stencil(device->device_parent,
5349                 swapchain_desc->backbuffer_width,
5350                 swapchain_desc->backbuffer_height,
5351                 swapchain_desc->auto_depth_stencil_format,
5352                 swapchain_desc->multisample_type,
5353                 swapchain_desc->multisample_quality,
5354                 FALSE,
5355                 &device->auto_depth_stencil);
5356         if (FAILED(hrc))
5357         {
5358             ERR("Failed to create the depth stencil buffer.\n");
5359             wined3d_swapchain_decref(swapchain);
5360             return WINED3DERR_INVALIDCALL;
5361         }
5362     }
5363
5364     if (device->onscreen_depth_stencil)
5365     {
5366         wined3d_surface_decref(device->onscreen_depth_stencil);
5367         device->onscreen_depth_stencil = NULL;
5368     }
5369
5370     /* Reset the depth stencil */
5371     if (swapchain_desc->enable_auto_depth_stencil)
5372         wined3d_device_set_depth_stencil(device, device->auto_depth_stencil);
5373     else
5374         wined3d_device_set_depth_stencil(device, NULL);
5375
5376     TRACE("Resetting stateblock\n");
5377     wined3d_stateblock_decref(device->updateStateBlock);
5378     wined3d_stateblock_decref(device->stateBlock);
5379
5380     if (swapchain_desc->windowed)
5381     {
5382         mode.width = swapchain->orig_width;
5383         mode.height = swapchain->orig_height;
5384         mode.refresh_rate = 0;
5385         mode.format_id = swapchain->desc.backbuffer_format;
5386     }
5387     else
5388     {
5389         mode.width = swapchain_desc->backbuffer_width;
5390         mode.height = swapchain_desc->backbuffer_height;
5391         mode.refresh_rate = swapchain_desc->refresh_rate;
5392         mode.format_id = swapchain_desc->backbuffer_format;
5393     }
5394
5395     /* Should Width == 800 && Height == 0 set 800x600? */
5396     if (swapchain_desc->backbuffer_width && swapchain_desc->backbuffer_height
5397             && (swapchain_desc->backbuffer_width != swapchain->desc.backbuffer_width
5398             || swapchain_desc->backbuffer_height != swapchain->desc.backbuffer_height))
5399     {
5400         if (!swapchain_desc->windowed)
5401             DisplayModeChanged = TRUE;
5402
5403         swapchain->desc.backbuffer_width = swapchain_desc->backbuffer_width;
5404         swapchain->desc.backbuffer_height = swapchain_desc->backbuffer_height;
5405         update_desc = TRUE;
5406     }
5407
5408     if (swapchain_desc->backbuffer_format != WINED3DFMT_UNKNOWN
5409             && swapchain_desc->backbuffer_format != swapchain->desc.backbuffer_format)
5410     {
5411         swapchain->desc.backbuffer_format = swapchain_desc->backbuffer_format;
5412         update_desc = TRUE;
5413     }
5414
5415     if (swapchain_desc->multisample_type != swapchain->desc.multisample_type
5416             || swapchain_desc->multisample_quality != swapchain->desc.multisample_quality)
5417     {
5418         swapchain->desc.multisample_type = swapchain_desc->multisample_type;
5419         swapchain->desc.multisample_quality = swapchain_desc->multisample_quality;
5420         update_desc = TRUE;
5421     }
5422
5423     if (update_desc)
5424     {
5425         UINT i;
5426
5427         hr = wined3d_surface_update_desc(swapchain->front_buffer, swapchain->desc.backbuffer_width,
5428                 swapchain->desc.backbuffer_height, swapchain->desc.backbuffer_format,
5429                 swapchain->desc.multisample_type, swapchain->desc.multisample_quality);
5430         if (FAILED(hr))
5431         {
5432             wined3d_swapchain_decref(swapchain);
5433             return hr;
5434         }
5435
5436         for (i = 0; i < swapchain->desc.backbuffer_count; ++i)
5437         {
5438             hr = wined3d_surface_update_desc(swapchain->back_buffers[i], swapchain->desc.backbuffer_width,
5439                     swapchain->desc.backbuffer_height, swapchain->desc.backbuffer_format,
5440                     swapchain->desc.multisample_type, swapchain->desc.multisample_quality);
5441             if (FAILED(hr))
5442             {
5443                 wined3d_swapchain_decref(swapchain);
5444                 return hr;
5445             }
5446         }
5447         if (device->auto_depth_stencil)
5448         {
5449             hr = wined3d_surface_update_desc(device->auto_depth_stencil, swapchain->desc.backbuffer_width,
5450                     swapchain->desc.backbuffer_height, device->auto_depth_stencil->resource.format->id,
5451                     swapchain->desc.multisample_type, swapchain->desc.multisample_quality);
5452             if (FAILED(hr))
5453             {
5454                 wined3d_swapchain_decref(swapchain);
5455                 return hr;
5456             }
5457         }
5458     }
5459
5460     if (device->d3d_initialized)
5461         delete_opengl_contexts(device, swapchain);
5462
5463     if (!swapchain_desc->windowed != !swapchain->desc.windowed
5464             || DisplayModeChanged)
5465     {
5466         wined3d_device_set_display_mode(device, 0, &mode);
5467
5468         if (!swapchain_desc->windowed)
5469         {
5470             if (swapchain->desc.windowed)
5471             {
5472                 HWND focus_window = device->create_parms.focus_window;
5473                 if (!focus_window)
5474                     focus_window = swapchain_desc->device_window;
5475                 if (FAILED(hr = wined3d_device_acquire_focus_window(device, focus_window)))
5476                 {
5477                     ERR("Failed to acquire focus window, hr %#x.\n", hr);
5478                     wined3d_swapchain_decref(swapchain);
5479                     return hr;
5480                 }
5481
5482                 /* switch from windowed to fs */
5483                 wined3d_device_setup_fullscreen_window(device, swapchain->device_window,
5484                         swapchain_desc->backbuffer_width,
5485                         swapchain_desc->backbuffer_height);
5486             }
5487             else
5488             {
5489                 /* Fullscreen -> fullscreen mode change */
5490                 MoveWindow(swapchain->device_window, 0, 0,
5491                         swapchain_desc->backbuffer_width,
5492                         swapchain_desc->backbuffer_height,
5493                         TRUE);
5494             }
5495         }
5496         else if (!swapchain->desc.windowed)
5497         {
5498             /* Fullscreen -> windowed switch */
5499             wined3d_device_restore_fullscreen_window(device, swapchain->device_window);
5500             wined3d_device_release_focus_window(device);
5501         }
5502         swapchain->desc.windowed = swapchain_desc->windowed;
5503     }
5504     else if (!swapchain_desc->windowed)
5505     {
5506         DWORD style = device->style;
5507         DWORD exStyle = device->exStyle;
5508         /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
5509          * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
5510          * Reset to clear up their mess. Guild Wars also loses the device during that.
5511          */
5512         device->style = 0;
5513         device->exStyle = 0;
5514         wined3d_device_setup_fullscreen_window(device, swapchain->device_window,
5515                 swapchain_desc->backbuffer_width,
5516                 swapchain_desc->backbuffer_height);
5517         device->style = style;
5518         device->exStyle = exStyle;
5519     }
5520
5521     /* Note: No parent needed for initial internal stateblock */
5522     hr = wined3d_stateblock_create(device, WINED3D_SBT_INIT, &device->stateBlock);
5523     if (FAILED(hr))
5524         ERR("Resetting the stateblock failed with error %#x.\n", hr);
5525     else
5526         TRACE("Created stateblock %p.\n", device->stateBlock);
5527     device->updateStateBlock = device->stateBlock;
5528     wined3d_stateblock_incref(device->updateStateBlock);
5529
5530     stateblock_init_default_state(device->stateBlock);
5531
5532     swapchain_update_render_to_fbo(swapchain);
5533     swapchain_update_draw_bindings(swapchain);
5534
5535     if (device->d3d_initialized)
5536         hr = create_primary_opengl_context(device, swapchain);
5537     wined3d_swapchain_decref(swapchain);
5538
5539     /* All done. There is no need to reload resources or shaders, this will happen automatically on the
5540      * first use
5541      */
5542     return hr;
5543 }
5544
5545 HRESULT CDECL wined3d_device_set_dialog_box_mode(struct wined3d_device *device, BOOL enable_dialogs)
5546 {
5547     TRACE("device %p, enable_dialogs %#x.\n", device, enable_dialogs);
5548
5549     if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
5550
5551     return WINED3D_OK;
5552 }
5553
5554
5555 HRESULT CDECL wined3d_device_get_creation_parameters(const struct wined3d_device *device,
5556         struct wined3d_device_creation_parameters *parameters)
5557 {
5558     TRACE("device %p, parameters %p.\n", device, parameters);
5559
5560     *parameters = device->create_parms;
5561     return WINED3D_OK;
5562 }
5563
5564 void CDECL wined3d_device_set_gamma_ramp(const struct wined3d_device *device,
5565         UINT swapchain_idx, DWORD flags, const struct wined3d_gamma_ramp *ramp)
5566 {
5567     struct wined3d_swapchain *swapchain;
5568
5569     TRACE("device %p, swapchain_idx %u, flags %#x, ramp %p.\n",
5570             device, swapchain_idx, flags, ramp);
5571
5572     if (SUCCEEDED(wined3d_device_get_swapchain(device, swapchain_idx, &swapchain)))
5573     {
5574         wined3d_swapchain_set_gamma_ramp(swapchain, flags, ramp);
5575         wined3d_swapchain_decref(swapchain);
5576     }
5577 }
5578
5579 void CDECL wined3d_device_get_gamma_ramp(const struct wined3d_device *device,
5580         UINT swapchain_idx, struct wined3d_gamma_ramp *ramp)
5581 {
5582     struct wined3d_swapchain *swapchain;
5583
5584     TRACE("device %p, swapchain_idx %u, ramp %p.\n",
5585             device, swapchain_idx, ramp);
5586
5587     if (SUCCEEDED(wined3d_device_get_swapchain(device, swapchain_idx, &swapchain)))
5588     {
5589         wined3d_swapchain_get_gamma_ramp(swapchain, ramp);
5590         wined3d_swapchain_decref(swapchain);
5591     }
5592 }
5593
5594 void device_resource_add(struct wined3d_device *device, struct wined3d_resource *resource)
5595 {
5596     TRACE("device %p, resource %p.\n", device, resource);
5597
5598     list_add_head(&device->resources, &resource->resource_list_entry);
5599 }
5600
5601 static void device_resource_remove(struct wined3d_device *device, struct wined3d_resource *resource)
5602 {
5603     TRACE("device %p, resource %p.\n", device, resource);
5604
5605     list_remove(&resource->resource_list_entry);
5606 }
5607
5608 void device_resource_released(struct wined3d_device *device, struct wined3d_resource *resource)
5609 {
5610     enum wined3d_resource_type type = resource->type;
5611     unsigned int i;
5612
5613     TRACE("device %p, resource %p, type %s.\n", device, resource, debug_d3dresourcetype(type));
5614
5615     context_resource_released(device, resource, type);
5616
5617     switch (type)
5618     {
5619         case WINED3D_RTYPE_SURFACE:
5620             {
5621                 struct wined3d_surface *surface = surface_from_resource(resource);
5622
5623                 if (!device->d3d_initialized) break;
5624
5625                 for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i)
5626                 {
5627                     if (device->fb.render_targets[i] == surface)
5628                     {
5629                         ERR("Surface %p is still in use as render target %u.\n", surface, i);
5630                         device->fb.render_targets[i] = NULL;
5631                     }
5632                 }
5633
5634                 if (device->fb.depth_stencil == surface)
5635                 {
5636                     ERR("Surface %p is still in use as depth/stencil buffer.\n", surface);
5637                     device->fb.depth_stencil = NULL;
5638                 }
5639             }
5640             break;
5641
5642         case WINED3D_RTYPE_TEXTURE:
5643         case WINED3D_RTYPE_CUBE_TEXTURE:
5644         case WINED3D_RTYPE_VOLUME_TEXTURE:
5645             for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5646             {
5647                 struct wined3d_texture *texture = wined3d_texture_from_resource(resource);
5648
5649                 if (device->stateBlock && device->stateBlock->state.textures[i] == texture)
5650                 {
5651                     ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
5652                             texture, device->stateBlock, i);
5653                     device->stateBlock->state.textures[i] = NULL;
5654                 }
5655
5656                 if (device->updateStateBlock != device->stateBlock
5657                         && device->updateStateBlock->state.textures[i] == texture)
5658                 {
5659                     ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
5660                             texture, device->updateStateBlock, i);
5661                     device->updateStateBlock->state.textures[i] = NULL;
5662                 }
5663             }
5664             break;
5665
5666         case WINED3D_RTYPE_BUFFER:
5667             {
5668                 struct wined3d_buffer *buffer = buffer_from_resource(resource);
5669
5670                 for (i = 0; i < MAX_STREAMS; ++i)
5671                 {
5672                     if (device->stateBlock && device->stateBlock->state.streams[i].buffer == buffer)
5673                     {
5674                         ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
5675                                 buffer, device->stateBlock, i);
5676                         device->stateBlock->state.streams[i].buffer = NULL;
5677                     }
5678
5679                     if (device->updateStateBlock != device->stateBlock
5680                             && device->updateStateBlock->state.streams[i].buffer == buffer)
5681                     {
5682                         ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
5683                                 buffer, device->updateStateBlock, i);
5684                         device->updateStateBlock->state.streams[i].buffer = NULL;
5685                     }
5686
5687                 }
5688
5689                 if (device->stateBlock && device->stateBlock->state.index_buffer == buffer)
5690                 {
5691                     ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
5692                             buffer, device->stateBlock);
5693                     device->stateBlock->state.index_buffer =  NULL;
5694                 }
5695
5696                 if (device->updateStateBlock != device->stateBlock
5697                         && device->updateStateBlock->state.index_buffer == buffer)
5698                 {
5699                     ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
5700                             buffer, device->updateStateBlock);
5701                     device->updateStateBlock->state.index_buffer =  NULL;
5702                 }
5703             }
5704             break;
5705
5706         default:
5707             break;
5708     }
5709
5710     /* Remove the resource from the resourceStore */
5711     device_resource_remove(device, resource);
5712
5713     TRACE("Resource released.\n");
5714 }
5715
5716 HRESULT CDECL wined3d_device_get_surface_from_dc(const struct wined3d_device *device,
5717         HDC dc, struct wined3d_surface **surface)
5718 {
5719     struct wined3d_resource *resource;
5720
5721     TRACE("device %p, dc %p, surface %p.\n", device, dc, surface);
5722
5723     if (!dc)
5724         return WINED3DERR_INVALIDCALL;
5725
5726     LIST_FOR_EACH_ENTRY(resource, &device->resources, struct wined3d_resource, resource_list_entry)
5727     {
5728         if (resource->type == WINED3D_RTYPE_SURFACE)
5729         {
5730             struct wined3d_surface *s = surface_from_resource(resource);
5731
5732             if (s->hDC == dc)
5733             {
5734                 TRACE("Found surface %p for dc %p.\n", s, dc);
5735                 *surface = s;
5736                 return WINED3D_OK;
5737             }
5738         }
5739     }
5740
5741     return WINED3DERR_INVALIDCALL;
5742 }
5743
5744 HRESULT device_init(struct wined3d_device *device, struct wined3d *wined3d,
5745         UINT adapter_idx, enum wined3d_device_type device_type, HWND focus_window, DWORD flags,
5746         BYTE surface_alignment, struct wined3d_device_parent *device_parent)
5747 {
5748     struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
5749     const struct fragment_pipeline *fragment_pipeline;
5750     struct wined3d_display_mode mode;
5751     struct shader_caps shader_caps;
5752     struct fragment_caps ffp_caps;
5753     unsigned int i;
5754     HRESULT hr;
5755
5756     device->ref = 1;
5757     device->wined3d = wined3d;
5758     wined3d_incref(device->wined3d);
5759     device->adapter = wined3d->adapter_count ? adapter : NULL;
5760     device->device_parent = device_parent;
5761     list_init(&device->resources);
5762     list_init(&device->shaders);
5763     device->surface_alignment = surface_alignment;
5764
5765     /* Get the initial screen setup for ddraw. */
5766     hr = wined3d_get_adapter_display_mode(wined3d, adapter_idx, &mode);
5767     if (FAILED(hr))
5768     {
5769         ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
5770         wined3d_decref(device->wined3d);
5771         return hr;
5772     }
5773     adapter->screen_size.cx = mode.width;
5774     adapter->screen_size.cy = mode.height;
5775     adapter->screen_format = mode.format_id;
5776
5777     /* Save the creation parameters. */
5778     device->create_parms.adapter_idx = adapter_idx;
5779     device->create_parms.device_type = device_type;
5780     device->create_parms.focus_window = focus_window;
5781     device->create_parms.flags = flags;
5782
5783     for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
5784
5785     select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
5786     device->shader_backend = adapter->shader_backend;
5787
5788     if (device->shader_backend)
5789     {
5790         device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
5791         device->vshader_version = shader_caps.VertexShaderVersion;
5792         device->pshader_version = shader_caps.PixelShaderVersion;
5793         device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
5794         device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
5795         device->vs_clipping = shader_caps.VSClipping;
5796     }
5797     fragment_pipeline = adapter->fragment_pipe;
5798     device->frag_pipe = fragment_pipeline;
5799     if (fragment_pipeline)
5800     {
5801         fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
5802         device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
5803
5804         hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
5805                                  ffp_vertexstate_template, fragment_pipeline, misc_state_template);
5806         if (FAILED(hr))
5807         {
5808             ERR("Failed to compile state table, hr %#x.\n", hr);
5809             wined3d_decref(device->wined3d);
5810             return hr;
5811         }
5812     }
5813     device->blitter = adapter->blitter;
5814
5815     hr = wined3d_stateblock_create(device, WINED3D_SBT_INIT, &device->stateBlock);
5816     if (FAILED(hr))
5817     {
5818         WARN("Failed to create stateblock.\n");
5819         for (i = 0; i < sizeof(device->multistate_funcs) / sizeof(device->multistate_funcs[0]); ++i)
5820         {
5821             HeapFree(GetProcessHeap(), 0, device->multistate_funcs[i]);
5822         }
5823         wined3d_decref(device->wined3d);
5824         return hr;
5825     }
5826
5827     TRACE("Created stateblock %p.\n", device->stateBlock);
5828     device->updateStateBlock = device->stateBlock;
5829     wined3d_stateblock_incref(device->updateStateBlock);
5830
5831     return WINED3D_OK;
5832 }
5833
5834
5835 void device_invalidate_state(const struct wined3d_device *device, DWORD state)
5836 {
5837     DWORD rep = device->StateTable[state].representative;
5838     struct wined3d_context *context;
5839     DWORD idx;
5840     BYTE shift;
5841     UINT i;
5842
5843     for (i = 0; i < device->context_count; ++i)
5844     {
5845         context = device->contexts[i];
5846         if(isStateDirty(context, rep)) continue;
5847
5848         context->dirtyArray[context->numDirtyEntries++] = rep;
5849         idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
5850         shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
5851         context->isStateDirty[idx] |= (1 << shift);
5852     }
5853 }
5854
5855 void get_drawable_size_fbo(const struct wined3d_context *context, UINT *width, UINT *height)
5856 {
5857     /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
5858     *width = context->current_rt->pow2Width;
5859     *height = context->current_rt->pow2Height;
5860 }
5861
5862 void get_drawable_size_backbuffer(const struct wined3d_context *context, UINT *width, UINT *height)
5863 {
5864     const struct wined3d_swapchain *swapchain = context->swapchain;
5865     /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
5866      * current context's drawable, which is the size of the back buffer of the swapchain
5867      * the active context belongs to. */
5868     *width = swapchain->desc.backbuffer_width;
5869     *height = swapchain->desc.backbuffer_height;
5870 }
5871
5872 LRESULT device_process_message(struct wined3d_device *device, HWND window, BOOL unicode,
5873         UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
5874 {
5875     if (device->filter_messages)
5876     {
5877         TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
5878                 window, message, wparam, lparam);
5879         if (unicode)
5880             return DefWindowProcW(window, message, wparam, lparam);
5881         else
5882             return DefWindowProcA(window, message, wparam, lparam);
5883     }
5884
5885     if (message == WM_DESTROY)
5886     {
5887         TRACE("unregister window %p.\n", window);
5888         wined3d_unregister_window(window);
5889
5890         if (InterlockedCompareExchangePointer((void **)&device->focus_window, NULL, window) != window)
5891             ERR("Window %p is not the focus window for device %p.\n", window, device);
5892     }
5893     else if (message == WM_DISPLAYCHANGE)
5894     {
5895         device->device_parent->ops->mode_changed(device->device_parent);
5896     }
5897
5898     if (unicode)
5899         return CallWindowProcW(proc, window, message, wparam, lparam);
5900     else
5901         return CallWindowProcA(proc, window, message, wparam, lparam);
5902 }