VirtualBox

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

最後變更 在這個檔案從51270是 51270,由 vboxsync 提交於 11 年 前

wine: update to 1.6.2

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

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