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