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