VirtualBox

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

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

wddm/crOpenGL: some bugfixes, more TexPresent fixes

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

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