VirtualBox

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

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

wined3d: update to wine 1.6

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

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