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