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