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