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