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