wbemprox: Return an empty object if the path is NULL or empty.
[wine] / dlls / wined3d / device.c
1 /*
2  * Copyright 2002 Lionel Ulmer
3  * Copyright 2002-2005 Jason Edmeades
4  * Copyright 2003-2004 Raphael Junqueira
5  * Copyright 2004 Christian Costa
6  * Copyright 2005 Oliver Stieber
7  * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
8  * Copyright 2006-2008 Henri Verbeet
9  * Copyright 2007 Andrew Riedi
10  * Copyright 2009-2011 Henri Verbeet for CodeWeavers
11  *
12  * This library is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Lesser General Public
14  * License as published by the Free Software Foundation; either
15  * version 2.1 of the License, or (at your option) any later version.
16  *
17  * This library is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * Lesser General Public License for more details.
21  *
22  * You should have received a copy of the GNU Lesser General Public
23  * License along with this library; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25  */
26
27 #include "config.h"
28 #include "wine/port.h"
29
30 #include <stdio.h>
31 #ifdef HAVE_FLOAT_H
32 # include <float.h>
33 #endif
34
35 #include "wined3d_private.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
38
39 /* Define the default light parameters as specified by MSDN. */
40 const struct wined3d_light WINED3D_default_light =
41 {
42     WINED3D_LIGHT_DIRECTIONAL,  /* Type */
43     { 1.0f, 1.0f, 1.0f, 0.0f }, /* Diffuse r,g,b,a */
44     { 0.0f, 0.0f, 0.0f, 0.0f }, /* Specular r,g,b,a */
45     { 0.0f, 0.0f, 0.0f, 0.0f }, /* Ambient r,g,b,a, */
46     { 0.0f, 0.0f, 0.0f },       /* Position x,y,z */
47     { 0.0f, 0.0f, 1.0f },       /* Direction x,y,z */
48     0.0f,                       /* Range */
49     0.0f,                       /* Falloff */
50     0.0f, 0.0f, 0.0f,           /* Attenuation 0,1,2 */
51     0.0f,                       /* Theta */
52     0.0f                        /* Phi */
53 };
54
55 /**********************************************************
56  * Global variable / Constants follow
57  **********************************************************/
58 const struct wined3d_matrix identity =
59 {{{
60     1.0f, 0.0f, 0.0f, 0.0f,
61     0.0f, 1.0f, 0.0f, 0.0f,
62     0.0f, 0.0f, 1.0f, 0.0f,
63     0.0f, 0.0f, 0.0f, 1.0f,
64 }}};  /* When needed for comparisons */
65
66 /* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these
67  * actually have the same values in GL and D3D. */
68 GLenum gl_primitive_type_from_d3d(enum wined3d_primitive_type primitive_type)
69 {
70     switch(primitive_type)
71     {
72         case WINED3D_PT_POINTLIST:
73             return GL_POINTS;
74
75         case WINED3D_PT_LINELIST:
76             return GL_LINES;
77
78         case WINED3D_PT_LINESTRIP:
79             return GL_LINE_STRIP;
80
81         case WINED3D_PT_TRIANGLELIST:
82             return GL_TRIANGLES;
83
84         case WINED3D_PT_TRIANGLESTRIP:
85             return GL_TRIANGLE_STRIP;
86
87         case WINED3D_PT_TRIANGLEFAN:
88             return GL_TRIANGLE_FAN;
89
90         case WINED3D_PT_LINELIST_ADJ:
91             return GL_LINES_ADJACENCY_ARB;
92
93         case WINED3D_PT_LINESTRIP_ADJ:
94             return GL_LINE_STRIP_ADJACENCY_ARB;
95
96         case WINED3D_PT_TRIANGLELIST_ADJ:
97             return GL_TRIANGLES_ADJACENCY_ARB;
98
99         case WINED3D_PT_TRIANGLESTRIP_ADJ:
100             return GL_TRIANGLE_STRIP_ADJACENCY_ARB;
101
102         default:
103             FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
104             return GL_NONE;
105     }
106 }
107
108 static enum wined3d_primitive_type d3d_primitive_type_from_gl(GLenum primitive_type)
109 {
110     switch(primitive_type)
111     {
112         case GL_POINTS:
113             return WINED3D_PT_POINTLIST;
114
115         case GL_LINES:
116             return WINED3D_PT_LINELIST;
117
118         case GL_LINE_STRIP:
119             return WINED3D_PT_LINESTRIP;
120
121         case GL_TRIANGLES:
122             return WINED3D_PT_TRIANGLELIST;
123
124         case GL_TRIANGLE_STRIP:
125             return WINED3D_PT_TRIANGLESTRIP;
126
127         case GL_TRIANGLE_FAN:
128             return WINED3D_PT_TRIANGLEFAN;
129
130         case GL_LINES_ADJACENCY_ARB:
131             return WINED3D_PT_LINELIST_ADJ;
132
133         case GL_LINE_STRIP_ADJACENCY_ARB:
134             return WINED3D_PT_LINESTRIP_ADJ;
135
136         case GL_TRIANGLES_ADJACENCY_ARB:
137             return WINED3D_PT_TRIANGLELIST_ADJ;
138
139         case GL_TRIANGLE_STRIP_ADJACENCY_ARB:
140             return WINED3D_PT_TRIANGLESTRIP_ADJ;
141
142         default:
143             FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
144             return WINED3D_PT_UNDEFINED;
145     }
146 }
147
148 static BOOL fixed_get_input(BYTE usage, BYTE usage_idx, unsigned int *regnum)
149 {
150     if ((usage == WINED3D_DECL_USAGE_POSITION || usage == WINED3D_DECL_USAGE_POSITIONT) && !usage_idx)
151         *regnum = WINED3D_FFP_POSITION;
152     else if (usage == WINED3D_DECL_USAGE_BLEND_WEIGHT && !usage_idx)
153         *regnum = WINED3D_FFP_BLENDWEIGHT;
154     else if (usage == WINED3D_DECL_USAGE_BLEND_INDICES && !usage_idx)
155         *regnum = WINED3D_FFP_BLENDINDICES;
156     else if (usage == WINED3D_DECL_USAGE_NORMAL && !usage_idx)
157         *regnum = WINED3D_FFP_NORMAL;
158     else if (usage == WINED3D_DECL_USAGE_PSIZE && !usage_idx)
159         *regnum = WINED3D_FFP_PSIZE;
160     else if (usage == WINED3D_DECL_USAGE_COLOR && !usage_idx)
161         *regnum = WINED3D_FFP_DIFFUSE;
162     else if (usage == WINED3D_DECL_USAGE_COLOR && usage_idx == 1)
163         *regnum = WINED3D_FFP_SPECULAR;
164     else if (usage == WINED3D_DECL_USAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
165         *regnum = WINED3D_FFP_TEXCOORD0 + usage_idx;
166     else
167     {
168         FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage), usage_idx);
169         *regnum = ~0U;
170         return FALSE;
171     }
172
173     return TRUE;
174 }
175
176 /* Context activation is done by the caller. */
177 void device_stream_info_from_declaration(struct wined3d_device *device, struct wined3d_stream_info *stream_info)
178 {
179     const struct wined3d_state *state = &device->stateBlock->state;
180     /* We need to deal with frequency data! */
181     struct wined3d_vertex_declaration *declaration = state->vertex_declaration;
182     BOOL use_vshader;
183     unsigned int i;
184     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         {
1769             ERR("Out of memory error when allocating a light\n");
1770             return E_OUTOFMEMORY;
1771         }
1772         list_add_head(&device->updateStateBlock->state.light_map[hash_idx], &object->entry);
1773         object->glIndex = -1;
1774         object->OriginalIndex = light_idx;
1775     }
1776
1777     /* Initialize the object. */
1778     TRACE("Light %d setting to type %d, Diffuse(%f,%f,%f,%f), Specular(%f,%f,%f,%f), Ambient(%f,%f,%f,%f)\n",
1779             light_idx, light->type,
1780             light->diffuse.r, light->diffuse.g, light->diffuse.b, light->diffuse.a,
1781             light->specular.r, light->specular.g, light->specular.b, light->specular.a,
1782             light->ambient.r, light->ambient.g, light->ambient.b, light->ambient.a);
1783     TRACE("... Pos(%f,%f,%f), Dir(%f,%f,%f)\n", light->position.x, light->position.y, light->position.z,
1784             light->direction.x, light->direction.y, light->direction.z);
1785     TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n",
1786             light->range, light->falloff, light->theta, light->phi);
1787
1788     /* Save away the information. */
1789     object->OriginalParms = *light;
1790
1791     switch (light->type)
1792     {
1793         case WINED3D_LIGHT_POINT:
1794             /* Position */
1795             object->lightPosn[0] = light->position.x;
1796             object->lightPosn[1] = light->position.y;
1797             object->lightPosn[2] = light->position.z;
1798             object->lightPosn[3] = 1.0f;
1799             object->cutoff = 180.0f;
1800             /* FIXME: Range */
1801             break;
1802
1803         case WINED3D_LIGHT_DIRECTIONAL:
1804             /* Direction */
1805             object->lightPosn[0] = -light->direction.x;
1806             object->lightPosn[1] = -light->direction.y;
1807             object->lightPosn[2] = -light->direction.z;
1808             object->lightPosn[3] = 0.0f;
1809             object->exponent = 0.0f;
1810             object->cutoff = 180.0f;
1811             break;
1812
1813         case WINED3D_LIGHT_SPOT:
1814             /* Position */
1815             object->lightPosn[0] = light->position.x;
1816             object->lightPosn[1] = light->position.y;
1817             object->lightPosn[2] = light->position.z;
1818             object->lightPosn[3] = 1.0f;
1819
1820             /* Direction */
1821             object->lightDirn[0] = light->direction.x;
1822             object->lightDirn[1] = light->direction.y;
1823             object->lightDirn[2] = light->direction.z;
1824             object->lightDirn[3] = 1.0f;
1825
1826             /* opengl-ish and d3d-ish spot lights use too different models
1827              * for the light "intensity" as a function of the angle towards
1828              * the main light direction, so we only can approximate very
1829              * roughly. However, spot lights are rather rarely used in games
1830              * (if ever used at all). Furthermore if still used, probably
1831              * nobody pays attention to such details. */
1832             if (!light->falloff)
1833             {
1834                 /* Falloff = 0 is easy, because d3d's and opengl's spot light
1835                  * equations have the falloff resp. exponent parameter as an
1836                  * exponent, so the spot light lighting will always be 1.0 for
1837                  * both of them, and we don't have to care for the rest of the
1838                  * rather complex calculation. */
1839                 object->exponent = 0.0f;
1840             }
1841             else
1842             {
1843                 rho = light->theta + (light->phi - light->theta) / (2 * light->falloff);
1844                 if (rho < 0.0001f)
1845                     rho = 0.0001f;
1846                 object->exponent = -0.3f / logf(cosf(rho / 2));
1847             }
1848
1849             if (object->exponent > 128.0f)
1850                 object->exponent = 128.0f;
1851
1852             object->cutoff = (float)(light->phi * 90 / M_PI);
1853             /* FIXME: Range */
1854             break;
1855
1856         default:
1857             FIXME("Unrecognized light type %#x.\n", light->type);
1858     }
1859
1860     /* Update the live definitions if the light is currently assigned a glIndex. */
1861     if (object->glIndex != -1 && !device->isRecordingState)
1862         device_invalidate_state(device, STATE_ACTIVELIGHT(object->glIndex));
1863
1864     return WINED3D_OK;
1865 }
1866
1867 HRESULT CDECL wined3d_device_get_light(const struct wined3d_device *device,
1868         UINT light_idx, struct wined3d_light *light)
1869 {
1870     UINT hash_idx = LIGHTMAP_HASHFUNC(light_idx);
1871     struct wined3d_light_info *light_info = NULL;
1872     struct list *e;
1873
1874     TRACE("device %p, light_idx %u, light %p.\n", device, light_idx, light);
1875
1876     LIST_FOR_EACH(e, &device->stateBlock->state.light_map[hash_idx])
1877     {
1878         light_info = LIST_ENTRY(e, struct wined3d_light_info, entry);
1879         if (light_info->OriginalIndex == light_idx)
1880             break;
1881         light_info = NULL;
1882     }
1883
1884     if (!light_info)
1885     {
1886         TRACE("Light information requested but light not defined\n");
1887         return WINED3DERR_INVALIDCALL;
1888     }
1889
1890     *light = light_info->OriginalParms;
1891     return WINED3D_OK;
1892 }
1893
1894 HRESULT CDECL wined3d_device_set_light_enable(struct wined3d_device *device, UINT light_idx, BOOL enable)
1895 {
1896     UINT hash_idx = LIGHTMAP_HASHFUNC(light_idx);
1897     struct wined3d_light_info *light_info = NULL;
1898     struct list *e;
1899
1900     TRACE("device %p, light_idx %u, enable %#x.\n", device, light_idx, enable);
1901
1902     LIST_FOR_EACH(e, &device->updateStateBlock->state.light_map[hash_idx])
1903     {
1904         light_info = LIST_ENTRY(e, struct wined3d_light_info, entry);
1905         if (light_info->OriginalIndex == light_idx)
1906             break;
1907         light_info = NULL;
1908     }
1909     TRACE("Found light %p.\n", light_info);
1910
1911     /* Special case - enabling an undefined light creates one with a strict set of parameters. */
1912     if (!light_info)
1913     {
1914         TRACE("Light enabled requested but light not defined, so defining one!\n");
1915         wined3d_device_set_light(device, light_idx, &WINED3D_default_light);
1916
1917         /* Search for it again! Should be fairly quick as near head of list. */
1918         LIST_FOR_EACH(e, &device->updateStateBlock->state.light_map[hash_idx])
1919         {
1920             light_info = LIST_ENTRY(e, struct wined3d_light_info, entry);
1921             if (light_info->OriginalIndex == light_idx)
1922                 break;
1923             light_info = NULL;
1924         }
1925         if (!light_info)
1926         {
1927             FIXME("Adding default lights has failed dismally\n");
1928             return WINED3DERR_INVALIDCALL;
1929         }
1930     }
1931
1932     if (!enable)
1933     {
1934         if (light_info->glIndex != -1)
1935         {
1936             if (!device->isRecordingState)
1937                 device_invalidate_state(device, STATE_ACTIVELIGHT(light_info->glIndex));
1938
1939             device->updateStateBlock->state.lights[light_info->glIndex] = NULL;
1940             light_info->glIndex = -1;
1941         }
1942         else
1943         {
1944             TRACE("Light already disabled, nothing to do\n");
1945         }
1946         light_info->enabled = FALSE;
1947     }
1948     else
1949     {
1950         light_info->enabled = TRUE;
1951         if (light_info->glIndex != -1)
1952         {
1953             TRACE("Nothing to do as light was enabled\n");
1954         }
1955         else
1956         {
1957             unsigned int i;
1958             const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1959             /* Find a free GL light. */
1960             for (i = 0; i < gl_info->limits.lights; ++i)
1961             {
1962                 if (!device->updateStateBlock->state.lights[i])
1963                 {
1964                     device->updateStateBlock->state.lights[i] = light_info;
1965                     light_info->glIndex = i;
1966                     break;
1967                 }
1968             }
1969             if (light_info->glIndex == -1)
1970             {
1971                 /* Our tests show that Windows returns D3D_OK in this situation, even with
1972                  * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
1973                  * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
1974                  * as well for those lights.
1975                  *
1976                  * TODO: Test how this affects rendering. */
1977                 WARN("Too many concurrently active lights\n");
1978                 return WINED3D_OK;
1979             }
1980
1981             /* i == light_info->glIndex */
1982             if (!device->isRecordingState)
1983                 device_invalidate_state(device, STATE_ACTIVELIGHT(i));
1984         }
1985     }
1986
1987     return WINED3D_OK;
1988 }
1989
1990 HRESULT CDECL wined3d_device_get_light_enable(const struct wined3d_device *device, UINT light_idx, BOOL *enable)
1991 {
1992     UINT hash_idx = LIGHTMAP_HASHFUNC(light_idx);
1993     struct wined3d_light_info *light_info = NULL;
1994     struct list *e;
1995
1996     TRACE("device %p, light_idx %u, enable %p.\n", device, light_idx, enable);
1997
1998     LIST_FOR_EACH(e, &device->stateBlock->state.light_map[hash_idx])
1999     {
2000         light_info = LIST_ENTRY(e, struct wined3d_light_info, entry);
2001         if (light_info->OriginalIndex == light_idx)
2002             break;
2003         light_info = NULL;
2004     }
2005
2006     if (!light_info)
2007     {
2008         TRACE("Light enabled state requested but light not defined.\n");
2009         return WINED3DERR_INVALIDCALL;
2010     }
2011     /* true is 128 according to SetLightEnable */
2012     *enable = light_info->enabled ? 128 : 0;
2013     return WINED3D_OK;
2014 }
2015
2016 HRESULT CDECL wined3d_device_set_clip_plane(struct wined3d_device *device,
2017         UINT plane_idx, const struct wined3d_vec4 *plane)
2018 {
2019     TRACE("device %p, plane_idx %u, plane %p.\n", device, plane_idx, plane);
2020
2021     /* Validate plane_idx. */
2022     if (plane_idx >= device->adapter->gl_info.limits.clipplanes)
2023     {
2024         TRACE("Application has requested clipplane this device doesn't support.\n");
2025         return WINED3DERR_INVALIDCALL;
2026     }
2027
2028     device->updateStateBlock->changed.clipplane |= 1 << plane_idx;
2029
2030     if (!memcmp(&device->updateStateBlock->state.clip_planes[plane_idx], plane, sizeof(*plane)))
2031     {
2032         TRACE("Application is setting old values over, nothing to do.\n");
2033         return WINED3D_OK;
2034     }
2035
2036     device->updateStateBlock->state.clip_planes[plane_idx] = *plane;
2037
2038     /* Handle recording of state blocks. */
2039     if (device->isRecordingState)
2040     {
2041         TRACE("Recording... not performing anything.\n");
2042         return WINED3D_OK;
2043     }
2044
2045     device_invalidate_state(device, STATE_CLIPPLANE(plane_idx));
2046
2047     return WINED3D_OK;
2048 }
2049
2050 HRESULT CDECL wined3d_device_get_clip_plane(const struct wined3d_device *device,
2051         UINT plane_idx, struct wined3d_vec4 *plane)
2052 {
2053     TRACE("device %p, plane_idx %u, plane %p.\n", device, plane_idx, plane);
2054
2055     /* Validate plane_idx. */
2056     if (plane_idx >= device->adapter->gl_info.limits.clipplanes)
2057     {
2058         TRACE("Application has requested clipplane this device doesn't support.\n");
2059         return WINED3DERR_INVALIDCALL;
2060     }
2061
2062     *plane = device->stateBlock->state.clip_planes[plane_idx];
2063
2064     return WINED3D_OK;
2065 }
2066
2067 HRESULT CDECL wined3d_device_set_clip_status(struct wined3d_device *device,
2068         const struct wined3d_clip_status *clip_status)
2069 {
2070     FIXME("device %p, clip_status %p stub!\n", device, clip_status);
2071
2072     if (!clip_status)
2073         return WINED3DERR_INVALIDCALL;
2074
2075     return WINED3D_OK;
2076 }
2077
2078 HRESULT CDECL wined3d_device_get_clip_status(const struct wined3d_device *device,
2079         struct wined3d_clip_status *clip_status)
2080 {
2081     FIXME("device %p, clip_status %p stub!\n", device, clip_status);
2082
2083     if (!clip_status)
2084         return WINED3DERR_INVALIDCALL;
2085
2086     return WINED3D_OK;
2087 }
2088
2089 void CDECL wined3d_device_set_material(struct wined3d_device *device, const struct wined3d_material *material)
2090 {
2091     TRACE("device %p, material %p.\n", device, material);
2092
2093     device->updateStateBlock->changed.material = TRUE;
2094     device->updateStateBlock->state.material = *material;
2095
2096     /* Handle recording of state blocks */
2097     if (device->isRecordingState)
2098     {
2099         TRACE("Recording... not performing anything.\n");
2100         return;
2101     }
2102
2103     device_invalidate_state(device, STATE_MATERIAL);
2104 }
2105
2106 void CDECL wined3d_device_get_material(const struct wined3d_device *device, struct wined3d_material *material)
2107 {
2108     TRACE("device %p, material %p.\n", device, material);
2109
2110     *material = device->updateStateBlock->state.material;
2111
2112     TRACE("diffuse {%.8e, %.8e, %.8e, %.8e}\n",
2113             material->diffuse.r, material->diffuse.g,
2114             material->diffuse.b, material->diffuse.a);
2115     TRACE("ambient {%.8e, %.8e, %.8e, %.8e}\n",
2116             material->ambient.r, material->ambient.g,
2117             material->ambient.b, material->ambient.a);
2118     TRACE("specular {%.8e, %.8e, %.8e, %.8e}\n",
2119             material->specular.r, material->specular.g,
2120             material->specular.b, material->specular.a);
2121     TRACE("emissive {%.8e, %.8e, %.8e, %.8e}\n",
2122             material->emissive.r, material->emissive.g,
2123             material->emissive.b, material->emissive.a);
2124     TRACE("power %.8e.\n", material->power);
2125 }
2126
2127 void CDECL wined3d_device_set_index_buffer(struct wined3d_device *device,
2128         struct wined3d_buffer *buffer, enum wined3d_format_id format_id)
2129 {
2130     struct wined3d_buffer *prev_buffer;
2131
2132     TRACE("device %p, buffer %p, format %s.\n",
2133             device, buffer, debug_d3dformat(format_id));
2134
2135     prev_buffer = device->updateStateBlock->state.index_buffer;
2136
2137     device->updateStateBlock->changed.indices = TRUE;
2138     device->updateStateBlock->state.index_buffer = buffer;
2139     device->updateStateBlock->state.index_format = format_id;
2140
2141     /* Handle recording of state blocks. */
2142     if (device->isRecordingState)
2143     {
2144         TRACE("Recording... not performing anything.\n");
2145         if (buffer)
2146             wined3d_buffer_incref(buffer);
2147         if (prev_buffer)
2148             wined3d_buffer_decref(prev_buffer);
2149         return;
2150     }
2151
2152     if (prev_buffer != buffer)
2153     {
2154         device_invalidate_state(device, STATE_INDEXBUFFER);
2155         if (buffer)
2156         {
2157             InterlockedIncrement(&buffer->resource.bind_count);
2158             wined3d_buffer_incref(buffer);
2159         }
2160         if (prev_buffer)
2161         {
2162             InterlockedDecrement(&prev_buffer->resource.bind_count);
2163             wined3d_buffer_decref(prev_buffer);
2164         }
2165     }
2166 }
2167
2168 struct wined3d_buffer * CDECL wined3d_device_get_index_buffer(const struct wined3d_device *device,
2169         enum wined3d_format_id *format)
2170 {
2171     TRACE("device %p, format %p.\n", device, format);
2172
2173     *format = device->stateBlock->state.index_format;
2174     return device->stateBlock->state.index_buffer;
2175 }
2176
2177 void CDECL wined3d_device_set_base_vertex_index(struct wined3d_device *device, INT base_index)
2178 {
2179     TRACE("device %p, base_index %d.\n", device, base_index);
2180
2181     device->updateStateBlock->state.base_vertex_index = base_index;
2182 }
2183
2184 INT CDECL wined3d_device_get_base_vertex_index(const struct wined3d_device *device)
2185 {
2186     TRACE("device %p.\n", device);
2187
2188     return device->stateBlock->state.base_vertex_index;
2189 }
2190
2191 void CDECL wined3d_device_set_viewport(struct wined3d_device *device, const struct wined3d_viewport *viewport)
2192 {
2193     TRACE("device %p, viewport %p.\n", device, viewport);
2194     TRACE("x %u, y %u, w %u, h %u, min_z %.8e, max_z %.8e.\n",
2195           viewport->x, viewport->y, viewport->width, viewport->height, viewport->min_z, viewport->max_z);
2196
2197     device->updateStateBlock->changed.viewport = TRUE;
2198     device->updateStateBlock->state.viewport = *viewport;
2199
2200     /* Handle recording of state blocks */
2201     if (device->isRecordingState)
2202     {
2203         TRACE("Recording... not performing anything\n");
2204         return;
2205     }
2206
2207     device_invalidate_state(device, STATE_VIEWPORT);
2208 }
2209
2210 void CDECL wined3d_device_get_viewport(const struct wined3d_device *device, struct wined3d_viewport *viewport)
2211 {
2212     TRACE("device %p, viewport %p.\n", device, viewport);
2213
2214     *viewport = device->stateBlock->state.viewport;
2215 }
2216
2217 void CDECL wined3d_device_set_render_state(struct wined3d_device *device,
2218         enum wined3d_render_state state, DWORD value)
2219 {
2220     DWORD old_value = device->stateBlock->state.render_states[state];
2221
2222     TRACE("device %p, state %s (%#x), value %#x.\n", device, debug_d3drenderstate(state), state, value);
2223
2224     device->updateStateBlock->changed.renderState[state >> 5] |= 1 << (state & 0x1f);
2225     device->updateStateBlock->state.render_states[state] = value;
2226
2227     /* Handle recording of state blocks. */
2228     if (device->isRecordingState)
2229     {
2230         TRACE("Recording... not performing anything.\n");
2231         return;
2232     }
2233
2234     /* Compared here and not before the assignment to allow proper stateblock recording. */
2235     if (value == old_value)
2236         TRACE("Application is setting the old value over, nothing to do.\n");
2237     else
2238         device_invalidate_state(device, STATE_RENDER(state));
2239 }
2240
2241 DWORD CDECL wined3d_device_get_render_state(const struct wined3d_device *device, enum wined3d_render_state state)
2242 {
2243     TRACE("device %p, state %s (%#x).\n", device, debug_d3drenderstate(state), state);
2244
2245     return device->stateBlock->state.render_states[state];
2246 }
2247
2248 void CDECL wined3d_device_set_sampler_state(struct wined3d_device *device,
2249         UINT sampler_idx, enum wined3d_sampler_state state, DWORD value)
2250 {
2251     DWORD old_value;
2252
2253     TRACE("device %p, sampler_idx %u, state %s, value %#x.\n",
2254             device, sampler_idx, debug_d3dsamplerstate(state), value);
2255
2256     if (sampler_idx >= WINED3DVERTEXTEXTURESAMPLER0 && sampler_idx <= WINED3DVERTEXTEXTURESAMPLER3)
2257         sampler_idx -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2258
2259     if (sampler_idx >= sizeof(device->stateBlock->state.sampler_states)
2260             / sizeof(*device->stateBlock->state.sampler_states))
2261     {
2262         WARN("Invalid sampler %u.\n", sampler_idx);
2263         return; /* Windows accepts overflowing this array ... we do not. */
2264     }
2265
2266     old_value = device->stateBlock->state.sampler_states[sampler_idx][state];
2267     device->updateStateBlock->state.sampler_states[sampler_idx][state] = value;
2268     device->updateStateBlock->changed.samplerState[sampler_idx] |= 1 << state;
2269
2270     /* Handle recording of state blocks. */
2271     if (device->isRecordingState)
2272     {
2273         TRACE("Recording... not performing anything.\n");
2274         return;
2275     }
2276
2277     if (old_value == value)
2278     {
2279         TRACE("Application is setting the old value over, nothing to do.\n");
2280         return;
2281     }
2282
2283     device_invalidate_state(device, STATE_SAMPLER(sampler_idx));
2284 }
2285
2286 DWORD CDECL wined3d_device_get_sampler_state(const struct wined3d_device *device,
2287         UINT sampler_idx, enum wined3d_sampler_state state)
2288 {
2289     TRACE("device %p, sampler_idx %u, state %s.\n",
2290             device, sampler_idx, debug_d3dsamplerstate(state));
2291
2292     if (sampler_idx >= WINED3DVERTEXTEXTURESAMPLER0 && sampler_idx <= WINED3DVERTEXTEXTURESAMPLER3)
2293         sampler_idx -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2294
2295     if (sampler_idx >= sizeof(device->stateBlock->state.sampler_states)
2296             / sizeof(*device->stateBlock->state.sampler_states))
2297     {
2298         WARN("Invalid sampler %u.\n", sampler_idx);
2299         return 0; /* Windows accepts overflowing this array ... we do not. */
2300     }
2301
2302     return device->stateBlock->state.sampler_states[sampler_idx][state];
2303 }
2304
2305 void CDECL wined3d_device_set_scissor_rect(struct wined3d_device *device, const RECT *rect)
2306 {
2307     TRACE("device %p, rect %s.\n", device, wine_dbgstr_rect(rect));
2308
2309     device->updateStateBlock->changed.scissorRect = TRUE;
2310     if (EqualRect(&device->updateStateBlock->state.scissor_rect, rect))
2311     {
2312         TRACE("App is setting the old scissor rectangle over, nothing to do.\n");
2313         return;
2314     }
2315     CopyRect(&device->updateStateBlock->state.scissor_rect, rect);
2316
2317     if (device->isRecordingState)
2318     {
2319         TRACE("Recording... not performing anything.\n");
2320         return;
2321     }
2322
2323     device_invalidate_state(device, STATE_SCISSORRECT);
2324 }
2325
2326 void CDECL wined3d_device_get_scissor_rect(const struct wined3d_device *device, RECT *rect)
2327 {
2328     TRACE("device %p, rect %p.\n", device, rect);
2329
2330     *rect = device->updateStateBlock->state.scissor_rect;
2331     TRACE("Returning rect %s.\n", wine_dbgstr_rect(rect));
2332 }
2333
2334 void CDECL wined3d_device_set_vertex_declaration(struct wined3d_device *device,
2335         struct wined3d_vertex_declaration *declaration)
2336 {
2337     struct wined3d_vertex_declaration *prev = device->updateStateBlock->state.vertex_declaration;
2338
2339     TRACE("device %p, declaration %p.\n", device, declaration);
2340
2341     if (declaration)
2342         wined3d_vertex_declaration_incref(declaration);
2343     if (prev)
2344         wined3d_vertex_declaration_decref(prev);
2345
2346     device->updateStateBlock->state.vertex_declaration = declaration;
2347     device->updateStateBlock->changed.vertexDecl = TRUE;
2348
2349     if (device->isRecordingState)
2350     {
2351         TRACE("Recording... not performing anything.\n");
2352         return;
2353     }
2354
2355     if (declaration == prev)
2356     {
2357         /* Checked after the assignment to allow proper stateblock recording. */
2358         TRACE("Application is setting the old declaration over, nothing to do.\n");
2359         return;
2360     }
2361
2362     device_invalidate_state(device, STATE_VDECL);
2363 }
2364
2365 struct wined3d_vertex_declaration * CDECL wined3d_device_get_vertex_declaration(const struct wined3d_device *device)
2366 {
2367     TRACE("device %p.\n", device);
2368
2369     return device->stateBlock->state.vertex_declaration;
2370 }
2371
2372 void CDECL wined3d_device_set_vertex_shader(struct wined3d_device *device, struct wined3d_shader *shader)
2373 {
2374     struct wined3d_shader *prev = device->updateStateBlock->state.vertex_shader;
2375
2376     TRACE("device %p, shader %p.\n", device, shader);
2377
2378     if (shader)
2379         wined3d_shader_incref(shader);
2380     if (prev)
2381         wined3d_shader_decref(prev);
2382
2383     device->updateStateBlock->state.vertex_shader = shader;
2384     device->updateStateBlock->changed.vertexShader = TRUE;
2385
2386     if (device->isRecordingState)
2387     {
2388         TRACE("Recording... not performing anything.\n");
2389         return;
2390     }
2391
2392     if (shader == prev)
2393     {
2394         TRACE("Application is setting the old shader over, nothing to do.\n");
2395         return;
2396     }
2397
2398     device_invalidate_state(device, STATE_VSHADER);
2399 }
2400
2401 struct wined3d_shader * CDECL wined3d_device_get_vertex_shader(const struct wined3d_device *device)
2402 {
2403     TRACE("device %p.\n", device);
2404
2405     return device->stateBlock->state.vertex_shader;
2406 }
2407
2408 void CDECL wined3d_device_set_vs_cb(struct wined3d_device *device, UINT idx, struct wined3d_buffer *buffer)
2409 {
2410     struct wined3d_buffer *prev;
2411
2412     TRACE("device %p, idx %u, buffer %p.\n", device, idx, buffer);
2413
2414     if (idx >= MAX_CONSTANT_BUFFERS)
2415     {
2416         WARN("Invalid constant buffer index %u.\n", idx);
2417         return;
2418     }
2419
2420     prev = device->updateStateBlock->state.vs_cb[idx];
2421     device->updateStateBlock->state.vs_cb[idx] = buffer;
2422
2423     if (device->isRecordingState)
2424     {
2425         if (buffer)
2426             wined3d_buffer_incref(buffer);
2427         if (prev)
2428             wined3d_buffer_decref(prev);
2429         return;
2430     }
2431
2432     if (prev != buffer)
2433     {
2434         if (buffer)
2435         {
2436             InterlockedIncrement(&buffer->resource.bind_count);
2437             wined3d_buffer_incref(buffer);
2438         }
2439         if (prev)
2440         {
2441             InterlockedDecrement(&prev->resource.bind_count);
2442             wined3d_buffer_decref(prev);
2443         }
2444     }
2445 }
2446
2447 struct wined3d_buffer * CDECL wined3d_device_get_vs_cb(const struct wined3d_device *device, UINT idx)
2448 {
2449     TRACE("device %p, idx %u.\n", device, idx);
2450
2451     if (idx >= MAX_CONSTANT_BUFFERS)
2452     {
2453         WARN("Invalid constant buffer index %u.\n", idx);
2454         return NULL;
2455     }
2456
2457     return device->stateBlock->state.vs_cb[idx];
2458 }
2459
2460 void CDECL wined3d_device_set_vs_sampler(struct wined3d_device *device, UINT idx, struct wined3d_sampler *sampler)
2461 {
2462     struct wined3d_sampler *prev;
2463
2464     TRACE("device %p, idx %u, sampler %p.\n", device, idx, sampler);
2465
2466     if (idx >= MAX_SAMPLER_OBJECTS)
2467     {
2468         WARN("Invalid sampler index %u.\n", idx);
2469         return;
2470     }
2471
2472     prev = device->updateStateBlock->state.vs_sampler[idx];
2473     device->updateStateBlock->state.vs_sampler[idx] = sampler;
2474
2475     if (sampler)
2476         wined3d_sampler_incref(sampler);
2477     if (prev)
2478         wined3d_sampler_decref(prev);
2479 }
2480
2481 struct wined3d_sampler * CDECL wined3d_device_get_vs_sampler(const struct wined3d_device *device, UINT idx)
2482 {
2483     TRACE("device %p, idx %u.\n", device, idx);
2484
2485     if (idx >= MAX_SAMPLER_OBJECTS)
2486     {
2487         WARN("Invalid sampler index %u.\n", idx);
2488         return NULL;
2489     }
2490
2491     return device->stateBlock->state.vs_sampler[idx];
2492 }
2493
2494 HRESULT CDECL wined3d_device_set_vs_consts_b(struct wined3d_device *device,
2495         UINT start_register, const BOOL *constants, UINT bool_count)
2496 {
2497     UINT count = min(bool_count, MAX_CONST_B - start_register);
2498     UINT i;
2499
2500     TRACE("device %p, start_register %u, constants %p, bool_count %u.\n",
2501             device, start_register, constants, bool_count);
2502
2503     if (!constants || start_register >= MAX_CONST_B)
2504         return WINED3DERR_INVALIDCALL;
2505
2506     memcpy(&device->updateStateBlock->state.vs_consts_b[start_register], constants, count * sizeof(BOOL));
2507     for (i = 0; i < count; ++i)
2508         TRACE("Set BOOL constant %u to %s.\n", start_register + i, constants[i] ? "true" : "false");
2509
2510     for (i = start_register; i < count + start_register; ++i)
2511         device->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
2512
2513     if (!device->isRecordingState)
2514         device_invalidate_state(device, STATE_VERTEXSHADERCONSTANT);
2515
2516     return WINED3D_OK;
2517 }
2518
2519 HRESULT CDECL wined3d_device_get_vs_consts_b(const struct wined3d_device *device,
2520         UINT start_register, BOOL *constants, UINT bool_count)
2521 {
2522     UINT count = min(bool_count, MAX_CONST_B - start_register);
2523
2524     TRACE("device %p, start_register %u, constants %p, bool_count %u.\n",
2525             device, start_register, constants, bool_count);
2526
2527     if (!constants || start_register >= MAX_CONST_B)
2528         return WINED3DERR_INVALIDCALL;
2529
2530     memcpy(constants, &device->stateBlock->state.vs_consts_b[start_register], count * sizeof(BOOL));
2531
2532     return WINED3D_OK;
2533 }
2534
2535 HRESULT CDECL wined3d_device_set_vs_consts_i(struct wined3d_device *device,
2536         UINT start_register, const int *constants, UINT vector4i_count)
2537 {
2538     UINT count = min(vector4i_count, MAX_CONST_I - start_register);
2539     UINT i;
2540
2541     TRACE("device %p, start_register %u, constants %p, vector4i_count %u.\n",
2542             device, start_register, constants, vector4i_count);
2543
2544     if (!constants || start_register >= MAX_CONST_I)
2545         return WINED3DERR_INVALIDCALL;
2546
2547     memcpy(&device->updateStateBlock->state.vs_consts_i[start_register * 4], constants, count * sizeof(int) * 4);
2548     for (i = 0; i < count; ++i)
2549         TRACE("Set INT constant %u to {%d, %d, %d, %d}.\n", start_register + i,
2550                 constants[i * 4], constants[i * 4 + 1],
2551                 constants[i * 4 + 2], constants[i * 4 + 3]);
2552
2553     for (i = start_register; i < count + start_register; ++i)
2554         device->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
2555
2556     if (!device->isRecordingState)
2557         device_invalidate_state(device, STATE_VERTEXSHADERCONSTANT);
2558
2559     return WINED3D_OK;
2560 }
2561
2562 HRESULT CDECL wined3d_device_get_vs_consts_i(const struct wined3d_device *device,
2563         UINT start_register, int *constants, UINT vector4i_count)
2564 {
2565     UINT count = min(vector4i_count, MAX_CONST_I - start_register);
2566
2567     TRACE("device %p, start_register %u, constants %p, vector4i_count %u.\n",
2568             device, start_register, constants, vector4i_count);
2569
2570     if (!constants || start_register >= MAX_CONST_I)
2571         return WINED3DERR_INVALIDCALL;
2572
2573     memcpy(constants, &device->stateBlock->state.vs_consts_i[start_register * 4], count * sizeof(int) * 4);
2574     return WINED3D_OK;
2575 }
2576
2577 HRESULT CDECL wined3d_device_set_vs_consts_f(struct wined3d_device *device,
2578         UINT start_register, const float *constants, UINT vector4f_count)
2579 {
2580     UINT i;
2581
2582     TRACE("device %p, start_register %u, constants %p, vector4f_count %u.\n",
2583             device, start_register, constants, vector4f_count);
2584
2585     /* Specifically test start_register > limit to catch MAX_UINT overflows
2586      * when adding start_register + vector4f_count. */
2587     if (!constants
2588             || start_register + vector4f_count > device->d3d_vshader_constantF
2589             || start_register > device->d3d_vshader_constantF)
2590         return WINED3DERR_INVALIDCALL;
2591
2592     memcpy(&device->updateStateBlock->state.vs_consts_f[start_register * 4],
2593             constants, vector4f_count * sizeof(float) * 4);
2594     if (TRACE_ON(d3d))
2595     {
2596         for (i = 0; i < vector4f_count; ++i)
2597             TRACE("Set FLOAT constant %u to {%.8e, %.8e, %.8e, %.8e}.\n", start_register + i,
2598                     constants[i * 4], constants[i * 4 + 1],
2599                     constants[i * 4 + 2], constants[i * 4 + 3]);
2600     }
2601
2602     if (!device->isRecordingState)
2603     {
2604         device->shader_backend->shader_update_float_vertex_constants(device, start_register, vector4f_count);
2605         device_invalidate_state(device, STATE_VERTEXSHADERCONSTANT);
2606     }
2607
2608     memset(device->updateStateBlock->changed.vertexShaderConstantsF + start_register, 1,
2609             sizeof(*device->updateStateBlock->changed.vertexShaderConstantsF) * vector4f_count);
2610
2611     return WINED3D_OK;
2612 }
2613
2614 HRESULT CDECL wined3d_device_get_vs_consts_f(const struct wined3d_device *device,
2615         UINT start_register, float *constants, UINT vector4f_count)
2616 {
2617     int count = min(vector4f_count, device->d3d_vshader_constantF - start_register);
2618
2619     TRACE("device %p, start_register %u, constants %p, vector4f_count %u.\n",
2620             device, start_register, constants, vector4f_count);
2621
2622     if (!constants || count < 0)
2623         return WINED3DERR_INVALIDCALL;
2624
2625     memcpy(constants, &device->stateBlock->state.vs_consts_f[start_register * 4], count * sizeof(float) * 4);
2626
2627     return WINED3D_OK;
2628 }
2629
2630 static void device_invalidate_texture_stage(const struct wined3d_device *device, DWORD stage)
2631 {
2632     DWORD i;
2633
2634     for (i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
2635     {
2636         device_invalidate_state(device, STATE_TEXTURESTAGE(stage, i));
2637     }
2638 }
2639
2640 static void device_map_stage(struct wined3d_device *device, DWORD stage, DWORD unit)
2641 {
2642     DWORD i = device->rev_tex_unit_map[unit];
2643     DWORD j = device->texUnitMap[stage];
2644
2645     device->texUnitMap[stage] = unit;
2646     if (i != WINED3D_UNMAPPED_STAGE && i != stage)
2647         device->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
2648
2649     device->rev_tex_unit_map[unit] = stage;
2650     if (j != WINED3D_UNMAPPED_STAGE && j != unit)
2651         device->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
2652 }
2653
2654 static void device_update_fixed_function_usage_map(struct wined3d_device *device)
2655 {
2656     UINT i;
2657
2658     device->fixed_function_usage_map = 0;
2659     for (i = 0; i < MAX_TEXTURES; ++i)
2660     {
2661         const struct wined3d_state *state = &device->stateBlock->state;
2662         enum wined3d_texture_op color_op = state->texture_states[i][WINED3D_TSS_COLOR_OP];
2663         enum wined3d_texture_op alpha_op = state->texture_states[i][WINED3D_TSS_ALPHA_OP];
2664         DWORD color_arg1 = state->texture_states[i][WINED3D_TSS_COLOR_ARG1] & WINED3DTA_SELECTMASK;
2665         DWORD color_arg2 = state->texture_states[i][WINED3D_TSS_COLOR_ARG2] & WINED3DTA_SELECTMASK;
2666         DWORD color_arg3 = state->texture_states[i][WINED3D_TSS_COLOR_ARG0] & WINED3DTA_SELECTMASK;
2667         DWORD alpha_arg1 = state->texture_states[i][WINED3D_TSS_ALPHA_ARG1] & WINED3DTA_SELECTMASK;
2668         DWORD alpha_arg2 = state->texture_states[i][WINED3D_TSS_ALPHA_ARG2] & WINED3DTA_SELECTMASK;
2669         DWORD alpha_arg3 = state->texture_states[i][WINED3D_TSS_ALPHA_ARG0] & WINED3DTA_SELECTMASK;
2670
2671         /* Not used, and disable higher stages. */
2672         if (color_op == WINED3D_TOP_DISABLE)
2673             break;
2674
2675         if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3D_TOP_SELECT_ARG2)
2676                 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3D_TOP_SELECT_ARG1)
2677                 || ((color_arg3 == WINED3DTA_TEXTURE)
2678                     && (color_op == WINED3D_TOP_MULTIPLY_ADD || color_op == WINED3D_TOP_LERP))
2679                 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3D_TOP_SELECT_ARG2)
2680                 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3D_TOP_SELECT_ARG1)
2681                 || ((alpha_arg3 == WINED3DTA_TEXTURE)
2682                     && (alpha_op == WINED3D_TOP_MULTIPLY_ADD || alpha_op == WINED3D_TOP_LERP)))
2683             device->fixed_function_usage_map |= (1 << i);
2684
2685         if ((color_op == WINED3D_TOP_BUMPENVMAP || color_op == WINED3D_TOP_BUMPENVMAP_LUMINANCE)
2686                 && i < MAX_TEXTURES - 1)
2687             device->fixed_function_usage_map |= (1 << (i + 1));
2688     }
2689 }
2690
2691 static void device_map_fixed_function_samplers(struct wined3d_device *device, const struct wined3d_gl_info *gl_info)
2692 {
2693     unsigned int i, tex;
2694     WORD ffu_map;
2695
2696     device_update_fixed_function_usage_map(device);
2697     ffu_map = device->fixed_function_usage_map;
2698
2699     if (device->max_ffp_textures == gl_info->limits.texture_stages
2700             || device->stateBlock->state.lowest_disabled_stage <= device->max_ffp_textures)
2701     {
2702         for (i = 0; ffu_map; ffu_map >>= 1, ++i)
2703         {
2704             if (!(ffu_map & 1)) continue;
2705
2706             if (device->texUnitMap[i] != i)
2707             {
2708                 device_map_stage(device, i, i);
2709                 device_invalidate_state(device, STATE_SAMPLER(i));
2710                 device_invalidate_texture_stage(device, i);
2711             }
2712         }
2713         return;
2714     }
2715
2716     /* Now work out the mapping */
2717     tex = 0;
2718     for (i = 0; ffu_map; ffu_map >>= 1, ++i)
2719     {
2720         if (!(ffu_map & 1)) continue;
2721
2722         if (device->texUnitMap[i] != tex)
2723         {
2724             device_map_stage(device, i, tex);
2725             device_invalidate_state(device, STATE_SAMPLER(i));
2726             device_invalidate_texture_stage(device, i);
2727         }
2728
2729         ++tex;
2730     }
2731 }
2732
2733 static void device_map_psamplers(struct wined3d_device *device, const struct wined3d_gl_info *gl_info)
2734 {
2735     const enum wined3d_sampler_texture_type *sampler_type =
2736             device->stateBlock->state.pixel_shader->reg_maps.sampler_type;
2737     unsigned int i;
2738
2739     for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i)
2740     {
2741         if (sampler_type[i] && device->texUnitMap[i] != i)
2742         {
2743             device_map_stage(device, i, i);
2744             device_invalidate_state(device, STATE_SAMPLER(i));
2745             if (i < gl_info->limits.texture_stages)
2746                 device_invalidate_texture_stage(device, i);
2747         }
2748     }
2749 }
2750
2751 static BOOL device_unit_free_for_vs(const struct wined3d_device *device,
2752         const enum wined3d_sampler_texture_type *pshader_sampler_tokens,
2753         const enum wined3d_sampler_texture_type *vshader_sampler_tokens, DWORD unit)
2754 {
2755     DWORD current_mapping = device->rev_tex_unit_map[unit];
2756
2757     /* Not currently used */
2758     if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
2759
2760     if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
2761         /* Used by a fragment sampler */
2762
2763         if (!pshader_sampler_tokens) {
2764             /* No pixel shader, check fixed function */
2765             return current_mapping >= MAX_TEXTURES || !(device->fixed_function_usage_map & (1 << current_mapping));
2766         }
2767
2768         /* Pixel shader, check the shader's sampler map */
2769         return !pshader_sampler_tokens[current_mapping];
2770     }
2771
2772     /* Used by a vertex sampler */
2773     return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
2774 }
2775
2776 static void device_map_vsamplers(struct wined3d_device *device, BOOL ps, const struct wined3d_gl_info *gl_info)
2777 {
2778     const enum wined3d_sampler_texture_type *vshader_sampler_type =
2779             device->stateBlock->state.vertex_shader->reg_maps.sampler_type;
2780     const enum wined3d_sampler_texture_type *pshader_sampler_type = NULL;
2781     int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
2782     int i;
2783
2784     if (ps)
2785     {
2786         /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
2787          * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
2788         pshader_sampler_type = device->stateBlock->state.pixel_shader->reg_maps.sampler_type;
2789     }
2790
2791     for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
2792         DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
2793         if (vshader_sampler_type[i])
2794         {
2795             if (device->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
2796             {
2797                 /* Already mapped somewhere */
2798                 continue;
2799             }
2800
2801             while (start >= 0)
2802             {
2803                 if (device_unit_free_for_vs(device, pshader_sampler_type, vshader_sampler_type, start))
2804                 {
2805                     device_map_stage(device, vsampler_idx, start);
2806                     device_invalidate_state(device, STATE_SAMPLER(vsampler_idx));
2807
2808                     --start;
2809                     break;
2810                 }
2811
2812                 --start;
2813             }
2814         }
2815     }
2816 }
2817
2818 void device_update_tex_unit_map(struct wined3d_device *device)
2819 {
2820     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
2821     const struct wined3d_state *state = &device->stateBlock->state;
2822     BOOL vs = use_vs(state);
2823     BOOL ps = use_ps(state);
2824     /*
2825      * Rules are:
2826      * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
2827      * that would be really messy and require shader recompilation
2828      * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
2829      * to be reset. Because of that try to work with a 1:1 mapping as much as possible
2830      */
2831     if (ps)
2832         device_map_psamplers(device, gl_info);
2833     else
2834         device_map_fixed_function_samplers(device, gl_info);
2835
2836     if (vs)
2837         device_map_vsamplers(device, ps, gl_info);
2838 }
2839
2840 void CDECL wined3d_device_set_pixel_shader(struct wined3d_device *device, struct wined3d_shader *shader)
2841 {
2842     struct wined3d_shader *prev = device->updateStateBlock->state.pixel_shader;
2843
2844     TRACE("device %p, shader %p.\n", device, shader);
2845
2846     if (shader)
2847         wined3d_shader_incref(shader);
2848     if (prev)
2849         wined3d_shader_decref(prev);
2850
2851     device->updateStateBlock->state.pixel_shader = shader;
2852     device->updateStateBlock->changed.pixelShader = TRUE;
2853
2854     if (device->isRecordingState)
2855     {
2856         TRACE("Recording... not performing anything.\n");
2857         return;
2858     }
2859
2860     if (shader == prev)
2861     {
2862         TRACE("Application is setting the old shader over, nothing to do.\n");
2863         return;
2864     }
2865
2866     device_invalidate_state(device, STATE_PIXELSHADER);
2867 }
2868
2869 struct wined3d_shader * CDECL wined3d_device_get_pixel_shader(const struct wined3d_device *device)
2870 {
2871     TRACE("device %p.\n", device);
2872
2873     return device->stateBlock->state.pixel_shader;
2874 }
2875
2876 void CDECL wined3d_device_set_ps_cb(struct wined3d_device *device, UINT idx, struct wined3d_buffer *buffer)
2877 {
2878     struct wined3d_buffer *prev;
2879
2880     TRACE("device %p, idx %u, buffer %p.\n", device, idx, buffer);
2881
2882     if (idx >= MAX_CONSTANT_BUFFERS)
2883     {
2884         WARN("Invalid constant buffer index %u.\n", idx);
2885         return;
2886     }
2887
2888     prev = device->updateStateBlock->state.ps_cb[idx];
2889     device->updateStateBlock->state.ps_cb[idx] = buffer;
2890
2891     if (device->isRecordingState)
2892     {
2893         if (buffer)
2894             wined3d_buffer_incref(buffer);
2895         if (prev)
2896             wined3d_buffer_decref(prev);
2897         return;
2898     }
2899
2900     if (prev != buffer)
2901     {
2902         if (buffer)
2903         {
2904             InterlockedIncrement(&buffer->resource.bind_count);
2905             wined3d_buffer_incref(buffer);
2906         }
2907         if (prev)
2908         {
2909             InterlockedDecrement(&prev->resource.bind_count);
2910             wined3d_buffer_decref(prev);
2911         }
2912     }
2913 }
2914
2915 struct wined3d_buffer * CDECL wined3d_device_get_ps_cb(const struct wined3d_device *device, UINT idx)
2916 {
2917     TRACE("device %p, idx %u.\n", device, idx);
2918
2919     if (idx >= MAX_CONSTANT_BUFFERS)
2920     {
2921         WARN("Invalid constant buffer index %u.\n", idx);
2922         return NULL;
2923     }
2924
2925     return device->stateBlock->state.ps_cb[idx];
2926 }
2927
2928 void CDECL wined3d_device_set_ps_sampler(struct wined3d_device *device, UINT idx, struct wined3d_sampler *sampler)
2929 {
2930     struct wined3d_sampler *prev;
2931
2932     TRACE("device %p, idx %u, sampler %p.\n", device, idx, sampler);
2933
2934     if (idx >= MAX_SAMPLER_OBJECTS)
2935     {
2936         WARN("Invalid sampler index %u.\n", idx);
2937         return;
2938     }
2939
2940     prev = device->updateStateBlock->state.ps_sampler[idx];
2941     device->updateStateBlock->state.ps_sampler[idx] = sampler;
2942
2943     if (sampler)
2944         wined3d_sampler_incref(sampler);
2945     if (prev)
2946         wined3d_sampler_decref(prev);
2947 }
2948
2949 struct wined3d_sampler * CDECL wined3d_device_get_ps_sampler(const struct wined3d_device *device, UINT idx)
2950 {
2951     TRACE("device %p, idx %u.\n", device, idx);
2952
2953     if (idx >= MAX_SAMPLER_OBJECTS)
2954     {
2955         WARN("Invalid sampler index %u.\n", idx);
2956         return NULL;
2957     }
2958
2959     return device->stateBlock->state.ps_sampler[idx];
2960 }
2961
2962 HRESULT CDECL wined3d_device_set_ps_consts_b(struct wined3d_device *device,
2963         UINT start_register, const BOOL *constants, UINT bool_count)
2964 {
2965     UINT count = min(bool_count, MAX_CONST_B - start_register);
2966     UINT i;
2967
2968     TRACE("device %p, start_register %u, constants %p, bool_count %u.\n",
2969             device, start_register, constants, bool_count);
2970
2971     if (!constants || start_register >= MAX_CONST_B)
2972         return WINED3DERR_INVALIDCALL;
2973
2974     memcpy(&device->updateStateBlock->state.ps_consts_b[start_register], constants, count * sizeof(BOOL));
2975     for (i = 0; i < count; ++i)
2976         TRACE("Set BOOL constant %u to %s.\n", start_register + i, constants[i] ? "true" : "false");
2977
2978     for (i = start_register; i < count + start_register; ++i)
2979         device->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
2980
2981     if (!device->isRecordingState)
2982         device_invalidate_state(device, STATE_PIXELSHADERCONSTANT);
2983
2984     return WINED3D_OK;
2985 }
2986
2987 HRESULT CDECL wined3d_device_get_ps_consts_b(const struct wined3d_device *device,
2988         UINT start_register, BOOL *constants, UINT bool_count)
2989 {
2990     UINT count = min(bool_count, MAX_CONST_B - start_register);
2991
2992     TRACE("device %p, start_register %u, constants %p, bool_count %u.\n",
2993             device, start_register, constants, bool_count);
2994
2995     if (!constants || start_register >= MAX_CONST_B)
2996         return WINED3DERR_INVALIDCALL;
2997
2998     memcpy(constants, &device->stateBlock->state.ps_consts_b[start_register], count * sizeof(BOOL));
2999
3000     return WINED3D_OK;
3001 }
3002
3003 HRESULT CDECL wined3d_device_set_ps_consts_i(struct wined3d_device *device,
3004         UINT start_register, const int *constants, UINT vector4i_count)
3005 {
3006     UINT count = min(vector4i_count, MAX_CONST_I - start_register);
3007     UINT i;
3008
3009     TRACE("device %p, start_register %u, constants %p, vector4i_count %u.\n",
3010             device, start_register, constants, vector4i_count);
3011
3012     if (!constants || start_register >= MAX_CONST_I)
3013         return WINED3DERR_INVALIDCALL;
3014
3015     memcpy(&device->updateStateBlock->state.ps_consts_i[start_register * 4], constants, count * sizeof(int) * 4);
3016     for (i = 0; i < count; ++i)
3017         TRACE("Set INT constant %u to {%d, %d, %d, %d}.\n", start_register + i,
3018                 constants[i * 4], constants[i * 4 + 1],
3019                 constants[i * 4 + 2], constants[i * 4 + 3]);
3020
3021     for (i = start_register; i < count + start_register; ++i)
3022         device->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3023
3024     if (!device->isRecordingState)
3025         device_invalidate_state(device, STATE_PIXELSHADERCONSTANT);
3026
3027     return WINED3D_OK;
3028 }
3029
3030 HRESULT CDECL wined3d_device_get_ps_consts_i(const struct wined3d_device *device,
3031         UINT start_register, int *constants, UINT vector4i_count)
3032 {
3033     UINT count = min(vector4i_count, MAX_CONST_I - start_register);
3034
3035     TRACE("device %p, start_register %u, constants %p, vector4i_count %u.\n",
3036             device, start_register, constants, vector4i_count);
3037
3038     if (!constants || start_register >= MAX_CONST_I)
3039         return WINED3DERR_INVALIDCALL;
3040
3041     memcpy(constants, &device->stateBlock->state.ps_consts_i[start_register * 4], count * sizeof(int) * 4);
3042
3043     return WINED3D_OK;
3044 }
3045
3046 HRESULT CDECL wined3d_device_set_ps_consts_f(struct wined3d_device *device,
3047         UINT start_register, const float *constants, UINT vector4f_count)
3048 {
3049     UINT i;
3050
3051     TRACE("device %p, start_register %u, constants %p, vector4f_count %u.\n",
3052             device, start_register, constants, vector4f_count);
3053
3054     /* Specifically test start_register > limit to catch MAX_UINT overflows
3055      * when adding start_register + vector4f_count. */
3056     if (!constants
3057             || start_register + vector4f_count > device->d3d_pshader_constantF
3058             || start_register > device->d3d_pshader_constantF)
3059         return WINED3DERR_INVALIDCALL;
3060
3061     memcpy(&device->updateStateBlock->state.ps_consts_f[start_register * 4],
3062             constants, vector4f_count * sizeof(float) * 4);
3063     if (TRACE_ON(d3d))
3064     {
3065         for (i = 0; i < vector4f_count; ++i)
3066             TRACE("Set FLOAT constant %u to {%.8e, %.8e, %.8e, %.8e}.\n", start_register + i,
3067                     constants[i * 4], constants[i * 4 + 1],
3068                     constants[i * 4 + 2], constants[i * 4 + 3]);
3069     }
3070
3071     if (!device->isRecordingState)
3072     {
3073         device->shader_backend->shader_update_float_pixel_constants(device, start_register, vector4f_count);
3074         device_invalidate_state(device, STATE_PIXELSHADERCONSTANT);
3075     }
3076
3077     memset(device->updateStateBlock->changed.pixelShaderConstantsF + start_register, 1,
3078             sizeof(*device->updateStateBlock->changed.pixelShaderConstantsF) * vector4f_count);
3079
3080     return WINED3D_OK;
3081 }
3082
3083 HRESULT CDECL wined3d_device_get_ps_consts_f(const struct wined3d_device *device,
3084         UINT start_register, float *constants, UINT vector4f_count)
3085 {
3086     int count = min(vector4f_count, device->d3d_pshader_constantF - start_register);
3087
3088     TRACE("device %p, start_register %u, constants %p, vector4f_count %u.\n",
3089             device, start_register, constants, vector4f_count);
3090
3091     if (!constants || count < 0)
3092         return WINED3DERR_INVALIDCALL;
3093
3094     memcpy(constants, &device->stateBlock->state.ps_consts_f[start_register * 4], count * sizeof(float) * 4);
3095
3096     return WINED3D_OK;
3097 }
3098
3099 void CDECL wined3d_device_set_geometry_shader(struct wined3d_device *device, struct wined3d_shader *shader)
3100 {
3101     struct wined3d_shader *prev = device->updateStateBlock->state.geometry_shader;
3102
3103     TRACE("device %p, shader %p.\n", device, shader);
3104
3105     if (shader)
3106         wined3d_shader_incref(shader);
3107     if (prev)
3108         wined3d_shader_decref(prev);
3109
3110     device->updateStateBlock->state.geometry_shader = shader;
3111
3112     if (device->isRecordingState || shader == prev)
3113         return;
3114
3115     device_invalidate_state(device, STATE_GEOMETRY_SHADER);
3116 }
3117
3118 struct wined3d_shader * CDECL wined3d_device_get_geometry_shader(const struct wined3d_device *device)
3119 {
3120     TRACE("device %p.\n", device);
3121
3122     return device->stateBlock->state.geometry_shader;
3123 }
3124
3125 void CDECL wined3d_device_set_gs_cb(struct wined3d_device *device, UINT idx, struct wined3d_buffer *buffer)
3126 {
3127     struct wined3d_buffer *prev;
3128
3129     TRACE("device %p, idx %u, buffer %p.\n", device, idx, buffer);
3130
3131     if (idx >= MAX_CONSTANT_BUFFERS)
3132     {
3133         WARN("Invalid constant buffer index %u.\n", idx);
3134         return;
3135     }
3136
3137     prev = device->updateStateBlock->state.gs_cb[idx];
3138     device->updateStateBlock->state.gs_cb[idx] = buffer;
3139
3140     if (device->isRecordingState)
3141     {
3142         if (buffer)
3143             wined3d_buffer_incref(buffer);
3144         if (prev)
3145             wined3d_buffer_decref(prev);
3146         return;
3147     }
3148
3149     if (prev != buffer)
3150     {
3151         if (buffer)
3152         {
3153             InterlockedIncrement(&buffer->resource.bind_count);
3154             wined3d_buffer_incref(buffer);
3155         }
3156         if (prev)
3157         {
3158             InterlockedDecrement(&prev->resource.bind_count);
3159             wined3d_buffer_decref(prev);
3160         }
3161     }
3162 }
3163
3164 struct wined3d_buffer * CDECL wined3d_device_get_gs_cb(const struct wined3d_device *device, UINT idx)
3165 {
3166     TRACE("device %p, idx %u.\n", device, idx);
3167
3168     if (idx >= MAX_CONSTANT_BUFFERS)
3169     {
3170         WARN("Invalid constant buffer index %u.\n", idx);
3171         return NULL;
3172     }
3173
3174     return device->stateBlock->state.gs_cb[idx];
3175 }
3176
3177 void CDECL wined3d_device_set_gs_sampler(struct wined3d_device *device, UINT idx, struct wined3d_sampler *sampler)
3178 {
3179     struct wined3d_sampler *prev;
3180
3181     TRACE("device %p, idx %u, sampler %p.\n", device, idx, sampler);
3182
3183     if (idx >= MAX_SAMPLER_OBJECTS)
3184     {
3185         WARN("Invalid sampler index %u.\n", idx);
3186         return;
3187     }
3188
3189     prev = device->updateStateBlock->state.gs_sampler[idx];
3190     device->updateStateBlock->state.gs_sampler[idx] = sampler;
3191
3192     if (sampler)
3193         wined3d_sampler_incref(sampler);
3194     if (prev)
3195         wined3d_sampler_decref(prev);
3196 }
3197
3198 struct wined3d_sampler * CDECL wined3d_device_get_gs_sampler(const struct wined3d_device *device, UINT idx)
3199 {
3200     TRACE("device %p, idx %u.\n", device, idx);
3201
3202     if (idx >= MAX_SAMPLER_OBJECTS)
3203     {
3204         WARN("Invalid sampler index %u.\n", idx);
3205         return NULL;
3206     }
3207
3208     return device->stateBlock->state.gs_sampler[idx];
3209 }
3210
3211 /* Context activation is done by the caller. */
3212 /* Do not call while under the GL lock. */
3213 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3214 static HRESULT process_vertices_strided(const struct wined3d_device *device, DWORD dwDestIndex, DWORD dwCount,
3215         const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD flags,
3216         DWORD DestFVF)
3217 {
3218     struct wined3d_matrix mat, proj_mat, view_mat, world_mat;
3219     struct wined3d_viewport vp;
3220     UINT vertex_size;
3221     unsigned int i;
3222     BYTE *dest_ptr;
3223     BOOL doClip;
3224     DWORD numTextures;
3225     HRESULT hr;
3226
3227     if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3228     {
3229         WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3230     }
3231
3232     if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3233     {
3234         ERR("Source has no position mask\n");
3235         return WINED3DERR_INVALIDCALL;
3236     }
3237
3238     if (device->stateBlock->state.render_states[WINED3D_RS_CLIPPING])
3239     {
3240         static BOOL warned = FALSE;
3241         /*
3242          * The clipping code is not quite correct. Some things need
3243          * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3244          * so disable clipping for now.
3245          * (The graphics in Half-Life are broken, and my processvertices
3246          *  test crashes with IDirect3DDevice3)
3247         doClip = TRUE;
3248          */
3249         doClip = FALSE;
3250         if(!warned) {
3251            warned = TRUE;
3252            FIXME("Clipping is broken and disabled for now\n");
3253         }
3254     }
3255     else
3256         doClip = FALSE;
3257
3258     vertex_size = get_flexible_vertex_size(DestFVF);
3259     if (FAILED(hr = wined3d_buffer_map(dest, dwDestIndex * vertex_size, dwCount * vertex_size, &dest_ptr, 0)))
3260     {
3261         WARN("Failed to map buffer, hr %#x.\n", hr);
3262         return hr;
3263     }
3264
3265     wined3d_device_get_transform(device, WINED3D_TS_VIEW, &view_mat);
3266     wined3d_device_get_transform(device, WINED3D_TS_PROJECTION, &proj_mat);
3267     wined3d_device_get_transform(device, WINED3D_TS_WORLD_MATRIX(0), &world_mat);
3268
3269     TRACE("View mat:\n");
3270     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);
3271     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);
3272     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);
3273     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);
3274
3275     TRACE("Proj mat:\n");
3276     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);
3277     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);
3278     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);
3279     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);
3280
3281     TRACE("World mat:\n");
3282     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);
3283     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);
3284     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);
3285     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);
3286
3287     /* Get the viewport */
3288     wined3d_device_get_viewport(device, &vp);
3289     TRACE("viewport  x %u, y %u, width %u, height %u, min_z %.8e, max_z %.8e.\n",
3290           vp.x, vp.y, vp.width, vp.height, vp.min_z, vp.max_z);
3291
3292     multiply_matrix(&mat,&view_mat,&world_mat);
3293     multiply_matrix(&mat,&proj_mat,&mat);
3294
3295     numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3296
3297     for (i = 0; i < dwCount; i+= 1) {
3298         unsigned int tex_index;
3299
3300         if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3301              ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3302             /* The position first */
3303             const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3304             const float *p = (const float *)(element->data.addr + i * element->stride);
3305             float x, y, z, rhw;
3306             TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3307
3308             /* Multiplication with world, view and projection matrix */
3309             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);
3310             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);
3311             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);
3312             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);
3313
3314             TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3315
3316             /* WARNING: The following things are taken from d3d7 and were not yet checked
3317              * against d3d8 or d3d9!
3318              */
3319
3320             /* Clipping conditions: From msdn
3321              *
3322              * A vertex is clipped if it does not match the following requirements
3323              * -rhw < x <= rhw
3324              * -rhw < y <= rhw
3325              *    0 < z <= rhw
3326              *    0 < rhw ( Not in d3d7, but tested in d3d7)
3327              *
3328              * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3329              * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3330              *
3331              */
3332
3333             if( !doClip ||
3334                 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3335                   (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3336                   ( rhw > eps ) ) ) {
3337
3338                 /* "Normal" viewport transformation (not clipped)
3339                  * 1) The values are divided by rhw
3340                  * 2) The y axis is negative, so multiply it with -1
3341                  * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3342                  *    -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3343                  * 4) Multiply x with Width/2 and add Width/2
3344                  * 5) The same for the height
3345                  * 6) Add the viewpoint X and Y to the 2D coordinates and
3346                  *    The minimum Z value to z
3347                  * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3348                  *
3349                  * Well, basically it's simply a linear transformation into viewport
3350                  * coordinates
3351                  */
3352
3353                 x /= rhw;
3354                 y /= rhw;
3355                 z /= rhw;
3356
3357                 y *= -1;
3358
3359                 x *= vp.width / 2;
3360                 y *= vp.height / 2;
3361                 z *= vp.max_z - vp.min_z;
3362
3363                 x += vp.width / 2 + vp.x;
3364                 y += vp.height / 2 + vp.y;
3365                 z += vp.min_z;
3366
3367                 rhw = 1 / rhw;
3368             } else {
3369                 /* That vertex got clipped
3370                  * Contrary to OpenGL it is not dropped completely, it just
3371                  * undergoes a different calculation.
3372                  */
3373                 TRACE("Vertex got clipped\n");
3374                 x += rhw;
3375                 y += rhw;
3376
3377                 x  /= 2;
3378                 y  /= 2;
3379
3380                 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3381                  * outside of the main vertex buffer memory. That needs some more
3382                  * investigation...
3383                  */
3384             }
3385
3386             TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3387
3388
3389             ( (float *) dest_ptr)[0] = x;
3390             ( (float *) dest_ptr)[1] = y;
3391             ( (float *) dest_ptr)[2] = z;
3392             ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3393
3394             dest_ptr += 3 * sizeof(float);
3395
3396             if ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW)
3397                 dest_ptr += sizeof(float);
3398         }
3399
3400         if (DestFVF & WINED3DFVF_PSIZE)
3401             dest_ptr += sizeof(DWORD);
3402
3403         if (DestFVF & WINED3DFVF_NORMAL)
3404         {
3405             const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
3406             const float *normal = (const float *)(element->data.addr + i * element->stride);
3407             /* AFAIK this should go into the lighting information */
3408             FIXME("Didn't expect the destination to have a normal\n");
3409             copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3410         }
3411
3412         if (DestFVF & WINED3DFVF_DIFFUSE)
3413         {
3414             const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
3415             const DWORD *color_d = (const DWORD *)(element->data.addr + i * element->stride);
3416             if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
3417             {
3418                 static BOOL warned = FALSE;
3419
3420                 if(!warned) {
3421                     ERR("No diffuse color in source, but destination has one\n");
3422                     warned = TRUE;
3423                 }
3424
3425                 *( (DWORD *) dest_ptr) = 0xffffffff;
3426                 dest_ptr += sizeof(DWORD);
3427             }
3428             else
3429             {
3430                 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3431             }
3432         }
3433
3434         if (DestFVF & WINED3DFVF_SPECULAR)
3435         {
3436             /* What's the color value in the feedback buffer? */
3437             const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
3438             const DWORD *color_s = (const DWORD *)(element->data.addr + i * element->stride);
3439             if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
3440             {
3441                 static BOOL warned = FALSE;
3442
3443                 if(!warned) {
3444                     ERR("No specular color in source, but destination has one\n");
3445                     warned = TRUE;
3446                 }
3447
3448                 *(DWORD *)dest_ptr = 0xff000000;
3449                 dest_ptr += sizeof(DWORD);
3450             }
3451             else
3452             {
3453                 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3454             }
3455         }
3456
3457         for (tex_index = 0; tex_index < numTextures; ++tex_index)
3458         {
3459             const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
3460             const float *tex_coord = (const float *)(element->data.addr + i * element->stride);
3461             if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
3462             {
3463                 ERR("No source texture, but destination requests one\n");
3464                 dest_ptr += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3465             }
3466             else
3467             {
3468                 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3469             }
3470         }
3471     }
3472
3473     wined3d_buffer_unmap(dest);
3474
3475     return WINED3D_OK;
3476 }
3477 #undef copy_and_next
3478
3479 /* Do not call while under the GL lock. */
3480 HRESULT CDECL wined3d_device_process_vertices(struct wined3d_device *device,
3481         UINT src_start_idx, UINT dst_idx, UINT vertex_count, struct wined3d_buffer *dst_buffer,
3482         const struct wined3d_vertex_declaration *declaration, DWORD flags, DWORD dst_fvf)
3483 {
3484     struct wined3d_state *state = &device->stateBlock->state;
3485     struct wined3d_stream_info stream_info;
3486     const struct wined3d_gl_info *gl_info;
3487     struct wined3d_context *context;
3488     struct wined3d_shader *vs;
3489     unsigned int i;
3490     HRESULT hr;
3491
3492     TRACE("device %p, src_start_idx %u, dst_idx %u, vertex_count %u, "
3493             "dst_buffer %p, declaration %p, flags %#x, dst_fvf %#x.\n",
3494             device, src_start_idx, dst_idx, vertex_count,
3495             dst_buffer, declaration, flags, dst_fvf);
3496
3497     if (declaration)
3498         FIXME("Output vertex declaration not implemented yet.\n");
3499
3500     /* Need any context to write to the vbo. */
3501     context = context_acquire(device, NULL);
3502     gl_info = context->gl_info;
3503
3504     vs = state->vertex_shader;
3505     state->vertex_shader = NULL;
3506     device_stream_info_from_declaration(device, &stream_info);
3507     state->vertex_shader = vs;
3508
3509     /* We can't convert FROM a VBO, and vertex buffers used to source into
3510      * process_vertices() are unlikely to ever be used for drawing. Release
3511      * VBOs in those buffers and fix up the stream_info structure.
3512      *
3513      * Also apply the start index. */
3514     for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
3515     {
3516         struct wined3d_stream_info_element *e;
3517
3518         if (!(stream_info.use_map & (1 << i)))
3519             continue;
3520
3521         e = &stream_info.elements[i];
3522         if (e->data.buffer_object)
3523         {
3524             struct wined3d_buffer *vb = state->streams[e->stream_idx].buffer;
3525             e->data.buffer_object = 0;
3526             e->data.addr = (BYTE *)((ULONG_PTR)e->data.addr + (ULONG_PTR)buffer_get_sysmem(vb, gl_info));
3527             GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
3528             vb->buffer_object = 0;
3529         }
3530         if (e->data.addr)
3531             e->data.addr += e->stride * src_start_idx;
3532     }
3533
3534     hr = process_vertices_strided(device, dst_idx, vertex_count,
3535             &stream_info, dst_buffer, flags, dst_fvf);
3536
3537     context_release(context);
3538
3539     return hr;
3540 }
3541
3542 void CDECL wined3d_device_set_texture_stage_state(struct wined3d_device *device,
3543         UINT stage, enum wined3d_texture_stage_state state, DWORD value)
3544 {
3545     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
3546     DWORD old_value;
3547
3548     TRACE("device %p, stage %u, state %s, value %#x.\n",
3549             device, stage, debug_d3dtexturestate(state), value);
3550
3551     if (state > WINED3D_HIGHEST_TEXTURE_STATE)
3552     {
3553         WARN("Invalid state %#x passed.\n", state);
3554         return;
3555     }
3556
3557     if (stage >= gl_info->limits.texture_stages)
3558     {
3559         WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
3560                 stage, gl_info->limits.texture_stages - 1);
3561         return;
3562     }
3563
3564     old_value = device->updateStateBlock->state.texture_states[stage][state];
3565     device->updateStateBlock->changed.textureState[stage] |= 1 << state;
3566     device->updateStateBlock->state.texture_states[stage][state] = value;
3567
3568     if (device->isRecordingState)
3569     {
3570         TRACE("Recording... not performing anything.\n");
3571         return;
3572     }
3573
3574     /* Checked after the assignments to allow proper stateblock recording. */
3575     if (old_value == value)
3576     {
3577         TRACE("Application is setting the old value over, nothing to do.\n");
3578         return;
3579     }
3580
3581     if (stage > device->stateBlock->state.lowest_disabled_stage
3582             && device->StateTable[STATE_TEXTURESTAGE(0, state)].representative
3583             == STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP))
3584     {
3585         /* Colorop change above lowest disabled stage? That won't change
3586          * anything in the GL setup. Changes in other states are important on
3587          * disabled stages too. */
3588         return;
3589     }
3590
3591     if (state == WINED3D_TSS_COLOR_OP)
3592     {
3593         unsigned int i;
3594
3595         if (value == WINED3D_TOP_DISABLE && old_value != WINED3D_TOP_DISABLE)
3596         {
3597             /* Previously enabled stage disabled now. Make sure to dirtify
3598              * all enabled stages above stage, they have to be disabled.
3599              *
3600              * The current stage is dirtified below. */
3601             for (i = stage + 1; i < device->stateBlock->state.lowest_disabled_stage; ++i)
3602             {
3603                 TRACE("Additionally dirtifying stage %u.\n", i);
3604                 device_invalidate_state(device, STATE_TEXTURESTAGE(i, WINED3D_TSS_COLOR_OP));
3605             }
3606             device->stateBlock->state.lowest_disabled_stage = stage;
3607             TRACE("New lowest disabled: %u.\n", stage);
3608         }
3609         else if (value != WINED3D_TOP_DISABLE && old_value == WINED3D_TOP_DISABLE)
3610         {
3611             /* Previously disabled stage enabled. Stages above it may need
3612              * enabling. Stage must be lowest_disabled_stage here, if it's
3613              * bigger success is returned above, and stages below the lowest
3614              * disabled stage can't be enabled (because they are enabled
3615              * already).
3616              *
3617              * Again stage stage doesn't need to be dirtified here, it is
3618              * handled below. */
3619             for (i = stage + 1; i < gl_info->limits.texture_stages; ++i)
3620             {
3621                 if (device->updateStateBlock->state.texture_states[i][WINED3D_TSS_COLOR_OP] == WINED3D_TOP_DISABLE)
3622                     break;
3623                 TRACE("Additionally dirtifying stage %u due to enable.\n", i);
3624                 device_invalidate_state(device, STATE_TEXTURESTAGE(i, WINED3D_TSS_COLOR_OP));
3625             }
3626             device->stateBlock->state.lowest_disabled_stage = i;
3627             TRACE("New lowest disabled: %u.\n", i);
3628         }
3629     }
3630
3631     device_invalidate_state(device, STATE_TEXTURESTAGE(stage, state));
3632 }
3633
3634 DWORD CDECL wined3d_device_get_texture_stage_state(const struct wined3d_device *device,
3635         UINT stage, enum wined3d_texture_stage_state state)
3636 {
3637     TRACE("device %p, stage %u, state %s.\n",
3638             device, stage, debug_d3dtexturestate(state));
3639
3640     if (state > WINED3D_HIGHEST_TEXTURE_STATE)
3641     {
3642         WARN("Invalid state %#x passed.\n", state);
3643         return 0;
3644     }
3645
3646     return device->updateStateBlock->state.texture_states[stage][state];
3647 }
3648
3649 HRESULT CDECL wined3d_device_set_texture(struct wined3d_device *device,
3650         UINT stage, struct wined3d_texture *texture)
3651 {
3652     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
3653     struct wined3d_texture *prev;
3654
3655     TRACE("device %p, stage %u, texture %p.\n", device, stage, texture);
3656
3657     if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
3658         stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3659
3660     /* Windows accepts overflowing this array... we do not. */
3661     if (stage >= sizeof(device->stateBlock->state.textures) / sizeof(*device->stateBlock->state.textures))
3662     {
3663         WARN("Ignoring invalid stage %u.\n", stage);
3664         return WINED3D_OK;
3665     }
3666
3667     if (texture && texture->resource.pool == WINED3D_POOL_SCRATCH)
3668     {
3669         WARN("Rejecting attempt to set scratch texture.\n");
3670         return WINED3DERR_INVALIDCALL;
3671     }
3672
3673     device->updateStateBlock->changed.textures |= 1 << stage;
3674
3675     prev = device->updateStateBlock->state.textures[stage];
3676     TRACE("Previous texture %p.\n", prev);
3677
3678     if (texture == prev)
3679     {
3680         TRACE("App is setting the same texture again, nothing to do.\n");
3681         return WINED3D_OK;
3682     }
3683
3684     TRACE("Setting new texture to %p.\n", texture);
3685     device->updateStateBlock->state.textures[stage] = texture;
3686
3687     if (device->isRecordingState)
3688     {
3689         TRACE("Recording... not performing anything\n");
3690
3691         if (texture) wined3d_texture_incref(texture);
3692         if (prev) wined3d_texture_decref(prev);
3693
3694         return WINED3D_OK;
3695     }
3696
3697     if (texture)
3698     {
3699         LONG bind_count = InterlockedIncrement(&texture->resource.bind_count);
3700
3701         wined3d_texture_incref(texture);
3702
3703         if (!prev || texture->target != prev->target)
3704             device_invalidate_state(device, STATE_PIXELSHADER);
3705
3706         if (!prev && stage < gl_info->limits.texture_stages)
3707         {
3708             /* The source arguments for color and alpha ops have different
3709              * meanings when a NULL texture is bound, so the COLOR_OP and
3710              * ALPHA_OP have to be dirtified. */
3711             device_invalidate_state(device, STATE_TEXTURESTAGE(stage, WINED3D_TSS_COLOR_OP));
3712             device_invalidate_state(device, STATE_TEXTURESTAGE(stage, WINED3D_TSS_ALPHA_OP));
3713         }
3714
3715         if (bind_count == 1)
3716             texture->sampler = stage;
3717     }
3718
3719     if (prev)
3720     {
3721         LONG bind_count = InterlockedDecrement(&prev->resource.bind_count);
3722
3723         if (!texture && stage < gl_info->limits.texture_stages)
3724         {
3725             device_invalidate_state(device, STATE_TEXTURESTAGE(stage, WINED3D_TSS_COLOR_OP));
3726             device_invalidate_state(device, STATE_TEXTURESTAGE(stage, WINED3D_TSS_ALPHA_OP));
3727         }
3728
3729         if (bind_count && prev->sampler == stage)
3730         {
3731             unsigned int i;
3732
3733             /* Search for other stages the texture is bound to. Shouldn't
3734              * happen if applications bind textures to a single stage only. */
3735             TRACE("Searching for other stages the texture is bound to.\n");
3736             for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
3737             {
3738                 if (device->updateStateBlock->state.textures[i] == prev)
3739                 {
3740                     TRACE("Texture is also bound to stage %u.\n", i);
3741                     prev->sampler = i;
3742                     break;
3743                 }
3744             }
3745         }
3746
3747         wined3d_texture_decref(prev);
3748     }
3749
3750     device_invalidate_state(device, STATE_SAMPLER(stage));
3751
3752     return WINED3D_OK;
3753 }
3754
3755 struct wined3d_texture * CDECL wined3d_device_get_texture(const struct wined3d_device *device, UINT stage)
3756 {
3757     TRACE("device %p, stage %u.\n", device, stage);
3758
3759     if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
3760         stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3761
3762     if (stage >= sizeof(device->stateBlock->state.textures) / sizeof(*device->stateBlock->state.textures))
3763     {
3764         WARN("Ignoring invalid stage %u.\n", stage);
3765         return NULL; /* Windows accepts overflowing this array ... we do not. */
3766     }
3767
3768     return device->stateBlock->state.textures[stage];
3769 }
3770
3771 HRESULT CDECL wined3d_device_get_back_buffer(const struct wined3d_device *device, UINT swapchain_idx,
3772         UINT backbuffer_idx, enum wined3d_backbuffer_type backbuffer_type, struct wined3d_surface **backbuffer)
3773 {
3774     struct wined3d_swapchain *swapchain;
3775
3776     TRACE("device %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
3777             device, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
3778
3779     if (!(swapchain = wined3d_device_get_swapchain(device, swapchain_idx)))
3780         return WINED3DERR_INVALIDCALL;
3781
3782     if (!(*backbuffer = wined3d_swapchain_get_back_buffer(swapchain, backbuffer_idx, backbuffer_type)))
3783         return WINED3DERR_INVALIDCALL;
3784     return WINED3D_OK;
3785 }
3786
3787 HRESULT CDECL wined3d_device_get_device_caps(const struct wined3d_device *device, WINED3DCAPS *caps)
3788 {
3789     TRACE("device %p, caps %p.\n", device, caps);
3790
3791     return wined3d_get_device_caps(device->wined3d, device->adapter->ordinal,
3792             device->create_parms.device_type, caps);
3793 }
3794
3795 HRESULT CDECL wined3d_device_get_display_mode(const struct wined3d_device *device, UINT swapchain_idx,
3796         struct wined3d_display_mode *mode, enum wined3d_display_rotation *rotation)
3797 {
3798     struct wined3d_swapchain *swapchain;
3799
3800     TRACE("device %p, swapchain_idx %u, mode %p, rotation %p.\n",
3801             device, swapchain_idx, mode, rotation);
3802
3803     if (!(swapchain = wined3d_device_get_swapchain(device, swapchain_idx)))
3804         return WINED3DERR_INVALIDCALL;
3805
3806     return wined3d_swapchain_get_display_mode(swapchain, mode, rotation);
3807 }
3808
3809 HRESULT CDECL wined3d_device_begin_stateblock(struct wined3d_device *device)
3810 {
3811     struct wined3d_stateblock *stateblock;
3812     HRESULT hr;
3813
3814     TRACE("device %p.\n", device);
3815
3816     if (device->isRecordingState)
3817         return WINED3DERR_INVALIDCALL;
3818
3819     hr = wined3d_stateblock_create(device, WINED3D_SBT_RECORDED, &stateblock);
3820     if (FAILED(hr))
3821         return hr;
3822
3823     wined3d_stateblock_decref(device->updateStateBlock);
3824     device->updateStateBlock = stateblock;
3825     device->isRecordingState = TRUE;
3826
3827     TRACE("Recording stateblock %p.\n", stateblock);
3828
3829     return WINED3D_OK;
3830 }
3831
3832 HRESULT CDECL wined3d_device_end_stateblock(struct wined3d_device *device,
3833         struct wined3d_stateblock **stateblock)
3834 {
3835     struct wined3d_stateblock *object = device->updateStateBlock;
3836
3837     TRACE("device %p, stateblock %p.\n", device, stateblock);
3838
3839     if (!device->isRecordingState)
3840     {
3841         WARN("Not recording.\n");
3842         *stateblock = NULL;
3843         return WINED3DERR_INVALIDCALL;
3844     }
3845
3846     stateblock_init_contained_states(object);
3847
3848     *stateblock = object;
3849     device->isRecordingState = FALSE;
3850     device->updateStateBlock = device->stateBlock;
3851     wined3d_stateblock_incref(device->updateStateBlock);
3852
3853     TRACE("Returning stateblock %p.\n", *stateblock);
3854
3855     return WINED3D_OK;
3856 }
3857
3858 HRESULT CDECL wined3d_device_begin_scene(struct wined3d_device *device)
3859 {
3860     /* At the moment we have no need for any functionality at the beginning
3861      * of a scene. */
3862     TRACE("device %p.\n", device);
3863
3864     if (device->inScene)
3865     {
3866         WARN("Already in scene, returning WINED3DERR_INVALIDCALL.\n");
3867         return WINED3DERR_INVALIDCALL;
3868     }
3869     device->inScene = TRUE;
3870     return WINED3D_OK;
3871 }
3872
3873 HRESULT CDECL wined3d_device_end_scene(struct wined3d_device *device)
3874 {
3875     struct wined3d_context *context;
3876
3877     TRACE("device %p.\n", device);
3878
3879     if (!device->inScene)
3880     {
3881         WARN("Not in scene, returning WINED3DERR_INVALIDCALL.\n");
3882         return WINED3DERR_INVALIDCALL;
3883     }
3884
3885     context = context_acquire(device, NULL);
3886     /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
3887     context->gl_info->gl_ops.gl.p_glFlush();
3888     /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
3889      * fails. */
3890     context_release(context);
3891
3892     device->inScene = FALSE;
3893     return WINED3D_OK;
3894 }
3895
3896 HRESULT CDECL wined3d_device_present(const struct wined3d_device *device, const RECT *src_rect,
3897         const RECT *dst_rect, HWND dst_window_override, const RGNDATA *dirty_region, DWORD flags)
3898 {
3899     UINT i;
3900
3901     TRACE("device %p, src_rect %s, dst_rect %s, dst_window_override %p, dirty_region %p, flags %#x.\n",
3902             device, wine_dbgstr_rect(src_rect), wine_dbgstr_rect(dst_rect),
3903             dst_window_override, dirty_region, flags);
3904
3905     for (i = 0; i < device->swapchain_count; ++i)
3906     {
3907         wined3d_swapchain_present(device->swapchains[i], src_rect,
3908                 dst_rect, dst_window_override, dirty_region, flags);
3909     }
3910
3911     return WINED3D_OK;
3912 }
3913
3914 /* Do not call while under the GL lock. */
3915 HRESULT CDECL wined3d_device_clear(struct wined3d_device *device, DWORD rect_count,
3916         const RECT *rects, DWORD flags, const struct wined3d_color *color, float depth, DWORD stencil)
3917 {
3918     RECT draw_rect;
3919
3920     TRACE("device %p, rect_count %u, rects %p, flags %#x, color {%.8e, %.8e, %.8e, %.8e}, depth %.8e, stencil %u.\n",
3921             device, rect_count, rects, flags, color->r, color->g, color->b, color->a, depth, stencil);
3922
3923     if (!rect_count && rects)
3924     {
3925         WARN("Rects is %p, but rect_count is 0, ignoring clear\n", rects);
3926         return WINED3D_OK;
3927     }
3928
3929     if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL))
3930     {
3931         struct wined3d_surface *ds = device->fb.depth_stencil;
3932         if (!ds)
3933         {
3934             WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
3935             /* TODO: What about depth stencil buffers without stencil bits? */
3936             return WINED3DERR_INVALIDCALL;
3937         }
3938         else if (flags & WINED3DCLEAR_TARGET)
3939         {
3940             if (ds->resource.width < device->fb.render_targets[0]->resource.width
3941                     || ds->resource.height < device->fb.render_targets[0]->resource.height)
3942             {
3943                 WARN("Silently ignoring depth and target clear with mismatching sizes\n");
3944                 return WINED3D_OK;
3945             }
3946         }
3947     }
3948
3949     wined3d_get_draw_rect(&device->stateBlock->state, &draw_rect);
3950     device_clear_render_targets(device, device->adapter->gl_info.limits.buffers,
3951             &device->fb, rect_count, rects, &draw_rect, flags, color, depth, stencil);
3952
3953     return WINED3D_OK;
3954 }
3955
3956 void CDECL wined3d_device_set_primitive_type(struct wined3d_device *device,
3957         enum wined3d_primitive_type primitive_type)
3958 {
3959     TRACE("device %p, primitive_type %s\n", device, debug_d3dprimitivetype(primitive_type));
3960
3961     device->updateStateBlock->changed.primitive_type = TRUE;
3962     device->updateStateBlock->state.gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
3963 }
3964
3965 void CDECL wined3d_device_get_primitive_type(const struct wined3d_device *device,
3966         enum wined3d_primitive_type *primitive_type)
3967 {
3968     TRACE("device %p, primitive_type %p\n", device, primitive_type);
3969
3970     *primitive_type = d3d_primitive_type_from_gl(device->stateBlock->state.gl_primitive_type);
3971
3972     TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
3973 }
3974
3975 HRESULT CDECL wined3d_device_draw_primitive(struct wined3d_device *device, UINT start_vertex, UINT vertex_count)
3976 {
3977     TRACE("device %p, start_vertex %u, vertex_count %u.\n", device, start_vertex, vertex_count);
3978
3979     if (!device->stateBlock->state.vertex_declaration)
3980     {
3981         WARN("Called without a valid vertex declaration set.\n");
3982         return WINED3DERR_INVALIDCALL;
3983     }
3984
3985     if (device->stateBlock->state.load_base_vertex_index)
3986     {
3987         device->stateBlock->state.load_base_vertex_index = 0;
3988         device_invalidate_state(device, STATE_BASEVERTEXINDEX);
3989     }
3990
3991     /* Account for the loading offset due to index buffers. Instead of
3992      * reloading all sources correct it with the startvertex parameter. */
3993     draw_primitive(device, start_vertex, vertex_count, 0, 0, FALSE, NULL);
3994     return WINED3D_OK;
3995 }
3996
3997 HRESULT CDECL wined3d_device_draw_indexed_primitive(struct wined3d_device *device, UINT start_idx, UINT index_count)
3998 {
3999     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
4000
4001     TRACE("device %p, start_idx %u, index_count %u.\n", device, start_idx, index_count);
4002
4003     if (!device->stateBlock->state.index_buffer)
4004     {
4005         /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4006          * without an index buffer set. (The first time at least...)
4007          * D3D8 simply dies, but I doubt it can do much harm to return
4008          * D3DERR_INVALIDCALL there as well. */
4009         WARN("Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL.\n");
4010         return WINED3DERR_INVALIDCALL;
4011     }
4012
4013     if (!device->stateBlock->state.vertex_declaration)
4014     {
4015         WARN("Called without a valid vertex declaration set.\n");
4016         return WINED3DERR_INVALIDCALL;
4017     }
4018
4019     if (!gl_info->supported[ARB_DRAW_ELEMENTS_BASE_VERTEX] &&
4020         device->stateBlock->state.load_base_vertex_index != device->stateBlock->state.base_vertex_index)
4021     {
4022         device->stateBlock->state.load_base_vertex_index = device->stateBlock->state.base_vertex_index;
4023         device_invalidate_state(device, STATE_BASEVERTEXINDEX);
4024     }
4025
4026     draw_primitive(device, start_idx, index_count, 0, 0, TRUE, NULL);
4027
4028     return WINED3D_OK;
4029 }
4030
4031 void CDECL wined3d_device_draw_indexed_primitive_instanced(struct wined3d_device *device,
4032         UINT start_idx, UINT index_count, UINT start_instance, UINT instance_count)
4033 {
4034     TRACE("device %p, start_idx %u, index_count %u.\n", device, start_idx, index_count);
4035
4036     draw_primitive(device, start_idx, index_count, start_instance, instance_count, TRUE, NULL);
4037 }
4038
4039 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4040 static HRESULT device_update_volume(struct wined3d_device *device,
4041         struct wined3d_volume *src_volume, struct wined3d_volume *dst_volume)
4042 {
4043     struct wined3d_map_desc src;
4044     struct wined3d_map_desc dst;
4045     HRESULT hr;
4046
4047     TRACE("device %p, src_volume %p, dst_volume %p.\n",
4048             device, src_volume, dst_volume);
4049
4050     /* TODO: Implement direct loading into the gl volume instead of using
4051      * memcpy and dirtification to improve loading performance. */
4052     if (FAILED(hr = wined3d_volume_map(src_volume, &src, NULL, WINED3D_MAP_READONLY)))
4053         return hr;
4054     if (FAILED(hr = wined3d_volume_map(dst_volume, &dst, NULL, WINED3D_MAP_DISCARD)))
4055     {
4056         wined3d_volume_unmap(src_volume);
4057         return hr;
4058     }
4059
4060     memcpy(dst.data, src.data, dst_volume->resource.size);
4061
4062     hr = wined3d_volume_unmap(dst_volume);
4063     if (FAILED(hr))
4064         wined3d_volume_unmap(src_volume);
4065     else
4066         hr = wined3d_volume_unmap(src_volume);
4067
4068     return hr;
4069 }
4070
4071 HRESULT CDECL wined3d_device_update_texture(struct wined3d_device *device,
4072         struct wined3d_texture *src_texture, struct wined3d_texture *dst_texture)
4073 {
4074     enum wined3d_resource_type type;
4075     unsigned int level_count, i;
4076     HRESULT hr;
4077
4078     TRACE("device %p, src_texture %p, dst_texture %p.\n", device, src_texture, dst_texture);
4079
4080     /* Verify that the source and destination textures are non-NULL. */
4081     if (!src_texture || !dst_texture)
4082     {
4083         WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4084         return WINED3DERR_INVALIDCALL;
4085     }
4086
4087     if (src_texture == dst_texture)
4088     {
4089         WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4090         return WINED3DERR_INVALIDCALL;
4091     }
4092
4093     /* Verify that the source and destination textures are the same type. */
4094     type = src_texture->resource.type;
4095     if (dst_texture->resource.type != type)
4096     {
4097         WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4098         return WINED3DERR_INVALIDCALL;
4099     }
4100
4101     /* Check that both textures have the identical numbers of levels. */
4102     level_count = wined3d_texture_get_level_count(src_texture);
4103     if (wined3d_texture_get_level_count(dst_texture) != level_count)
4104     {
4105         WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4106         return WINED3DERR_INVALIDCALL;
4107     }
4108
4109     /* Make sure that the destination texture is loaded. */
4110     dst_texture->texture_ops->texture_preload(dst_texture, SRGB_RGB);
4111
4112     /* Update every surface level of the texture. */
4113     switch (type)
4114     {
4115         case WINED3D_RTYPE_TEXTURE:
4116         {
4117             struct wined3d_surface *src_surface;
4118             struct wined3d_surface *dst_surface;
4119
4120             for (i = 0; i < level_count; ++i)
4121             {
4122                 src_surface = surface_from_resource(wined3d_texture_get_sub_resource(src_texture, i));
4123                 dst_surface = surface_from_resource(wined3d_texture_get_sub_resource(dst_texture, i));
4124                 hr = wined3d_device_update_surface(device, src_surface, NULL, dst_surface, NULL);
4125                 if (FAILED(hr))
4126                 {
4127                     WARN("Failed to update surface, hr %#x.\n", hr);
4128                     return hr;
4129                 }
4130             }
4131             break;
4132         }
4133
4134         case WINED3D_RTYPE_CUBE_TEXTURE:
4135         {
4136             struct wined3d_surface *src_surface;
4137             struct wined3d_surface *dst_surface;
4138
4139             for (i = 0; i < level_count * 6; ++i)
4140             {
4141                 src_surface = surface_from_resource(wined3d_texture_get_sub_resource(src_texture, i));
4142                 dst_surface = surface_from_resource(wined3d_texture_get_sub_resource(dst_texture, i));
4143                 hr = wined3d_device_update_surface(device, src_surface, NULL, dst_surface, NULL);
4144                 if (FAILED(hr))
4145                 {
4146                     WARN("Failed to update surface, hr %#x.\n", hr);
4147                     return hr;
4148                 }
4149             }
4150             break;
4151         }
4152
4153         case WINED3D_RTYPE_VOLUME_TEXTURE:
4154         {
4155             for (i = 0; i < level_count; ++i)
4156             {
4157                 hr = device_update_volume(device,
4158                         volume_from_resource(wined3d_texture_get_sub_resource(src_texture, i)),
4159                         volume_from_resource(wined3d_texture_get_sub_resource(dst_texture, i)));
4160                 if (FAILED(hr))
4161                 {
4162                     WARN("Failed to update volume, hr %#x.\n", hr);
4163                     return hr;
4164                 }
4165             }
4166             break;
4167         }
4168
4169         default:
4170             FIXME("Unsupported texture type %#x.\n", type);
4171             return WINED3DERR_INVALIDCALL;
4172     }
4173
4174     return WINED3D_OK;
4175 }
4176
4177 HRESULT CDECL wined3d_device_get_front_buffer_data(const struct wined3d_device *device,
4178         UINT swapchain_idx, struct wined3d_surface *dst_surface)
4179 {
4180     struct wined3d_swapchain *swapchain;
4181
4182     TRACE("device %p, swapchain_idx %u, dst_surface %p.\n", device, swapchain_idx, dst_surface);
4183
4184     if (!(swapchain = wined3d_device_get_swapchain(device, swapchain_idx)))
4185         return WINED3DERR_INVALIDCALL;
4186
4187     return wined3d_swapchain_get_front_buffer_data(swapchain, dst_surface);
4188 }
4189
4190 HRESULT CDECL wined3d_device_validate_device(const struct wined3d_device *device, DWORD *num_passes)
4191 {
4192     const struct wined3d_state *state = &device->stateBlock->state;
4193     struct wined3d_texture *texture;
4194     DWORD i;
4195
4196     TRACE("device %p, num_passes %p.\n", device, num_passes);
4197
4198     for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4199     {
4200         if (state->sampler_states[i][WINED3D_SAMP_MIN_FILTER] == WINED3D_TEXF_NONE)
4201         {
4202             WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4203             return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4204         }
4205         if (state->sampler_states[i][WINED3D_SAMP_MAG_FILTER] == WINED3D_TEXF_NONE)
4206         {
4207             WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4208             return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4209         }
4210
4211         texture = state->textures[i];
4212         if (!texture || texture->resource.format->flags & WINED3DFMT_FLAG_FILTERING) continue;
4213
4214         if (state->sampler_states[i][WINED3D_SAMP_MAG_FILTER] != WINED3D_TEXF_POINT)
4215         {
4216             WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
4217             return E_FAIL;
4218         }
4219         if (state->sampler_states[i][WINED3D_SAMP_MIN_FILTER] != WINED3D_TEXF_POINT)
4220         {
4221             WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
4222             return E_FAIL;
4223         }
4224         if (state->sampler_states[i][WINED3D_SAMP_MIP_FILTER] != WINED3D_TEXF_NONE
4225                 && state->sampler_states[i][WINED3D_SAMP_MIP_FILTER] != WINED3D_TEXF_POINT)
4226         {
4227             WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
4228             return E_FAIL;
4229         }
4230     }
4231
4232     if (state->render_states[WINED3D_RS_ZENABLE] || state->render_states[WINED3D_RS_ZWRITEENABLE]
4233             || state->render_states[WINED3D_RS_STENCILENABLE])
4234     {
4235         struct wined3d_surface *ds = device->fb.depth_stencil;
4236         struct wined3d_surface *target = device->fb.render_targets[0];
4237
4238         if(ds && target
4239                 && (ds->resource.width < target->resource.width || ds->resource.height < target->resource.height))
4240         {
4241             WARN("Depth stencil is smaller than the color buffer, returning D3DERR_CONFLICTINGRENDERSTATE\n");
4242             return WINED3DERR_CONFLICTINGRENDERSTATE;
4243         }
4244     }
4245
4246     /* return a sensible default */
4247     *num_passes = 1;
4248
4249     TRACE("returning D3D_OK\n");
4250     return WINED3D_OK;
4251 }
4252
4253 void CDECL wined3d_device_set_software_vertex_processing(struct wined3d_device *device, BOOL software)
4254 {
4255     static BOOL warned;
4256
4257     TRACE("device %p, software %#x.\n", device, software);
4258
4259     if (!warned)
4260     {
4261         FIXME("device %p, software %#x stub!\n", device, software);
4262         warned = TRUE;
4263     }
4264
4265     device->softwareVertexProcessing = software;
4266 }
4267
4268 BOOL CDECL wined3d_device_get_software_vertex_processing(const struct wined3d_device *device)
4269 {
4270     static BOOL warned;
4271
4272     TRACE("device %p.\n", device);
4273
4274     if (!warned)
4275     {
4276         TRACE("device %p stub!\n", device);
4277         warned = TRUE;
4278     }
4279
4280     return device->softwareVertexProcessing;
4281 }
4282
4283 HRESULT CDECL wined3d_device_get_raster_status(const struct wined3d_device *device,
4284         UINT swapchain_idx, struct wined3d_raster_status *raster_status)
4285 {
4286     struct wined3d_swapchain *swapchain;
4287
4288     TRACE("device %p, swapchain_idx %u, raster_status %p.\n",
4289             device, swapchain_idx, raster_status);
4290
4291     if (!(swapchain = wined3d_device_get_swapchain(device, swapchain_idx)))
4292         return WINED3DERR_INVALIDCALL;
4293
4294     return wined3d_swapchain_get_raster_status(swapchain, raster_status);
4295 }
4296
4297 HRESULT CDECL wined3d_device_set_npatch_mode(struct wined3d_device *device, float segments)
4298 {
4299     static BOOL warned;
4300
4301     TRACE("device %p, segments %.8e.\n", device, segments);
4302
4303     if (segments != 0.0f)
4304     {
4305         if (!warned)
4306         {
4307             FIXME("device %p, segments %.8e stub!\n", device, segments);
4308             warned = TRUE;
4309         }
4310     }
4311
4312     return WINED3D_OK;
4313 }
4314
4315 float CDECL wined3d_device_get_npatch_mode(const struct wined3d_device *device)
4316 {
4317     static BOOL warned;
4318
4319     TRACE("device %p.\n", device);
4320
4321     if (!warned)
4322     {
4323         FIXME("device %p stub!\n", device);
4324         warned = TRUE;
4325     }
4326
4327     return 0.0f;
4328 }
4329
4330 HRESULT CDECL wined3d_device_update_surface(struct wined3d_device *device,
4331         struct wined3d_surface *src_surface, const RECT *src_rect,
4332         struct wined3d_surface *dst_surface, const POINT *dst_point)
4333 {
4334     TRACE("device %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s.\n",
4335             device, src_surface, wine_dbgstr_rect(src_rect),
4336             dst_surface, wine_dbgstr_point(dst_point));
4337
4338     if (src_surface->resource.pool != WINED3D_POOL_SYSTEM_MEM || dst_surface->resource.pool != WINED3D_POOL_DEFAULT)
4339     {
4340         WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
4341                 src_surface, dst_surface);
4342         return WINED3DERR_INVALIDCALL;
4343     }
4344
4345     return surface_upload_from_surface(dst_surface, dst_point, src_surface, src_rect);
4346 }
4347
4348 /* Do not call while under the GL lock. */
4349 HRESULT CDECL wined3d_device_color_fill(struct wined3d_device *device,
4350         struct wined3d_surface *surface, const RECT *rect, const struct wined3d_color *color)
4351 {
4352     RECT r;
4353
4354     TRACE("device %p, surface %p, rect %s, color {%.8e, %.8e, %.8e, %.8e}.\n",
4355             device, surface, wine_dbgstr_rect(rect),
4356             color->r, color->g, color->b, color->a);
4357
4358     if (surface->resource.pool != WINED3D_POOL_DEFAULT && surface->resource.pool != WINED3D_POOL_SYSTEM_MEM)
4359     {
4360         WARN("Color-fill not allowed on %s surfaces.\n", debug_d3dpool(surface->resource.pool));
4361         return WINED3DERR_INVALIDCALL;
4362     }
4363
4364     if (!rect)
4365     {
4366         SetRect(&r, 0, 0, surface->resource.width, surface->resource.height);
4367         rect = &r;
4368     }
4369
4370     return surface_color_fill(surface, rect, color);
4371 }
4372
4373 /* Do not call while under the GL lock. */
4374 void CDECL wined3d_device_clear_rendertarget_view(struct wined3d_device *device,
4375         struct wined3d_rendertarget_view *rendertarget_view, const struct wined3d_color *color)
4376 {
4377     struct wined3d_resource *resource;
4378     HRESULT hr;
4379     RECT rect;
4380
4381     resource = rendertarget_view->resource;
4382     if (resource->type != WINED3D_RTYPE_SURFACE)
4383     {
4384         FIXME("Only supported on surface resources\n");
4385         return;
4386     }
4387
4388     SetRect(&rect, 0, 0, resource->width, resource->height);
4389     hr = surface_color_fill(surface_from_resource(resource), &rect, color);
4390     if (FAILED(hr)) ERR("Color fill failed, hr %#x.\n", hr);
4391 }
4392
4393 struct wined3d_surface * CDECL wined3d_device_get_render_target(const struct wined3d_device *device,
4394         UINT render_target_idx)
4395 {
4396     TRACE("device %p, render_target_idx %u.\n", device, render_target_idx);
4397
4398     if (render_target_idx >= device->adapter->gl_info.limits.buffers)
4399     {
4400         WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
4401         return NULL;
4402     }
4403
4404     return device->fb.render_targets[render_target_idx];
4405 }
4406
4407 struct wined3d_surface * CDECL wined3d_device_get_depth_stencil(const struct wined3d_device *device)
4408 {
4409     TRACE("device %p.\n", device);
4410
4411     return device->fb.depth_stencil;
4412 }
4413
4414 HRESULT CDECL wined3d_device_set_render_target(struct wined3d_device *device,
4415         UINT render_target_idx, struct wined3d_surface *render_target, BOOL set_viewport)
4416 {
4417     struct wined3d_surface *prev;
4418
4419     TRACE("device %p, render_target_idx %u, render_target %p, set_viewport %#x.\n",
4420             device, render_target_idx, render_target, set_viewport);
4421
4422     if (render_target_idx >= device->adapter->gl_info.limits.buffers)
4423     {
4424         WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
4425         return WINED3DERR_INVALIDCALL;
4426     }
4427
4428     /* Render target 0 can't be set to NULL. */
4429     if (!render_target && !render_target_idx)
4430     {
4431         WARN("Trying to set render target 0 to NULL.\n");
4432         return WINED3DERR_INVALIDCALL;
4433     }
4434
4435     if (render_target && !(render_target->resource.usage & WINED3DUSAGE_RENDERTARGET))
4436     {
4437         FIXME("Surface %p doesn't have render target usage.\n", render_target);
4438         return WINED3DERR_INVALIDCALL;
4439     }
4440
4441     /* Set the viewport and scissor rectangles, if requested. Tests show that
4442      * stateblock recording is ignored, the change goes directly into the
4443      * primary stateblock. */
4444     if (!render_target_idx && set_viewport)
4445     {
4446         struct wined3d_state *state = &device->stateBlock->state;
4447
4448         state->viewport.x = 0;
4449         state->viewport.y = 0;
4450         state->viewport.width = render_target->resource.width;
4451         state->viewport.height = render_target->resource.height;
4452         state->viewport.min_z = 0.0f;
4453         state->viewport.max_z = 1.0f;
4454         device_invalidate_state(device, STATE_VIEWPORT);
4455
4456         state->scissor_rect.top = 0;
4457         state->scissor_rect.left = 0;
4458         state->scissor_rect.right = render_target->resource.width;
4459         state->scissor_rect.bottom = render_target->resource.height;
4460         device_invalidate_state(device, STATE_SCISSORRECT);
4461     }
4462
4463
4464     prev = device->fb.render_targets[render_target_idx];
4465     if (render_target == prev)
4466         return WINED3D_OK;
4467
4468     if (render_target)
4469         wined3d_surface_incref(render_target);
4470     device->fb.render_targets[render_target_idx] = render_target;
4471     /* Release after the assignment, to prevent device_resource_released()
4472      * from seeing the surface as still in use. */
4473     if (prev)
4474         wined3d_surface_decref(prev);
4475
4476     device_invalidate_state(device, STATE_FRAMEBUFFER);
4477
4478     return WINED3D_OK;
4479 }
4480
4481 void CDECL wined3d_device_set_depth_stencil(struct wined3d_device *device, struct wined3d_surface *depth_stencil)
4482 {
4483     struct wined3d_surface *prev = device->fb.depth_stencil;
4484
4485     TRACE("device %p, depth_stencil %p, old depth_stencil %p.\n",
4486             device, depth_stencil, prev);
4487
4488     if (prev == depth_stencil)
4489     {
4490         TRACE("Trying to do a NOP SetRenderTarget operation.\n");
4491         return;
4492     }
4493
4494     if (prev)
4495     {
4496         if (device->swapchains[0]->desc.flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
4497                 || prev->flags & SFLAG_DISCARD)
4498         {
4499             surface_modify_ds_location(prev, SFLAG_DISCARDED,
4500                     prev->resource.width, prev->resource.height);
4501             if (prev == device->onscreen_depth_stencil)
4502             {
4503                 wined3d_surface_decref(device->onscreen_depth_stencil);
4504                 device->onscreen_depth_stencil = NULL;
4505             }
4506         }
4507     }
4508
4509     device->fb.depth_stencil = depth_stencil;
4510     if (depth_stencil)
4511         wined3d_surface_incref(depth_stencil);
4512
4513     if (!prev != !depth_stencil)
4514     {
4515         /* Swapping NULL / non NULL depth stencil affects the depth and tests */
4516         device_invalidate_state(device, STATE_RENDER(WINED3D_RS_ZENABLE));
4517         device_invalidate_state(device, STATE_RENDER(WINED3D_RS_STENCILENABLE));
4518         device_invalidate_state(device, STATE_RENDER(WINED3D_RS_STENCILWRITEMASK));
4519         device_invalidate_state(device, STATE_RENDER(WINED3D_RS_DEPTHBIAS));
4520     }
4521     else if (prev && prev->resource.format->depth_size != depth_stencil->resource.format->depth_size)
4522     {
4523         device_invalidate_state(device, STATE_RENDER(WINED3D_RS_DEPTHBIAS));
4524     }
4525     if (prev)
4526         wined3d_surface_decref(prev);
4527
4528     device_invalidate_state(device, STATE_FRAMEBUFFER);
4529
4530     return;
4531 }
4532
4533 HRESULT CDECL wined3d_device_set_cursor_properties(struct wined3d_device *device,
4534         UINT x_hotspot, UINT y_hotspot, struct wined3d_surface *cursor_image)
4535 {
4536     TRACE("device %p, x_hotspot %u, y_hotspot %u, cursor_image %p.\n",
4537             device, x_hotspot, y_hotspot, cursor_image);
4538
4539     /* some basic validation checks */
4540     if (device->cursorTexture)
4541     {
4542         struct wined3d_context *context = context_acquire(device, NULL);
4543         context->gl_info->gl_ops.gl.p_glDeleteTextures(1, &device->cursorTexture);
4544         context_release(context);
4545         device->cursorTexture = 0;
4546     }
4547
4548     if (cursor_image)
4549     {
4550         struct wined3d_display_mode mode;
4551         struct wined3d_map_desc map_desc;
4552         HRESULT hr;
4553
4554         /* MSDN: Cursor must be A8R8G8B8 */
4555         if (cursor_image->resource.format->id != WINED3DFMT_B8G8R8A8_UNORM)
4556         {
4557             WARN("surface %p has an invalid format.\n", cursor_image);
4558             return WINED3DERR_INVALIDCALL;
4559         }
4560
4561         if (FAILED(hr = wined3d_get_adapter_display_mode(device->wined3d, device->adapter->ordinal, &mode, NULL)))
4562         {
4563             ERR("Failed to get display mode, hr %#x.\n", hr);
4564             return WINED3DERR_INVALIDCALL;
4565         }
4566
4567         /* MSDN: Cursor must be smaller than the display mode */
4568         if (cursor_image->resource.width > mode.width || cursor_image->resource.height > mode.height)
4569         {
4570             WARN("Surface %p dimensions are %ux%u, but screen dimensions are %ux%u.\n",
4571                     cursor_image, cursor_image->resource.width, cursor_image->resource.height,
4572                     mode.width, mode.height);
4573             return WINED3DERR_INVALIDCALL;
4574         }
4575
4576         /* TODO: MSDN: Cursor sizes must be a power of 2 */
4577
4578         /* Do not store the surface's pointer because the application may
4579          * release it after setting the cursor image. Windows doesn't
4580          * addref the set surface, so we can't do this either without
4581          * creating circular refcount dependencies. Copy out the gl texture
4582          * instead. */
4583         device->cursorWidth = cursor_image->resource.width;
4584         device->cursorHeight = cursor_image->resource.height;
4585         if (SUCCEEDED(wined3d_surface_map(cursor_image, &map_desc, NULL, WINED3D_MAP_READONLY)))
4586         {
4587             const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
4588             const struct wined3d_format *format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM);
4589             struct wined3d_context *context;
4590             char *mem, *bits = map_desc.data;
4591             GLint intfmt = format->glInternal;
4592             GLint gl_format = format->glFormat;
4593             GLint type = format->glType;
4594             INT height = device->cursorHeight;
4595             INT width = device->cursorWidth;
4596             INT bpp = format->byte_count;
4597             INT i;
4598
4599             /* Reformat the texture memory (pitch and width can be
4600              * different) */
4601             mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
4602             for (i = 0; i < height; ++i)
4603                 memcpy(&mem[width * bpp * i], &bits[map_desc.row_pitch * i], width * bpp);
4604             wined3d_surface_unmap(cursor_image);
4605
4606             context = context_acquire(device, NULL);
4607
4608             if (gl_info->supported[APPLE_CLIENT_STORAGE])
4609             {
4610                 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
4611                 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
4612             }
4613
4614             invalidate_active_texture(device, context);
4615             /* Create a new cursor texture */
4616             gl_info->gl_ops.gl.p_glGenTextures(1, &device->cursorTexture);
4617             checkGLcall("glGenTextures");
4618             context_bind_texture(context, GL_TEXTURE_2D, device->cursorTexture);
4619             /* Copy the bitmap memory into the cursor texture */
4620             gl_info->gl_ops.gl.p_glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, gl_format, type, mem);
4621             checkGLcall("glTexImage2D");
4622             HeapFree(GetProcessHeap(), 0, mem);
4623
4624             if (gl_info->supported[APPLE_CLIENT_STORAGE])
4625             {
4626                 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
4627                 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
4628             }
4629
4630             context_release(context);
4631         }
4632         else
4633         {
4634             FIXME("A cursor texture was not returned.\n");
4635             device->cursorTexture = 0;
4636         }
4637
4638         if (cursor_image->resource.width == 32 && cursor_image->resource.height == 32)
4639         {
4640             UINT mask_size = cursor_image->resource.width * cursor_image->resource.height / 8;
4641             ICONINFO cursorInfo;
4642             DWORD *maskBits;
4643             HCURSOR cursor;
4644
4645             /* 32-bit user32 cursors ignore the alpha channel if it's all
4646              * zeroes, and use the mask instead. Fill the mask with all ones
4647              * to ensure we still get a fully transparent cursor. */
4648             maskBits = HeapAlloc(GetProcessHeap(), 0, mask_size);
4649             memset(maskBits, 0xff, mask_size);
4650             wined3d_surface_map(cursor_image, &map_desc, NULL,
4651                     WINED3D_MAP_NO_DIRTY_UPDATE | WINED3D_MAP_READONLY);
4652             TRACE("width: %u height: %u.\n", cursor_image->resource.width, cursor_image->resource.height);
4653
4654             cursorInfo.fIcon = FALSE;
4655             cursorInfo.xHotspot = x_hotspot;
4656             cursorInfo.yHotspot = y_hotspot;
4657             cursorInfo.hbmMask = CreateBitmap(cursor_image->resource.width, cursor_image->resource.height,
4658                     1, 1, maskBits);
4659             cursorInfo.hbmColor = CreateBitmap(cursor_image->resource.width, cursor_image->resource.height,
4660                     1, 32, map_desc.data);
4661             wined3d_surface_unmap(cursor_image);
4662             /* Create our cursor and clean up. */
4663             cursor = CreateIconIndirect(&cursorInfo);
4664             if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
4665             if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
4666             if (device->hardwareCursor) DestroyCursor(device->hardwareCursor);
4667             device->hardwareCursor = cursor;
4668             if (device->bCursorVisible) SetCursor( cursor );
4669             HeapFree(GetProcessHeap(), 0, maskBits);
4670         }
4671     }
4672
4673     device->xHotSpot = x_hotspot;
4674     device->yHotSpot = y_hotspot;
4675     return WINED3D_OK;
4676 }
4677
4678 void CDECL wined3d_device_set_cursor_position(struct wined3d_device *device,
4679         int x_screen_space, int y_screen_space, DWORD flags)
4680 {
4681     TRACE("device %p, x %d, y %d, flags %#x.\n",
4682             device, x_screen_space, y_screen_space, flags);
4683
4684     device->xScreenSpace = x_screen_space;
4685     device->yScreenSpace = y_screen_space;
4686
4687     if (device->hardwareCursor)
4688     {
4689         POINT pt;
4690
4691         GetCursorPos( &pt );
4692         if (x_screen_space == pt.x && y_screen_space == pt.y)
4693             return;
4694         SetCursorPos( x_screen_space, y_screen_space );
4695
4696         /* Switch to the software cursor if position diverges from the hardware one. */
4697         GetCursorPos( &pt );
4698         if (x_screen_space != pt.x || y_screen_space != pt.y)
4699         {
4700             if (device->bCursorVisible) SetCursor( NULL );
4701             DestroyCursor( device->hardwareCursor );
4702             device->hardwareCursor = 0;
4703         }
4704     }
4705 }
4706
4707 BOOL CDECL wined3d_device_show_cursor(struct wined3d_device *device, BOOL show)
4708 {
4709     BOOL oldVisible = device->bCursorVisible;
4710
4711     TRACE("device %p, show %#x.\n", device, show);
4712
4713     /*
4714      * When ShowCursor is first called it should make the cursor appear at the OS's last
4715      * known cursor position.
4716      */
4717     if (show && !oldVisible)
4718     {
4719         POINT pt;
4720         GetCursorPos(&pt);
4721         device->xScreenSpace = pt.x;
4722         device->yScreenSpace = pt.y;
4723     }
4724
4725     if (device->hardwareCursor)
4726     {
4727         device->bCursorVisible = show;
4728         if (show)
4729             SetCursor(device->hardwareCursor);
4730         else
4731             SetCursor(NULL);
4732     }
4733     else
4734     {
4735         if (device->cursorTexture)
4736             device->bCursorVisible = show;
4737     }
4738
4739     return oldVisible;
4740 }
4741
4742 void CDECL wined3d_device_evict_managed_resources(struct wined3d_device *device)
4743 {
4744     struct wined3d_resource *resource, *cursor;
4745
4746     TRACE("device %p.\n", device);
4747
4748     LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &device->resources, struct wined3d_resource, resource_list_entry)
4749     {
4750         TRACE("Checking resource %p for eviction.\n", resource);
4751
4752         if (resource->pool == WINED3D_POOL_MANAGED && !resource->map_count)
4753         {
4754             TRACE("Evicting %p.\n", resource);
4755             resource->resource_ops->resource_unload(resource);
4756         }
4757     }
4758
4759     /* Invalidate stream sources, the buffer(s) may have been evicted. */
4760     device_invalidate_state(device, STATE_STREAMSRC);
4761 }
4762
4763 /* Do not call while under the GL lock. */
4764 static void delete_opengl_contexts(struct wined3d_device *device, struct wined3d_swapchain *swapchain)
4765 {
4766     struct wined3d_resource *resource, *cursor;
4767     const struct wined3d_gl_info *gl_info;
4768     struct wined3d_context *context;
4769     struct wined3d_shader *shader;
4770
4771     context = context_acquire(device, NULL);
4772     gl_info = context->gl_info;
4773
4774     LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &device->resources, struct wined3d_resource, resource_list_entry)
4775     {
4776         TRACE("Unloading resource %p.\n", resource);
4777
4778         resource->resource_ops->resource_unload(resource);
4779     }
4780
4781     LIST_FOR_EACH_ENTRY(shader, &device->shaders, struct wined3d_shader, shader_list_entry)
4782     {
4783         device->shader_backend->shader_destroy(shader);
4784     }
4785
4786     if (device->depth_blt_texture)
4787     {
4788         gl_info->gl_ops.gl.p_glDeleteTextures(1, &device->depth_blt_texture);
4789         device->depth_blt_texture = 0;
4790     }
4791     if (device->cursorTexture)
4792     {
4793         gl_info->gl_ops.gl.p_glDeleteTextures(1, &device->cursorTexture);
4794         device->cursorTexture = 0;
4795     }
4796
4797     device->blitter->free_private(device);
4798     device->shader_backend->shader_free_private(device);
4799     destroy_dummy_textures(device, gl_info);
4800
4801     context_release(context);
4802
4803     while (device->context_count)
4804     {
4805         swapchain_destroy_contexts(device->contexts[0]->swapchain);
4806     }
4807
4808     HeapFree(GetProcessHeap(), 0, swapchain->context);
4809     swapchain->context = NULL;
4810 }
4811
4812 /* Do not call while under the GL lock. */
4813 static HRESULT create_primary_opengl_context(struct wined3d_device *device, struct wined3d_swapchain *swapchain)
4814 {
4815     struct wined3d_context *context;
4816     struct wined3d_surface *target;
4817     HRESULT hr;
4818
4819     if (FAILED(hr = device->shader_backend->shader_alloc_private(device, device->adapter->fragment_pipe)))
4820     {
4821         ERR("Failed to allocate shader private data, hr %#x.\n", hr);
4822         return hr;
4823     }
4824
4825     if (FAILED(hr = device->blitter->alloc_private(device)))
4826     {
4827         ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
4828         device->shader_backend->shader_free_private(device);
4829         return hr;
4830     }
4831
4832     /* Recreate the primary swapchain's context */
4833     swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
4834     if (!swapchain->context)
4835     {
4836         ERR("Failed to allocate memory for swapchain context array.\n");
4837         device->blitter->free_private(device);
4838         device->shader_backend->shader_free_private(device);
4839         return E_OUTOFMEMORY;
4840     }
4841
4842     target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer;
4843     if (!(context = context_create(swapchain, target, swapchain->ds_format)))
4844     {
4845         WARN("Failed to create context.\n");
4846         device->blitter->free_private(device);
4847         device->shader_backend->shader_free_private(device);
4848         HeapFree(GetProcessHeap(), 0, swapchain->context);
4849         return E_FAIL;
4850     }
4851
4852     swapchain->context[0] = context;
4853     swapchain->num_contexts = 1;
4854     create_dummy_textures(device, context);
4855     context_release(context);
4856
4857     return WINED3D_OK;
4858 }
4859
4860 /* Do not call while under the GL lock. */
4861 HRESULT CDECL wined3d_device_reset(struct wined3d_device *device,
4862         const struct wined3d_swapchain_desc *swapchain_desc, const struct wined3d_display_mode *mode,
4863         wined3d_device_reset_cb callback, BOOL reset_state)
4864 {
4865     struct wined3d_resource *resource, *cursor;
4866     struct wined3d_swapchain *swapchain;
4867     struct wined3d_display_mode m;
4868     BOOL DisplayModeChanged = FALSE;
4869     BOOL update_desc = FALSE;
4870     HRESULT hr = WINED3D_OK;
4871     unsigned int i;
4872
4873     TRACE("device %p, swapchain_desc %p, mode %p, callback %p.\n", device, swapchain_desc, mode, callback);
4874
4875     if (!(swapchain = wined3d_device_get_swapchain(device, 0)))
4876     {
4877         ERR("Failed to get the first implicit swapchain.\n");
4878         return WINED3DERR_INVALIDCALL;
4879     }
4880
4881     if (reset_state)
4882         stateblock_unbind_resources(device->stateBlock);
4883
4884     if (device->fb.render_targets)
4885     {
4886         if (swapchain->back_buffers && swapchain->back_buffers[0])
4887             wined3d_device_set_render_target(device, 0, swapchain->back_buffers[0], FALSE);
4888         else
4889             wined3d_device_set_render_target(device, 0, swapchain->front_buffer, FALSE);
4890         for (i = 1; i < device->adapter->gl_info.limits.buffers; ++i)
4891         {
4892             wined3d_device_set_render_target(device, i, NULL, FALSE);
4893         }
4894     }
4895     wined3d_device_set_depth_stencil(device, NULL);
4896
4897     if (device->onscreen_depth_stencil)
4898     {
4899         wined3d_surface_decref(device->onscreen_depth_stencil);
4900         device->onscreen_depth_stencil = NULL;
4901     }
4902
4903     if (reset_state)
4904     {
4905         LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &device->resources, struct wined3d_resource, resource_list_entry)
4906         {
4907             TRACE("Enumerating resource %p.\n", resource);
4908             if (FAILED(hr = callback(resource)))
4909                 return hr;
4910         }
4911     }
4912
4913     /* Is it necessary to recreate the gl context? Actually every setting can be changed
4914      * on an existing gl context, so there's no real need for recreation.
4915      *
4916      * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
4917      *
4918      * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
4919      */
4920     TRACE("New params:\n");
4921     TRACE("backbuffer_width %u\n", swapchain_desc->backbuffer_width);
4922     TRACE("backbuffer_height %u\n", swapchain_desc->backbuffer_height);
4923     TRACE("backbuffer_format %s\n", debug_d3dformat(swapchain_desc->backbuffer_format));
4924     TRACE("backbuffer_count %u\n", swapchain_desc->backbuffer_count);
4925     TRACE("multisample_type %#x\n", swapchain_desc->multisample_type);
4926     TRACE("multisample_quality %u\n", swapchain_desc->multisample_quality);
4927     TRACE("swap_effect %#x\n", swapchain_desc->swap_effect);
4928     TRACE("device_window %p\n", swapchain_desc->device_window);
4929     TRACE("windowed %#x\n", swapchain_desc->windowed);
4930     TRACE("enable_auto_depth_stencil %#x\n", swapchain_desc->enable_auto_depth_stencil);
4931     if (swapchain_desc->enable_auto_depth_stencil)
4932         TRACE("auto_depth_stencil_format %s\n", debug_d3dformat(swapchain_desc->auto_depth_stencil_format));
4933     TRACE("flags %#x\n", swapchain_desc->flags);
4934     TRACE("refresh_rate %u\n", swapchain_desc->refresh_rate);
4935     TRACE("swap_interval %u\n", swapchain_desc->swap_interval);
4936     TRACE("auto_restore_display_mode %#x\n", swapchain_desc->auto_restore_display_mode);
4937
4938     /* No special treatment of these parameters. Just store them */
4939     swapchain->desc.swap_effect = swapchain_desc->swap_effect;
4940     swapchain->desc.flags = swapchain_desc->flags;
4941     swapchain->desc.swap_interval = swapchain_desc->swap_interval;
4942     swapchain->desc.refresh_rate = swapchain_desc->refresh_rate;
4943
4944     /* What to do about these? */
4945     if (swapchain_desc->backbuffer_count
4946             && swapchain_desc->backbuffer_count != swapchain->desc.backbuffer_count)
4947         FIXME("Cannot change the back buffer count yet.\n");
4948
4949     if (swapchain_desc->device_window
4950             && swapchain_desc->device_window != swapchain->desc.device_window)
4951     {
4952         TRACE("Changing the device window from %p to %p.\n",
4953                 swapchain->desc.device_window, swapchain_desc->device_window);
4954         swapchain->desc.device_window = swapchain_desc->device_window;
4955         swapchain->device_window = swapchain_desc->device_window;
4956         wined3d_swapchain_set_window(swapchain, NULL);
4957     }
4958
4959     if (swapchain_desc->enable_auto_depth_stencil && !device->auto_depth_stencil)
4960     {
4961         TRACE("Creating the depth stencil buffer\n");
4962
4963         if (FAILED(hr = device->device_parent->ops->create_swapchain_surface(device->device_parent,
4964                 device->device_parent, swapchain_desc->backbuffer_width, swapchain_desc->backbuffer_height,
4965                 swapchain_desc->auto_depth_stencil_format, WINED3DUSAGE_DEPTHSTENCIL,
4966                 swapchain_desc->multisample_type, swapchain_desc->multisample_quality,
4967                 &device->auto_depth_stencil)))
4968         {
4969             ERR("Failed to create the depth stencil buffer, hr %#x.\n", hr);
4970             return WINED3DERR_INVALIDCALL;
4971         }
4972     }
4973
4974     /* Reset the depth stencil */
4975     if (swapchain_desc->enable_auto_depth_stencil)
4976         wined3d_device_set_depth_stencil(device, device->auto_depth_stencil);
4977
4978     if (mode)
4979     {
4980         DisplayModeChanged = TRUE;
4981         m = *mode;
4982     }
4983     else if (swapchain_desc->windowed)
4984     {
4985         m.width = swapchain->orig_width;
4986         m.height = swapchain->orig_height;
4987         m.refresh_rate = 0;
4988         m.format_id = swapchain->desc.backbuffer_format;
4989         m.scanline_ordering = WINED3D_SCANLINE_ORDERING_UNKNOWN;
4990     }
4991     else
4992     {
4993         m.width = swapchain_desc->backbuffer_width;
4994         m.height = swapchain_desc->backbuffer_height;
4995         m.refresh_rate = swapchain_desc->refresh_rate;
4996         m.format_id = swapchain_desc->backbuffer_format;
4997         m.scanline_ordering = WINED3D_SCANLINE_ORDERING_UNKNOWN;
4998     }
4999
5000     /* Should Width == 800 && Height == 0 set 800x600? */
5001     if (swapchain_desc->backbuffer_width && swapchain_desc->backbuffer_height
5002             && (swapchain_desc->backbuffer_width != swapchain->desc.backbuffer_width
5003             || swapchain_desc->backbuffer_height != swapchain->desc.backbuffer_height))
5004     {
5005         if (!swapchain_desc->windowed)
5006             DisplayModeChanged = TRUE;
5007
5008         swapchain->desc.backbuffer_width = swapchain_desc->backbuffer_width;
5009         swapchain->desc.backbuffer_height = swapchain_desc->backbuffer_height;
5010         update_desc = TRUE;
5011     }
5012
5013     if (swapchain_desc->backbuffer_format != WINED3DFMT_UNKNOWN
5014             && swapchain_desc->backbuffer_format != swapchain->desc.backbuffer_format)
5015     {
5016         swapchain->desc.backbuffer_format = swapchain_desc->backbuffer_format;
5017         update_desc = TRUE;
5018     }
5019
5020     if (swapchain_desc->multisample_type != swapchain->desc.multisample_type
5021             || swapchain_desc->multisample_quality != swapchain->desc.multisample_quality)
5022     {
5023         swapchain->desc.multisample_type = swapchain_desc->multisample_type;
5024         swapchain->desc.multisample_quality = swapchain_desc->multisample_quality;
5025         update_desc = TRUE;
5026     }
5027
5028     if (update_desc)
5029     {
5030         UINT i;
5031
5032         if (FAILED(hr = wined3d_surface_update_desc(swapchain->front_buffer, swapchain->desc.backbuffer_width,
5033                 swapchain->desc.backbuffer_height, swapchain->desc.backbuffer_format,
5034                 swapchain->desc.multisample_type, swapchain->desc.multisample_quality)))
5035             return hr;
5036
5037         for (i = 0; i < swapchain->desc.backbuffer_count; ++i)
5038         {
5039             if (FAILED(hr = wined3d_surface_update_desc(swapchain->back_buffers[i], swapchain->desc.backbuffer_width,
5040                     swapchain->desc.backbuffer_height, swapchain->desc.backbuffer_format,
5041                     swapchain->desc.multisample_type, swapchain->desc.multisample_quality)))
5042                 return hr;
5043         }
5044         if (device->auto_depth_stencil)
5045         {
5046             if (FAILED(hr = wined3d_surface_update_desc(device->auto_depth_stencil, swapchain->desc.backbuffer_width,
5047                     swapchain->desc.backbuffer_height, device->auto_depth_stencil->resource.format->id,
5048                     swapchain->desc.multisample_type, swapchain->desc.multisample_quality)))
5049                 return hr;
5050         }
5051     }
5052
5053     if (!swapchain_desc->windowed != !swapchain->desc.windowed
5054             || DisplayModeChanged)
5055     {
5056         if (FAILED(hr = wined3d_set_adapter_display_mode(device->wined3d, device->adapter->ordinal, &m)))
5057         {
5058             WARN("Failed to set display mode, hr %#x.\n", hr);
5059             return WINED3DERR_INVALIDCALL;
5060         }
5061
5062         if (!swapchain_desc->windowed)
5063         {
5064             if (swapchain->desc.windowed)
5065             {
5066                 HWND focus_window = device->create_parms.focus_window;
5067                 if (!focus_window)
5068                     focus_window = swapchain_desc->device_window;
5069                 if (FAILED(hr = wined3d_device_acquire_focus_window(device, focus_window)))
5070                 {
5071                     ERR("Failed to acquire focus window, hr %#x.\n", hr);
5072                     return hr;
5073                 }
5074
5075                 /* switch from windowed to fs */
5076                 wined3d_device_setup_fullscreen_window(device, swapchain->device_window,
5077                         swapchain_desc->backbuffer_width,
5078                         swapchain_desc->backbuffer_height);
5079             }
5080             else
5081             {
5082                 /* Fullscreen -> fullscreen mode change */
5083                 MoveWindow(swapchain->device_window, 0, 0,
5084                         swapchain_desc->backbuffer_width,
5085                         swapchain_desc->backbuffer_height,
5086                         TRUE);
5087             }
5088         }
5089         else if (!swapchain->desc.windowed)
5090         {
5091             /* Fullscreen -> windowed switch */
5092             wined3d_device_restore_fullscreen_window(device, swapchain->device_window);
5093             wined3d_device_release_focus_window(device);
5094         }
5095         swapchain->desc.windowed = swapchain_desc->windowed;
5096     }
5097     else if (!swapchain_desc->windowed)
5098     {
5099         DWORD style = device->style;
5100         DWORD exStyle = device->exStyle;
5101         /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
5102          * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
5103          * Reset to clear up their mess. Guild Wars also loses the device during that.
5104          */
5105         device->style = 0;
5106         device->exStyle = 0;
5107         wined3d_device_setup_fullscreen_window(device, swapchain->device_window,
5108                 swapchain_desc->backbuffer_width,
5109                 swapchain_desc->backbuffer_height);
5110         device->style = style;
5111         device->exStyle = exStyle;
5112     }
5113
5114     if (reset_state)
5115     {
5116         TRACE("Resetting stateblock.\n");
5117         wined3d_stateblock_decref(device->updateStateBlock);
5118         wined3d_stateblock_decref(device->stateBlock);
5119
5120         if (device->d3d_initialized)
5121             delete_opengl_contexts(device, swapchain);
5122
5123         /* Note: No parent needed for initial internal stateblock */
5124         hr = wined3d_stateblock_create(device, WINED3D_SBT_INIT, &device->stateBlock);
5125         if (FAILED(hr))
5126             ERR("Resetting the stateblock failed with error %#x.\n", hr);
5127         else
5128             TRACE("Created stateblock %p.\n", device->stateBlock);
5129         device->updateStateBlock = device->stateBlock;
5130         wined3d_stateblock_incref(device->updateStateBlock);
5131
5132         stateblock_init_default_state(device->stateBlock);
5133     }
5134     else
5135     {
5136         struct wined3d_surface *rt = device->fb.render_targets[0];
5137         struct wined3d_state *state = &device->stateBlock->state;
5138
5139         /* Note the min_z / max_z is not reset. */
5140         state->viewport.x = 0;
5141         state->viewport.y = 0;
5142         state->viewport.width = rt->resource.width;
5143         state->viewport.height = rt->resource.height;
5144         device_invalidate_state(device, STATE_VIEWPORT);
5145
5146         state->scissor_rect.top = 0;
5147         state->scissor_rect.left = 0;
5148         state->scissor_rect.right = rt->resource.width;
5149         state->scissor_rect.bottom = rt->resource.height;
5150         device_invalidate_state(device, STATE_SCISSORRECT);
5151     }
5152
5153     swapchain_update_render_to_fbo(swapchain);
5154     swapchain_update_draw_bindings(swapchain);
5155
5156     if (reset_state && device->d3d_initialized)
5157         hr = create_primary_opengl_context(device, swapchain);
5158
5159     /* All done. There is no need to reload resources or shaders, this will happen automatically on the
5160      * first use
5161      */
5162     return hr;
5163 }
5164
5165 HRESULT CDECL wined3d_device_set_dialog_box_mode(struct wined3d_device *device, BOOL enable_dialogs)
5166 {
5167     TRACE("device %p, enable_dialogs %#x.\n", device, enable_dialogs);
5168
5169     if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
5170
5171     return WINED3D_OK;
5172 }
5173
5174
5175 void CDECL wined3d_device_get_creation_parameters(const struct wined3d_device *device,
5176         struct wined3d_device_creation_parameters *parameters)
5177 {
5178     TRACE("device %p, parameters %p.\n", device, parameters);
5179
5180     *parameters = device->create_parms;
5181 }
5182
5183 void CDECL wined3d_device_set_gamma_ramp(const struct wined3d_device *device,
5184         UINT swapchain_idx, DWORD flags, const struct wined3d_gamma_ramp *ramp)
5185 {
5186     struct wined3d_swapchain *swapchain;
5187
5188     TRACE("device %p, swapchain_idx %u, flags %#x, ramp %p.\n",
5189             device, swapchain_idx, flags, ramp);
5190
5191     if ((swapchain = wined3d_device_get_swapchain(device, swapchain_idx)))
5192         wined3d_swapchain_set_gamma_ramp(swapchain, flags, ramp);
5193 }
5194
5195 void CDECL wined3d_device_get_gamma_ramp(const struct wined3d_device *device,
5196         UINT swapchain_idx, struct wined3d_gamma_ramp *ramp)
5197 {
5198     struct wined3d_swapchain *swapchain;
5199
5200     TRACE("device %p, swapchain_idx %u, ramp %p.\n",
5201             device, swapchain_idx, ramp);
5202
5203     if ((swapchain = wined3d_device_get_swapchain(device, swapchain_idx)))
5204         wined3d_swapchain_get_gamma_ramp(swapchain, ramp);
5205 }
5206
5207 void device_resource_add(struct wined3d_device *device, struct wined3d_resource *resource)
5208 {
5209     TRACE("device %p, resource %p.\n", device, resource);
5210
5211     list_add_head(&device->resources, &resource->resource_list_entry);
5212 }
5213
5214 static void device_resource_remove(struct wined3d_device *device, struct wined3d_resource *resource)
5215 {
5216     TRACE("device %p, resource %p.\n", device, resource);
5217
5218     list_remove(&resource->resource_list_entry);
5219 }
5220
5221 void device_resource_released(struct wined3d_device *device, struct wined3d_resource *resource)
5222 {
5223     enum wined3d_resource_type type = resource->type;
5224     unsigned int i;
5225
5226     TRACE("device %p, resource %p, type %s.\n", device, resource, debug_d3dresourcetype(type));
5227
5228     context_resource_released(device, resource, type);
5229
5230     switch (type)
5231     {
5232         case WINED3D_RTYPE_SURFACE:
5233             {
5234                 struct wined3d_surface *surface = surface_from_resource(resource);
5235
5236                 if (!device->d3d_initialized) break;
5237
5238                 for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i)
5239                 {
5240                     if (device->fb.render_targets[i] == surface)
5241                     {
5242                         ERR("Surface %p is still in use as render target %u.\n", surface, i);
5243                         device->fb.render_targets[i] = NULL;
5244                     }
5245                 }
5246
5247                 if (device->fb.depth_stencil == surface)
5248                 {
5249                     ERR("Surface %p is still in use as depth/stencil buffer.\n", surface);
5250                     device->fb.depth_stencil = NULL;
5251                 }
5252             }
5253             break;
5254
5255         case WINED3D_RTYPE_TEXTURE:
5256         case WINED3D_RTYPE_CUBE_TEXTURE:
5257         case WINED3D_RTYPE_VOLUME_TEXTURE:
5258             for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5259             {
5260                 struct wined3d_texture *texture = wined3d_texture_from_resource(resource);
5261
5262                 if (device->stateBlock && device->stateBlock->state.textures[i] == texture)
5263                 {
5264                     ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
5265                             texture, device->stateBlock, i);
5266                     device->stateBlock->state.textures[i] = NULL;
5267                 }
5268
5269                 if (device->updateStateBlock != device->stateBlock
5270                         && device->updateStateBlock->state.textures[i] == texture)
5271                 {
5272                     ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
5273                             texture, device->updateStateBlock, i);
5274                     device->updateStateBlock->state.textures[i] = NULL;
5275                 }
5276             }
5277             break;
5278
5279         case WINED3D_RTYPE_BUFFER:
5280             {
5281                 struct wined3d_buffer *buffer = buffer_from_resource(resource);
5282
5283                 for (i = 0; i < MAX_STREAMS; ++i)
5284                 {
5285                     if (device->stateBlock && device->stateBlock->state.streams[i].buffer == buffer)
5286                     {
5287                         ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
5288                                 buffer, device->stateBlock, i);
5289                         device->stateBlock->state.streams[i].buffer = NULL;
5290                     }
5291
5292                     if (device->updateStateBlock != device->stateBlock
5293                             && device->updateStateBlock->state.streams[i].buffer == buffer)
5294                     {
5295                         ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
5296                                 buffer, device->updateStateBlock, i);
5297                         device->updateStateBlock->state.streams[i].buffer = NULL;
5298                     }
5299
5300                 }
5301
5302                 if (device->stateBlock && device->stateBlock->state.index_buffer == buffer)
5303                 {
5304                     ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
5305                             buffer, device->stateBlock);
5306                     device->stateBlock->state.index_buffer =  NULL;
5307                 }
5308
5309                 if (device->updateStateBlock != device->stateBlock
5310                         && device->updateStateBlock->state.index_buffer == buffer)
5311                 {
5312                     ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
5313                             buffer, device->updateStateBlock);
5314                     device->updateStateBlock->state.index_buffer =  NULL;
5315                 }
5316             }
5317             break;
5318
5319         default:
5320             break;
5321     }
5322
5323     /* Remove the resource from the resourceStore */
5324     device_resource_remove(device, resource);
5325
5326     TRACE("Resource released.\n");
5327 }
5328
5329 struct wined3d_surface * CDECL wined3d_device_get_surface_from_dc(const struct wined3d_device *device, HDC dc)
5330 {
5331     struct wined3d_resource *resource;
5332
5333     TRACE("device %p, dc %p.\n", device, dc);
5334
5335     if (!dc)
5336         return NULL;
5337
5338     LIST_FOR_EACH_ENTRY(resource, &device->resources, struct wined3d_resource, resource_list_entry)
5339     {
5340         if (resource->type == WINED3D_RTYPE_SURFACE)
5341         {
5342             struct wined3d_surface *s = surface_from_resource(resource);
5343
5344             if (s->hDC == dc)
5345             {
5346                 TRACE("Found surface %p for dc %p.\n", s, dc);
5347                 return s;
5348             }
5349         }
5350     }
5351
5352     return NULL;
5353 }
5354
5355 HRESULT device_init(struct wined3d_device *device, struct wined3d *wined3d,
5356         UINT adapter_idx, enum wined3d_device_type device_type, HWND focus_window, DWORD flags,
5357         BYTE surface_alignment, struct wined3d_device_parent *device_parent)
5358 {
5359     struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
5360     const struct fragment_pipeline *fragment_pipeline;
5361     struct shader_caps shader_caps;
5362     struct fragment_caps ffp_caps;
5363     unsigned int i;
5364     HRESULT hr;
5365
5366     device->ref = 1;
5367     device->wined3d = wined3d;
5368     wined3d_incref(device->wined3d);
5369     device->adapter = wined3d->adapter_count ? adapter : NULL;
5370     device->device_parent = device_parent;
5371     list_init(&device->resources);
5372     list_init(&device->shaders);
5373     device->surface_alignment = surface_alignment;
5374
5375     /* Save the creation parameters. */
5376     device->create_parms.adapter_idx = adapter_idx;
5377     device->create_parms.device_type = device_type;
5378     device->create_parms.focus_window = focus_window;
5379     device->create_parms.flags = flags;
5380
5381     device->shader_backend = adapter->shader_backend;
5382     device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
5383     device->vs_version = shader_caps.vs_version;
5384     device->gs_version = shader_caps.gs_version;
5385     device->ps_version = shader_caps.ps_version;
5386     device->d3d_vshader_constantF = shader_caps.vs_uniform_count;
5387     device->d3d_pshader_constantF = shader_caps.ps_uniform_count;
5388     device->vs_clipping = shader_caps.wined3d_caps & WINED3D_SHADER_CAP_VS_CLIPPING;
5389
5390     fragment_pipeline = adapter->fragment_pipe;
5391     fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
5392     device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
5393
5394     if (fragment_pipeline->states
5395             && FAILED(hr = compile_state_table(device->StateTable, device->multistate_funcs,
5396             &adapter->gl_info, ffp_vertexstate_template, fragment_pipeline, misc_state_template)))
5397     {
5398         ERR("Failed to compile state table, hr %#x.\n", hr);
5399         wined3d_decref(device->wined3d);
5400         return hr;
5401     }
5402
5403     device->blitter = adapter->blitter;
5404
5405     hr = wined3d_stateblock_create(device, WINED3D_SBT_INIT, &device->stateBlock);
5406     if (FAILED(hr))
5407     {
5408         WARN("Failed to create stateblock.\n");
5409         for (i = 0; i < sizeof(device->multistate_funcs) / sizeof(device->multistate_funcs[0]); ++i)
5410         {
5411             HeapFree(GetProcessHeap(), 0, device->multistate_funcs[i]);
5412         }
5413         wined3d_decref(device->wined3d);
5414         return hr;
5415     }
5416
5417     TRACE("Created stateblock %p.\n", device->stateBlock);
5418     device->updateStateBlock = device->stateBlock;
5419     wined3d_stateblock_incref(device->updateStateBlock);
5420
5421     return WINED3D_OK;
5422 }
5423
5424
5425 void device_invalidate_state(const struct wined3d_device *device, DWORD state)
5426 {
5427     DWORD rep = device->StateTable[state].representative;
5428     struct wined3d_context *context;
5429     DWORD idx;
5430     BYTE shift;
5431     UINT i;
5432
5433     for (i = 0; i < device->context_count; ++i)
5434     {
5435         context = device->contexts[i];
5436         if(isStateDirty(context, rep)) continue;
5437
5438         context->dirtyArray[context->numDirtyEntries++] = rep;
5439         idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
5440         shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
5441         context->isStateDirty[idx] |= (1 << shift);
5442     }
5443 }
5444
5445 void get_drawable_size_fbo(const struct wined3d_context *context, UINT *width, UINT *height)
5446 {
5447     /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
5448     *width = context->current_rt->pow2Width;
5449     *height = context->current_rt->pow2Height;
5450 }
5451
5452 void get_drawable_size_backbuffer(const struct wined3d_context *context, UINT *width, UINT *height)
5453 {
5454     const struct wined3d_swapchain *swapchain = context->swapchain;
5455     /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
5456      * current context's drawable, which is the size of the back buffer of the swapchain
5457      * the active context belongs to. */
5458     *width = swapchain->desc.backbuffer_width;
5459     *height = swapchain->desc.backbuffer_height;
5460 }
5461
5462 LRESULT device_process_message(struct wined3d_device *device, HWND window, BOOL unicode,
5463         UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
5464 {
5465     if (device->filter_messages)
5466     {
5467         TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
5468                 window, message, wparam, lparam);
5469         if (unicode)
5470             return DefWindowProcW(window, message, wparam, lparam);
5471         else
5472             return DefWindowProcA(window, message, wparam, lparam);
5473     }
5474
5475     if (message == WM_DESTROY)
5476     {
5477         TRACE("unregister window %p.\n", window);
5478         wined3d_unregister_window(window);
5479
5480         if (InterlockedCompareExchangePointer((void **)&device->focus_window, NULL, window) != window)
5481             ERR("Window %p is not the focus window for device %p.\n", window, device);
5482     }
5483     else if (message == WM_DISPLAYCHANGE)
5484     {
5485         device->device_parent->ops->mode_changed(device->device_parent);
5486     }
5487
5488     if (unicode)
5489         return CallWindowProcW(proc, window, message, wparam, lparam);
5490     else
5491         return CallWindowProcA(proc, window, message, wparam, lparam);
5492 }