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