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