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