VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/Wine_new/wined3d/device.c@ 48896

Last change on this file since 48896 was 48896, checked in by vboxsync, 11 years ago

wined3d: fix vista Aero (do not resent viewport on same rt)

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette