VirtualBox

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

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

crOpenGL: bugfixes and work-arounds for wine issues

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 200.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#ifdef VBOX_WITH_WINE_FIX_ZEROVERTATTR
1344 zv_destroy(device);
1345#endif
1346
1347 if (device->logo_surface)
1348 wined3d_surface_decref(device->logo_surface);
1349
1350 stateblock_unbind_resources(device->stateBlock);
1351
1352 /* Unload resources */
1353 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &device->resources, struct wined3d_resource, resource_list_entry)
1354 {
1355 TRACE("Unloading resource %p.\n", resource);
1356
1357 resource->resource_ops->resource_unload(resource);
1358 }
1359
1360 /* Delete the mouse cursor texture */
1361 if (device->cursorTexture)
1362 {
1363 gl_info->gl_ops.gl.p_glDeleteTextures(1, &device->cursorTexture);
1364 device->cursorTexture = 0;
1365 }
1366
1367 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
1368 * private data, it might contain opengl pointers
1369 */
1370 if (device->depth_blt_texture)
1371 {
1372 gl_info->gl_ops.gl.p_glDeleteTextures(1, &device->depth_blt_texture);
1373 device->depth_blt_texture = 0;
1374 }
1375
1376#ifdef VBOX_WINE_WITH_SHADER_CACHE
1377 shader_chaches_term(device);
1378#endif
1379
1380 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
1381 device->blitter->free_private(device);
1382 device->shader_backend->shader_free_private(device);
1383 destroy_dummy_textures(device, gl_info);
1384
1385 /* Release the buffers (with sanity checks)*/
1386 if (device->onscreen_depth_stencil)
1387 {
1388 surface = device->onscreen_depth_stencil;
1389 device->onscreen_depth_stencil = NULL;
1390 wined3d_surface_decref(surface);
1391 }
1392
1393 if (device->fb.depth_stencil)
1394 {
1395 surface = device->fb.depth_stencil;
1396
1397 TRACE("Releasing depth/stencil buffer %p.\n", surface);
1398
1399 device->fb.depth_stencil = NULL;
1400 wined3d_surface_decref(surface);
1401 }
1402
1403 if (device->auto_depth_stencil)
1404 {
1405 surface = device->auto_depth_stencil;
1406 device->auto_depth_stencil = NULL;
1407 if (wined3d_surface_decref(surface))
1408 FIXME("Something's still holding the auto depth stencil buffer (%p).\n", surface);
1409 }
1410
1411 for (i = 1; i < gl_info->limits.buffers; ++i)
1412 {
1413 wined3d_device_set_render_target(device, i, NULL, FALSE);
1414 }
1415
1416 surface = device->fb.render_targets[0];
1417 TRACE("Setting rendertarget 0 to NULL\n");
1418 device->fb.render_targets[0] = NULL;
1419 TRACE("Releasing the render target at %p\n", surface);
1420 wined3d_surface_decref(surface);
1421
1422 context_release(context);
1423
1424 for (i = 0; i < device->swapchain_count; ++i)
1425 {
1426 TRACE("Releasing the implicit swapchain %u.\n", i);
1427 if (wined3d_swapchain_decref(device->swapchains[i]))
1428 FIXME("Something's still holding the implicit swapchain.\n");
1429 }
1430
1431#ifdef VBOX_WINE_WITH_SINGLE_CONTEXT
1432 while (device->context_count)
1433 {
1434 context_destroy(device, device->contexts[0]);
1435 }
1436#endif
1437
1438 HeapFree(GetProcessHeap(), 0, device->swapchains);
1439 device->swapchains = NULL;
1440 device->swapchain_count = 0;
1441
1442 HeapFree(GetProcessHeap(), 0, device->fb.render_targets);
1443 device->fb.render_targets = NULL;
1444
1445 device->d3d_initialized = FALSE;
1446
1447 return WINED3D_OK;
1448}
1449
1450HRESULT CDECL wined3d_device_uninit_gdi(struct wined3d_device *device)
1451{
1452 unsigned int i;
1453
1454 for (i = 0; i < device->swapchain_count; ++i)
1455 {
1456 TRACE("Releasing the implicit swapchain %u.\n", i);
1457 if (wined3d_swapchain_decref(device->swapchains[i]))
1458 FIXME("Something's still holding the implicit swapchain.\n");
1459 }
1460
1461 HeapFree(GetProcessHeap(), 0, device->swapchains);
1462 device->swapchains = NULL;
1463 device->swapchain_count = 0;
1464 return WINED3D_OK;
1465}
1466
1467/* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
1468 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
1469 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
1470 *
1471 * There is no way to deactivate thread safety once it is enabled.
1472 */
1473void CDECL wined3d_device_set_multithreaded(struct wined3d_device *device)
1474{
1475 TRACE("device %p.\n", device);
1476
1477 /* For now just store the flag (needed in case of ddraw). */
1478 device->create_parms.flags |= WINED3DCREATE_MULTITHREADED;
1479}
1480
1481
1482UINT CDECL wined3d_device_get_available_texture_mem(const struct wined3d_device *device)
1483{
1484#ifndef VBOX_WITH_WDDM
1485 TRACE("device %p.\n", device);
1486
1487 TRACE("Emulating %d MB, returning %d MB left.\n",
1488 device->adapter->TextureRam / (1024 * 1024),
1489 (device->adapter->TextureRam - device->adapter->UsedTextureRam) / (1024 * 1024));
1490
1491 return device->adapter->TextureRam - device->adapter->UsedTextureRam;
1492#else
1493 ERR("unsupported!");
1494 return ~0UL;
1495#endif
1496}
1497
1498void CDECL wined3d_device_set_stream_output(struct wined3d_device *device, UINT idx,
1499 struct wined3d_buffer *buffer, UINT offset)
1500{
1501 struct wined3d_buffer *prev_buffer;
1502
1503 TRACE("device %p, idx %u, buffer %p, offset %u.\n", device, idx, buffer, offset);
1504
1505 if (idx >= MAX_STREAM_OUT)
1506 {
1507 WARN("Invalid stream output %u.\n", idx);
1508 return;
1509 }
1510
1511 prev_buffer = device->updateStateBlock->state.stream_output[idx].buffer;
1512 device->updateStateBlock->state.stream_output[idx].buffer = buffer;
1513 device->updateStateBlock->state.stream_output[idx].offset = offset;
1514
1515 if (device->isRecordingState)
1516 {
1517 if (buffer)
1518 wined3d_buffer_incref(buffer);
1519 if (prev_buffer)
1520 wined3d_buffer_decref(prev_buffer);
1521 return;
1522 }
1523
1524 if (prev_buffer != buffer)
1525 {
1526 if (buffer)
1527 {
1528 InterlockedIncrement(&buffer->resource.bind_count);
1529 wined3d_buffer_incref(buffer);
1530 }
1531 if (prev_buffer)
1532 {
1533 InterlockedDecrement(&prev_buffer->resource.bind_count);
1534 wined3d_buffer_decref(prev_buffer);
1535 }
1536 }
1537}
1538
1539struct wined3d_buffer * CDECL wined3d_device_get_stream_output(struct wined3d_device *device,
1540 UINT idx, UINT *offset)
1541{
1542 TRACE("device %p, idx %u, offset %p.\n", device, idx, offset);
1543
1544 if (idx >= MAX_STREAM_OUT)
1545 {
1546 WARN("Invalid stream output %u.\n", idx);
1547 return NULL;
1548 }
1549
1550 *offset = device->stateBlock->state.stream_output[idx].offset;
1551 return device->stateBlock->state.stream_output[idx].buffer;
1552}
1553
1554HRESULT CDECL wined3d_device_set_stream_source(struct wined3d_device *device, UINT stream_idx,
1555 struct wined3d_buffer *buffer, UINT offset, UINT stride)
1556{
1557 struct wined3d_stream_state *stream;
1558 struct wined3d_buffer *prev_buffer;
1559
1560 TRACE("device %p, stream_idx %u, buffer %p, offset %u, stride %u.\n",
1561 device, stream_idx, buffer, offset, stride);
1562
1563 if (stream_idx >= MAX_STREAMS)
1564 {
1565 WARN("Stream index %u out of range.\n", stream_idx);
1566 return WINED3DERR_INVALIDCALL;
1567 }
1568 else if (offset & 0x3)
1569 {
1570 WARN("Offset %u is not 4 byte aligned.\n", offset);
1571 return WINED3DERR_INVALIDCALL;
1572 }
1573
1574 stream = &device->updateStateBlock->state.streams[stream_idx];
1575 prev_buffer = stream->buffer;
1576
1577 device->updateStateBlock->changed.streamSource |= 1 << stream_idx;
1578
1579 if (prev_buffer == buffer
1580 && stream->stride == stride
1581 && stream->offset == offset)
1582 {
1583 TRACE("Application is setting the old values over, nothing to do.\n");
1584 return WINED3D_OK;
1585 }
1586
1587 stream->buffer = buffer;
1588 if (buffer)
1589 {
1590 stream->stride = stride;
1591 stream->offset = offset;
1592 }
1593
1594 /* Handle recording of state blocks. */
1595 if (device->isRecordingState)
1596 {
1597 TRACE("Recording... not performing anything.\n");
1598 if (buffer)
1599 wined3d_buffer_incref(buffer);
1600 if (prev_buffer)
1601 wined3d_buffer_decref(prev_buffer);
1602 return WINED3D_OK;
1603 }
1604
1605 if (buffer)
1606 {
1607 InterlockedIncrement(&buffer->resource.bind_count);
1608 wined3d_buffer_incref(buffer);
1609 }
1610 if (prev_buffer)
1611 {
1612 InterlockedDecrement(&prev_buffer->resource.bind_count);
1613 wined3d_buffer_decref(prev_buffer);
1614 }
1615
1616 device_invalidate_state(device, STATE_STREAMSRC);
1617
1618 return WINED3D_OK;
1619}
1620
1621HRESULT CDECL wined3d_device_get_stream_source(const struct wined3d_device *device,
1622 UINT stream_idx, struct wined3d_buffer **buffer, UINT *offset, UINT *stride)
1623{
1624 struct wined3d_stream_state *stream;
1625
1626 TRACE("device %p, stream_idx %u, buffer %p, offset %p, stride %p.\n",
1627 device, stream_idx, buffer, offset, stride);
1628
1629 if (stream_idx >= MAX_STREAMS)
1630 {
1631 WARN("Stream index %u out of range.\n", stream_idx);
1632 return WINED3DERR_INVALIDCALL;
1633 }
1634
1635 stream = &device->stateBlock->state.streams[stream_idx];
1636 *buffer = stream->buffer;
1637 if (*buffer)
1638 wined3d_buffer_incref(*buffer);
1639 if (offset)
1640 *offset = stream->offset;
1641 *stride = stream->stride;
1642
1643 return WINED3D_OK;
1644}
1645
1646HRESULT CDECL wined3d_device_set_stream_source_freq(struct wined3d_device *device, UINT stream_idx, UINT divider)
1647{
1648 struct wined3d_stream_state *stream;
1649 UINT old_flags, old_freq;
1650
1651 TRACE("device %p, stream_idx %u, divider %#x.\n", device, stream_idx, divider);
1652
1653 /* Verify input. At least in d3d9 this is invalid. */
1654 if ((divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (divider & WINED3DSTREAMSOURCE_INDEXEDDATA))
1655 {
1656 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL.\n");
1657 return WINED3DERR_INVALIDCALL;
1658 }
1659 if ((divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && !stream_idx)
1660 {
1661 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL.\n");
1662 return WINED3DERR_INVALIDCALL;
1663 }
1664 if (!divider)
1665 {
1666 WARN("Divider is 0, returning D3DERR_INVALIDCALL.\n");
1667 return WINED3DERR_INVALIDCALL;
1668 }
1669
1670 stream = &device->updateStateBlock->state.streams[stream_idx];
1671 old_flags = stream->flags;
1672 old_freq = stream->frequency;
1673
1674 stream->flags = divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA);
1675 stream->frequency = divider & 0x7fffff;
1676
1677 device->updateStateBlock->changed.streamFreq |= 1 << stream_idx;
1678
1679 if (stream->frequency != old_freq || stream->flags != old_flags)
1680 device_invalidate_state(device, STATE_STREAMSRC);
1681
1682 return WINED3D_OK;
1683}
1684
1685HRESULT CDECL wined3d_device_get_stream_source_freq(const struct wined3d_device *device,
1686 UINT stream_idx, UINT *divider)
1687{
1688 struct wined3d_stream_state *stream;
1689
1690 TRACE("device %p, stream_idx %u, divider %p.\n", device, stream_idx, divider);
1691
1692 stream = &device->updateStateBlock->state.streams[stream_idx];
1693 *divider = stream->flags | stream->frequency;
1694
1695 TRACE("Returning %#x.\n", *divider);
1696
1697 return WINED3D_OK;
1698}
1699
1700void CDECL wined3d_device_set_transform(struct wined3d_device *device,
1701 enum wined3d_transform_state d3dts, const struct wined3d_matrix *matrix)
1702{
1703 TRACE("device %p, state %s, matrix %p.\n",
1704 device, debug_d3dtstype(d3dts), matrix);
1705 TRACE("%.8e %.8e %.8e %.8e\n", matrix->u.s._11, matrix->u.s._12, matrix->u.s._13, matrix->u.s._14);
1706 TRACE("%.8e %.8e %.8e %.8e\n", matrix->u.s._21, matrix->u.s._22, matrix->u.s._23, matrix->u.s._24);
1707 TRACE("%.8e %.8e %.8e %.8e\n", matrix->u.s._31, matrix->u.s._32, matrix->u.s._33, matrix->u.s._34);
1708 TRACE("%.8e %.8e %.8e %.8e\n", matrix->u.s._41, matrix->u.s._42, matrix->u.s._43, matrix->u.s._44);
1709
1710 /* Handle recording of state blocks. */
1711 if (device->isRecordingState)
1712 {
1713 TRACE("Recording... not performing anything.\n");
1714 device->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
1715 device->updateStateBlock->state.transforms[d3dts] = *matrix;
1716 return;
1717 }
1718
1719 /* If the new matrix is the same as the current one,
1720 * we cut off any further processing. this seems to be a reasonable
1721 * optimization because as was noticed, some apps (warcraft3 for example)
1722 * tend towards setting the same matrix repeatedly for some reason.
1723 *
1724 * From here on we assume that the new matrix is different, wherever it matters. */
1725 if (!memcmp(&device->stateBlock->state.transforms[d3dts].u.m[0][0], matrix, sizeof(*matrix)))
1726 {
1727 TRACE("The application is setting the same matrix over again.\n");
1728 return;
1729 }
1730
1731 device->stateBlock->state.transforms[d3dts] = *matrix;
1732
1733 if (d3dts < WINED3D_TS_WORLD_MATRIX(device->adapter->gl_info.limits.blends))
1734 device_invalidate_state(device, STATE_TRANSFORM(d3dts));
1735}
1736
1737void CDECL wined3d_device_get_transform(const struct wined3d_device *device,
1738 enum wined3d_transform_state state, struct wined3d_matrix *matrix)
1739{
1740 TRACE("device %p, state %s, matrix %p.\n", device, debug_d3dtstype(state), matrix);
1741
1742 *matrix = device->stateBlock->state.transforms[state];
1743}
1744
1745void CDECL wined3d_device_multiply_transform(struct wined3d_device *device,
1746 enum wined3d_transform_state state, const struct wined3d_matrix *matrix)
1747{
1748 const struct wined3d_matrix *mat;
1749 struct wined3d_matrix temp;
1750
1751 TRACE("device %p, state %s, matrix %p.\n", device, debug_d3dtstype(state), matrix);
1752
1753 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
1754 * below means it will be recorded in a state block change, but it
1755 * works regardless where it is recorded.
1756 * If this is found to be wrong, change to StateBlock. */
1757 if (state > HIGHEST_TRANSFORMSTATE)
1758 {
1759 WARN("Unhandled transform state %#x.\n", state);
1760 return;
1761 }
1762
1763 mat = &device->updateStateBlock->state.transforms[state];
1764 multiply_matrix(&temp, mat, matrix);
1765
1766 /* Apply change via set transform - will reapply to eg. lights this way. */
1767 wined3d_device_set_transform(device, state, &temp);
1768}
1769
1770/* Note lights are real special cases. Although the device caps state only
1771 * e.g. 8 are supported, you can reference any indexes you want as long as
1772 * that number max are enabled at any one point in time. Therefore since the
1773 * indices can be anything, we need a hashmap of them. However, this causes
1774 * stateblock problems. When capturing the state block, I duplicate the
1775 * hashmap, but when recording, just build a chain pretty much of commands to
1776 * be replayed. */
1777HRESULT CDECL wined3d_device_set_light(struct wined3d_device *device,
1778 UINT light_idx, const struct wined3d_light *light)
1779{
1780 UINT hash_idx = LIGHTMAP_HASHFUNC(light_idx);
1781 struct wined3d_light_info *object = NULL;
1782 struct list *e;
1783 float rho;
1784
1785 TRACE("device %p, light_idx %u, light %p.\n", device, light_idx, light);
1786
1787 /* Check the parameter range. Need for speed most wanted sets junk lights
1788 * which confuse the GL driver. */
1789 if (!light)
1790 return WINED3DERR_INVALIDCALL;
1791
1792 switch (light->type)
1793 {
1794 case WINED3D_LIGHT_POINT:
1795 case WINED3D_LIGHT_SPOT:
1796 case WINED3D_LIGHT_PARALLELPOINT:
1797 case WINED3D_LIGHT_GLSPOT:
1798 /* Incorrect attenuation values can cause the gl driver to crash.
1799 * Happens with Need for speed most wanted. */
1800 if (light->attenuation0 < 0.0f || light->attenuation1 < 0.0f || light->attenuation2 < 0.0f)
1801 {
1802 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL.\n");
1803 return WINED3DERR_INVALIDCALL;
1804 }
1805 break;
1806
1807 case WINED3D_LIGHT_DIRECTIONAL:
1808 /* Ignores attenuation */
1809 break;
1810
1811 default:
1812 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
1813 return WINED3DERR_INVALIDCALL;
1814 }
1815
1816 LIST_FOR_EACH(e, &device->updateStateBlock->state.light_map[hash_idx])
1817 {
1818 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
1819 if (object->OriginalIndex == light_idx)
1820 break;
1821 object = NULL;
1822 }
1823
1824 if (!object)
1825 {
1826 TRACE("Adding new light\n");
1827 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1828 if (!object)
1829 return E_OUTOFMEMORY;
1830
1831 list_add_head(&device->updateStateBlock->state.light_map[hash_idx], &object->entry);
1832 object->glIndex = -1;
1833 object->OriginalIndex = light_idx;
1834 }
1835
1836 /* Initialize the object. */
1837 TRACE("Light %d setting to type %d, Diffuse(%f,%f,%f,%f), Specular(%f,%f,%f,%f), Ambient(%f,%f,%f,%f)\n",
1838 light_idx, light->type,
1839 light->diffuse.r, light->diffuse.g, light->diffuse.b, light->diffuse.a,
1840 light->specular.r, light->specular.g, light->specular.b, light->specular.a,
1841 light->ambient.r, light->ambient.g, light->ambient.b, light->ambient.a);
1842 TRACE("... Pos(%f,%f,%f), Dir(%f,%f,%f)\n", light->position.x, light->position.y, light->position.z,
1843 light->direction.x, light->direction.y, light->direction.z);
1844 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n",
1845 light->range, light->falloff, light->theta, light->phi);
1846
1847 /* Update the live definitions if the light is currently assigned a glIndex. */
1848 if (object->glIndex != -1 && !device->isRecordingState)
1849 {
1850 if (object->OriginalParms.type != light->type)
1851 device_invalidate_state(device, STATE_LIGHT_TYPE);
1852 device_invalidate_state(device, STATE_ACTIVELIGHT(object->glIndex));
1853 }
1854
1855 /* Save away the information. */
1856 object->OriginalParms = *light;
1857
1858 switch (light->type)
1859 {
1860 case WINED3D_LIGHT_POINT:
1861 /* Position */
1862 object->lightPosn[0] = light->position.x;
1863 object->lightPosn[1] = light->position.y;
1864 object->lightPosn[2] = light->position.z;
1865 object->lightPosn[3] = 1.0f;
1866 object->cutoff = 180.0f;
1867 /* FIXME: Range */
1868 break;
1869
1870 case WINED3D_LIGHT_DIRECTIONAL:
1871 /* Direction */
1872 object->lightPosn[0] = -light->direction.x;
1873 object->lightPosn[1] = -light->direction.y;
1874 object->lightPosn[2] = -light->direction.z;
1875 object->lightPosn[3] = 0.0f;
1876 object->exponent = 0.0f;
1877 object->cutoff = 180.0f;
1878 break;
1879
1880 case WINED3D_LIGHT_SPOT:
1881 /* Position */
1882 object->lightPosn[0] = light->position.x;
1883 object->lightPosn[1] = light->position.y;
1884 object->lightPosn[2] = light->position.z;
1885 object->lightPosn[3] = 1.0f;
1886
1887 /* Direction */
1888 object->lightDirn[0] = light->direction.x;
1889 object->lightDirn[1] = light->direction.y;
1890 object->lightDirn[2] = light->direction.z;
1891 object->lightDirn[3] = 1.0f;
1892
1893 /* opengl-ish and d3d-ish spot lights use too different models
1894 * for the light "intensity" as a function of the angle towards
1895 * the main light direction, so we only can approximate very
1896 * roughly. However, spot lights are rather rarely used in games
1897 * (if ever used at all). Furthermore if still used, probably
1898 * nobody pays attention to such details. */
1899 if (!light->falloff)
1900 {
1901 /* Falloff = 0 is easy, because d3d's and opengl's spot light
1902 * equations have the falloff resp. exponent parameter as an
1903 * exponent, so the spot light lighting will always be 1.0 for
1904 * both of them, and we don't have to care for the rest of the
1905 * rather complex calculation. */
1906 object->exponent = 0.0f;
1907 }
1908 else
1909 {
1910 rho = light->theta + (light->phi - light->theta) / (2 * light->falloff);
1911 if (rho < 0.0001f)
1912 rho = 0.0001f;
1913#ifdef VBOX_WITH_WINE_FIXES
1914 object->exponent = -0.3f / log(cos(rho / 2));
1915#else
1916 object->exponent = -0.3f / logf(cosf(rho / 2));
1917#endif
1918 }
1919
1920 if (object->exponent > 128.0f)
1921 object->exponent = 128.0f;
1922
1923 object->cutoff = (float)(light->phi * 90 / M_PI);
1924 /* FIXME: Range */
1925 break;
1926
1927 default:
1928 FIXME("Unrecognized light type %#x.\n", light->type);
1929 }
1930
1931 return WINED3D_OK;
1932}
1933
1934HRESULT CDECL wined3d_device_get_light(const struct wined3d_device *device,
1935 UINT light_idx, struct wined3d_light *light)
1936{
1937 UINT hash_idx = LIGHTMAP_HASHFUNC(light_idx);
1938 struct wined3d_light_info *light_info = NULL;
1939 struct list *e;
1940
1941 TRACE("device %p, light_idx %u, light %p.\n", device, light_idx, light);
1942
1943 LIST_FOR_EACH(e, &device->stateBlock->state.light_map[hash_idx])
1944 {
1945 light_info = LIST_ENTRY(e, struct wined3d_light_info, entry);
1946 if (light_info->OriginalIndex == light_idx)
1947 break;
1948 light_info = NULL;
1949 }
1950
1951 if (!light_info)
1952 {
1953 TRACE("Light information requested but light not defined\n");
1954 return WINED3DERR_INVALIDCALL;
1955 }
1956
1957 *light = light_info->OriginalParms;
1958 return WINED3D_OK;
1959}
1960
1961HRESULT CDECL wined3d_device_set_light_enable(struct wined3d_device *device, UINT light_idx, BOOL enable)
1962{
1963 UINT hash_idx = LIGHTMAP_HASHFUNC(light_idx);
1964 struct wined3d_light_info *light_info = NULL;
1965 struct list *e;
1966
1967 TRACE("device %p, light_idx %u, enable %#x.\n", device, light_idx, enable);
1968
1969 LIST_FOR_EACH(e, &device->updateStateBlock->state.light_map[hash_idx])
1970 {
1971 light_info = LIST_ENTRY(e, struct wined3d_light_info, entry);
1972 if (light_info->OriginalIndex == light_idx)
1973 break;
1974 light_info = NULL;
1975 }
1976 TRACE("Found light %p.\n", light_info);
1977
1978 /* Special case - enabling an undefined light creates one with a strict set of parameters. */
1979 if (!light_info)
1980 {
1981 TRACE("Light enabled requested but light not defined, so defining one!\n");
1982 wined3d_device_set_light(device, light_idx, &WINED3D_default_light);
1983
1984 /* Search for it again! Should be fairly quick as near head of list. */
1985 LIST_FOR_EACH(e, &device->updateStateBlock->state.light_map[hash_idx])
1986 {
1987 light_info = LIST_ENTRY(e, struct wined3d_light_info, entry);
1988 if (light_info->OriginalIndex == light_idx)
1989 break;
1990 light_info = NULL;
1991 }
1992 if (!light_info)
1993 {
1994 FIXME("Adding default lights has failed dismally\n");
1995 return WINED3DERR_INVALIDCALL;
1996 }
1997 }
1998
1999 if (!enable)
2000 {
2001 if (light_info->glIndex != -1)
2002 {
2003 if (!device->isRecordingState)
2004 {
2005 device_invalidate_state(device, STATE_LIGHT_TYPE);
2006 device_invalidate_state(device, STATE_ACTIVELIGHT(light_info->glIndex));
2007 }
2008
2009 device->updateStateBlock->state.lights[light_info->glIndex] = NULL;
2010 light_info->glIndex = -1;
2011 }
2012 else
2013 {
2014 TRACE("Light already disabled, nothing to do\n");
2015 }
2016 light_info->enabled = FALSE;
2017 }
2018 else
2019 {
2020 light_info->enabled = TRUE;
2021 if (light_info->glIndex != -1)
2022 {
2023 TRACE("Nothing to do as light was enabled\n");
2024 }
2025 else
2026 {
2027 unsigned int i;
2028 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
2029 /* Find a free GL light. */
2030 for (i = 0; i < gl_info->limits.lights; ++i)
2031 {
2032 if (!device->updateStateBlock->state.lights[i])
2033 {
2034 device->updateStateBlock->state.lights[i] = light_info;
2035 light_info->glIndex = i;
2036 break;
2037 }
2038 }
2039 if (light_info->glIndex == -1)
2040 {
2041 /* Our tests show that Windows returns D3D_OK in this situation, even with
2042 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2043 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2044 * as well for those lights.
2045 *
2046 * TODO: Test how this affects rendering. */
2047 WARN("Too many concurrently active lights\n");
2048 return WINED3D_OK;
2049 }
2050
2051 /* i == light_info->glIndex */
2052 if (!device->isRecordingState)
2053 {
2054 device_invalidate_state(device, STATE_LIGHT_TYPE);
2055 device_invalidate_state(device, STATE_ACTIVELIGHT(i));
2056 }
2057 }
2058 }
2059
2060 return WINED3D_OK;
2061}
2062
2063HRESULT CDECL wined3d_device_get_light_enable(const struct wined3d_device *device, UINT light_idx, BOOL *enable)
2064{
2065 UINT hash_idx = LIGHTMAP_HASHFUNC(light_idx);
2066 struct wined3d_light_info *light_info = NULL;
2067 struct list *e;
2068
2069 TRACE("device %p, light_idx %u, enable %p.\n", device, light_idx, enable);
2070
2071 LIST_FOR_EACH(e, &device->stateBlock->state.light_map[hash_idx])
2072 {
2073 light_info = LIST_ENTRY(e, struct wined3d_light_info, entry);
2074 if (light_info->OriginalIndex == light_idx)
2075 break;
2076 light_info = NULL;
2077 }
2078
2079 if (!light_info)
2080 {
2081 TRACE("Light enabled state requested but light not defined.\n");
2082 return WINED3DERR_INVALIDCALL;
2083 }
2084 /* true is 128 according to SetLightEnable */
2085 *enable = light_info->enabled ? 128 : 0;
2086 return WINED3D_OK;
2087}
2088
2089HRESULT CDECL wined3d_device_set_clip_plane(struct wined3d_device *device,
2090 UINT plane_idx, const struct wined3d_vec4 *plane)
2091{
2092 TRACE("device %p, plane_idx %u, plane %p.\n", device, plane_idx, plane);
2093
2094 /* Validate plane_idx. */
2095 if (plane_idx >= device->adapter->gl_info.limits.clipplanes)
2096 {
2097 TRACE("Application has requested clipplane this device doesn't support.\n");
2098 return WINED3DERR_INVALIDCALL;
2099 }
2100
2101 device->updateStateBlock->changed.clipplane |= 1 << plane_idx;
2102
2103 if (!memcmp(&device->updateStateBlock->state.clip_planes[plane_idx], plane, sizeof(*plane)))
2104 {
2105 TRACE("Application is setting old values over, nothing to do.\n");
2106 return WINED3D_OK;
2107 }
2108
2109 device->updateStateBlock->state.clip_planes[plane_idx] = *plane;
2110
2111 /* Handle recording of state blocks. */
2112 if (device->isRecordingState)
2113 {
2114 TRACE("Recording... not performing anything.\n");
2115 return WINED3D_OK;
2116 }
2117
2118 device_invalidate_state(device, STATE_CLIPPLANE(plane_idx));
2119
2120 return WINED3D_OK;
2121}
2122
2123HRESULT CDECL wined3d_device_get_clip_plane(const struct wined3d_device *device,
2124 UINT plane_idx, struct wined3d_vec4 *plane)
2125{
2126 TRACE("device %p, plane_idx %u, plane %p.\n", device, plane_idx, plane);
2127
2128 /* Validate plane_idx. */
2129 if (plane_idx >= device->adapter->gl_info.limits.clipplanes)
2130 {
2131 TRACE("Application has requested clipplane this device doesn't support.\n");
2132 return WINED3DERR_INVALIDCALL;
2133 }
2134
2135 *plane = device->stateBlock->state.clip_planes[plane_idx];
2136
2137 return WINED3D_OK;
2138}
2139
2140HRESULT CDECL wined3d_device_set_clip_status(struct wined3d_device *device,
2141 const struct wined3d_clip_status *clip_status)
2142{
2143 FIXME("device %p, clip_status %p stub!\n", device, clip_status);
2144
2145 if (!clip_status)
2146 return WINED3DERR_INVALIDCALL;
2147
2148 return WINED3D_OK;
2149}
2150
2151HRESULT CDECL wined3d_device_get_clip_status(const struct wined3d_device *device,
2152 struct wined3d_clip_status *clip_status)
2153{
2154 FIXME("device %p, clip_status %p stub!\n", device, clip_status);
2155
2156 if (!clip_status)
2157 return WINED3DERR_INVALIDCALL;
2158
2159 return WINED3D_OK;
2160}
2161
2162void CDECL wined3d_device_set_material(struct wined3d_device *device, const struct wined3d_material *material)
2163{
2164 TRACE("device %p, material %p.\n", device, material);
2165
2166 device->updateStateBlock->changed.material = TRUE;
2167 device->updateStateBlock->state.material = *material;
2168
2169 /* Handle recording of state blocks */
2170 if (device->isRecordingState)
2171 {
2172 TRACE("Recording... not performing anything.\n");
2173 return;
2174 }
2175
2176 device_invalidate_state(device, STATE_MATERIAL);
2177}
2178
2179void CDECL wined3d_device_get_material(const struct wined3d_device *device, struct wined3d_material *material)
2180{
2181 TRACE("device %p, material %p.\n", device, material);
2182
2183 *material = device->updateStateBlock->state.material;
2184
2185 TRACE("diffuse {%.8e, %.8e, %.8e, %.8e}\n",
2186 material->diffuse.r, material->diffuse.g,
2187 material->diffuse.b, material->diffuse.a);
2188 TRACE("ambient {%.8e, %.8e, %.8e, %.8e}\n",
2189 material->ambient.r, material->ambient.g,
2190 material->ambient.b, material->ambient.a);
2191 TRACE("specular {%.8e, %.8e, %.8e, %.8e}\n",
2192 material->specular.r, material->specular.g,
2193 material->specular.b, material->specular.a);
2194 TRACE("emissive {%.8e, %.8e, %.8e, %.8e}\n",
2195 material->emissive.r, material->emissive.g,
2196 material->emissive.b, material->emissive.a);
2197 TRACE("power %.8e.\n", material->power);
2198}
2199
2200void CDECL wined3d_device_set_index_buffer(struct wined3d_device *device,
2201 struct wined3d_buffer *buffer, enum wined3d_format_id format_id)
2202{
2203 struct wined3d_buffer *prev_buffer;
2204
2205 TRACE("device %p, buffer %p, format %s.\n",
2206 device, buffer, debug_d3dformat(format_id));
2207
2208 prev_buffer = device->updateStateBlock->state.index_buffer;
2209
2210 device->updateStateBlock->changed.indices = TRUE;
2211 device->updateStateBlock->state.index_buffer = buffer;
2212 device->updateStateBlock->state.index_format = format_id;
2213
2214 /* Handle recording of state blocks. */
2215 if (device->isRecordingState)
2216 {
2217 TRACE("Recording... not performing anything.\n");
2218 if (buffer)
2219 wined3d_buffer_incref(buffer);
2220 if (prev_buffer)
2221 wined3d_buffer_decref(prev_buffer);
2222 return;
2223 }
2224
2225 if (prev_buffer != buffer)
2226 {
2227 device_invalidate_state(device, STATE_INDEXBUFFER);
2228 if (buffer)
2229 {
2230 InterlockedIncrement(&buffer->resource.bind_count);
2231 wined3d_buffer_incref(buffer);
2232 }
2233 if (prev_buffer)
2234 {
2235 InterlockedDecrement(&prev_buffer->resource.bind_count);
2236 wined3d_buffer_decref(prev_buffer);
2237 }
2238 }
2239}
2240
2241struct wined3d_buffer * CDECL wined3d_device_get_index_buffer(const struct wined3d_device *device,
2242 enum wined3d_format_id *format)
2243{
2244 TRACE("device %p, format %p.\n", device, format);
2245
2246 *format = device->stateBlock->state.index_format;
2247 return device->stateBlock->state.index_buffer;
2248}
2249
2250void CDECL wined3d_device_set_base_vertex_index(struct wined3d_device *device, INT base_index)
2251{
2252 TRACE("device %p, base_index %d.\n", device, base_index);
2253
2254 device->updateStateBlock->state.base_vertex_index = base_index;
2255}
2256
2257INT CDECL wined3d_device_get_base_vertex_index(const struct wined3d_device *device)
2258{
2259 TRACE("device %p.\n", device);
2260
2261 return device->stateBlock->state.base_vertex_index;
2262}
2263
2264void CDECL wined3d_device_set_viewport(struct wined3d_device *device, const struct wined3d_viewport *viewport)
2265{
2266 TRACE("device %p, viewport %p.\n", device, viewport);
2267 TRACE("x %u, y %u, w %u, h %u, min_z %.8e, max_z %.8e.\n",
2268 viewport->x, viewport->y, viewport->width, viewport->height, viewport->min_z, viewport->max_z);
2269
2270 device->updateStateBlock->changed.viewport = TRUE;
2271 device->updateStateBlock->state.viewport = *viewport;
2272
2273 /* Handle recording of state blocks */
2274 if (device->isRecordingState)
2275 {
2276 TRACE("Recording... not performing anything\n");
2277 return;
2278 }
2279
2280 device_invalidate_state(device, STATE_VIEWPORT);
2281}
2282
2283void CDECL wined3d_device_get_viewport(const struct wined3d_device *device, struct wined3d_viewport *viewport)
2284{
2285 TRACE("device %p, viewport %p.\n", device, viewport);
2286
2287 *viewport = device->stateBlock->state.viewport;
2288}
2289
2290static void resolve_depth_buffer(struct wined3d_state *state)
2291{
2292 struct wined3d_texture *texture = state->textures[0];
2293 struct wined3d_surface *depth_stencil, *surface;
2294
2295 if (!texture || texture->resource.type != WINED3D_RTYPE_TEXTURE
2296 || !(texture->resource.format->flags & WINED3DFMT_FLAG_DEPTH))
2297 return;
2298 surface = surface_from_resource(texture->sub_resources[0]);
2299 depth_stencil = state->fb->depth_stencil;
2300 if (!depth_stencil)
2301 return;
2302
2303 wined3d_surface_blt(surface, NULL, depth_stencil, NULL, 0, NULL, WINED3D_TEXF_POINT);
2304}
2305
2306void CDECL wined3d_device_set_render_state(struct wined3d_device *device,
2307 enum wined3d_render_state state, DWORD value)
2308{
2309 DWORD old_value = device->stateBlock->state.render_states[state];
2310
2311 TRACE("device %p, state %s (%#x), value %#x.\n", device, debug_d3drenderstate(state), state, value);
2312
2313 device->updateStateBlock->changed.renderState[state >> 5] |= 1 << (state & 0x1f);
2314 device->updateStateBlock->state.render_states[state] = value;
2315
2316 /* Handle recording of state blocks. */
2317 if (device->isRecordingState)
2318 {
2319 TRACE("Recording... not performing anything.\n");
2320 return;
2321 }
2322
2323 /* Compared here and not before the assignment to allow proper stateblock recording. */
2324 if (value == old_value)
2325 TRACE("Application is setting the old value over, nothing to do.\n");
2326 else
2327 device_invalidate_state(device, STATE_RENDER(state));
2328
2329 if (state == WINED3D_RS_POINTSIZE && value == WINED3D_RESZ_CODE)
2330 {
2331 TRACE("RESZ multisampled depth buffer resolve triggered.\n");
2332 resolve_depth_buffer(&device->stateBlock->state);
2333 }
2334}
2335
2336DWORD CDECL wined3d_device_get_render_state(const struct wined3d_device *device, enum wined3d_render_state state)
2337{
2338 TRACE("device %p, state %s (%#x).\n", device, debug_d3drenderstate(state), state);
2339
2340 return device->stateBlock->state.render_states[state];
2341}
2342
2343void CDECL wined3d_device_set_sampler_state(struct wined3d_device *device,
2344 UINT sampler_idx, enum wined3d_sampler_state state, DWORD value)
2345{
2346 DWORD old_value;
2347
2348 TRACE("device %p, sampler_idx %u, state %s, value %#x.\n",
2349 device, sampler_idx, debug_d3dsamplerstate(state), value);
2350
2351 if (sampler_idx >= WINED3DVERTEXTEXTURESAMPLER0 && sampler_idx <= WINED3DVERTEXTEXTURESAMPLER3)
2352 sampler_idx -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2353
2354 if (sampler_idx >= sizeof(device->stateBlock->state.sampler_states)
2355 / sizeof(*device->stateBlock->state.sampler_states))
2356 {
2357 WARN("Invalid sampler %u.\n", sampler_idx);
2358 return; /* Windows accepts overflowing this array ... we do not. */
2359 }
2360
2361 old_value = device->stateBlock->state.sampler_states[sampler_idx][state];
2362 device->updateStateBlock->state.sampler_states[sampler_idx][state] = value;
2363 device->updateStateBlock->changed.samplerState[sampler_idx] |= 1 << state;
2364
2365 /* Handle recording of state blocks. */
2366 if (device->isRecordingState)
2367 {
2368 TRACE("Recording... not performing anything.\n");
2369 return;
2370 }
2371
2372 if (old_value == value)
2373 {
2374 TRACE("Application is setting the old value over, nothing to do.\n");
2375 return;
2376 }
2377
2378 device_invalidate_state(device, STATE_SAMPLER(sampler_idx));
2379}
2380
2381DWORD CDECL wined3d_device_get_sampler_state(const struct wined3d_device *device,
2382 UINT sampler_idx, enum wined3d_sampler_state state)
2383{
2384 TRACE("device %p, sampler_idx %u, state %s.\n",
2385 device, sampler_idx, debug_d3dsamplerstate(state));
2386
2387 if (sampler_idx >= WINED3DVERTEXTEXTURESAMPLER0 && sampler_idx <= WINED3DVERTEXTEXTURESAMPLER3)
2388 sampler_idx -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2389
2390 if (sampler_idx >= sizeof(device->stateBlock->state.sampler_states)
2391 / sizeof(*device->stateBlock->state.sampler_states))
2392 {
2393 WARN("Invalid sampler %u.\n", sampler_idx);
2394 return 0; /* Windows accepts overflowing this array ... we do not. */
2395 }
2396
2397 return device->stateBlock->state.sampler_states[sampler_idx][state];
2398}
2399
2400void CDECL wined3d_device_set_scissor_rect(struct wined3d_device *device, const RECT *rect)
2401{
2402 TRACE("device %p, rect %s.\n", device, wine_dbgstr_rect(rect));
2403
2404 device->updateStateBlock->changed.scissorRect = TRUE;
2405 if (EqualRect(&device->updateStateBlock->state.scissor_rect, rect))
2406 {
2407 TRACE("App is setting the old scissor rectangle over, nothing to do.\n");
2408 return;
2409 }
2410 CopyRect(&device->updateStateBlock->state.scissor_rect, rect);
2411
2412 if (device->isRecordingState)
2413 {
2414 TRACE("Recording... not performing anything.\n");
2415 return;
2416 }
2417
2418 device_invalidate_state(device, STATE_SCISSORRECT);
2419}
2420
2421void CDECL wined3d_device_get_scissor_rect(const struct wined3d_device *device, RECT *rect)
2422{
2423 TRACE("device %p, rect %p.\n", device, rect);
2424
2425 *rect = device->updateStateBlock->state.scissor_rect;
2426 TRACE("Returning rect %s.\n", wine_dbgstr_rect(rect));
2427}
2428
2429void CDECL wined3d_device_set_vertex_declaration(struct wined3d_device *device,
2430 struct wined3d_vertex_declaration *declaration)
2431{
2432 struct wined3d_vertex_declaration *prev = device->updateStateBlock->state.vertex_declaration;
2433
2434 TRACE("device %p, declaration %p.\n", device, declaration);
2435
2436 if (declaration)
2437 wined3d_vertex_declaration_incref(declaration);
2438 if (prev)
2439 wined3d_vertex_declaration_decref(prev);
2440
2441 device->updateStateBlock->state.vertex_declaration = declaration;
2442 device->updateStateBlock->changed.vertexDecl = TRUE;
2443
2444 if (device->isRecordingState)
2445 {
2446 TRACE("Recording... not performing anything.\n");
2447 return;
2448 }
2449
2450 if (declaration == prev)
2451 {
2452 /* Checked after the assignment to allow proper stateblock recording. */
2453 TRACE("Application is setting the old declaration over, nothing to do.\n");
2454 return;
2455 }
2456
2457 device_invalidate_state(device, STATE_VDECL);
2458}
2459
2460struct wined3d_vertex_declaration * CDECL wined3d_device_get_vertex_declaration(const struct wined3d_device *device)
2461{
2462 TRACE("device %p.\n", device);
2463
2464 return device->stateBlock->state.vertex_declaration;
2465}
2466
2467void CDECL wined3d_device_set_vertex_shader(struct wined3d_device *device, struct wined3d_shader *shader)
2468{
2469 struct wined3d_shader *prev = device->updateStateBlock->state.vertex_shader;
2470
2471 TRACE("device %p, shader %p.\n", device, shader);
2472
2473 if (shader)
2474 wined3d_shader_incref(shader);
2475 if (prev)
2476 wined3d_shader_decref(prev);
2477
2478 device->updateStateBlock->state.vertex_shader = shader;
2479 device->updateStateBlock->changed.vertexShader = TRUE;
2480
2481 if (device->isRecordingState)
2482 {
2483 TRACE("Recording... not performing anything.\n");
2484 return;
2485 }
2486
2487 if (shader == prev)
2488 {
2489 TRACE("Application is setting the old shader over, nothing to do.\n");
2490 return;
2491 }
2492
2493 device_invalidate_state(device, STATE_VSHADER);
2494}
2495
2496struct wined3d_shader * CDECL wined3d_device_get_vertex_shader(const struct wined3d_device *device)
2497{
2498 TRACE("device %p.\n", device);
2499
2500 return device->stateBlock->state.vertex_shader;
2501}
2502
2503void CDECL wined3d_device_set_vs_cb(struct wined3d_device *device, UINT idx, struct wined3d_buffer *buffer)
2504{
2505 struct wined3d_buffer *prev;
2506
2507 TRACE("device %p, idx %u, buffer %p.\n", device, idx, buffer);
2508
2509 if (idx >= MAX_CONSTANT_BUFFERS)
2510 {
2511 WARN("Invalid constant buffer index %u.\n", idx);
2512 return;
2513 }
2514
2515 prev = device->updateStateBlock->state.vs_cb[idx];
2516 device->updateStateBlock->state.vs_cb[idx] = buffer;
2517
2518 if (device->isRecordingState)
2519 {
2520 if (buffer)
2521 wined3d_buffer_incref(buffer);
2522 if (prev)
2523 wined3d_buffer_decref(prev);
2524 return;
2525 }
2526
2527 if (prev != buffer)
2528 {
2529 if (buffer)
2530 {
2531 InterlockedIncrement(&buffer->resource.bind_count);
2532 wined3d_buffer_incref(buffer);
2533 }
2534 if (prev)
2535 {
2536 InterlockedDecrement(&prev->resource.bind_count);
2537 wined3d_buffer_decref(prev);
2538 }
2539 }
2540}
2541
2542struct wined3d_buffer * CDECL wined3d_device_get_vs_cb(const struct wined3d_device *device, UINT idx)
2543{
2544 TRACE("device %p, idx %u.\n", device, idx);
2545
2546 if (idx >= MAX_CONSTANT_BUFFERS)
2547 {
2548 WARN("Invalid constant buffer index %u.\n", idx);
2549 return NULL;
2550 }
2551
2552 return device->stateBlock->state.vs_cb[idx];
2553}
2554
2555void CDECL wined3d_device_set_vs_sampler(struct wined3d_device *device, UINT idx, struct wined3d_sampler *sampler)
2556{
2557 struct wined3d_sampler *prev;
2558
2559 TRACE("device %p, idx %u, sampler %p.\n", device, idx, sampler);
2560
2561 if (idx >= MAX_SAMPLER_OBJECTS)
2562 {
2563 WARN("Invalid sampler index %u.\n", idx);
2564 return;
2565 }
2566
2567 prev = device->updateStateBlock->state.vs_sampler[idx];
2568 device->updateStateBlock->state.vs_sampler[idx] = sampler;
2569
2570 if (sampler)
2571 wined3d_sampler_incref(sampler);
2572 if (prev)
2573 wined3d_sampler_decref(prev);
2574}
2575
2576struct wined3d_sampler * CDECL wined3d_device_get_vs_sampler(const struct wined3d_device *device, UINT idx)
2577{
2578 TRACE("device %p, idx %u.\n", device, idx);
2579
2580 if (idx >= MAX_SAMPLER_OBJECTS)
2581 {
2582 WARN("Invalid sampler index %u.\n", idx);
2583 return NULL;
2584 }
2585
2586 return device->stateBlock->state.vs_sampler[idx];
2587}
2588
2589HRESULT CDECL wined3d_device_set_vs_consts_b(struct wined3d_device *device,
2590 UINT start_register, const BOOL *constants, UINT bool_count)
2591{
2592 UINT count = min(bool_count, MAX_CONST_B - start_register);
2593 UINT i;
2594
2595 TRACE("device %p, start_register %u, constants %p, bool_count %u.\n",
2596 device, start_register, constants, bool_count);
2597
2598 if (!constants || start_register >= MAX_CONST_B)
2599 return WINED3DERR_INVALIDCALL;
2600
2601 memcpy(&device->updateStateBlock->state.vs_consts_b[start_register], constants, count * sizeof(BOOL));
2602 for (i = 0; i < count; ++i)
2603 TRACE("Set BOOL constant %u to %s.\n", start_register + i, constants[i] ? "true" : "false");
2604
2605 for (i = start_register; i < count + start_register; ++i)
2606 device->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
2607
2608 if (!device->isRecordingState)
2609 device_invalidate_state(device, STATE_VERTEXSHADERCONSTANT);
2610
2611 return WINED3D_OK;
2612}
2613
2614HRESULT CDECL wined3d_device_get_vs_consts_b(const struct wined3d_device *device,
2615 UINT start_register, BOOL *constants, UINT bool_count)
2616{
2617 UINT count = min(bool_count, MAX_CONST_B - start_register);
2618
2619 TRACE("device %p, start_register %u, constants %p, bool_count %u.\n",
2620 device, start_register, constants, bool_count);
2621
2622 if (!constants || start_register >= MAX_CONST_B)
2623 return WINED3DERR_INVALIDCALL;
2624
2625 memcpy(constants, &device->stateBlock->state.vs_consts_b[start_register], count * sizeof(BOOL));
2626
2627 return WINED3D_OK;
2628}
2629
2630HRESULT CDECL wined3d_device_set_vs_consts_i(struct wined3d_device *device,
2631 UINT start_register, const int *constants, UINT vector4i_count)
2632{
2633 UINT count = min(vector4i_count, MAX_CONST_I - start_register);
2634 UINT i;
2635
2636 TRACE("device %p, start_register %u, constants %p, vector4i_count %u.\n",
2637 device, start_register, constants, vector4i_count);
2638
2639 if (!constants || start_register >= MAX_CONST_I)
2640 return WINED3DERR_INVALIDCALL;
2641
2642 memcpy(&device->updateStateBlock->state.vs_consts_i[start_register * 4], constants, count * sizeof(int) * 4);
2643 for (i = 0; i < count; ++i)
2644 TRACE("Set INT constant %u to {%d, %d, %d, %d}.\n", start_register + i,
2645 constants[i * 4], constants[i * 4 + 1],
2646 constants[i * 4 + 2], constants[i * 4 + 3]);
2647
2648 for (i = start_register; i < count + start_register; ++i)
2649 device->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
2650
2651 if (!device->isRecordingState)
2652 device_invalidate_state(device, STATE_VERTEXSHADERCONSTANT);
2653
2654 return WINED3D_OK;
2655}
2656
2657HRESULT CDECL wined3d_device_get_vs_consts_i(const struct wined3d_device *device,
2658 UINT start_register, int *constants, UINT vector4i_count)
2659{
2660 UINT count = min(vector4i_count, MAX_CONST_I - start_register);
2661
2662 TRACE("device %p, start_register %u, constants %p, vector4i_count %u.\n",
2663 device, start_register, constants, vector4i_count);
2664
2665 if (!constants || start_register >= MAX_CONST_I)
2666 return WINED3DERR_INVALIDCALL;
2667
2668 memcpy(constants, &device->stateBlock->state.vs_consts_i[start_register * 4], count * sizeof(int) * 4);
2669 return WINED3D_OK;
2670}
2671
2672HRESULT CDECL wined3d_device_set_vs_consts_f(struct wined3d_device *device,
2673 UINT start_register, const float *constants, UINT vector4f_count)
2674{
2675 UINT i;
2676 const struct wined3d_d3d_info *d3d_info = &device->adapter->d3d_info;
2677
2678 TRACE("device %p, start_register %u, constants %p, vector4f_count %u.\n",
2679 device, start_register, constants, vector4f_count);
2680
2681 /* Specifically test start_register > limit to catch MAX_UINT overflows
2682 * when adding start_register + vector4f_count. */
2683 if (!constants
2684 || start_register + vector4f_count > d3d_info->limits.vs_uniform_count
2685 || start_register > d3d_info->limits.vs_uniform_count)
2686 return WINED3DERR_INVALIDCALL;
2687
2688 memcpy(&device->updateStateBlock->state.vs_consts_f[start_register * 4],
2689 constants, vector4f_count * sizeof(float) * 4);
2690 if (TRACE_ON(d3d))
2691 {
2692 for (i = 0; i < vector4f_count; ++i)
2693 TRACE("Set FLOAT constant %u to {%.8e, %.8e, %.8e, %.8e}.\n", start_register + i,
2694 constants[i * 4], constants[i * 4 + 1],
2695 constants[i * 4 + 2], constants[i * 4 + 3]);
2696 }
2697
2698 if (!device->isRecordingState)
2699 {
2700 device->shader_backend->shader_update_float_vertex_constants(device, start_register, vector4f_count);
2701 device_invalidate_state(device, STATE_VERTEXSHADERCONSTANT);
2702 }
2703
2704 memset(device->updateStateBlock->changed.vertexShaderConstantsF + start_register, 1,
2705 sizeof(*device->updateStateBlock->changed.vertexShaderConstantsF) * vector4f_count);
2706
2707 return WINED3D_OK;
2708}
2709
2710HRESULT CDECL wined3d_device_get_vs_consts_f(const struct wined3d_device *device,
2711 UINT start_register, float *constants, UINT vector4f_count)
2712{
2713 const struct wined3d_d3d_info *d3d_info = &device->adapter->d3d_info;
2714 int count = min(vector4f_count, d3d_info->limits.vs_uniform_count - start_register);
2715
2716 TRACE("device %p, start_register %u, constants %p, vector4f_count %u.\n",
2717 device, start_register, constants, vector4f_count);
2718
2719 if (!constants || count < 0)
2720 return WINED3DERR_INVALIDCALL;
2721
2722 memcpy(constants, &device->stateBlock->state.vs_consts_f[start_register * 4], count * sizeof(float) * 4);
2723
2724 return WINED3D_OK;
2725}
2726
2727static void device_invalidate_texture_stage(const struct wined3d_device *device, DWORD stage)
2728{
2729 DWORD i;
2730
2731 for (i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
2732 {
2733 device_invalidate_state(device, STATE_TEXTURESTAGE(stage, i));
2734 }
2735}
2736
2737static void device_map_stage(struct wined3d_device *device, DWORD stage, DWORD unit)
2738{
2739 DWORD i = device->rev_tex_unit_map[unit];
2740 DWORD j = device->texUnitMap[stage];
2741
2742 device->texUnitMap[stage] = unit;
2743 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
2744 device->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
2745
2746 device->rev_tex_unit_map[unit] = stage;
2747 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
2748 device->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
2749}
2750
2751static void device_update_fixed_function_usage_map(struct wined3d_device *device)
2752{
2753 UINT i;
2754
2755 device->fixed_function_usage_map = 0;
2756 for (i = 0; i < MAX_TEXTURES; ++i)
2757 {
2758 const struct wined3d_state *state = &device->stateBlock->state;
2759 enum wined3d_texture_op color_op = state->texture_states[i][WINED3D_TSS_COLOR_OP];
2760 enum wined3d_texture_op alpha_op = state->texture_states[i][WINED3D_TSS_ALPHA_OP];
2761 DWORD color_arg1 = state->texture_states[i][WINED3D_TSS_COLOR_ARG1] & WINED3DTA_SELECTMASK;
2762 DWORD color_arg2 = state->texture_states[i][WINED3D_TSS_COLOR_ARG2] & WINED3DTA_SELECTMASK;
2763 DWORD color_arg3 = state->texture_states[i][WINED3D_TSS_COLOR_ARG0] & WINED3DTA_SELECTMASK;
2764 DWORD alpha_arg1 = state->texture_states[i][WINED3D_TSS_ALPHA_ARG1] & WINED3DTA_SELECTMASK;
2765 DWORD alpha_arg2 = state->texture_states[i][WINED3D_TSS_ALPHA_ARG2] & WINED3DTA_SELECTMASK;
2766 DWORD alpha_arg3 = state->texture_states[i][WINED3D_TSS_ALPHA_ARG0] & WINED3DTA_SELECTMASK;
2767
2768 /* Not used, and disable higher stages. */
2769 if (color_op == WINED3D_TOP_DISABLE)
2770 break;
2771
2772 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3D_TOP_SELECT_ARG2)
2773 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3D_TOP_SELECT_ARG1)
2774 || ((color_arg3 == WINED3DTA_TEXTURE)
2775 && (color_op == WINED3D_TOP_MULTIPLY_ADD || color_op == WINED3D_TOP_LERP))
2776 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3D_TOP_SELECT_ARG2)
2777 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3D_TOP_SELECT_ARG1)
2778 || ((alpha_arg3 == WINED3DTA_TEXTURE)
2779 && (alpha_op == WINED3D_TOP_MULTIPLY_ADD || alpha_op == WINED3D_TOP_LERP)))
2780 device->fixed_function_usage_map |= (1 << i);
2781
2782 if ((color_op == WINED3D_TOP_BUMPENVMAP || color_op == WINED3D_TOP_BUMPENVMAP_LUMINANCE)
2783 && i < MAX_TEXTURES - 1)
2784 device->fixed_function_usage_map |= (1 << (i + 1));
2785 }
2786}
2787
2788static void device_map_fixed_function_samplers(struct wined3d_device *device, const struct wined3d_d3d_info *d3d_info)
2789{
2790 unsigned int i, tex;
2791 WORD ffu_map;
2792
2793 device_update_fixed_function_usage_map(device);
2794 ffu_map = device->fixed_function_usage_map;
2795
2796 if (d3d_info->limits.ffp_textures == d3d_info->limits.ffp_blend_stages
2797 || device->stateBlock->state.lowest_disabled_stage <= d3d_info->limits.ffp_textures)
2798 {
2799 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
2800 {
2801 if (!(ffu_map & 1)) continue;
2802
2803 if (device->texUnitMap[i] != i)
2804 {
2805 device_map_stage(device, i, i);
2806 device_invalidate_state(device, STATE_SAMPLER(i));
2807 device_invalidate_texture_stage(device, i);
2808 }
2809 }
2810 return;
2811 }
2812
2813 /* Now work out the mapping */
2814 tex = 0;
2815 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
2816 {
2817 if (!(ffu_map & 1)) continue;
2818
2819 if (device->texUnitMap[i] != tex)
2820 {
2821 device_map_stage(device, i, tex);
2822 device_invalidate_state(device, STATE_SAMPLER(i));
2823 device_invalidate_texture_stage(device, i);
2824 }
2825
2826 ++tex;
2827 }
2828}
2829
2830static void device_map_psamplers(struct wined3d_device *device, const struct wined3d_d3d_info *d3d_info)
2831{
2832 const enum wined3d_sampler_texture_type *sampler_type =
2833 device->stateBlock->state.pixel_shader->reg_maps.sampler_type;
2834 unsigned int i;
2835
2836 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i)
2837 {
2838 if (sampler_type[i] && device->texUnitMap[i] != i)
2839 {
2840 device_map_stage(device, i, i);
2841 device_invalidate_state(device, STATE_SAMPLER(i));
2842 if (i < d3d_info->limits.ffp_blend_stages)
2843 device_invalidate_texture_stage(device, i);
2844 }
2845 }
2846}
2847
2848static BOOL device_unit_free_for_vs(const struct wined3d_device *device,
2849 const enum wined3d_sampler_texture_type *pshader_sampler_tokens,
2850 const enum wined3d_sampler_texture_type *vshader_sampler_tokens, DWORD unit)
2851{
2852 DWORD current_mapping = device->rev_tex_unit_map[unit];
2853
2854 /* Not currently used */
2855 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
2856
2857 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
2858 /* Used by a fragment sampler */
2859
2860 if (!pshader_sampler_tokens) {
2861 /* No pixel shader, check fixed function */
2862 return current_mapping >= MAX_TEXTURES || !(device->fixed_function_usage_map & (1 << current_mapping));
2863 }
2864
2865 /* Pixel shader, check the shader's sampler map */
2866 return !pshader_sampler_tokens[current_mapping];
2867 }
2868
2869 /* Used by a vertex sampler */
2870 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
2871}
2872
2873static void device_map_vsamplers(struct wined3d_device *device, BOOL ps, const struct wined3d_gl_info *gl_info)
2874{
2875 const enum wined3d_sampler_texture_type *vshader_sampler_type =
2876 device->stateBlock->state.vertex_shader->reg_maps.sampler_type;
2877 const enum wined3d_sampler_texture_type *pshader_sampler_type = NULL;
2878 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
2879 int i;
2880
2881 if (ps)
2882 {
2883 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
2884 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
2885 pshader_sampler_type = device->stateBlock->state.pixel_shader->reg_maps.sampler_type;
2886 }
2887
2888 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
2889 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
2890 if (vshader_sampler_type[i])
2891 {
2892 if (device->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
2893 {
2894 /* Already mapped somewhere */
2895 continue;
2896 }
2897
2898 while (start >= 0)
2899 {
2900 if (device_unit_free_for_vs(device, pshader_sampler_type, vshader_sampler_type, start))
2901 {
2902 device_map_stage(device, vsampler_idx, start);
2903 device_invalidate_state(device, STATE_SAMPLER(vsampler_idx));
2904
2905 --start;
2906 break;
2907 }
2908
2909 --start;
2910 }
2911 }
2912 }
2913}
2914
2915void device_update_tex_unit_map(struct wined3d_device *device)
2916{
2917 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
2918 const struct wined3d_d3d_info *d3d_info = &device->adapter->d3d_info;
2919 const struct wined3d_state *state = &device->stateBlock->state;
2920 BOOL vs = use_vs(state);
2921 BOOL ps = use_ps(state);
2922 /*
2923 * Rules are:
2924 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
2925 * that would be really messy and require shader recompilation
2926 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
2927 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
2928 */
2929 if (ps)
2930 device_map_psamplers(device, d3d_info);
2931 else
2932 device_map_fixed_function_samplers(device, d3d_info);
2933
2934 if (vs)
2935 device_map_vsamplers(device, ps, gl_info);
2936}
2937
2938void CDECL wined3d_device_set_pixel_shader(struct wined3d_device *device, struct wined3d_shader *shader)
2939{
2940 struct wined3d_shader *prev = device->updateStateBlock->state.pixel_shader;
2941
2942 TRACE("device %p, shader %p.\n", device, shader);
2943
2944 if (shader)
2945 wined3d_shader_incref(shader);
2946 if (prev)
2947 wined3d_shader_decref(prev);
2948
2949 device->updateStateBlock->state.pixel_shader = shader;
2950 device->updateStateBlock->changed.pixelShader = TRUE;
2951
2952 if (device->isRecordingState)
2953 {
2954 TRACE("Recording... not performing anything.\n");
2955 return;
2956 }
2957
2958 if (shader == prev)
2959 {
2960 TRACE("Application is setting the old shader over, nothing to do.\n");
2961 return;
2962 }
2963
2964 device_invalidate_state(device, STATE_PIXELSHADER);
2965}
2966
2967struct wined3d_shader * CDECL wined3d_device_get_pixel_shader(const struct wined3d_device *device)
2968{
2969 TRACE("device %p.\n", device);
2970
2971 return device->stateBlock->state.pixel_shader;
2972}
2973
2974void CDECL wined3d_device_set_ps_cb(struct wined3d_device *device, UINT idx, struct wined3d_buffer *buffer)
2975{
2976 struct wined3d_buffer *prev;
2977
2978 TRACE("device %p, idx %u, buffer %p.\n", device, idx, buffer);
2979
2980 if (idx >= MAX_CONSTANT_BUFFERS)
2981 {
2982 WARN("Invalid constant buffer index %u.\n", idx);
2983 return;
2984 }
2985
2986 prev = device->updateStateBlock->state.ps_cb[idx];
2987 device->updateStateBlock->state.ps_cb[idx] = buffer;
2988
2989 if (device->isRecordingState)
2990 {
2991 if (buffer)
2992 wined3d_buffer_incref(buffer);
2993 if (prev)
2994 wined3d_buffer_decref(prev);
2995 return;
2996 }
2997
2998 if (prev != buffer)
2999 {
3000 if (buffer)
3001 {
3002 InterlockedIncrement(&buffer->resource.bind_count);
3003 wined3d_buffer_incref(buffer);
3004 }
3005 if (prev)
3006 {
3007 InterlockedDecrement(&prev->resource.bind_count);
3008 wined3d_buffer_decref(prev);
3009 }
3010 }
3011}
3012
3013struct wined3d_buffer * CDECL wined3d_device_get_ps_cb(const struct wined3d_device *device, UINT idx)
3014{
3015 TRACE("device %p, idx %u.\n", device, idx);
3016
3017 if (idx >= MAX_CONSTANT_BUFFERS)
3018 {
3019 WARN("Invalid constant buffer index %u.\n", idx);
3020 return NULL;
3021 }
3022
3023 return device->stateBlock->state.ps_cb[idx];
3024}
3025
3026void CDECL wined3d_device_set_ps_sampler(struct wined3d_device *device, UINT idx, struct wined3d_sampler *sampler)
3027{
3028 struct wined3d_sampler *prev;
3029
3030 TRACE("device %p, idx %u, sampler %p.\n", device, idx, sampler);
3031
3032 if (idx >= MAX_SAMPLER_OBJECTS)
3033 {
3034 WARN("Invalid sampler index %u.\n", idx);
3035 return;
3036 }
3037
3038 prev = device->updateStateBlock->state.ps_sampler[idx];
3039 device->updateStateBlock->state.ps_sampler[idx] = sampler;
3040
3041 if (sampler)
3042 wined3d_sampler_incref(sampler);
3043 if (prev)
3044 wined3d_sampler_decref(prev);
3045}
3046
3047struct wined3d_sampler * CDECL wined3d_device_get_ps_sampler(const struct wined3d_device *device, UINT idx)
3048{
3049 TRACE("device %p, idx %u.\n", device, idx);
3050
3051 if (idx >= MAX_SAMPLER_OBJECTS)
3052 {
3053 WARN("Invalid sampler index %u.\n", idx);
3054 return NULL;
3055 }
3056
3057 return device->stateBlock->state.ps_sampler[idx];
3058}
3059
3060HRESULT CDECL wined3d_device_set_ps_consts_b(struct wined3d_device *device,
3061 UINT start_register, const BOOL *constants, UINT bool_count)
3062{
3063 UINT count = min(bool_count, MAX_CONST_B - start_register);
3064 UINT i;
3065
3066 TRACE("device %p, start_register %u, constants %p, bool_count %u.\n",
3067 device, start_register, constants, bool_count);
3068
3069 if (!constants || start_register >= MAX_CONST_B)
3070 return WINED3DERR_INVALIDCALL;
3071
3072 memcpy(&device->updateStateBlock->state.ps_consts_b[start_register], constants, count * sizeof(BOOL));
3073 for (i = 0; i < count; ++i)
3074 TRACE("Set BOOL constant %u to %s.\n", start_register + i, constants[i] ? "true" : "false");
3075
3076 for (i = start_register; i < count + start_register; ++i)
3077 device->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3078
3079 if (!device->isRecordingState)
3080 device_invalidate_state(device, STATE_PIXELSHADERCONSTANT);
3081
3082 return WINED3D_OK;
3083}
3084
3085HRESULT CDECL wined3d_device_get_ps_consts_b(const struct wined3d_device *device,
3086 UINT start_register, BOOL *constants, UINT bool_count)
3087{
3088 UINT count = min(bool_count, MAX_CONST_B - start_register);
3089
3090 TRACE("device %p, start_register %u, constants %p, bool_count %u.\n",
3091 device, start_register, constants, bool_count);
3092
3093 if (!constants || start_register >= MAX_CONST_B)
3094 return WINED3DERR_INVALIDCALL;
3095
3096 memcpy(constants, &device->stateBlock->state.ps_consts_b[start_register], count * sizeof(BOOL));
3097
3098 return WINED3D_OK;
3099}
3100
3101HRESULT CDECL wined3d_device_set_ps_consts_i(struct wined3d_device *device,
3102 UINT start_register, const int *constants, UINT vector4i_count)
3103{
3104 UINT count = min(vector4i_count, MAX_CONST_I - start_register);
3105 UINT i;
3106
3107 TRACE("device %p, start_register %u, constants %p, vector4i_count %u.\n",
3108 device, start_register, constants, vector4i_count);
3109
3110 if (!constants || start_register >= MAX_CONST_I)
3111 return WINED3DERR_INVALIDCALL;
3112
3113 memcpy(&device->updateStateBlock->state.ps_consts_i[start_register * 4], constants, count * sizeof(int) * 4);
3114 for (i = 0; i < count; ++i)
3115 TRACE("Set INT constant %u to {%d, %d, %d, %d}.\n", start_register + i,
3116 constants[i * 4], constants[i * 4 + 1],
3117 constants[i * 4 + 2], constants[i * 4 + 3]);
3118
3119 for (i = start_register; i < count + start_register; ++i)
3120 device->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3121
3122 if (!device->isRecordingState)
3123 device_invalidate_state(device, STATE_PIXELSHADERCONSTANT);
3124
3125 return WINED3D_OK;
3126}
3127
3128HRESULT CDECL wined3d_device_get_ps_consts_i(const struct wined3d_device *device,
3129 UINT start_register, int *constants, UINT vector4i_count)
3130{
3131 UINT count = min(vector4i_count, MAX_CONST_I - start_register);
3132
3133 TRACE("device %p, start_register %u, constants %p, vector4i_count %u.\n",
3134 device, start_register, constants, vector4i_count);
3135
3136 if (!constants || start_register >= MAX_CONST_I)
3137 return WINED3DERR_INVALIDCALL;
3138
3139 memcpy(constants, &device->stateBlock->state.ps_consts_i[start_register * 4], count * sizeof(int) * 4);
3140
3141 return WINED3D_OK;
3142}
3143
3144HRESULT CDECL wined3d_device_set_ps_consts_f(struct wined3d_device *device,
3145 UINT start_register, const float *constants, UINT vector4f_count)
3146{
3147 UINT i;
3148 const struct wined3d_d3d_info *d3d_info = &device->adapter->d3d_info;
3149
3150 TRACE("device %p, start_register %u, constants %p, vector4f_count %u.\n",
3151 device, start_register, constants, vector4f_count);
3152
3153 /* Specifically test start_register > limit to catch MAX_UINT overflows
3154 * when adding start_register + vector4f_count. */
3155 if (!constants
3156 || start_register + vector4f_count > d3d_info->limits.ps_uniform_count
3157 || start_register > d3d_info->limits.ps_uniform_count)
3158 return WINED3DERR_INVALIDCALL;
3159
3160 memcpy(&device->updateStateBlock->state.ps_consts_f[start_register * 4],
3161 constants, vector4f_count * sizeof(float) * 4);
3162 if (TRACE_ON(d3d))
3163 {
3164 for (i = 0; i < vector4f_count; ++i)
3165 TRACE("Set FLOAT constant %u to {%.8e, %.8e, %.8e, %.8e}.\n", start_register + i,
3166 constants[i * 4], constants[i * 4 + 1],
3167 constants[i * 4 + 2], constants[i * 4 + 3]);
3168 }
3169
3170 if (!device->isRecordingState)
3171 {
3172 device->shader_backend->shader_update_float_pixel_constants(device, start_register, vector4f_count);
3173 device_invalidate_state(device, STATE_PIXELSHADERCONSTANT);
3174 }
3175
3176 memset(device->updateStateBlock->changed.pixelShaderConstantsF + start_register, 1,
3177 sizeof(*device->updateStateBlock->changed.pixelShaderConstantsF) * vector4f_count);
3178
3179 return WINED3D_OK;
3180}
3181
3182HRESULT CDECL wined3d_device_get_ps_consts_f(const struct wined3d_device *device,
3183 UINT start_register, float *constants, UINT vector4f_count)
3184{
3185 const struct wined3d_d3d_info *d3d_info = &device->adapter->d3d_info;
3186 int count = min(vector4f_count, d3d_info->limits.ps_uniform_count - start_register);
3187
3188 TRACE("device %p, start_register %u, constants %p, vector4f_count %u.\n",
3189 device, start_register, constants, vector4f_count);
3190
3191 if (!constants || count < 0)
3192 return WINED3DERR_INVALIDCALL;
3193
3194 memcpy(constants, &device->stateBlock->state.ps_consts_f[start_register * 4], count * sizeof(float) * 4);
3195
3196 return WINED3D_OK;
3197}
3198
3199void CDECL wined3d_device_set_geometry_shader(struct wined3d_device *device, struct wined3d_shader *shader)
3200{
3201 struct wined3d_shader *prev = device->updateStateBlock->state.geometry_shader;
3202
3203 TRACE("device %p, shader %p.\n", device, shader);
3204
3205 if (shader)
3206 wined3d_shader_incref(shader);
3207 if (prev)
3208 wined3d_shader_decref(prev);
3209
3210 device->updateStateBlock->state.geometry_shader = shader;
3211
3212 if (device->isRecordingState || shader == prev)
3213 return;
3214
3215 device_invalidate_state(device, STATE_GEOMETRY_SHADER);
3216}
3217
3218struct wined3d_shader * CDECL wined3d_device_get_geometry_shader(const struct wined3d_device *device)
3219{
3220 TRACE("device %p.\n", device);
3221
3222 return device->stateBlock->state.geometry_shader;
3223}
3224
3225void CDECL wined3d_device_set_gs_cb(struct wined3d_device *device, UINT idx, struct wined3d_buffer *buffer)
3226{
3227 struct wined3d_buffer *prev;
3228
3229 TRACE("device %p, idx %u, buffer %p.\n", device, idx, buffer);
3230
3231 if (idx >= MAX_CONSTANT_BUFFERS)
3232 {
3233 WARN("Invalid constant buffer index %u.\n", idx);
3234 return;
3235 }
3236
3237 prev = device->updateStateBlock->state.gs_cb[idx];
3238 device->updateStateBlock->state.gs_cb[idx] = buffer;
3239
3240 if (device->isRecordingState)
3241 {
3242 if (buffer)
3243 wined3d_buffer_incref(buffer);
3244 if (prev)
3245 wined3d_buffer_decref(prev);
3246 return;
3247 }
3248
3249 if (prev != buffer)
3250 {
3251 if (buffer)
3252 {
3253 InterlockedIncrement(&buffer->resource.bind_count);
3254 wined3d_buffer_incref(buffer);
3255 }
3256 if (prev)
3257 {
3258 InterlockedDecrement(&prev->resource.bind_count);
3259 wined3d_buffer_decref(prev);
3260 }
3261 }
3262}
3263
3264struct wined3d_buffer * CDECL wined3d_device_get_gs_cb(const struct wined3d_device *device, UINT idx)
3265{
3266 TRACE("device %p, idx %u.\n", device, idx);
3267
3268 if (idx >= MAX_CONSTANT_BUFFERS)
3269 {
3270 WARN("Invalid constant buffer index %u.\n", idx);
3271 return NULL;
3272 }
3273
3274 return device->stateBlock->state.gs_cb[idx];
3275}
3276
3277void CDECL wined3d_device_set_gs_sampler(struct wined3d_device *device, UINT idx, struct wined3d_sampler *sampler)
3278{
3279 struct wined3d_sampler *prev;
3280
3281 TRACE("device %p, idx %u, sampler %p.\n", device, idx, sampler);
3282
3283 if (idx >= MAX_SAMPLER_OBJECTS)
3284 {
3285 WARN("Invalid sampler index %u.\n", idx);
3286 return;
3287 }
3288
3289 prev = device->updateStateBlock->state.gs_sampler[idx];
3290 device->updateStateBlock->state.gs_sampler[idx] = sampler;
3291
3292 if (sampler)
3293 wined3d_sampler_incref(sampler);
3294 if (prev)
3295 wined3d_sampler_decref(prev);
3296}
3297
3298struct wined3d_sampler * CDECL wined3d_device_get_gs_sampler(const struct wined3d_device *device, UINT idx)
3299{
3300 TRACE("device %p, idx %u.\n", device, idx);
3301
3302 if (idx >= MAX_SAMPLER_OBJECTS)
3303 {
3304 WARN("Invalid sampler index %u.\n", idx);
3305 return NULL;
3306 }
3307
3308 return device->stateBlock->state.gs_sampler[idx];
3309}
3310
3311/* Context activation is done by the caller. */
3312/* Do not call while under the GL lock. */
3313#define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3314static HRESULT process_vertices_strided(const struct wined3d_device *device, DWORD dwDestIndex, DWORD dwCount,
3315 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD flags,
3316 DWORD DestFVF)
3317{
3318 struct wined3d_matrix mat, proj_mat, view_mat, world_mat;
3319 struct wined3d_viewport vp;
3320 UINT vertex_size;
3321 unsigned int i;
3322 BYTE *dest_ptr;
3323 BOOL doClip;
3324 DWORD numTextures;
3325 HRESULT hr;
3326
3327 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3328 {
3329 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3330 }
3331
3332 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3333 {
3334 ERR("Source has no position mask\n");
3335 return WINED3DERR_INVALIDCALL;
3336 }
3337
3338 if (device->stateBlock->state.render_states[WINED3D_RS_CLIPPING])
3339 {
3340 static BOOL warned = FALSE;
3341 /*
3342 * The clipping code is not quite correct. Some things need
3343 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3344 * so disable clipping for now.
3345 * (The graphics in Half-Life are broken, and my processvertices
3346 * test crashes with IDirect3DDevice3)
3347 doClip = TRUE;
3348 */
3349 doClip = FALSE;
3350 if(!warned) {
3351 warned = TRUE;
3352 FIXME("Clipping is broken and disabled for now\n");
3353 }
3354 }
3355 else
3356 doClip = FALSE;
3357
3358 vertex_size = get_flexible_vertex_size(DestFVF);
3359 if (FAILED(hr = wined3d_buffer_map(dest, dwDestIndex * vertex_size, dwCount * vertex_size, &dest_ptr, 0)))
3360 {
3361 WARN("Failed to map buffer, hr %#x.\n", hr);
3362 return hr;
3363 }
3364
3365 wined3d_device_get_transform(device, WINED3D_TS_VIEW, &view_mat);
3366 wined3d_device_get_transform(device, WINED3D_TS_PROJECTION, &proj_mat);
3367 wined3d_device_get_transform(device, WINED3D_TS_WORLD_MATRIX(0), &world_mat);
3368
3369 TRACE("View mat:\n");
3370 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);
3371 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);
3372 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);
3373 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);
3374
3375 TRACE("Proj mat:\n");
3376 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);
3377 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);
3378 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);
3379 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);
3380
3381 TRACE("World mat:\n");
3382 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);
3383 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);
3384 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);
3385 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);
3386
3387 /* Get the viewport */
3388 wined3d_device_get_viewport(device, &vp);
3389 TRACE("viewport x %u, y %u, width %u, height %u, min_z %.8e, max_z %.8e.\n",
3390 vp.x, vp.y, vp.width, vp.height, vp.min_z, vp.max_z);
3391
3392 multiply_matrix(&mat,&view_mat,&world_mat);
3393 multiply_matrix(&mat,&proj_mat,&mat);
3394
3395 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3396
3397 for (i = 0; i < dwCount; i+= 1) {
3398 unsigned int tex_index;
3399
3400 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3401 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3402 /* The position first */
3403 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3404 const float *p = (const float *)(element->data.addr + i * element->stride);
3405 float x, y, z, rhw;
3406 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3407
3408 /* Multiplication with world, view and projection matrix */
3409 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);
3410 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);
3411 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);
3412 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);
3413
3414 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3415
3416 /* WARNING: The following things are taken from d3d7 and were not yet checked
3417 * against d3d8 or d3d9!
3418 */
3419
3420 /* Clipping conditions: From msdn
3421 *
3422 * A vertex is clipped if it does not match the following requirements
3423 * -rhw < x <= rhw
3424 * -rhw < y <= rhw
3425 * 0 < z <= rhw
3426 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3427 *
3428 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3429 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3430 *
3431 */
3432
3433 if( !doClip ||
3434 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3435 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3436 ( rhw > eps ) ) ) {
3437
3438 /* "Normal" viewport transformation (not clipped)
3439 * 1) The values are divided by rhw
3440 * 2) The y axis is negative, so multiply it with -1
3441 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3442 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3443 * 4) Multiply x with Width/2 and add Width/2
3444 * 5) The same for the height
3445 * 6) Add the viewpoint X and Y to the 2D coordinates and
3446 * The minimum Z value to z
3447 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3448 *
3449 * Well, basically it's simply a linear transformation into viewport
3450 * coordinates
3451 */
3452
3453 x /= rhw;
3454 y /= rhw;
3455 z /= rhw;
3456
3457 y *= -1;
3458
3459 x *= vp.width / 2;
3460 y *= vp.height / 2;
3461 z *= vp.max_z - vp.min_z;
3462
3463 x += vp.width / 2 + vp.x;
3464 y += vp.height / 2 + vp.y;
3465 z += vp.min_z;
3466
3467 rhw = 1 / rhw;
3468 } else {
3469 /* That vertex got clipped
3470 * Contrary to OpenGL it is not dropped completely, it just
3471 * undergoes a different calculation.
3472 */
3473 TRACE("Vertex got clipped\n");
3474 x += rhw;
3475 y += rhw;
3476
3477 x /= 2;
3478 y /= 2;
3479
3480 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3481 * outside of the main vertex buffer memory. That needs some more
3482 * investigation...
3483 */
3484 }
3485
3486 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3487
3488
3489 ( (float *) dest_ptr)[0] = x;
3490 ( (float *) dest_ptr)[1] = y;
3491 ( (float *) dest_ptr)[2] = z;
3492 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3493
3494 dest_ptr += 3 * sizeof(float);
3495
3496 if ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW)
3497 dest_ptr += sizeof(float);
3498 }
3499
3500 if (DestFVF & WINED3DFVF_PSIZE)
3501 dest_ptr += sizeof(DWORD);
3502
3503 if (DestFVF & WINED3DFVF_NORMAL)
3504 {
3505 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
3506 const float *normal = (const float *)(element->data.addr + i * element->stride);
3507 /* AFAIK this should go into the lighting information */
3508 FIXME("Didn't expect the destination to have a normal\n");
3509 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3510 }
3511
3512 if (DestFVF & WINED3DFVF_DIFFUSE)
3513 {
3514 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
3515 const DWORD *color_d = (const DWORD *)(element->data.addr + i * element->stride);
3516 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
3517 {
3518 static BOOL warned = FALSE;
3519
3520 if(!warned) {
3521 ERR("No diffuse color in source, but destination has one\n");
3522 warned = TRUE;
3523 }
3524
3525 *( (DWORD *) dest_ptr) = 0xffffffff;
3526 dest_ptr += sizeof(DWORD);
3527 }
3528 else
3529 {
3530 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3531 }
3532 }
3533
3534 if (DestFVF & WINED3DFVF_SPECULAR)
3535 {
3536 /* What's the color value in the feedback buffer? */
3537 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
3538 const DWORD *color_s = (const DWORD *)(element->data.addr + i * element->stride);
3539 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
3540 {
3541 static BOOL warned = FALSE;
3542
3543 if(!warned) {
3544 ERR("No specular color in source, but destination has one\n");
3545 warned = TRUE;
3546 }
3547
3548 *(DWORD *)dest_ptr = 0xff000000;
3549 dest_ptr += sizeof(DWORD);
3550 }
3551 else
3552 {
3553 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3554 }
3555 }
3556
3557 for (tex_index = 0; tex_index < numTextures; ++tex_index)
3558 {
3559 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
3560 const float *tex_coord = (const float *)(element->data.addr + i * element->stride);
3561 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
3562 {
3563 ERR("No source texture, but destination requests one\n");
3564 dest_ptr += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3565 }
3566 else
3567 {
3568 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3569 }
3570 }
3571 }
3572
3573 wined3d_buffer_unmap(dest);
3574
3575 return WINED3D_OK;
3576}
3577#undef copy_and_next
3578
3579/* Do not call while under the GL lock. */
3580HRESULT CDECL wined3d_device_process_vertices(struct wined3d_device *device,
3581 UINT src_start_idx, UINT dst_idx, UINT vertex_count, struct wined3d_buffer *dst_buffer,
3582 const struct wined3d_vertex_declaration *declaration, DWORD flags, DWORD dst_fvf)
3583{
3584 struct wined3d_state *state = &device->stateBlock->state;
3585 struct wined3d_stream_info stream_info;
3586 const struct wined3d_gl_info *gl_info;
3587 struct wined3d_context *context;
3588 struct wined3d_shader *vs;
3589 unsigned int i;
3590 HRESULT hr;
3591
3592 TRACE("device %p, src_start_idx %u, dst_idx %u, vertex_count %u, "
3593 "dst_buffer %p, declaration %p, flags %#x, dst_fvf %#x.\n",
3594 device, src_start_idx, dst_idx, vertex_count,
3595 dst_buffer, declaration, flags, dst_fvf);
3596
3597 if (declaration)
3598 FIXME("Output vertex declaration not implemented yet.\n");
3599
3600 /* Need any context to write to the vbo. */
3601 context = context_acquire(device, NULL);
3602 gl_info = context->gl_info;
3603
3604 vs = state->vertex_shader;
3605 state->vertex_shader = NULL;
3606 device_stream_info_from_declaration(device, &stream_info);
3607 state->vertex_shader = vs;
3608
3609 /* We can't convert FROM a VBO, and vertex buffers used to source into
3610 * process_vertices() are unlikely to ever be used for drawing. Release
3611 * VBOs in those buffers and fix up the stream_info structure.
3612 *
3613 * Also apply the start index. */
3614 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
3615 {
3616 struct wined3d_stream_info_element *e;
3617
3618 if (!(stream_info.use_map & (1 << i)))
3619 continue;
3620
3621 e = &stream_info.elements[i];
3622 if (e->data.buffer_object)
3623 {
3624 struct wined3d_buffer *vb = state->streams[e->stream_idx].buffer;
3625 e->data.buffer_object = 0;
3626 e->data.addr = (BYTE *)((ULONG_PTR)e->data.addr + (ULONG_PTR)buffer_get_sysmem(vb, gl_info));
3627 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
3628 vb->buffer_object = 0;
3629 }
3630 if (e->data.addr)
3631 e->data.addr += e->stride * src_start_idx;
3632 }
3633
3634 hr = process_vertices_strided(device, dst_idx, vertex_count,
3635 &stream_info, dst_buffer, flags, dst_fvf);
3636
3637 context_release(context);
3638
3639 return hr;
3640}
3641
3642void CDECL wined3d_device_set_texture_stage_state(struct wined3d_device *device,
3643 UINT stage, enum wined3d_texture_stage_state state, DWORD value)
3644{
3645 const struct wined3d_d3d_info *d3d_info = &device->adapter->d3d_info;
3646 DWORD old_value;
3647
3648 TRACE("device %p, stage %u, state %s, value %#x.\n",
3649 device, stage, debug_d3dtexturestate(state), value);
3650
3651 if (state > WINED3D_HIGHEST_TEXTURE_STATE)
3652 {
3653 WARN("Invalid state %#x passed.\n", state);
3654 return;
3655 }
3656
3657 if (stage >= d3d_info->limits.ffp_blend_stages)
3658 {
3659 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
3660 stage, d3d_info->limits.ffp_blend_stages - 1);
3661 return;
3662 }
3663
3664 old_value = device->updateStateBlock->state.texture_states[stage][state];
3665 device->updateStateBlock->changed.textureState[stage] |= 1 << state;
3666 device->updateStateBlock->state.texture_states[stage][state] = value;
3667
3668 if (device->isRecordingState)
3669 {
3670 TRACE("Recording... not performing anything.\n");
3671 return;
3672 }
3673
3674 /* Checked after the assignments to allow proper stateblock recording. */
3675 if (old_value == value)
3676 {
3677 TRACE("Application is setting the old value over, nothing to do.\n");
3678 return;
3679 }
3680
3681 if (stage > device->stateBlock->state.lowest_disabled_stage
3682 && device->StateTable[STATE_TEXTURESTAGE(0, state)].representative
3683 == STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP))
3684 {
3685 /* Colorop change above lowest disabled stage? That won't change
3686 * anything in the GL setup. Changes in other states are important on
3687 * disabled stages too. */
3688 return;
3689 }
3690
3691 if (state == WINED3D_TSS_COLOR_OP)
3692 {
3693 unsigned int i;
3694
3695 if (value == WINED3D_TOP_DISABLE && old_value != WINED3D_TOP_DISABLE)
3696 {
3697 /* Previously enabled stage disabled now. Make sure to dirtify
3698 * all enabled stages above stage, they have to be disabled.
3699 *
3700 * The current stage is dirtified below. */
3701 for (i = stage + 1; i < device->stateBlock->state.lowest_disabled_stage; ++i)
3702 {
3703 TRACE("Additionally dirtifying stage %u.\n", i);
3704 device_invalidate_state(device, STATE_TEXTURESTAGE(i, WINED3D_TSS_COLOR_OP));
3705 }
3706 device->stateBlock->state.lowest_disabled_stage = stage;
3707 TRACE("New lowest disabled: %u.\n", stage);
3708 }
3709 else if (value != WINED3D_TOP_DISABLE && old_value == WINED3D_TOP_DISABLE)
3710 {
3711 /* Previously disabled stage enabled. Stages above it may need
3712 * enabling. Stage must be lowest_disabled_stage here, if it's
3713 * bigger success is returned above, and stages below the lowest
3714 * disabled stage can't be enabled (because they are enabled
3715 * already).
3716 *
3717 * Again stage stage doesn't need to be dirtified here, it is
3718 * handled below. */
3719 for (i = stage + 1; i < d3d_info->limits.ffp_blend_stages; ++i)
3720 {
3721 if (device->updateStateBlock->state.texture_states[i][WINED3D_TSS_COLOR_OP] == WINED3D_TOP_DISABLE)
3722 break;
3723 TRACE("Additionally dirtifying stage %u due to enable.\n", i);
3724 device_invalidate_state(device, STATE_TEXTURESTAGE(i, WINED3D_TSS_COLOR_OP));
3725 }
3726 device->stateBlock->state.lowest_disabled_stage = i;
3727 TRACE("New lowest disabled: %u.\n", i);
3728 }
3729 }
3730
3731 device_invalidate_state(device, STATE_TEXTURESTAGE(stage, state));
3732}
3733
3734DWORD CDECL wined3d_device_get_texture_stage_state(const struct wined3d_device *device,
3735 UINT stage, enum wined3d_texture_stage_state state)
3736{
3737 TRACE("device %p, stage %u, state %s.\n",
3738 device, stage, debug_d3dtexturestate(state));
3739
3740 if (state > WINED3D_HIGHEST_TEXTURE_STATE)
3741 {
3742 WARN("Invalid state %#x passed.\n", state);
3743 return 0;
3744 }
3745
3746 return device->updateStateBlock->state.texture_states[stage][state];
3747}
3748
3749HRESULT CDECL wined3d_device_set_texture(struct wined3d_device *device,
3750 UINT stage, struct wined3d_texture *texture)
3751{
3752 const struct wined3d_d3d_info *d3d_info = &device->adapter->d3d_info;
3753 struct wined3d_texture *prev;
3754
3755 TRACE("device %p, stage %u, texture %p.\n", device, stage, texture);
3756
3757 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
3758 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3759
3760 /* Windows accepts overflowing this array... we do not. */
3761 if (stage >= sizeof(device->stateBlock->state.textures) / sizeof(*device->stateBlock->state.textures))
3762 {
3763 WARN("Ignoring invalid stage %u.\n", stage);
3764 return WINED3D_OK;
3765 }
3766
3767 if (texture && texture->resource.pool == WINED3D_POOL_SCRATCH)
3768 {
3769 WARN("Rejecting attempt to set scratch texture.\n");
3770 return WINED3DERR_INVALIDCALL;
3771 }
3772
3773 device->updateStateBlock->changed.textures |= 1 << stage;
3774
3775 prev = device->updateStateBlock->state.textures[stage];
3776 TRACE("Previous texture %p.\n", prev);
3777
3778 if (texture == prev)
3779 {
3780 TRACE("App is setting the same texture again, nothing to do.\n");
3781 return WINED3D_OK;
3782 }
3783
3784 TRACE("Setting new texture to %p.\n", texture);
3785 device->updateStateBlock->state.textures[stage] = texture;
3786
3787 if (device->isRecordingState)
3788 {
3789 TRACE("Recording... not performing anything\n");
3790
3791 if (texture) wined3d_texture_incref(texture);
3792 if (prev) wined3d_texture_decref(prev);
3793
3794 return WINED3D_OK;
3795 }
3796
3797 if (texture)
3798 {
3799 LONG bind_count = InterlockedIncrement(&texture->resource.bind_count);
3800
3801 wined3d_texture_incref(texture);
3802
3803 if (!prev || texture->target != prev->target)
3804 device_invalidate_state(device, STATE_PIXELSHADER);
3805
3806 if (!prev && stage < d3d_info->limits.ffp_blend_stages)
3807 {
3808 /* The source arguments for color and alpha ops have different
3809 * meanings when a NULL texture is bound, so the COLOR_OP and
3810 * ALPHA_OP have to be dirtified. */
3811 device_invalidate_state(device, STATE_TEXTURESTAGE(stage, WINED3D_TSS_COLOR_OP));
3812 device_invalidate_state(device, STATE_TEXTURESTAGE(stage, WINED3D_TSS_ALPHA_OP));
3813 }
3814
3815 if (bind_count == 1)
3816 texture->sampler = stage;
3817 }
3818
3819 if (prev)
3820 {
3821 LONG bind_count = InterlockedDecrement(&prev->resource.bind_count);
3822
3823 if (!texture && stage < d3d_info->limits.ffp_blend_stages)
3824 {
3825 device_invalidate_state(device, STATE_TEXTURESTAGE(stage, WINED3D_TSS_COLOR_OP));
3826 device_invalidate_state(device, STATE_TEXTURESTAGE(stage, WINED3D_TSS_ALPHA_OP));
3827 }
3828
3829 if (bind_count && prev->sampler == stage)
3830 {
3831 unsigned int i;
3832
3833 /* Search for other stages the texture is bound to. Shouldn't
3834 * happen if applications bind textures to a single stage only. */
3835 TRACE("Searching for other stages the texture is bound to.\n");
3836 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
3837 {
3838 if (device->updateStateBlock->state.textures[i] == prev)
3839 {
3840 TRACE("Texture is also bound to stage %u.\n", i);
3841 prev->sampler = i;
3842 break;
3843 }
3844 }
3845 }
3846
3847 wined3d_texture_decref(prev);
3848 }
3849
3850 device_invalidate_state(device, STATE_SAMPLER(stage));
3851
3852 return WINED3D_OK;
3853}
3854
3855struct wined3d_texture * CDECL wined3d_device_get_texture(const struct wined3d_device *device, UINT stage)
3856{
3857 TRACE("device %p, stage %u.\n", device, stage);
3858
3859 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
3860 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3861
3862 if (stage >= sizeof(device->stateBlock->state.textures) / sizeof(*device->stateBlock->state.textures))
3863 {
3864 WARN("Ignoring invalid stage %u.\n", stage);
3865 return NULL; /* Windows accepts overflowing this array ... we do not. */
3866 }
3867
3868 return device->stateBlock->state.textures[stage];
3869}
3870
3871HRESULT CDECL wined3d_device_get_back_buffer(const struct wined3d_device *device, UINT swapchain_idx,
3872 UINT backbuffer_idx, enum wined3d_backbuffer_type backbuffer_type, struct wined3d_surface **backbuffer)
3873{
3874 struct wined3d_swapchain *swapchain;
3875
3876 TRACE("device %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
3877 device, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
3878
3879 if (!(swapchain = wined3d_device_get_swapchain(device, swapchain_idx)))
3880 return WINED3DERR_INVALIDCALL;
3881
3882 if (!(*backbuffer = wined3d_swapchain_get_back_buffer(swapchain, backbuffer_idx, backbuffer_type)))
3883 return WINED3DERR_INVALIDCALL;
3884 return WINED3D_OK;
3885}
3886
3887HRESULT CDECL wined3d_device_get_device_caps(const struct wined3d_device *device, WINED3DCAPS *caps)
3888{
3889 TRACE("device %p, caps %p.\n", device, caps);
3890
3891 return wined3d_get_device_caps(device->wined3d, device->adapter->ordinal,
3892 device->create_parms.device_type, caps);
3893}
3894
3895HRESULT CDECL wined3d_device_get_display_mode(const struct wined3d_device *device, UINT swapchain_idx,
3896 struct wined3d_display_mode *mode, enum wined3d_display_rotation *rotation)
3897{
3898 struct wined3d_swapchain *swapchain;
3899
3900 TRACE("device %p, swapchain_idx %u, mode %p, rotation %p.\n",
3901 device, swapchain_idx, mode, rotation);
3902
3903 if (!(swapchain = wined3d_device_get_swapchain(device, swapchain_idx)))
3904 return WINED3DERR_INVALIDCALL;
3905
3906 return wined3d_swapchain_get_display_mode(swapchain, mode, rotation);
3907}
3908
3909HRESULT CDECL wined3d_device_begin_stateblock(struct wined3d_device *device)
3910{
3911 struct wined3d_stateblock *stateblock;
3912 HRESULT hr;
3913
3914 TRACE("device %p.\n", device);
3915
3916 if (device->isRecordingState)
3917 return WINED3DERR_INVALIDCALL;
3918
3919 hr = wined3d_stateblock_create(device, WINED3D_SBT_RECORDED, &stateblock);
3920 if (FAILED(hr))
3921 return hr;
3922
3923 wined3d_stateblock_decref(device->updateStateBlock);
3924 device->updateStateBlock = stateblock;
3925 device->isRecordingState = TRUE;
3926
3927 TRACE("Recording stateblock %p.\n", stateblock);
3928
3929 return WINED3D_OK;
3930}
3931
3932HRESULT CDECL wined3d_device_end_stateblock(struct wined3d_device *device,
3933 struct wined3d_stateblock **stateblock)
3934{
3935 struct wined3d_stateblock *object = device->updateStateBlock;
3936
3937 TRACE("device %p, stateblock %p.\n", device, stateblock);
3938
3939 if (!device->isRecordingState)
3940 {
3941 WARN("Not recording.\n");
3942 *stateblock = NULL;
3943 return WINED3DERR_INVALIDCALL;
3944 }
3945
3946 stateblock_init_contained_states(object);
3947
3948 *stateblock = object;
3949 device->isRecordingState = FALSE;
3950 device->updateStateBlock = device->stateBlock;
3951 wined3d_stateblock_incref(device->updateStateBlock);
3952
3953 TRACE("Returning stateblock %p.\n", *stateblock);
3954
3955 return WINED3D_OK;
3956}
3957
3958HRESULT CDECL wined3d_device_begin_scene(struct wined3d_device *device)
3959{
3960 /* At the moment we have no need for any functionality at the beginning
3961 * of a scene. */
3962 TRACE("device %p.\n", device);
3963
3964 if (device->inScene)
3965 {
3966 WARN("Already in scene, returning WINED3DERR_INVALIDCALL.\n");
3967 return WINED3DERR_INVALIDCALL;
3968 }
3969 device->inScene = TRUE;
3970 return WINED3D_OK;
3971}
3972
3973HRESULT CDECL wined3d_device_end_scene(struct wined3d_device *device)
3974{
3975 struct wined3d_context *context;
3976
3977 TRACE("device %p.\n", device);
3978
3979 if (!device->inScene)
3980 {
3981 WARN("Not in scene, returning WINED3DERR_INVALIDCALL.\n");
3982 return WINED3DERR_INVALIDCALL;
3983 }
3984
3985 context = context_acquire(device, NULL);
3986 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
3987 context->gl_info->gl_ops.gl.p_glFlush();
3988 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
3989 * fails. */
3990 context_release(context);
3991
3992 device->inScene = FALSE;
3993 return WINED3D_OK;
3994}
3995
3996HRESULT CDECL wined3d_device_present(const struct wined3d_device *device, const RECT *src_rect,
3997 const RECT *dst_rect, HWND dst_window_override, const RGNDATA *dirty_region, DWORD flags)
3998{
3999 UINT i;
4000
4001 TRACE("device %p, src_rect %s, dst_rect %s, dst_window_override %p, dirty_region %p, flags %#x.\n",
4002 device, wine_dbgstr_rect(src_rect), wine_dbgstr_rect(dst_rect),
4003 dst_window_override, dirty_region, flags);
4004
4005 for (i = 0; i < device->swapchain_count; ++i)
4006 {
4007 wined3d_swapchain_present(device->swapchains[i], src_rect,
4008 dst_rect, dst_window_override, dirty_region, flags);
4009 }
4010
4011 return WINED3D_OK;
4012}
4013
4014/* Do not call while under the GL lock. */
4015HRESULT CDECL wined3d_device_clear(struct wined3d_device *device, DWORD rect_count,
4016 const RECT *rects, DWORD flags, const struct wined3d_color *color, float depth, DWORD stencil)
4017{
4018 RECT draw_rect;
4019
4020 TRACE("device %p, rect_count %u, rects %p, flags %#x, color {%.8e, %.8e, %.8e, %.8e}, depth %.8e, stencil %u.\n",
4021 device, rect_count, rects, flags, color->r, color->g, color->b, color->a, depth, stencil);
4022
4023 if (!rect_count && rects)
4024 {
4025 WARN("Rects is %p, but rect_count is 0, ignoring clear\n", rects);
4026 return WINED3D_OK;
4027 }
4028
4029 if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL))
4030 {
4031 struct wined3d_surface *ds = device->fb.depth_stencil;
4032 if (!ds)
4033 {
4034 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4035 /* TODO: What about depth stencil buffers without stencil bits? */
4036 return WINED3DERR_INVALIDCALL;
4037 }
4038 else if (flags & WINED3DCLEAR_TARGET)
4039 {
4040 if (ds->resource.width < device->fb.render_targets[0]->resource.width
4041 || ds->resource.height < device->fb.render_targets[0]->resource.height)
4042 {
4043 WARN("Silently ignoring depth and target clear with mismatching sizes\n");
4044 return WINED3D_OK;
4045 }
4046 }
4047 }
4048
4049 wined3d_get_draw_rect(&device->stateBlock->state, &draw_rect);
4050 device_clear_render_targets(device, device->adapter->gl_info.limits.buffers,
4051 &device->fb, rect_count, rects, &draw_rect, flags, color, depth, stencil);
4052
4053 return WINED3D_OK;
4054}
4055
4056void CDECL wined3d_device_set_primitive_type(struct wined3d_device *device,
4057 enum wined3d_primitive_type primitive_type)
4058{
4059 GLenum gl_primitive_type, prev;
4060
4061 TRACE("device %p, primitive_type %s\n", device, debug_d3dprimitivetype(primitive_type));
4062
4063 device->updateStateBlock->changed.primitive_type = TRUE;
4064 gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4065 prev = device->updateStateBlock->state.gl_primitive_type;
4066 device->updateStateBlock->state.gl_primitive_type = gl_primitive_type;
4067 if (!device->isRecordingState && gl_primitive_type != prev
4068 && (gl_primitive_type == GL_POINTS || prev == GL_POINTS))
4069 device_invalidate_state(device, STATE_POINT_SIZE_ENABLE);
4070}
4071
4072void CDECL wined3d_device_get_primitive_type(const struct wined3d_device *device,
4073 enum wined3d_primitive_type *primitive_type)
4074{
4075 TRACE("device %p, primitive_type %p\n", device, primitive_type);
4076
4077 *primitive_type = d3d_primitive_type_from_gl(device->stateBlock->state.gl_primitive_type);
4078
4079 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4080}
4081
4082HRESULT CDECL wined3d_device_draw_primitive(struct wined3d_device *device, UINT start_vertex, UINT vertex_count)
4083{
4084 TRACE("device %p, start_vertex %u, vertex_count %u.\n", device, start_vertex, vertex_count);
4085
4086 if (!device->stateBlock->state.vertex_declaration)
4087 {
4088 WARN("Called without a valid vertex declaration set.\n");
4089 return WINED3DERR_INVALIDCALL;
4090 }
4091
4092 if (device->stateBlock->state.load_base_vertex_index)
4093 {
4094 device->stateBlock->state.load_base_vertex_index = 0;
4095 device_invalidate_state(device, STATE_BASEVERTEXINDEX);
4096 }
4097
4098 /* Account for the loading offset due to index buffers. Instead of
4099 * reloading all sources correct it with the startvertex parameter. */
4100 draw_primitive(device, start_vertex, vertex_count, 0, 0, FALSE);
4101 return WINED3D_OK;
4102}
4103
4104HRESULT CDECL wined3d_device_draw_indexed_primitive(struct wined3d_device *device, UINT start_idx, UINT index_count)
4105{
4106 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
4107
4108 TRACE("device %p, start_idx %u, index_count %u.\n", device, start_idx, index_count);
4109
4110 if (!device->stateBlock->state.index_buffer)
4111 {
4112 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4113 * without an index buffer set. (The first time at least...)
4114 * D3D8 simply dies, but I doubt it can do much harm to return
4115 * D3DERR_INVALIDCALL there as well. */
4116 WARN("Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL.\n");
4117 return WINED3DERR_INVALIDCALL;
4118 }
4119
4120 if (!device->stateBlock->state.vertex_declaration)
4121 {
4122 WARN("Called without a valid vertex declaration set.\n");
4123 return WINED3DERR_INVALIDCALL;
4124 }
4125
4126 if (!gl_info->supported[ARB_DRAW_ELEMENTS_BASE_VERTEX] &&
4127 device->stateBlock->state.load_base_vertex_index != device->stateBlock->state.base_vertex_index)
4128 {
4129 device->stateBlock->state.load_base_vertex_index = device->stateBlock->state.base_vertex_index;
4130 device_invalidate_state(device, STATE_BASEVERTEXINDEX);
4131 }
4132
4133 draw_primitive(device, start_idx, index_count, 0, 0, TRUE);
4134
4135 return WINED3D_OK;
4136}
4137
4138void CDECL wined3d_device_draw_indexed_primitive_instanced(struct wined3d_device *device,
4139 UINT start_idx, UINT index_count, UINT start_instance, UINT instance_count)
4140{
4141 TRACE("device %p, start_idx %u, index_count %u.\n", device, start_idx, index_count);
4142
4143 draw_primitive(device, start_idx, index_count, start_instance, instance_count, TRUE);
4144}
4145
4146/* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4147static HRESULT device_update_volume(struct wined3d_device *device,
4148 struct wined3d_volume *src_volume, struct wined3d_volume *dst_volume)
4149{
4150 struct wined3d_map_desc src;
4151 struct wined3d_map_desc dst;
4152 HRESULT hr;
4153
4154 TRACE("device %p, src_volume %p, dst_volume %p.\n",
4155 device, src_volume, dst_volume);
4156
4157 /* TODO: Implement direct loading into the gl volume instead of using
4158 * memcpy and dirtification to improve loading performance. */
4159 if (FAILED(hr = wined3d_volume_map(src_volume, &src, NULL, WINED3D_MAP_READONLY)))
4160 return hr;
4161 if (FAILED(hr = wined3d_volume_map(dst_volume, &dst, NULL, WINED3D_MAP_DISCARD)))
4162 {
4163 wined3d_volume_unmap(src_volume);
4164 return hr;
4165 }
4166
4167 memcpy(dst.data, src.data, dst_volume->resource.size);
4168
4169 hr = wined3d_volume_unmap(dst_volume);
4170 if (FAILED(hr))
4171 wined3d_volume_unmap(src_volume);
4172 else
4173 hr = wined3d_volume_unmap(src_volume);
4174
4175 return hr;
4176}
4177
4178HRESULT CDECL wined3d_device_update_texture(struct wined3d_device *device,
4179 struct wined3d_texture *src_texture, struct wined3d_texture *dst_texture)
4180{
4181 enum wined3d_resource_type type;
4182 unsigned int level_count, i;
4183 HRESULT hr;
4184
4185 TRACE("device %p, src_texture %p, dst_texture %p.\n", device, src_texture, dst_texture);
4186
4187 /* Verify that the source and destination textures are non-NULL. */
4188 if (!src_texture || !dst_texture)
4189 {
4190 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4191 return WINED3DERR_INVALIDCALL;
4192 }
4193
4194 if (src_texture == dst_texture)
4195 {
4196 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4197 return WINED3DERR_INVALIDCALL;
4198 }
4199
4200 /* Verify that the source and destination textures are the same type. */
4201 type = src_texture->resource.type;
4202 if (dst_texture->resource.type != type)
4203 {
4204 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4205 return WINED3DERR_INVALIDCALL;
4206 }
4207
4208 /* Check that both textures have the identical numbers of levels. */
4209 level_count = wined3d_texture_get_level_count(src_texture);
4210 if (wined3d_texture_get_level_count(dst_texture) != level_count)
4211 {
4212 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4213 return WINED3DERR_INVALIDCALL;
4214 }
4215
4216 /* Make sure that the destination texture is loaded. */
4217 dst_texture->texture_ops->texture_preload(dst_texture, SRGB_RGB);
4218
4219 /* Update every surface level of the texture. */
4220 switch (type)
4221 {
4222 case WINED3D_RTYPE_TEXTURE:
4223 {
4224 struct wined3d_surface *src_surface;
4225 struct wined3d_surface *dst_surface;
4226
4227 for (i = 0; i < level_count; ++i)
4228 {
4229 src_surface = surface_from_resource(wined3d_texture_get_sub_resource(src_texture, i));
4230 dst_surface = surface_from_resource(wined3d_texture_get_sub_resource(dst_texture, i));
4231 hr = wined3d_device_update_surface(device, src_surface, NULL, dst_surface, NULL);
4232 if (FAILED(hr))
4233 {
4234 WARN("Failed to update surface, hr %#x.\n", hr);
4235 return hr;
4236 }
4237 }
4238 break;
4239 }
4240
4241 case WINED3D_RTYPE_CUBE_TEXTURE:
4242 {
4243 struct wined3d_surface *src_surface;
4244 struct wined3d_surface *dst_surface;
4245
4246 for (i = 0; i < level_count * 6; ++i)
4247 {
4248 src_surface = surface_from_resource(wined3d_texture_get_sub_resource(src_texture, i));
4249 dst_surface = surface_from_resource(wined3d_texture_get_sub_resource(dst_texture, i));
4250 hr = wined3d_device_update_surface(device, src_surface, NULL, dst_surface, NULL);
4251 if (FAILED(hr))
4252 {
4253 WARN("Failed to update surface, hr %#x.\n", hr);
4254 return hr;
4255 }
4256 }
4257 break;
4258 }
4259
4260 case WINED3D_RTYPE_VOLUME_TEXTURE:
4261 {
4262 for (i = 0; i < level_count; ++i)
4263 {
4264 hr = device_update_volume(device,
4265 volume_from_resource(wined3d_texture_get_sub_resource(src_texture, i)),
4266 volume_from_resource(wined3d_texture_get_sub_resource(dst_texture, i)));
4267 if (FAILED(hr))
4268 {
4269 WARN("Failed to update volume, hr %#x.\n", hr);
4270 return hr;
4271 }
4272 }
4273 break;
4274 }
4275
4276 default:
4277 FIXME("Unsupported texture type %#x.\n", type);
4278 return WINED3DERR_INVALIDCALL;
4279 }
4280
4281 return WINED3D_OK;
4282}
4283
4284HRESULT CDECL wined3d_device_get_front_buffer_data(const struct wined3d_device *device,
4285 UINT swapchain_idx, struct wined3d_surface *dst_surface)
4286{
4287 struct wined3d_swapchain *swapchain;
4288
4289 TRACE("device %p, swapchain_idx %u, dst_surface %p.\n", device, swapchain_idx, dst_surface);
4290
4291 if (!(swapchain = wined3d_device_get_swapchain(device, swapchain_idx)))
4292 return WINED3DERR_INVALIDCALL;
4293
4294 return wined3d_swapchain_get_front_buffer_data(swapchain, dst_surface);
4295}
4296
4297HRESULT CDECL wined3d_device_validate_device(const struct wined3d_device *device, DWORD *num_passes)
4298{
4299 const struct wined3d_state *state = &device->stateBlock->state;
4300 struct wined3d_texture *texture;
4301 DWORD i;
4302
4303 TRACE("device %p, num_passes %p.\n", device, num_passes);
4304
4305 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4306 {
4307 if (state->sampler_states[i][WINED3D_SAMP_MIN_FILTER] == WINED3D_TEXF_NONE)
4308 {
4309 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4310 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4311 }
4312 if (state->sampler_states[i][WINED3D_SAMP_MAG_FILTER] == WINED3D_TEXF_NONE)
4313 {
4314 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4315 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4316 }
4317
4318 texture = state->textures[i];
4319 if (!texture || texture->resource.format->flags & WINED3DFMT_FLAG_FILTERING) continue;
4320
4321 if (state->sampler_states[i][WINED3D_SAMP_MAG_FILTER] != WINED3D_TEXF_POINT)
4322 {
4323 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
4324 return E_FAIL;
4325 }
4326 if (state->sampler_states[i][WINED3D_SAMP_MIN_FILTER] != WINED3D_TEXF_POINT)
4327 {
4328 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
4329 return E_FAIL;
4330 }
4331 if (state->sampler_states[i][WINED3D_SAMP_MIP_FILTER] != WINED3D_TEXF_NONE
4332 && state->sampler_states[i][WINED3D_SAMP_MIP_FILTER] != WINED3D_TEXF_POINT)
4333 {
4334 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
4335 return E_FAIL;
4336 }
4337 }
4338
4339 if (state->render_states[WINED3D_RS_ZENABLE] || state->render_states[WINED3D_RS_ZWRITEENABLE]
4340 || state->render_states[WINED3D_RS_STENCILENABLE])
4341 {
4342 struct wined3d_surface *ds = device->fb.depth_stencil;
4343 struct wined3d_surface *target = device->fb.render_targets[0];
4344
4345 if(ds && target
4346 && (ds->resource.width < target->resource.width || ds->resource.height < target->resource.height))
4347 {
4348 WARN("Depth stencil is smaller than the color buffer, returning D3DERR_CONFLICTINGRENDERSTATE\n");
4349 return WINED3DERR_CONFLICTINGRENDERSTATE;
4350 }
4351 }
4352
4353 /* return a sensible default */
4354 *num_passes = 1;
4355
4356 TRACE("returning D3D_OK\n");
4357 return WINED3D_OK;
4358}
4359
4360void CDECL wined3d_device_set_software_vertex_processing(struct wined3d_device *device, BOOL software)
4361{
4362 static BOOL warned;
4363
4364 TRACE("device %p, software %#x.\n", device, software);
4365
4366 if (!warned)
4367 {
4368 FIXME("device %p, software %#x stub!\n", device, software);
4369 warned = TRUE;
4370 }
4371
4372 device->softwareVertexProcessing = software;
4373}
4374
4375BOOL CDECL wined3d_device_get_software_vertex_processing(const struct wined3d_device *device)
4376{
4377 static BOOL warned;
4378
4379 TRACE("device %p.\n", device);
4380
4381 if (!warned)
4382 {
4383 TRACE("device %p stub!\n", device);
4384 warned = TRUE;
4385 }
4386
4387 return device->softwareVertexProcessing;
4388}
4389
4390HRESULT CDECL wined3d_device_get_raster_status(const struct wined3d_device *device,
4391 UINT swapchain_idx, struct wined3d_raster_status *raster_status)
4392{
4393 struct wined3d_swapchain *swapchain;
4394
4395 TRACE("device %p, swapchain_idx %u, raster_status %p.\n",
4396 device, swapchain_idx, raster_status);
4397
4398 if (!(swapchain = wined3d_device_get_swapchain(device, swapchain_idx)))
4399 return WINED3DERR_INVALIDCALL;
4400
4401 return wined3d_swapchain_get_raster_status(swapchain, raster_status);
4402}
4403
4404HRESULT CDECL wined3d_device_set_npatch_mode(struct wined3d_device *device, float segments)
4405{
4406 static BOOL warned;
4407
4408 TRACE("device %p, segments %.8e.\n", device, segments);
4409
4410 if (segments != 0.0f)
4411 {
4412 if (!warned)
4413 {
4414 FIXME("device %p, segments %.8e stub!\n", device, segments);
4415 warned = TRUE;
4416 }
4417 }
4418
4419 return WINED3D_OK;
4420}
4421
4422float CDECL wined3d_device_get_npatch_mode(const struct wined3d_device *device)
4423{
4424 static BOOL warned;
4425
4426 TRACE("device %p.\n", device);
4427
4428 if (!warned)
4429 {
4430 FIXME("device %p stub!\n", device);
4431 warned = TRUE;
4432 }
4433
4434 return 0.0f;
4435}
4436
4437HRESULT CDECL wined3d_device_update_surface(struct wined3d_device *device,
4438 struct wined3d_surface *src_surface, const RECT *src_rect,
4439 struct wined3d_surface *dst_surface, const POINT *dst_point)
4440{
4441 TRACE("device %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s.\n",
4442 device, src_surface, wine_dbgstr_rect(src_rect),
4443 dst_surface, wine_dbgstr_point(dst_point));
4444
4445 if (src_surface->resource.pool != WINED3D_POOL_SYSTEM_MEM || dst_surface->resource.pool != WINED3D_POOL_DEFAULT)
4446 {
4447 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
4448 src_surface, dst_surface);
4449 return WINED3DERR_INVALIDCALL;
4450 }
4451
4452 return surface_upload_from_surface(dst_surface, dst_point, src_surface, src_rect);
4453}
4454
4455/* Do not call while under the GL lock. */
4456HRESULT CDECL wined3d_device_color_fill(struct wined3d_device *device,
4457 struct wined3d_surface *surface, const RECT *rect, const struct wined3d_color *color)
4458{
4459 RECT r;
4460
4461 TRACE("device %p, surface %p, rect %s, color {%.8e, %.8e, %.8e, %.8e}.\n",
4462 device, surface, wine_dbgstr_rect(rect),
4463 color->r, color->g, color->b, color->a);
4464
4465 if (surface->resource.pool != WINED3D_POOL_DEFAULT && surface->resource.pool != WINED3D_POOL_SYSTEM_MEM)
4466 {
4467 WARN("Color-fill not allowed on %s surfaces.\n", debug_d3dpool(surface->resource.pool));
4468 return WINED3DERR_INVALIDCALL;
4469 }
4470
4471 if (!rect)
4472 {
4473 SetRect(&r, 0, 0, surface->resource.width, surface->resource.height);
4474 rect = &r;
4475 }
4476
4477 return surface_color_fill(surface, rect, color);
4478}
4479
4480/* Do not call while under the GL lock. */
4481void CDECL wined3d_device_clear_rendertarget_view(struct wined3d_device *device,
4482 struct wined3d_rendertarget_view *rendertarget_view, const struct wined3d_color *color)
4483{
4484 struct wined3d_resource *resource;
4485 HRESULT hr;
4486 RECT rect;
4487
4488 resource = rendertarget_view->resource;
4489 if (resource->type != WINED3D_RTYPE_SURFACE)
4490 {
4491 FIXME("Only supported on surface resources\n");
4492 return;
4493 }
4494
4495 SetRect(&rect, 0, 0, resource->width, resource->height);
4496 hr = surface_color_fill(surface_from_resource(resource), &rect, color);
4497 if (FAILED(hr)) ERR("Color fill failed, hr %#x.\n", hr);
4498}
4499
4500struct wined3d_surface * CDECL wined3d_device_get_render_target(const struct wined3d_device *device,
4501 UINT render_target_idx)
4502{
4503 TRACE("device %p, render_target_idx %u.\n", device, render_target_idx);
4504
4505 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
4506 {
4507 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
4508 return NULL;
4509 }
4510
4511 return device->fb.render_targets[render_target_idx];
4512}
4513
4514struct wined3d_surface * CDECL wined3d_device_get_depth_stencil(const struct wined3d_device *device)
4515{
4516 TRACE("device %p.\n", device);
4517
4518 return device->fb.depth_stencil;
4519}
4520
4521HRESULT CDECL wined3d_device_set_render_target(struct wined3d_device *device,
4522 UINT render_target_idx, struct wined3d_surface *render_target, BOOL set_viewport)
4523{
4524 struct wined3d_surface *prev;
4525
4526 TRACE("device %p, render_target_idx %u, render_target %p, set_viewport %#x.\n",
4527 device, render_target_idx, render_target, set_viewport);
4528
4529 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
4530 {
4531 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
4532 return WINED3DERR_INVALIDCALL;
4533 }
4534
4535 /* Render target 0 can't be set to NULL. */
4536 if (!render_target && !render_target_idx)
4537 {
4538 WARN("Trying to set render target 0 to NULL.\n");
4539 return WINED3DERR_INVALIDCALL;
4540 }
4541
4542 if (render_target && !(render_target->resource.usage & WINED3DUSAGE_RENDERTARGET))
4543 {
4544 FIXME("Surface %p doesn't have render target usage.\n", render_target);
4545 return WINED3DERR_INVALIDCALL;
4546 }
4547
4548 /* Set the viewport and scissor rectangles, if requested. Tests show that
4549 * stateblock recording is ignored, the change goes directly into the
4550 * primary stateblock. */
4551 if (!render_target_idx && set_viewport)
4552 {
4553 struct wined3d_state *state = &device->stateBlock->state;
4554
4555 state->viewport.x = 0;
4556 state->viewport.y = 0;
4557 state->viewport.width = render_target->resource.width;
4558 state->viewport.height = render_target->resource.height;
4559 state->viewport.min_z = 0.0f;
4560 state->viewport.max_z = 1.0f;
4561 device_invalidate_state(device, STATE_VIEWPORT);
4562
4563 state->scissor_rect.top = 0;
4564 state->scissor_rect.left = 0;
4565 state->scissor_rect.right = render_target->resource.width;
4566 state->scissor_rect.bottom = render_target->resource.height;
4567 device_invalidate_state(device, STATE_SCISSORRECT);
4568 }
4569
4570
4571 prev = device->fb.render_targets[render_target_idx];
4572 if (render_target == prev)
4573 return WINED3D_OK;
4574
4575 if (render_target)
4576 wined3d_surface_incref(render_target);
4577 device->fb.render_targets[render_target_idx] = render_target;
4578 /* Release after the assignment, to prevent device_resource_released()
4579 * from seeing the surface as still in use. */
4580 if (prev)
4581 wined3d_surface_decref(prev);
4582
4583 device_invalidate_state(device, STATE_FRAMEBUFFER);
4584
4585 return WINED3D_OK;
4586}
4587
4588void CDECL wined3d_device_set_depth_stencil(struct wined3d_device *device, struct wined3d_surface *depth_stencil)
4589{
4590 struct wined3d_surface *prev = device->fb.depth_stencil;
4591
4592 TRACE("device %p, depth_stencil %p, old depth_stencil %p.\n",
4593 device, depth_stencil, prev);
4594
4595 if (prev == depth_stencil)
4596 {
4597 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
4598 return;
4599 }
4600
4601 if (prev)
4602 {
4603 if (device->swapchains[0]->desc.flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
4604 || prev->flags & SFLAG_DISCARD)
4605 {
4606 surface_modify_ds_location(prev, SFLAG_DISCARDED,
4607 prev->resource.width, prev->resource.height);
4608 if (prev == device->onscreen_depth_stencil)
4609 {
4610 wined3d_surface_decref(device->onscreen_depth_stencil);
4611 device->onscreen_depth_stencil = NULL;
4612 }
4613 }
4614 }
4615
4616 device->fb.depth_stencil = depth_stencil;
4617 if (depth_stencil)
4618 wined3d_surface_incref(depth_stencil);
4619
4620 if (!prev != !depth_stencil)
4621 {
4622 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
4623 device_invalidate_state(device, STATE_RENDER(WINED3D_RS_ZENABLE));
4624 device_invalidate_state(device, STATE_RENDER(WINED3D_RS_STENCILENABLE));
4625 device_invalidate_state(device, STATE_RENDER(WINED3D_RS_STENCILWRITEMASK));
4626 device_invalidate_state(device, STATE_RENDER(WINED3D_RS_DEPTHBIAS));
4627 }
4628 else if (prev && prev->resource.format->depth_size != depth_stencil->resource.format->depth_size)
4629 {
4630 device_invalidate_state(device, STATE_RENDER(WINED3D_RS_DEPTHBIAS));
4631 }
4632 if (prev)
4633 wined3d_surface_decref(prev);
4634
4635 device_invalidate_state(device, STATE_FRAMEBUFFER);
4636
4637 return;
4638}
4639
4640HRESULT CDECL wined3d_device_set_cursor_properties(struct wined3d_device *device,
4641 UINT x_hotspot, UINT y_hotspot, struct wined3d_surface *cursor_image)
4642{
4643 TRACE("device %p, x_hotspot %u, y_hotspot %u, cursor_image %p.\n",
4644 device, x_hotspot, y_hotspot, cursor_image);
4645
4646 /* some basic validation checks */
4647 if (device->cursorTexture)
4648 {
4649 struct wined3d_context *context = context_acquire(device, NULL);
4650 context->gl_info->gl_ops.gl.p_glDeleteTextures(1, &device->cursorTexture);
4651 context_release(context);
4652 device->cursorTexture = 0;
4653 }
4654
4655 if (cursor_image)
4656 {
4657 struct wined3d_display_mode mode;
4658 struct wined3d_map_desc map_desc;
4659 HRESULT hr;
4660
4661 /* MSDN: Cursor must be A8R8G8B8 */
4662 if (cursor_image->resource.format->id != WINED3DFMT_B8G8R8A8_UNORM)
4663 {
4664 WARN("surface %p has an invalid format.\n", cursor_image);
4665 return WINED3DERR_INVALIDCALL;
4666 }
4667
4668 if (FAILED(hr = wined3d_get_adapter_display_mode(device->wined3d, device->adapter->ordinal, &mode, NULL)))
4669 {
4670 ERR("Failed to get display mode, hr %#x.\n", hr);
4671 return WINED3DERR_INVALIDCALL;
4672 }
4673
4674 /* MSDN: Cursor must be smaller than the display mode */
4675 if (cursor_image->resource.width > mode.width || cursor_image->resource.height > mode.height)
4676 {
4677 WARN("Surface %p dimensions are %ux%u, but screen dimensions are %ux%u.\n",
4678 cursor_image, cursor_image->resource.width, cursor_image->resource.height,
4679 mode.width, mode.height);
4680 return WINED3DERR_INVALIDCALL;
4681 }
4682
4683 /* TODO: MSDN: Cursor sizes must be a power of 2 */
4684
4685 /* Do not store the surface's pointer because the application may
4686 * release it after setting the cursor image. Windows doesn't
4687 * addref the set surface, so we can't do this either without
4688 * creating circular refcount dependencies. Copy out the gl texture
4689 * instead. */
4690 device->cursorWidth = cursor_image->resource.width;
4691 device->cursorHeight = cursor_image->resource.height;
4692 if (SUCCEEDED(wined3d_surface_map(cursor_image, &map_desc, NULL, WINED3D_MAP_READONLY)))
4693 {
4694 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
4695 const struct wined3d_format *format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM);
4696 struct wined3d_context *context;
4697 char *mem, *bits = map_desc.data;
4698 GLint intfmt = format->glInternal;
4699 GLint gl_format = format->glFormat;
4700 GLint type = format->glType;
4701 INT height = device->cursorHeight;
4702 INT width = device->cursorWidth;
4703 INT bpp = format->byte_count;
4704 INT i;
4705
4706 /* Reformat the texture memory (pitch and width can be
4707 * different) */
4708 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
4709 for (i = 0; i < height; ++i)
4710 memcpy(&mem[width * bpp * i], &bits[map_desc.row_pitch * i], width * bpp);
4711 wined3d_surface_unmap(cursor_image);
4712
4713 context = context_acquire(device, NULL);
4714
4715 if (gl_info->supported[APPLE_CLIENT_STORAGE])
4716 {
4717 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
4718 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
4719 }
4720
4721 invalidate_active_texture(device, context);
4722 /* Create a new cursor texture */
4723 gl_info->gl_ops.gl.p_glGenTextures(1, &device->cursorTexture);
4724 checkGLcall("glGenTextures");
4725 context_bind_texture(context, GL_TEXTURE_2D, device->cursorTexture);
4726 /* Copy the bitmap memory into the cursor texture */
4727 gl_info->gl_ops.gl.p_glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, gl_format, type, mem);
4728 checkGLcall("glTexImage2D");
4729 HeapFree(GetProcessHeap(), 0, mem);
4730
4731 if (gl_info->supported[APPLE_CLIENT_STORAGE])
4732 {
4733 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
4734 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
4735 }
4736
4737 context_release(context);
4738 }
4739 else
4740 {
4741 FIXME("A cursor texture was not returned.\n");
4742 device->cursorTexture = 0;
4743 }
4744
4745 if (cursor_image->resource.width == 32 && cursor_image->resource.height == 32)
4746 {
4747 UINT mask_size = cursor_image->resource.width * cursor_image->resource.height / 8;
4748 ICONINFO cursorInfo;
4749 DWORD *maskBits;
4750 HCURSOR cursor;
4751
4752 /* 32-bit user32 cursors ignore the alpha channel if it's all
4753 * zeroes, and use the mask instead. Fill the mask with all ones
4754 * to ensure we still get a fully transparent cursor. */
4755 maskBits = HeapAlloc(GetProcessHeap(), 0, mask_size);
4756 memset(maskBits, 0xff, mask_size);
4757 wined3d_surface_map(cursor_image, &map_desc, NULL,
4758 WINED3D_MAP_NO_DIRTY_UPDATE | WINED3D_MAP_READONLY);
4759 TRACE("width: %u height: %u.\n", cursor_image->resource.width, cursor_image->resource.height);
4760
4761 cursorInfo.fIcon = FALSE;
4762 cursorInfo.xHotspot = x_hotspot;
4763 cursorInfo.yHotspot = y_hotspot;
4764 cursorInfo.hbmMask = CreateBitmap(cursor_image->resource.width, cursor_image->resource.height,
4765 1, 1, maskBits);
4766 cursorInfo.hbmColor = CreateBitmap(cursor_image->resource.width, cursor_image->resource.height,
4767 1, 32, map_desc.data);
4768 wined3d_surface_unmap(cursor_image);
4769 /* Create our cursor and clean up. */
4770 cursor = CreateIconIndirect(&cursorInfo);
4771 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
4772 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
4773 if (device->hardwareCursor) DestroyCursor(device->hardwareCursor);
4774 device->hardwareCursor = cursor;
4775 if (device->bCursorVisible) SetCursor( cursor );
4776 HeapFree(GetProcessHeap(), 0, maskBits);
4777 }
4778 }
4779
4780 device->xHotSpot = x_hotspot;
4781 device->yHotSpot = y_hotspot;
4782 return WINED3D_OK;
4783}
4784
4785void CDECL wined3d_device_set_cursor_position(struct wined3d_device *device,
4786 int x_screen_space, int y_screen_space, DWORD flags)
4787{
4788 TRACE("device %p, x %d, y %d, flags %#x.\n",
4789 device, x_screen_space, y_screen_space, flags);
4790
4791 device->xScreenSpace = x_screen_space;
4792 device->yScreenSpace = y_screen_space;
4793
4794 if (device->hardwareCursor)
4795 {
4796 POINT pt;
4797
4798 GetCursorPos( &pt );
4799 if (x_screen_space == pt.x && y_screen_space == pt.y)
4800 return;
4801 SetCursorPos( x_screen_space, y_screen_space );
4802
4803 /* Switch to the software cursor if position diverges from the hardware one. */
4804 GetCursorPos( &pt );
4805 if (x_screen_space != pt.x || y_screen_space != pt.y)
4806 {
4807 if (device->bCursorVisible) SetCursor( NULL );
4808 DestroyCursor( device->hardwareCursor );
4809 device->hardwareCursor = 0;
4810 }
4811 }
4812}
4813
4814BOOL CDECL wined3d_device_show_cursor(struct wined3d_device *device, BOOL show)
4815{
4816 BOOL oldVisible = device->bCursorVisible;
4817
4818 TRACE("device %p, show %#x.\n", device, show);
4819
4820 /*
4821 * When ShowCursor is first called it should make the cursor appear at the OS's last
4822 * known cursor position.
4823 */
4824 if (show && !oldVisible)
4825 {
4826 POINT pt;
4827 GetCursorPos(&pt);
4828 device->xScreenSpace = pt.x;
4829 device->yScreenSpace = pt.y;
4830 }
4831
4832 if (device->hardwareCursor)
4833 {
4834 device->bCursorVisible = show;
4835 if (show)
4836 SetCursor(device->hardwareCursor);
4837 else
4838 SetCursor(NULL);
4839 }
4840 else
4841 {
4842 if (device->cursorTexture)
4843 device->bCursorVisible = show;
4844 }
4845
4846 return oldVisible;
4847}
4848
4849void CDECL wined3d_device_evict_managed_resources(struct wined3d_device *device)
4850{
4851 struct wined3d_resource *resource, *cursor;
4852
4853 TRACE("device %p.\n", device);
4854
4855 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &device->resources, struct wined3d_resource, resource_list_entry)
4856 {
4857 TRACE("Checking resource %p for eviction.\n", resource);
4858
4859 if (resource->pool == WINED3D_POOL_MANAGED && !resource->map_count)
4860 {
4861 TRACE("Evicting %p.\n", resource);
4862 resource->resource_ops->resource_unload(resource);
4863 }
4864 }
4865
4866 /* Invalidate stream sources, the buffer(s) may have been evicted. */
4867 device_invalidate_state(device, STATE_STREAMSRC);
4868}
4869
4870#ifndef VBOX_WITH_WDDM
4871/* Do not call while under the GL lock. */
4872static void delete_opengl_contexts(struct wined3d_device *device, struct wined3d_swapchain *swapchain)
4873{
4874 struct wined3d_resource *resource, *cursor;
4875 const struct wined3d_gl_info *gl_info;
4876 struct wined3d_context *context;
4877 struct wined3d_shader *shader;
4878
4879 context = context_acquire(device, NULL);
4880 gl_info = context->gl_info;
4881
4882 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &device->resources, struct wined3d_resource, resource_list_entry)
4883 {
4884 TRACE("Unloading resource %p.\n", resource);
4885
4886 resource->resource_ops->resource_unload(resource);
4887 }
4888
4889 LIST_FOR_EACH_ENTRY(shader, &device->shaders, struct wined3d_shader, shader_list_entry)
4890 {
4891 device->shader_backend->shader_destroy(shader);
4892 }
4893
4894 if (device->depth_blt_texture)
4895 {
4896 gl_info->gl_ops.gl.p_glDeleteTextures(1, &device->depth_blt_texture);
4897 device->depth_blt_texture = 0;
4898 }
4899 if (device->cursorTexture)
4900 {
4901 gl_info->gl_ops.gl.p_glDeleteTextures(1, &device->cursorTexture);
4902 device->cursorTexture = 0;
4903 }
4904
4905 device->blitter->free_private(device);
4906 device->shader_backend->shader_free_private(device);
4907 destroy_dummy_textures(device, gl_info);
4908
4909 context_release(context);
4910
4911 while (device->context_count)
4912 {
4913#ifndef VBOX_WINE_WITH_SINGLE_CONTEXT
4914 swapchain_destroy_contexts(device->contexts[0]->swapchain);
4915#else
4916 context_destroy(device, device->contexts[0]);
4917#endif
4918 }
4919
4920#ifndef VBOX_WINE_WITH_SINGLE_CONTEXT
4921 HeapFree(GetProcessHeap(), 0, swapchain->context);
4922 swapchain->context = NULL;
4923#else
4924#endif
4925}
4926
4927/* Do not call while under the GL lock. */
4928static HRESULT create_primary_opengl_context(struct wined3d_device *device, struct wined3d_swapchain *swapchain)
4929{
4930 struct wined3d_context *context;
4931 struct wined3d_surface *target;
4932 HRESULT hr;
4933
4934 if (FAILED(hr = device->shader_backend->shader_alloc_private(device,
4935 device->adapter->vertex_pipe, device->adapter->fragment_pipe)))
4936 {
4937 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
4938 return hr;
4939 }
4940
4941 if (FAILED(hr = device->blitter->alloc_private(device)))
4942 {
4943 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
4944 device->shader_backend->shader_free_private(device);
4945 return hr;
4946 }
4947
4948 /* Recreate the primary swapchain's context */
4949#ifndef VBOX_WINE_WITH_SINGLE_CONTEXT
4950 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
4951 if (!swapchain->context)
4952#else
4953 device->contexts = HeapAlloc(GetProcessHeap(), 0, sizeof(*device->contexts));
4954 if (!device->contexts)
4955#endif
4956 {
4957 ERR("Failed to allocate memory for swapchain context array.\n");
4958 device->blitter->free_private(device);
4959 device->shader_backend->shader_free_private(device);
4960 return E_OUTOFMEMORY;
4961 }
4962
4963 target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer;
4964 if (!(context = context_create(swapchain, target, swapchain->ds_format)))
4965 {
4966 WARN("Failed to create context.\n");
4967 device->blitter->free_private(device);
4968 device->shader_backend->shader_free_private(device);
4969#ifndef VBOX_WINE_WITH_SINGLE_CONTEXT
4970 HeapFree(GetProcessHeap(), 0, swapchain->context);
4971#else
4972 HeapFree(GetProcessHeap(), 0, device->contexts);
4973#endif
4974 return E_FAIL;
4975 }
4976
4977#ifndef VBOX_WINE_WITH_SINGLE_CONTEXT
4978 swapchain->context[0] = context;
4979 swapchain->num_contexts = 1;
4980#endif
4981 create_dummy_textures(device, context);
4982 context_release(context);
4983
4984 return WINED3D_OK;
4985}
4986#endif
4987/* Do not call while under the GL lock. */
4988HRESULT CDECL wined3d_device_reset(struct wined3d_device *device,
4989 const struct wined3d_swapchain_desc *swapchain_desc, const struct wined3d_display_mode *mode,
4990 wined3d_device_reset_cb callback, BOOL reset_state)
4991{
4992#ifndef VBOX_WITH_WDDM
4993 struct wined3d_resource *resource, *cursor;
4994 struct wined3d_swapchain *swapchain;
4995 struct wined3d_display_mode m;
4996 BOOL DisplayModeChanged = FALSE;
4997 BOOL update_desc = FALSE;
4998 UINT backbuffer_width = swapchain_desc->backbuffer_width;
4999 UINT backbuffer_height = swapchain_desc->backbuffer_height;
5000 HRESULT hr = WINED3D_OK;
5001 unsigned int i;
5002
5003 TRACE("device %p, swapchain_desc %p, mode %p, callback %p.\n", device, swapchain_desc, mode, callback);
5004
5005 if (!(swapchain = wined3d_device_get_swapchain(device, 0)))
5006 {
5007 ERR("Failed to get the first implicit swapchain.\n");
5008 return WINED3DERR_INVALIDCALL;
5009 }
5010
5011 if (reset_state)
5012 stateblock_unbind_resources(device->stateBlock);
5013
5014 if (device->fb.render_targets)
5015 {
5016 if (swapchain->back_buffers && swapchain->back_buffers[0])
5017 wined3d_device_set_render_target(device, 0, swapchain->back_buffers[0], FALSE);
5018 else
5019 wined3d_device_set_render_target(device, 0, swapchain->front_buffer, FALSE);
5020 for (i = 1; i < device->adapter->gl_info.limits.buffers; ++i)
5021 {
5022 wined3d_device_set_render_target(device, i, NULL, FALSE);
5023 }
5024 }
5025 wined3d_device_set_depth_stencil(device, NULL);
5026
5027 if (device->onscreen_depth_stencil)
5028 {
5029 wined3d_surface_decref(device->onscreen_depth_stencil);
5030 device->onscreen_depth_stencil = NULL;
5031 }
5032
5033 if (reset_state)
5034 {
5035 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &device->resources, struct wined3d_resource, resource_list_entry)
5036 {
5037 TRACE("Enumerating resource %p.\n", resource);
5038 if (FAILED(hr = callback(resource)))
5039 return hr;
5040 }
5041 }
5042
5043 /* Is it necessary to recreate the gl context? Actually every setting can be changed
5044 * on an existing gl context, so there's no real need for recreation.
5045 *
5046 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
5047 *
5048 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
5049 */
5050 TRACE("New params:\n");
5051 TRACE("backbuffer_width %u\n", swapchain_desc->backbuffer_width);
5052 TRACE("backbuffer_height %u\n", swapchain_desc->backbuffer_height);
5053 TRACE("backbuffer_format %s\n", debug_d3dformat(swapchain_desc->backbuffer_format));
5054 TRACE("backbuffer_count %u\n", swapchain_desc->backbuffer_count);
5055 TRACE("multisample_type %#x\n", swapchain_desc->multisample_type);
5056 TRACE("multisample_quality %u\n", swapchain_desc->multisample_quality);
5057 TRACE("swap_effect %#x\n", swapchain_desc->swap_effect);
5058 TRACE("device_window %p\n", swapchain_desc->device_window);
5059 TRACE("windowed %#x\n", swapchain_desc->windowed);
5060 TRACE("enable_auto_depth_stencil %#x\n", swapchain_desc->enable_auto_depth_stencil);
5061 if (swapchain_desc->enable_auto_depth_stencil)
5062 TRACE("auto_depth_stencil_format %s\n", debug_d3dformat(swapchain_desc->auto_depth_stencil_format));
5063 TRACE("flags %#x\n", swapchain_desc->flags);
5064 TRACE("refresh_rate %u\n", swapchain_desc->refresh_rate);
5065 TRACE("swap_interval %u\n", swapchain_desc->swap_interval);
5066 TRACE("auto_restore_display_mode %#x\n", swapchain_desc->auto_restore_display_mode);
5067
5068 /* No special treatment of these parameters. Just store them */
5069 swapchain->desc.swap_effect = swapchain_desc->swap_effect;
5070 swapchain->desc.flags = swapchain_desc->flags;
5071 swapchain->desc.swap_interval = swapchain_desc->swap_interval;
5072 swapchain->desc.refresh_rate = swapchain_desc->refresh_rate;
5073
5074 /* What to do about these? */
5075 if (swapchain_desc->backbuffer_count
5076 && swapchain_desc->backbuffer_count != swapchain->desc.backbuffer_count)
5077 FIXME("Cannot change the back buffer count yet.\n");
5078
5079 if (swapchain_desc->device_window
5080 && swapchain_desc->device_window != swapchain->desc.device_window)
5081 {
5082 TRACE("Changing the device window from %p to %p.\n",
5083 swapchain->desc.device_window, swapchain_desc->device_window);
5084 swapchain->desc.device_window = swapchain_desc->device_window;
5085 swapchain->device_window = swapchain_desc->device_window;
5086 wined3d_swapchain_set_window(swapchain, NULL);
5087 }
5088
5089 if (swapchain_desc->enable_auto_depth_stencil && !device->auto_depth_stencil)
5090 {
5091 struct wined3d_resource_desc surface_desc;
5092
5093 TRACE("Creating the depth stencil buffer\n");
5094
5095 surface_desc.resource_type = WINED3D_RTYPE_SURFACE;
5096 surface_desc.format = swapchain_desc->auto_depth_stencil_format;
5097 surface_desc.multisample_type = swapchain_desc->multisample_type;
5098 surface_desc.multisample_quality = swapchain_desc->multisample_quality;
5099 surface_desc.usage = WINED3DUSAGE_DEPTHSTENCIL;
5100 surface_desc.pool = WINED3D_POOL_DEFAULT;
5101 surface_desc.width = swapchain_desc->backbuffer_width;
5102 surface_desc.height = swapchain_desc->backbuffer_height;
5103 surface_desc.depth = 1;
5104 surface_desc.size = 0;
5105
5106 if (FAILED(hr = device->device_parent->ops->create_swapchain_surface(device->device_parent,
5107 device->device_parent, &surface_desc, &device->auto_depth_stencil)))
5108 {
5109 ERR("Failed to create the depth stencil buffer, hr %#x.\n", hr);
5110 return WINED3DERR_INVALIDCALL;
5111 }
5112 }
5113
5114 /* Reset the depth stencil */
5115 if (swapchain_desc->enable_auto_depth_stencil)
5116 wined3d_device_set_depth_stencil(device, device->auto_depth_stencil);
5117
5118 if (mode)
5119 {
5120 DisplayModeChanged = TRUE;
5121 m = *mode;
5122 }
5123 else if (swapchain_desc->windowed)
5124 {
5125 m = swapchain->original_mode;
5126 }
5127 else
5128 {
5129 m.width = swapchain_desc->backbuffer_width;
5130 m.height = swapchain_desc->backbuffer_height;
5131 m.refresh_rate = swapchain_desc->refresh_rate;
5132 m.format_id = swapchain_desc->backbuffer_format;
5133 m.scanline_ordering = WINED3D_SCANLINE_ORDERING_UNKNOWN;
5134 }
5135
5136 if (!backbuffer_width || !backbuffer_height)
5137 {
5138 /* The application is requesting that either the swapchain width or
5139 * height be set to the corresponding dimension in the window's
5140 * client rect. */
5141
5142 RECT client_rect;
5143
5144 if (!swapchain_desc->windowed)
5145 return WINED3DERR_INVALIDCALL;
5146
5147 if (!GetClientRect(swapchain->device_window, &client_rect))
5148 {
5149 ERR("Failed to get client rect, last error %#x.\n", GetLastError());
5150 return WINED3DERR_INVALIDCALL;
5151 }
5152
5153 if (!backbuffer_width)
5154 backbuffer_width = client_rect.right;
5155
5156 if (!backbuffer_height)
5157 backbuffer_height = client_rect.bottom;
5158 }
5159
5160 if (backbuffer_width != swapchain->desc.backbuffer_width
5161 || backbuffer_height != swapchain->desc.backbuffer_height)
5162 {
5163 if (!swapchain_desc->windowed)
5164 DisplayModeChanged = TRUE;
5165
5166 swapchain->desc.backbuffer_width = backbuffer_width;
5167 swapchain->desc.backbuffer_height = backbuffer_height;
5168 update_desc = TRUE;
5169 }
5170
5171 if (swapchain_desc->backbuffer_format != WINED3DFMT_UNKNOWN
5172 && swapchain_desc->backbuffer_format != swapchain->desc.backbuffer_format)
5173 {
5174 swapchain->desc.backbuffer_format = swapchain_desc->backbuffer_format;
5175 update_desc = TRUE;
5176 }
5177
5178 if (swapchain_desc->multisample_type != swapchain->desc.multisample_type
5179 || swapchain_desc->multisample_quality != swapchain->desc.multisample_quality)
5180 {
5181 swapchain->desc.multisample_type = swapchain_desc->multisample_type;
5182 swapchain->desc.multisample_quality = swapchain_desc->multisample_quality;
5183 update_desc = TRUE;
5184 }
5185
5186 if (update_desc)
5187 {
5188 UINT i;
5189
5190 if (FAILED(hr = wined3d_surface_update_desc(swapchain->front_buffer, swapchain->desc.backbuffer_width,
5191 swapchain->desc.backbuffer_height, swapchain->desc.backbuffer_format,
5192 swapchain->desc.multisample_type, swapchain->desc.multisample_quality)))
5193 return hr;
5194
5195 for (i = 0; i < swapchain->desc.backbuffer_count; ++i)
5196 {
5197 if (FAILED(hr = wined3d_surface_update_desc(swapchain->back_buffers[i], swapchain->desc.backbuffer_width,
5198 swapchain->desc.backbuffer_height, swapchain->desc.backbuffer_format,
5199 swapchain->desc.multisample_type, swapchain->desc.multisample_quality)))
5200 return hr;
5201 }
5202 if (device->auto_depth_stencil)
5203 {
5204 if (FAILED(hr = wined3d_surface_update_desc(device->auto_depth_stencil, swapchain->desc.backbuffer_width,
5205 swapchain->desc.backbuffer_height, device->auto_depth_stencil->resource.format->id,
5206 swapchain->desc.multisample_type, swapchain->desc.multisample_quality)))
5207 return hr;
5208 }
5209 }
5210
5211 if (!swapchain_desc->windowed != !swapchain->desc.windowed
5212 || DisplayModeChanged)
5213 {
5214 if (FAILED(hr = wined3d_set_adapter_display_mode(device->wined3d, device->adapter->ordinal, &m)))
5215 {
5216 WARN("Failed to set display mode, hr %#x.\n", hr);
5217 return WINED3DERR_INVALIDCALL;
5218 }
5219
5220 if (!swapchain_desc->windowed)
5221 {
5222 if (swapchain->desc.windowed)
5223 {
5224 HWND focus_window = device->create_parms.focus_window;
5225 if (!focus_window)
5226 focus_window = swapchain_desc->device_window;
5227 if (FAILED(hr = wined3d_device_acquire_focus_window(device, focus_window)))
5228 {
5229 ERR("Failed to acquire focus window, hr %#x.\n", hr);
5230 return hr;
5231 }
5232
5233 /* switch from windowed to fs */
5234 wined3d_device_setup_fullscreen_window(device, swapchain->device_window,
5235 swapchain_desc->backbuffer_width,
5236 swapchain_desc->backbuffer_height);
5237 }
5238 else
5239 {
5240 /* Fullscreen -> fullscreen mode change */
5241 MoveWindow(swapchain->device_window, 0, 0,
5242 swapchain_desc->backbuffer_width,
5243 swapchain_desc->backbuffer_height,
5244 TRUE);
5245 }
5246 }
5247 else if (!swapchain->desc.windowed)
5248 {
5249 /* Fullscreen -> windowed switch */
5250 wined3d_device_restore_fullscreen_window(device, swapchain->device_window);
5251 wined3d_device_release_focus_window(device);
5252 }
5253 swapchain->desc.windowed = swapchain_desc->windowed;
5254 }
5255 else if (!swapchain_desc->windowed)
5256 {
5257 DWORD style = device->style;
5258 DWORD exStyle = device->exStyle;
5259 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
5260 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
5261 * Reset to clear up their mess. Guild Wars also loses the device during that.
5262 */
5263 device->style = 0;
5264 device->exStyle = 0;
5265 wined3d_device_setup_fullscreen_window(device, swapchain->device_window,
5266 swapchain_desc->backbuffer_width,
5267 swapchain_desc->backbuffer_height);
5268 device->style = style;
5269 device->exStyle = exStyle;
5270 }
5271
5272 if (reset_state)
5273 {
5274 TRACE("Resetting stateblock.\n");
5275 wined3d_stateblock_decref(device->updateStateBlock);
5276 wined3d_stateblock_decref(device->stateBlock);
5277
5278 if (device->d3d_initialized)
5279 delete_opengl_contexts(device, swapchain);
5280
5281 /* Note: No parent needed for initial internal stateblock */
5282 hr = wined3d_stateblock_create(device, WINED3D_SBT_INIT, &device->stateBlock);
5283 if (FAILED(hr))
5284 ERR("Resetting the stateblock failed with error %#x.\n", hr);
5285 else
5286 TRACE("Created stateblock %p.\n", device->stateBlock);
5287 device->updateStateBlock = device->stateBlock;
5288 wined3d_stateblock_incref(device->updateStateBlock);
5289
5290 stateblock_init_default_state(device->stateBlock);
5291 }
5292 else
5293 {
5294 struct wined3d_surface *rt = device->fb.render_targets[0];
5295 struct wined3d_state *state = &device->stateBlock->state;
5296
5297 /* Note the min_z / max_z is not reset. */
5298 state->viewport.x = 0;
5299 state->viewport.y = 0;
5300 state->viewport.width = rt->resource.width;
5301 state->viewport.height = rt->resource.height;
5302 device_invalidate_state(device, STATE_VIEWPORT);
5303
5304 state->scissor_rect.top = 0;
5305 state->scissor_rect.left = 0;
5306 state->scissor_rect.right = rt->resource.width;
5307 state->scissor_rect.bottom = rt->resource.height;
5308 device_invalidate_state(device, STATE_SCISSORRECT);
5309 }
5310
5311 swapchain_update_render_to_fbo(swapchain);
5312 swapchain_update_draw_bindings(swapchain);
5313
5314 if (reset_state && device->d3d_initialized)
5315 hr = create_primary_opengl_context(device, swapchain);
5316
5317 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
5318 * first use
5319 */
5320 return hr;
5321#else
5322 ERR("not supported!");
5323 return E_FAIL;
5324#endif
5325}
5326
5327HRESULT CDECL wined3d_device_set_dialog_box_mode(struct wined3d_device *device, BOOL enable_dialogs)
5328{
5329 TRACE("device %p, enable_dialogs %#x.\n", device, enable_dialogs);
5330
5331 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
5332
5333 return WINED3D_OK;
5334}
5335
5336
5337void CDECL wined3d_device_get_creation_parameters(const struct wined3d_device *device,
5338 struct wined3d_device_creation_parameters *parameters)
5339{
5340 TRACE("device %p, parameters %p.\n", device, parameters);
5341
5342 *parameters = device->create_parms;
5343}
5344
5345void CDECL wined3d_device_set_gamma_ramp(const struct wined3d_device *device,
5346 UINT swapchain_idx, DWORD flags, const struct wined3d_gamma_ramp *ramp)
5347{
5348 struct wined3d_swapchain *swapchain;
5349
5350 TRACE("device %p, swapchain_idx %u, flags %#x, ramp %p.\n",
5351 device, swapchain_idx, flags, ramp);
5352
5353 if ((swapchain = wined3d_device_get_swapchain(device, swapchain_idx)))
5354 wined3d_swapchain_set_gamma_ramp(swapchain, flags, ramp);
5355}
5356
5357void CDECL wined3d_device_get_gamma_ramp(const struct wined3d_device *device,
5358 UINT swapchain_idx, struct wined3d_gamma_ramp *ramp)
5359{
5360 struct wined3d_swapchain *swapchain;
5361
5362 TRACE("device %p, swapchain_idx %u, ramp %p.\n",
5363 device, swapchain_idx, ramp);
5364
5365 if ((swapchain = wined3d_device_get_swapchain(device, swapchain_idx)))
5366 wined3d_swapchain_get_gamma_ramp(swapchain, ramp);
5367}
5368
5369void device_resource_add(struct wined3d_device *device, struct wined3d_resource *resource)
5370{
5371 TRACE("device %p, resource %p.\n", device, resource);
5372
5373 list_add_head(&device->resources, &resource->resource_list_entry);
5374}
5375
5376static void device_resource_remove(struct wined3d_device *device, struct wined3d_resource *resource)
5377{
5378 TRACE("device %p, resource %p.\n", device, resource);
5379
5380 list_remove(&resource->resource_list_entry);
5381}
5382
5383void device_resource_released(struct wined3d_device *device, struct wined3d_resource *resource)
5384{
5385 enum wined3d_resource_type type = resource->type;
5386 unsigned int i;
5387
5388 TRACE("device %p, resource %p, type %s.\n", device, resource, debug_d3dresourcetype(type));
5389
5390 context_resource_released(device, resource, type);
5391
5392 switch (type)
5393 {
5394 case WINED3D_RTYPE_SURFACE:
5395 {
5396 struct wined3d_surface *surface = surface_from_resource(resource);
5397
5398 if (!device->d3d_initialized) break;
5399
5400 for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i)
5401 {
5402 if (device->fb.render_targets[i] == surface)
5403 {
5404 ERR("Surface %p is still in use as render target %u.\n", surface, i);
5405 device->fb.render_targets[i] = NULL;
5406 }
5407 }
5408
5409 if (device->fb.depth_stencil == surface)
5410 {
5411 ERR("Surface %p is still in use as depth/stencil buffer.\n", surface);
5412 device->fb.depth_stencil = NULL;
5413 }
5414 }
5415 break;
5416
5417 case WINED3D_RTYPE_TEXTURE:
5418 case WINED3D_RTYPE_CUBE_TEXTURE:
5419 case WINED3D_RTYPE_VOLUME_TEXTURE:
5420 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5421 {
5422 struct wined3d_texture *texture = wined3d_texture_from_resource(resource);
5423
5424 if (device->stateBlock && device->stateBlock->state.textures[i] == texture)
5425 {
5426 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
5427 texture, device->stateBlock, i);
5428 device->stateBlock->state.textures[i] = NULL;
5429 }
5430
5431 if (device->updateStateBlock != device->stateBlock
5432 && device->updateStateBlock->state.textures[i] == texture)
5433 {
5434 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
5435 texture, device->updateStateBlock, i);
5436 device->updateStateBlock->state.textures[i] = NULL;
5437 }
5438 }
5439 break;
5440
5441 case WINED3D_RTYPE_BUFFER:
5442 {
5443 struct wined3d_buffer *buffer = buffer_from_resource(resource);
5444
5445 for (i = 0; i < MAX_STREAMS; ++i)
5446 {
5447 if (device->stateBlock && device->stateBlock->state.streams[i].buffer == buffer)
5448 {
5449 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
5450 buffer, device->stateBlock, i);
5451 device->stateBlock->state.streams[i].buffer = NULL;
5452 }
5453
5454 if (device->updateStateBlock != device->stateBlock
5455 && device->updateStateBlock->state.streams[i].buffer == buffer)
5456 {
5457 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
5458 buffer, device->updateStateBlock, i);
5459 device->updateStateBlock->state.streams[i].buffer = NULL;
5460 }
5461
5462 }
5463
5464 if (device->stateBlock && device->stateBlock->state.index_buffer == buffer)
5465 {
5466 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
5467 buffer, device->stateBlock);
5468 device->stateBlock->state.index_buffer = NULL;
5469 }
5470
5471 if (device->updateStateBlock != device->stateBlock
5472 && device->updateStateBlock->state.index_buffer == buffer)
5473 {
5474 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
5475 buffer, device->updateStateBlock);
5476 device->updateStateBlock->state.index_buffer = NULL;
5477 }
5478 }
5479 break;
5480
5481 default:
5482 break;
5483 }
5484
5485 /* Remove the resource from the resourceStore */
5486 device_resource_remove(device, resource);
5487
5488 TRACE("Resource released.\n");
5489}
5490
5491struct wined3d_surface * CDECL wined3d_device_get_surface_from_dc(const struct wined3d_device *device, HDC dc)
5492{
5493 struct wined3d_resource *resource;
5494
5495 TRACE("device %p, dc %p.\n", device, dc);
5496
5497 if (!dc)
5498 return NULL;
5499
5500 LIST_FOR_EACH_ENTRY(resource, &device->resources, struct wined3d_resource, resource_list_entry)
5501 {
5502 if (resource->type == WINED3D_RTYPE_SURFACE)
5503 {
5504 struct wined3d_surface *s = surface_from_resource(resource);
5505
5506 if (s->hDC == dc)
5507 {
5508 TRACE("Found surface %p for dc %p.\n", s, dc);
5509 return s;
5510 }
5511 }
5512 }
5513
5514 return NULL;
5515}
5516
5517HRESULT device_init(struct wined3d_device *device, struct wined3d *wined3d,
5518 UINT adapter_idx, enum wined3d_device_type device_type, HWND focus_window, DWORD flags,
5519 BYTE surface_alignment, struct wined3d_device_parent *device_parent)
5520{
5521 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
5522 const struct fragment_pipeline *fragment_pipeline;
5523 const struct wined3d_vertex_pipe_ops *vertex_pipeline;
5524 unsigned int i;
5525 HRESULT hr;
5526
5527 device->ref = 1;
5528 device->wined3d = wined3d;
5529 wined3d_incref(device->wined3d);
5530 device->adapter = wined3d->adapter_count ? adapter : NULL;
5531 device->device_parent = device_parent;
5532 list_init(&device->resources);
5533 list_init(&device->shaders);
5534 device->surface_alignment = surface_alignment;
5535
5536 /* Save the creation parameters. */
5537 device->create_parms.adapter_idx = adapter_idx;
5538 device->create_parms.device_type = device_type;
5539 device->create_parms.focus_window = focus_window;
5540 device->create_parms.flags = flags;
5541
5542#ifdef VBOX_WINE_WITH_PROFILE
5543 VBOXWINEPROFILE_DRAWPRIM_INIT(&device->DrawPrimProfile);
5544#endif
5545
5546 device->shader_backend = adapter->shader_backend;
5547
5548 vertex_pipeline = adapter->vertex_pipe;
5549
5550 fragment_pipeline = adapter->fragment_pipe;
5551
5552 if (vertex_pipeline->vp_states && fragment_pipeline->states
5553 && FAILED(hr = compile_state_table(device->StateTable, device->multistate_funcs,
5554 &adapter->gl_info, &adapter->d3d_info, vertex_pipeline,
5555 fragment_pipeline, misc_state_template)))
5556 {
5557 ERR("Failed to compile state table, hr %#x.\n", hr);
5558 wined3d_decref(device->wined3d);
5559 return hr;
5560 }
5561
5562 device->blitter = adapter->blitter;
5563
5564 hr = wined3d_stateblock_create(device, WINED3D_SBT_INIT, &device->stateBlock);
5565 if (FAILED(hr))
5566 {
5567 WARN("Failed to create stateblock.\n");
5568 for (i = 0; i < sizeof(device->multistate_funcs) / sizeof(device->multistate_funcs[0]); ++i)
5569 {
5570 HeapFree(GetProcessHeap(), 0, device->multistate_funcs[i]);
5571 }
5572 wined3d_decref(device->wined3d);
5573 return hr;
5574 }
5575
5576 TRACE("Created stateblock %p.\n", device->stateBlock);
5577 device->updateStateBlock = device->stateBlock;
5578 wined3d_stateblock_incref(device->updateStateBlock);
5579
5580#ifdef VBOX_WINE_WITH_SHADER_CACHE
5581 shader_chaches_init(device);
5582#endif
5583
5584 return WINED3D_OK;
5585}
5586
5587
5588void device_invalidate_state(const struct wined3d_device *device, DWORD state)
5589{
5590 DWORD rep = device->StateTable[state].representative;
5591 struct wined3d_context *context;
5592 DWORD idx;
5593 BYTE shift;
5594 UINT i;
5595
5596 for (i = 0; i < device->context_count; ++i)
5597 {
5598 context = device->contexts[i];
5599 if(isStateDirty(context, rep)) continue;
5600
5601 context->dirtyArray[context->numDirtyEntries++] = rep;
5602 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
5603 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
5604 context->isStateDirty[idx] |= (1 << shift);
5605 }
5606}
5607
5608void get_drawable_size_fbo(const struct wined3d_context *context, UINT *width, UINT *height)
5609{
5610 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
5611 *width = context->current_rt->pow2Width;
5612 *height = context->current_rt->pow2Height;
5613}
5614
5615void get_drawable_size_backbuffer(const struct wined3d_context *context, UINT *width, UINT *height)
5616{
5617 const struct wined3d_swapchain *swapchain = context->swapchain;
5618 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
5619 * current context's drawable, which is the size of the back buffer of the swapchain
5620 * the active context belongs to. */
5621 *width = swapchain->desc.backbuffer_width;
5622 *height = swapchain->desc.backbuffer_height;
5623}
5624
5625#ifndef VBOX_WITH_WDDM
5626LRESULT device_process_message(struct wined3d_device *device, HWND window, BOOL unicode,
5627 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
5628{
5629 if (device->filter_messages)
5630 {
5631 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
5632 window, message, wparam, lparam);
5633 if (unicode)
5634 return DefWindowProcW(window, message, wparam, lparam);
5635 else
5636 return DefWindowProcA(window, message, wparam, lparam);
5637 }
5638
5639 if (message == WM_DESTROY)
5640 {
5641 TRACE("unregister window %p.\n", window);
5642 wined3d_unregister_window(window);
5643
5644 if (InterlockedCompareExchangePointer((void **)&device->focus_window, NULL, window) != window)
5645 ERR("Window %p is not the focus window for device %p.\n", window, device);
5646 }
5647 else if (message == WM_DISPLAYCHANGE)
5648 {
5649 device->device_parent->ops->mode_changed(device->device_parent);
5650 }
5651
5652 if (unicode)
5653 return CallWindowProcW(proc, window, message, wparam, lparam);
5654 else
5655 return CallWindowProcA(proc, window, message, wparam, lparam);
5656}
5657
5658#else
5659HRESULT CDECL wined3d_device_flush(struct wined3d_device *device)
5660{
5661 /* we use only one context, so just acquiring it here should do the job,
5662 * @todo: perhaps we should introduce the mechanism similar to the one used in flush_to_host
5663 * to avoid context acquisition */
5664 struct wined3d_context *context = context_acquire(device, NULL);
5665 Assert(context->valid);
5666 context->gl_info->gl_ops.gl.p_glFlush();
5667 context_release(context);
5668 return WINED3D_OK;
5669}
5670
5671HRESULT CDECL wined3d_device_flush_to_host(struct wined3d_device *device)
5672{
5673 struct wined3d_context *context;
5674 int i;
5675
5676 /* no context acquisition is needed */
5677 for (i = 0; i < device->context_count; ++i)
5678 {
5679 context = device->contexts[i];
5680 pVBoxFlushToHost(context->glCtx);
5681 }
5682 return WINED3D_OK;
5683}
5684
5685HRESULT CDECL wined3d_device_finish(struct wined3d_device *device)
5686{
5687 /* we use only one context, so just acquiring it here should do the job,
5688 * @todo: perhaps we should introduce the mechanism similar to the one used in flush_to_host
5689 * to avoid context acquisition */
5690 struct wined3d_context *context = context_acquire(device, NULL);
5691 Assert(context->valid);
5692 context->gl_info->gl_ops.gl.p_glFinish();
5693 context_release(context);
5694 return WINED3D_OK;
5695
5696}
5697
5698HRESULT CDECL wined3d_device_get_host_id(struct wined3d_device *device, int32_t *pid)
5699{
5700 int32_t id = pVBoxGetContextId(device->contexts[0]->glCtx);
5701 if (!id)
5702 {
5703 *pid = 0;
5704 ERR("pVBoxGetContextId to get id for context 0x%x", device->contexts[0]->glCtx);
5705 return E_FAIL;
5706 }
5707
5708 *pid = id;
5709 return WINED3D_OK;
5710}
5711#endif
5712
5713
5714#ifdef VBOX_WITH_WINE_FIX_ZEROVERTATTR
5715static GLuint zv_value_el_size(GLenum enmzvValue)
5716{
5717 switch (enmzvValue)
5718 {
5719 case GL_FLOAT:
5720 return 4;
5721 case GL_UNSIGNED_SHORT:
5722 case GL_SHORT:
5723 return 2;
5724 case GL_BYTE:
5725 case GL_UNSIGNED_BYTE:
5726 return 1;
5727 default:
5728 ERR("unexpected value type %#x\n", enmzvValue);
5729 return 0;
5730 }
5731}
5732
5733static void zv_create(struct wined3d_device *device, GLenum enmzvValue, GLuint czvValue, GLuint czvValueElements, const GLvoid *pzvValue)
5734{
5735 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
5736 GLuint cbValel = zv_value_el_size(enmzvValue);
5737 GLuint cbVal = cbValel * czvValueElements;
5738 GLuint cbBuf = cbVal * czvValue;
5739 GLvoid *pvBuf;
5740 GLubyte *pubBuf;
5741 GLuint i;
5742
5743 /* quickly sort out if we can use the current value */
5744 if (device->zvBuffer
5745 && device->enmzvValue == enmzvValue
5746 && device->czvValue >= czvValue
5747 && device->czvValueElements == czvValueElements
5748 && !memcmp(pzvValue, &device->zvValue, cbVal))
5749 return;
5750
5751 if (czvValueElements > 4)
5752 {
5753 ERR("invalid czvValueElements %d\n", czvValueElements);
5754 return;
5755 }
5756
5757 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5758 pubBuf = (GLubyte*)pvBuf;
5759
5760 for (i = 0; i < czvValue; ++i)
5761 {
5762 memcpy(pubBuf, pzvValue, cbVal);
5763 pubBuf += cbVal;
5764 }
5765
5766 /* */
5767 if (!device->zvBuffer)
5768 {
5769 GL_EXTCALL(glGenBuffersARB(1, &device->zvBuffer));
5770 Assert(device->zvBuffer);
5771 }
5772
5773 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, device->zvBuffer));
5774
5775 if (device->cbzvBuffer < cbBuf)
5776 {
5777 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, cbBuf, pvBuf, GL_DYNAMIC_DRAW_ARB));
5778 device->cbzvBuffer = cbBuf;
5779 }
5780 else
5781 {
5782 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, cbBuf, pvBuf));
5783 }
5784
5785 device->enmzvValue = enmzvValue;
5786 device->czvValue = czvValue;
5787 device->czvValueElements = czvValueElements;
5788 memcpy(&device->zvValue, pzvValue, cbVal);
5789
5790 HeapFree(GetProcessHeap(), 0, pvBuf);
5791}
5792
5793void zv_destroy(struct wined3d_device *device)
5794{
5795 if (device->zvBuffer)
5796 {
5797 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
5798 GL_EXTCALL(glDeleteBuffersARB(1, &device->zvBuffer));
5799 }
5800
5801 device->zvBuffer = 0;
5802 device->cbzvBuffer = 0;
5803}
5804
5805void zv_bind(struct wined3d_context *context, GLenum enmzvValue, GLuint czvValue, GLuint czvValueElements, GLboolean bzvNormalized, const GLvoid *pzvValue)
5806{
5807 struct wined3d_device *device = context->swapchain->device;
5808 const struct wined3d_gl_info *gl_info = context->gl_info;
5809
5810 zv_create(device, enmzvValue, czvValue, czvValueElements, pzvValue);
5811
5812 Assert(device->zvBuffer);
5813
5814 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, device->zvBuffer));
5815
5816 GL_EXTCALL(glVertexAttribPointerARB(0, czvValueElements,
5817 enmzvValue,
5818 bzvNormalized,
5819 0, /*stride*/
5820 NULL /*addr*/));
5821
5822 if (!(context->numbered_array_mask & (1 << 0)))
5823 {
5824 GL_EXTCALL(glEnableVertexAttribArrayARB(0));
5825 context->numbered_array_mask |= (1 << 0);
5826 }
5827}
5828
5829void zv_bind_by_element(struct wined3d_context *context, const struct wined3d_stream_info_element *element, GLuint czvValue, const GLvoid *pzvValue)
5830{
5831 zv_bind(context, element->format->gl_vtx_type, czvValue, element->format->gl_vtx_format, element->format->gl_normalized, pzvValue);
5832}
5833
5834#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