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