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