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