wined3d: Make wined3d_event_query_test() and resource_get_type() static.
[wine/wine-gecko.git] / dlls / wined3d / device.c
bloba57ce5ebb93a9c507acc4a7088ac33244b49456b
1 /*
2 * IWineD3DDevice implementation
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
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.
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.
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
29 #include "config.h"
30 #include <stdio.h>
31 #ifdef HAVE_FLOAT_H
32 # include <float.h>
33 #endif
34 #include "wined3d_private.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
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 */
54 /**********************************************************
55 * Global variable / Constants follow
56 **********************************************************/
57 const float identity[] =
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 */
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)
69 switch(primitive_type)
71 case WINED3DPT_POINTLIST:
72 return GL_POINTS;
74 case WINED3DPT_LINELIST:
75 return GL_LINES;
77 case WINED3DPT_LINESTRIP:
78 return GL_LINE_STRIP;
80 case WINED3DPT_TRIANGLELIST:
81 return GL_TRIANGLES;
83 case WINED3DPT_TRIANGLESTRIP:
84 return GL_TRIANGLE_STRIP;
86 case WINED3DPT_TRIANGLEFAN:
87 return GL_TRIANGLE_FAN;
89 case WINED3DPT_LINELIST_ADJ:
90 return GL_LINES_ADJACENCY_ARB;
92 case WINED3DPT_LINESTRIP_ADJ:
93 return GL_LINE_STRIP_ADJACENCY_ARB;
95 case WINED3DPT_TRIANGLELIST_ADJ:
96 return GL_TRIANGLES_ADJACENCY_ARB;
98 case WINED3DPT_TRIANGLESTRIP_ADJ:
99 return GL_TRIANGLE_STRIP_ADJACENCY_ARB;
101 default:
102 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
103 return GL_NONE;
107 static WINED3DPRIMITIVETYPE d3d_primitive_type_from_gl(GLenum primitive_type)
109 switch(primitive_type)
111 case GL_POINTS:
112 return WINED3DPT_POINTLIST;
114 case GL_LINES:
115 return WINED3DPT_LINELIST;
117 case GL_LINE_STRIP:
118 return WINED3DPT_LINESTRIP;
120 case GL_TRIANGLES:
121 return WINED3DPT_TRIANGLELIST;
123 case GL_TRIANGLE_STRIP:
124 return WINED3DPT_TRIANGLESTRIP;
126 case GL_TRIANGLE_FAN:
127 return WINED3DPT_TRIANGLEFAN;
129 case GL_LINES_ADJACENCY_ARB:
130 return WINED3DPT_LINELIST_ADJ;
132 case GL_LINE_STRIP_ADJACENCY_ARB:
133 return WINED3DPT_LINESTRIP_ADJ;
135 case GL_TRIANGLES_ADJACENCY_ARB:
136 return WINED3DPT_TRIANGLELIST_ADJ;
138 case GL_TRIANGLE_STRIP_ADJACENCY_ARB:
139 return WINED3DPT_TRIANGLESTRIP_ADJ;
141 default:
142 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
143 return WINED3DPT_UNDEFINED;
147 static BOOL fixed_get_input(BYTE usage, BYTE usage_idx, unsigned int *regnum)
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
167 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage), usage_idx);
168 *regnum = ~0U;
169 return FALSE;
172 return TRUE;
175 /* Context activation is done by the caller. */
176 void device_stream_info_from_declaration(IWineD3DDeviceImpl *This,
177 BOOL use_vshader, struct wined3d_stream_info *stream_info, BOOL *fixup)
179 /* We need to deal with frequency data! */
180 struct wined3d_vertex_declaration *declaration = This->stateBlock->state.vertex_declaration;
181 unsigned int i;
183 stream_info->use_map = 0;
184 stream_info->swizzle_map = 0;
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;
190 /* Translate the declaration into strided data. */
191 for (i = 0; i < declaration->element_count; ++i)
193 const struct wined3d_vertex_declaration_element *element = &declaration->elements[i];
194 struct wined3d_buffer *buffer = This->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;
201 TRACE("%p Element %p (%u of %u)\n", declaration->elements,
202 element, i + 1, declaration->element_count);
204 if (!buffer) continue;
206 stride = This->stateBlock->state.streams[element->input_slot].stride;
207 if (This->stateBlock->state.user_stream)
209 TRACE("Stream %u is UP, %p\n", element->input_slot, buffer);
210 buffer_object = 0;
211 data = (BYTE *)buffer;
213 else
215 TRACE("Stream %u isn't UP, %p\n", element->input_slot, buffer);
216 data = buffer_get_memory(buffer, &This->adapter->gl_info, &buffer_object);
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 (This->stateBlock->state.load_base_vertex_index < 0)
225 WARN("load_base_vertex_index is < 0 (%d), not using VBOs.\n",
226 This->stateBlock->state.load_base_vertex_index);
227 buffer_object = 0;
228 data = buffer_get_sysmem(buffer, &This->adapter->gl_info);
229 if ((UINT_PTR)data < -This->stateBlock->state.load_base_vertex_index * stride)
231 FIXME("System memory vertex data load offset is negative!\n");
235 if (fixup)
237 if (buffer_object) *fixup = TRUE;
238 else if (*fixup && !use_vshader
239 && (element->usage == WINED3DDECLUSAGE_COLOR
240 || element->usage == WINED3DDECLUSAGE_POSITIONT))
242 static BOOL warned = FALSE;
243 if (!warned)
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;
252 data += element->offset;
254 TRACE("offset %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx);
256 if (use_vshader)
258 if (element->output_slot == ~0U)
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(This->stateBlock->state.vertex_shader,
264 element->usage, element->usage_idx, &idx);
266 else
268 idx = element->output_slot;
269 stride_used = TRUE;
272 else
274 if (!element->ffp_valid)
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;
280 else
282 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
286 if (stride_used)
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);
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;
300 if (!This->adapter->gl_info.supported[ARB_VERTEX_ARRAY_BGRA]
301 && element->format->id == WINED3DFMT_B8G8R8A8_UNORM)
303 stream_info->swizzle_map |= 1 << idx;
305 stream_info->use_map |= 1 << idx;
309 This->num_buffer_queries = 0;
310 if (!This->stateBlock->state.user_stream)
312 WORD map = stream_info->use_map;
314 /* PreLoad all the vertex buffers. */
315 for (i = 0; map; map >>= 1, ++i)
317 struct wined3d_stream_info_element *element;
318 struct wined3d_buffer *buffer;
320 if (!(map & 1)) continue;
322 element = &stream_info->elements[i];
323 buffer = This->stateBlock->state.streams[element->stream_idx].buffer;
324 wined3d_buffer_preload(buffer);
326 /* If PreLoad dropped the buffer object, update the stream info. */
327 if (buffer->buffer_object != element->buffer_object)
329 element->buffer_object = 0;
330 element->data = buffer_get_sysmem(buffer, &This->adapter->gl_info) + (ptrdiff_t)element->data;
333 if (buffer->query)
334 This->buffer_queries[This->num_buffer_queries++] = buffer->query;
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)
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;
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)
352 unsigned int i;
354 memset(stream_info, 0, sizeof(*stream_info));
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]);
365 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
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]);
372 stream_info->position_transformed = strided->position_transformed;
374 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
376 if (!stream_info->elements[i].format) continue;
378 if (!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
379 && stream_info->elements[i].format->id == WINED3DFMT_B8G8R8A8_UNORM)
381 stream_info->swizzle_map |= 1 << i;
383 stream_info->use_map |= 1 << i;
387 static void device_trace_strided_stream_info(const struct wined3d_stream_info *stream_info)
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);
407 /* Context activation is done by the caller. */
408 void device_update_stream_info(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
410 struct wined3d_stream_info *stream_info = &device->strided_streams;
411 const struct wined3d_state *state = &device->stateBlock->state;
412 BOOL fixup = FALSE;
414 if (device->up_strided)
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);
421 else
423 TRACE("============================= Vertex Declaration =============================\n");
424 device_stream_info_from_declaration(device, !!state->vertex_shader, stream_info, &fixup);
427 if (state->vertex_shader && !stream_info->position_transformed)
429 if (state->vertex_declaration->half_float_conv_needed && !fixup)
431 TRACE("Using drawStridedSlow with vertex shaders for FLOAT16 conversion.\n");
432 device->useDrawStridedSlow = TRUE;
434 else
436 device->useDrawStridedSlow = FALSE;
439 else
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));
445 if ((stream_info->position_transformed || (stream_info->use_map & slow_mask)) && !fixup)
447 device->useDrawStridedSlow = TRUE;
449 else
451 device->useDrawStridedSlow = FALSE;
456 static void device_preload_texture(const struct wined3d_state *state, unsigned int idx)
458 struct wined3d_texture *texture;
459 enum WINED3DSRGB srgb;
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);
466 void device_preload_textures(IWineD3DDeviceImpl *device)
468 const struct wined3d_state *state = &device->stateBlock->state;
469 unsigned int i;
471 if (use_vs(state))
473 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i)
475 if (state->vertex_shader->reg_maps.sampler_type[i])
476 device_preload_texture(state, MAX_FRAGMENT_SAMPLERS + i);
480 if (use_ps(state))
482 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i)
484 if (state->pixel_shader->reg_maps.sampler_type[i])
485 device_preload_texture(state, i);
488 else
490 WORD ffu_map = device->fixed_function_usage_map;
492 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
494 if (ffu_map & 1)
495 device_preload_texture(state, i);
500 BOOL device_context_add(IWineD3DDeviceImpl *device, struct wined3d_context *context)
502 struct wined3d_context **new_array;
504 TRACE("Adding context %p.\n", context);
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));
510 if (!new_array)
512 ERR("Failed to grow the context array.\n");
513 return FALSE;
516 new_array[device->context_count++] = context;
517 device->contexts = new_array;
518 return TRUE;
521 void device_context_remove(IWineD3DDeviceImpl *device, struct wined3d_context *context)
523 struct wined3d_context **new_array;
524 BOOL found = FALSE;
525 UINT i;
527 TRACE("Removing context %p.\n", context);
529 for (i = 0; i < device->context_count; ++i)
531 if (device->contexts[i] == context)
533 found = TRUE;
534 break;
538 if (!found)
540 ERR("Context %p doesn't exist in context array.\n", context);
541 return;
544 if (!--device->context_count)
546 HeapFree(GetProcessHeap(), 0, device->contexts);
547 device->contexts = NULL;
548 return;
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)
555 ERR("Failed to shrink context array. Oh well.\n");
556 return;
559 device->contexts = new_array;
562 void device_get_draw_rect(IWineD3DDeviceImpl *device, RECT *rect)
564 struct wined3d_stateblock *stateblock = device->stateBlock;
565 WINED3DVIEWPORT *vp = &stateblock->state.viewport;
567 SetRect(rect, vp->X, vp->Y, vp->X + vp->Width, vp->Y + vp->Height);
569 if (stateblock->state.render_states[WINED3DRS_SCISSORTESTENABLE])
571 IntersectRect(rect, rect, &stateblock->state.scissor_rect);
575 /* Do not call while under the GL lock. */
576 void device_switch_onscreen_ds(IWineD3DDeviceImpl *device,
577 struct wined3d_context *context, struct wined3d_surface *depth_stencil)
579 if (device->onscreen_depth_stencil)
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);
587 device->onscreen_depth_stencil = depth_stencil;
588 wined3d_surface_incref(device->onscreen_depth_stencil);
591 static BOOL is_full_clear(struct wined3d_surface *target, const RECT *draw_rect, const RECT *clear_rect)
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;
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;
605 return TRUE;
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)
611 RECT current_rect, r;
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);
620 IntersectRect(&r, draw_rect, &current_rect);
621 if (EqualRect(&r, draw_rect))
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;
628 if (EqualRect(&r, &current_rect))
630 /* draw_rect ⊇ current_rect, test if we're doing a full clear. */
632 if (!clear_rect)
634 /* Full clear, modify only. */
635 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
636 return;
639 IntersectRect(&r, draw_rect, clear_rect);
640 if (EqualRect(&r, draw_rect))
642 /* clear_rect ⊇ draw_rect, modify only. */
643 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
644 return;
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);
653 /* Do not call while under the GL lock. */
654 HRESULT device_clear_render_targets(IWineD3DDeviceImpl *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)
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;
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.
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))
676 for (i = 0; i < rt_count; ++i)
678 if (rts[i]) surface_load_location(rts[i], SFLAG_INDRAWABLE, NULL);
682 context = context_acquire(device, target);
683 if (!context->valid)
685 context_release(context);
686 WARN("Invalid context, skipping clear.\n");
687 return WINED3D_OK;
690 if (!context_apply_clear_state(context, device, rt_count, rts, depth_stencil))
692 context_release(context);
693 WARN("Failed to apply clear state, skipping clear.\n");
694 return WINED3D_OK;
697 if (target)
699 render_offscreen = context->render_offscreen;
700 target->get_drawable_size(context, &drawable_width, &drawable_height);
702 else
704 render_offscreen = TRUE;
705 drawable_width = depth_stencil->pow2Width;
706 drawable_height = depth_stencil->pow2Height;
709 ENTER_GL();
711 /* Only set the values up once, as they are not changing. */
712 if (flags & WINED3DCLEAR_STENCIL)
714 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
716 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
717 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_TWOSIDEDSTENCILMODE));
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;
726 if (flags & WINED3DCLEAR_ZBUFFER)
728 DWORD location = render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
730 if (location == SFLAG_DS_ONSCREEN && depth_stencil != device->onscreen_depth_stencil)
732 LEAVE_GL();
733 device_switch_onscreen_ds(device, context, depth_stencil);
734 ENTER_GL();
736 prepare_ds_clear(depth_stencil, context, location, draw_rect, rect_count, clear_rect);
737 surface_modify_location(depth_stencil, SFLAG_INDRAWABLE, TRUE);
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;
746 if (flags & WINED3DCLEAR_TARGET)
748 for (i = 0; i < rt_count; ++i)
750 if (rts[i]) surface_modify_location(rts[i], SFLAG_INDRAWABLE, TRUE);
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;
763 if (!clear_rect)
765 if (render_offscreen)
767 glScissor(draw_rect->left, draw_rect->top,
768 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
770 else
772 glScissor(draw_rect->left, drawable_height - draw_rect->bottom,
773 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
775 checkGLcall("glScissor");
776 glClear(clear_mask);
777 checkGLcall("glClear");
779 else
781 RECT current_rect;
783 /* Now process each rect in turn. */
784 for (i = 0; i < rect_count; ++i)
786 /* Note that GL uses lower left, width/height. */
787 IntersectRect(&current_rect, draw_rect, &clear_rect[i]);
789 TRACE("clear_rect[%u] %s, current_rect %s.\n", i,
790 wine_dbgstr_rect(&clear_rect[i]),
791 wine_dbgstr_rect(&current_rect));
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)
798 TRACE("Rectangle with negative dimensions, ignoring.\n");
799 continue;
802 if (render_offscreen)
804 glScissor(current_rect.left, current_rect.top,
805 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
807 else
809 glScissor(current_rect.left, drawable_height - current_rect.bottom,
810 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
812 checkGLcall("glScissor");
814 glClear(clear_mask);
815 checkGLcall("glClear");
819 LEAVE_GL();
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. */
826 context_release(context);
828 return WINED3D_OK;
832 /**********************************************************
833 * IUnknown parts follows
834 **********************************************************/
836 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface, REFIID riid, void **object)
838 TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
840 if (IsEqualGUID(riid, &IID_IWineD3DDevice)
841 || IsEqualGUID(riid, &IID_IUnknown))
843 IUnknown_AddRef(iface);
844 *object = iface;
845 return S_OK;
848 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
850 *object = NULL;
851 return E_NOINTERFACE;
854 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
855 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
856 ULONG refCount = InterlockedIncrement(&This->ref);
858 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
859 return refCount;
862 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
863 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
864 ULONG refCount = InterlockedDecrement(&This->ref);
866 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
868 if (!refCount) {
869 UINT i;
871 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
872 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
873 This->multistate_funcs[i] = NULL;
876 /* TODO: Clean up all the surfaces and textures! */
877 /* NOTE: You must release the parent if the object was created via a callback
878 ** ***************************/
880 if (!list_empty(&This->resources))
882 struct wined3d_resource *resource;
883 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
885 LIST_FOR_EACH_ENTRY(resource, &This->resources, struct wined3d_resource, resource_list_entry)
887 FIXME("Leftover resource %p with type %s (%#x).\n",
888 resource, debug_d3dresourcetype(resource->resourceType), resource->resourceType);
892 if(This->contexts) ERR("Context array not freed!\n");
893 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
894 This->haveHardwareCursor = FALSE;
896 wined3d_decref(This->wined3d);
897 This->wined3d = NULL;
898 HeapFree(GetProcessHeap(), 0, This);
899 TRACE("Freed device %p\n", This);
900 This = NULL;
902 return refCount;
905 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
906 const void *data, void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_buffer **buffer)
908 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
909 struct wined3d_buffer *object;
910 HRESULT hr;
912 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
914 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
915 if (!object)
917 ERR("Failed to allocate memory\n");
918 return E_OUTOFMEMORY;
921 FIXME("Ignoring access flags (pool)\n");
923 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
924 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
925 if (FAILED(hr))
927 WARN("Failed to initialize buffer, hr %#x.\n", hr);
928 HeapFree(GetProcessHeap(), 0, object);
929 return hr;
931 object->desc = *desc;
933 TRACE("Created buffer %p.\n", object);
935 *buffer = object;
937 return WINED3D_OK;
940 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
941 WINED3DPOOL Pool, void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_buffer **buffer)
943 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
944 struct wined3d_buffer *object;
945 HRESULT hr;
947 TRACE("iface %p, size %u, usage %#x, pool %#x, parent %p, parent_ops %p, buffer %p.\n",
948 iface, Size, Usage, Pool, parent, parent_ops, buffer);
950 if (Pool == WINED3DPOOL_SCRATCH)
952 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
953 * anyway, SCRATCH vertex buffers aren't usable anywhere
955 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
956 *buffer = NULL;
957 return WINED3DERR_INVALIDCALL;
960 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
961 if (!object)
963 ERR("Out of memory\n");
964 *buffer = NULL;
965 return WINED3DERR_OUTOFVIDEOMEMORY;
968 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
969 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
970 if (FAILED(hr))
972 WARN("Failed to initialize buffer, hr %#x.\n", hr);
973 HeapFree(GetProcessHeap(), 0, object);
974 return hr;
977 TRACE("Created buffer %p.\n", object);
978 *buffer = object;
980 return WINED3D_OK;
983 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
984 WINED3DPOOL Pool, void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_buffer **buffer)
986 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
987 struct wined3d_buffer *object;
988 HRESULT hr;
990 TRACE("iface %p, size %u, usage %#x, pool %#x, parent %p, parent_ops %p, buffer %p.\n",
991 iface, Length, Usage, Pool, parent, parent_ops, buffer);
993 /* Allocate the storage for the device */
994 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
995 if (!object)
997 ERR("Out of memory\n");
998 *buffer = NULL;
999 return WINED3DERR_OUTOFVIDEOMEMORY;
1002 hr = buffer_init(object, This, Length, Usage | WINED3DUSAGE_STATICDECL,
1003 WINED3DFMT_UNKNOWN, Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL,
1004 parent, parent_ops);
1005 if (FAILED(hr))
1007 WARN("Failed to initialize buffer, hr %#x\n", hr);
1008 HeapFree(GetProcessHeap(), 0, object);
1009 return hr;
1012 TRACE("Created buffer %p.\n", object);
1014 *buffer = object;
1016 return WINED3D_OK;
1019 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
1020 WINED3DSTATEBLOCKTYPE type, struct wined3d_stateblock **stateblock)
1022 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1023 struct wined3d_stateblock *object;
1024 HRESULT hr;
1026 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1027 if(!object)
1029 ERR("Failed to allocate stateblock memory.\n");
1030 return E_OUTOFMEMORY;
1033 hr = stateblock_init(object, This, type);
1034 if (FAILED(hr))
1036 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
1037 HeapFree(GetProcessHeap(), 0, object);
1038 return hr;
1041 TRACE("Created stateblock %p.\n", object);
1042 *stateblock = object;
1044 return WINED3D_OK;
1047 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
1048 enum wined3d_format_id Format, BOOL Lockable, BOOL Discard, UINT Level, DWORD Usage, WINED3DPOOL Pool,
1049 WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, WINED3DSURFTYPE Impl,
1050 void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_surface **surface)
1052 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1053 struct wined3d_surface *object;
1054 HRESULT hr;
1056 TRACE("iface %p, width %u, height %u, format %s (%#x), lockable %#x, discard %#x, level %u\n",
1057 iface, Width, Height, debug_d3dformat(Format), Format, Lockable, Discard, Level);
1058 TRACE("surface %p, usage %s (%#x), pool %s (%#x), multisample_type %#x, multisample_quality %u\n",
1059 surface, debug_d3dusage(Usage), Usage, debug_d3dpool(Pool), Pool, MultiSample, MultisampleQuality);
1060 TRACE("surface_type %#x, parent %p, parent_ops %p.\n", Impl, parent, parent_ops);
1062 if (Impl == SURFACE_OPENGL && !This->adapter)
1064 ERR("OpenGL surfaces are not available without OpenGL.\n");
1065 return WINED3DERR_NOTAVAILABLE;
1068 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1069 if (!object)
1071 ERR("Failed to allocate surface memory.\n");
1072 return WINED3DERR_OUTOFVIDEOMEMORY;
1075 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
1076 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
1077 if (FAILED(hr))
1079 WARN("Failed to initialize surface, returning %#x.\n", hr);
1080 HeapFree(GetProcessHeap(), 0, object);
1081 return hr;
1084 TRACE("(%p) : Created surface %p\n", This, object);
1086 *surface = object;
1088 return hr;
1091 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
1092 struct wined3d_resource *resource, void *parent, struct wined3d_rendertarget_view **rendertarget_view)
1094 struct wined3d_rendertarget_view *object;
1096 TRACE("iface %p, resource %p, parent %p, rendertarget_view %p.\n",
1097 iface, resource, parent, rendertarget_view);
1099 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1100 if (!object)
1102 ERR("Failed to allocate memory\n");
1103 return E_OUTOFMEMORY;
1106 wined3d_rendertarget_view_init(object, resource, parent);
1108 TRACE("Created render target view %p.\n", object);
1109 *rendertarget_view = object;
1111 return WINED3D_OK;
1114 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
1115 UINT Width, UINT Height, UINT Levels, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool,
1116 void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_texture **texture)
1118 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1119 struct wined3d_texture *object;
1120 HRESULT hr;
1122 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
1123 TRACE("Format %#x (%s), Pool %#x, texture %p, parent %p\n",
1124 Format, debug_d3dformat(Format), Pool, texture, parent);
1126 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1127 if (!object)
1129 ERR("Out of memory\n");
1130 *texture = NULL;
1131 return WINED3DERR_OUTOFVIDEOMEMORY;
1134 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
1135 if (FAILED(hr))
1137 WARN("Failed to initialize texture, returning %#x\n", hr);
1138 HeapFree(GetProcessHeap(), 0, object);
1139 *texture = NULL;
1140 return hr;
1143 *texture = object;
1145 TRACE("(%p) : Created texture %p\n", This, object);
1147 return WINED3D_OK;
1150 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1151 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool,
1152 void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_texture **texture)
1154 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1155 struct wined3d_texture *object;
1156 HRESULT hr;
1158 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1159 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1161 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1162 if (!object)
1164 ERR("Out of memory\n");
1165 *texture = NULL;
1166 return WINED3DERR_OUTOFVIDEOMEMORY;
1169 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
1170 if (FAILED(hr))
1172 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
1173 HeapFree(GetProcessHeap(), 0, object);
1174 *texture = NULL;
1175 return hr;
1178 TRACE("(%p) : Created volume texture %p.\n", This, object);
1179 *texture = object;
1181 return WINED3D_OK;
1184 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
1185 UINT Depth, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool, void *parent,
1186 const struct wined3d_parent_ops *parent_ops, struct wined3d_volume **volume)
1188 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1189 struct wined3d_volume *object;
1190 HRESULT hr;
1192 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1193 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1195 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1196 if (!object)
1198 ERR("Out of memory\n");
1199 *volume = NULL;
1200 return WINED3DERR_OUTOFVIDEOMEMORY;
1203 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
1204 if (FAILED(hr))
1206 WARN("Failed to initialize volume, returning %#x.\n", hr);
1207 HeapFree(GetProcessHeap(), 0, object);
1208 return hr;
1211 TRACE("(%p) : Created volume %p.\n", This, object);
1212 *volume = object;
1214 return WINED3D_OK;
1217 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
1218 DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool, void *parent,
1219 const struct wined3d_parent_ops *parent_ops, struct wined3d_texture **texture)
1221 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1222 struct wined3d_texture *object;
1223 HRESULT hr;
1225 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1226 if (!object)
1228 ERR("Out of memory\n");
1229 *texture = NULL;
1230 return WINED3DERR_OUTOFVIDEOMEMORY;
1233 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
1234 if (FAILED(hr))
1236 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
1237 HeapFree(GetProcessHeap(), 0, object);
1238 *texture = NULL;
1239 return hr;
1242 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1243 *texture = object;
1245 return WINED3D_OK;
1248 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface,
1249 WINED3DQUERYTYPE type, struct wined3d_query **query)
1251 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1252 struct wined3d_query *object;
1253 HRESULT hr;
1255 TRACE("iface %p, type %#x, query %p.\n", iface, type, query);
1257 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1258 if (!object)
1260 ERR("Failed to allocate query memory.\n");
1261 return E_OUTOFMEMORY;
1264 hr = query_init(object, This, type);
1265 if (FAILED(hr))
1267 WARN("Failed to initialize query, hr %#x.\n", hr);
1268 HeapFree(GetProcessHeap(), 0, object);
1269 return hr;
1272 TRACE("Created query %p.\n", object);
1273 *query = object;
1275 return WINED3D_OK;
1278 /* Do not call while under the GL lock. */
1279 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1280 WINED3DPRESENT_PARAMETERS *present_parameters, WINED3DSURFTYPE surface_type,
1281 void *parent, const struct wined3d_parent_ops *parent_ops,
1282 struct wined3d_swapchain **swapchain)
1284 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1285 struct wined3d_swapchain *object;
1286 HRESULT hr;
1288 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
1289 iface, present_parameters, swapchain, parent, surface_type);
1291 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1292 if (!object)
1294 ERR("Failed to allocate swapchain memory.\n");
1295 return E_OUTOFMEMORY;
1298 hr = swapchain_init(object, surface_type, This, present_parameters, parent, parent_ops);
1299 if (FAILED(hr))
1301 WARN("Failed to initialize swapchain, hr %#x.\n", hr);
1302 HeapFree(GetProcessHeap(), 0, object);
1303 return hr;
1306 TRACE("Created swapchain %p.\n", object);
1307 *swapchain = object;
1309 return WINED3D_OK;
1312 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface)
1314 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1316 TRACE("iface %p.\n", iface);
1318 return device->swapchain_count;
1321 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface,
1322 UINT swapchain_idx, struct wined3d_swapchain **swapchain)
1324 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1326 TRACE("iface %p, swapchain_idx %u, swapchain %p.\n",
1327 iface, swapchain_idx, swapchain);
1329 if (swapchain_idx >= device->swapchain_count)
1331 WARN("swapchain_idx %u >= swapchain_count %u.\n",
1332 swapchain_idx, device->swapchain_count);
1333 *swapchain = NULL;
1335 return WINED3DERR_INVALIDCALL;
1338 *swapchain = device->swapchains[swapchain_idx];
1339 wined3d_swapchain_incref(*swapchain);
1340 TRACE("Returning %p.\n", *swapchain);
1342 return WINED3D_OK;
1345 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
1346 const WINED3DVERTEXELEMENT *elements, UINT element_count, void *parent,
1347 const struct wined3d_parent_ops *parent_ops, struct wined3d_vertex_declaration **declaration)
1349 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1350 struct wined3d_vertex_declaration *object;
1351 HRESULT hr;
1353 TRACE("iface %p, elements %p, element_count %u, parent %p, parent_ops %p, declaration %p.\n",
1354 iface, elements, element_count, parent, parent_ops, declaration);
1356 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1357 if(!object)
1359 ERR("Failed to allocate vertex declaration memory.\n");
1360 return E_OUTOFMEMORY;
1363 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1364 if (FAILED(hr))
1366 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1367 HeapFree(GetProcessHeap(), 0, object);
1368 return hr;
1371 TRACE("Created vertex declaration %p.\n", object);
1372 *declaration = object;
1374 return WINED3D_OK;
1377 struct wined3d_fvf_convert_state
1379 const struct wined3d_gl_info *gl_info;
1380 WINED3DVERTEXELEMENT *elements;
1381 UINT offset;
1382 UINT idx;
1385 static void append_decl_element(struct wined3d_fvf_convert_state *state,
1386 enum wined3d_format_id format_id, WINED3DDECLUSAGE usage, UINT usage_idx)
1388 WINED3DVERTEXELEMENT *elements = state->elements;
1389 const struct wined3d_format *format;
1390 UINT offset = state->offset;
1391 UINT idx = state->idx;
1393 elements[idx].format = format_id;
1394 elements[idx].input_slot = 0;
1395 elements[idx].offset = offset;
1396 elements[idx].output_slot = 0;
1397 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1398 elements[idx].usage = usage;
1399 elements[idx].usage_idx = usage_idx;
1401 format = wined3d_get_format(state->gl_info, format_id);
1402 state->offset += format->component_count * format->component_size;
1403 ++state->idx;
1406 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1407 DWORD fvf, WINED3DVERTEXELEMENT **ppVertexElements)
1409 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1410 BOOL has_pos = !!(fvf & WINED3DFVF_POSITION_MASK);
1411 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1412 BOOL has_blend_idx = has_blend &&
1413 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1414 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1415 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1416 BOOL has_normal = !!(fvf & WINED3DFVF_NORMAL);
1417 BOOL has_psize = !!(fvf & WINED3DFVF_PSIZE);
1418 BOOL has_diffuse = !!(fvf & WINED3DFVF_DIFFUSE);
1419 BOOL has_specular = !!(fvf & WINED3DFVF_SPECULAR);
1421 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1422 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1423 struct wined3d_fvf_convert_state state;
1424 unsigned int size;
1425 unsigned int idx;
1426 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1427 if (has_blend_idx) num_blends--;
1429 /* Compute declaration size */
1430 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1431 has_psize + has_diffuse + has_specular + num_textures;
1433 state.gl_info = gl_info;
1434 state.elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*state.elements));
1435 if (!state.elements) return ~0U;
1436 state.offset = 0;
1437 state.idx = 0;
1439 if (has_pos)
1441 if (!has_blend && (fvf & WINED3DFVF_XYZRHW))
1442 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITIONT, 0);
1443 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW)
1444 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1445 else
1446 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1449 if (has_blend && (num_blends > 0))
1451 if ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1452 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1453 else
1455 switch (num_blends)
1457 case 1:
1458 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1459 break;
1460 case 2:
1461 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1462 break;
1463 case 3:
1464 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1465 break;
1466 case 4:
1467 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1468 break;
1469 default:
1470 ERR("Unexpected amount of blend values: %u\n", num_blends);
1475 if (has_blend_idx)
1477 if ((fvf & WINED3DFVF_LASTBETA_UBYTE4)
1478 || ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1479 append_decl_element(&state, WINED3DFMT_R8G8B8A8_UINT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1480 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1481 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDINDICES, 0);
1482 else
1483 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1486 if (has_normal) append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_NORMAL, 0);
1487 if (has_psize) append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_PSIZE, 0);
1488 if (has_diffuse) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 0);
1489 if (has_specular) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 1);
1491 for (idx = 0; idx < num_textures; ++idx)
1493 switch ((texcoords >> (idx * 2)) & 0x03)
1495 case WINED3DFVF_TEXTUREFORMAT1:
1496 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1497 break;
1498 case WINED3DFVF_TEXTUREFORMAT2:
1499 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1500 break;
1501 case WINED3DFVF_TEXTUREFORMAT3:
1502 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1503 break;
1504 case WINED3DFVF_TEXTUREFORMAT4:
1505 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1506 break;
1510 *ppVertexElements = state.elements;
1511 return size;
1514 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1515 DWORD fvf, void *parent, const struct wined3d_parent_ops *parent_ops,
1516 struct wined3d_vertex_declaration **declaration)
1518 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1519 WINED3DVERTEXELEMENT *elements;
1520 unsigned int size;
1521 DWORD hr;
1523 TRACE("iface %p, fvf %#x, parent %p, parent_ops %p, declaration %p.\n",
1524 iface, fvf, parent, parent_ops, declaration);
1526 size = ConvertFvfToDeclaration(This, fvf, &elements);
1527 if (size == ~0U) return E_OUTOFMEMORY;
1529 hr = IWineD3DDeviceImpl_CreateVertexDeclaration(iface, elements, size, parent, parent_ops, declaration);
1530 HeapFree(GetProcessHeap(), 0, elements);
1531 return hr;
1534 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1535 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1536 void *parent, const struct wined3d_parent_ops *parent_ops,
1537 struct wined3d_shader **shader)
1539 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1540 struct wined3d_shader *object;
1541 HRESULT hr;
1543 if (This->vs_selected_mode == SHADER_NONE)
1544 return WINED3DERR_INVALIDCALL;
1546 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1547 if (!object)
1549 ERR("Failed to allocate shader memory.\n");
1550 return E_OUTOFMEMORY;
1553 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1554 if (FAILED(hr))
1556 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1557 HeapFree(GetProcessHeap(), 0, object);
1558 return hr;
1561 TRACE("Created vertex shader %p.\n", object);
1562 *shader = object;
1564 return WINED3D_OK;
1567 static HRESULT WINAPI IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice *iface,
1568 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
1569 void *parent, const struct wined3d_parent_ops *parent_ops,
1570 struct wined3d_shader **shader)
1572 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1573 struct wined3d_shader *object;
1574 HRESULT hr;
1576 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1577 if (!object)
1579 ERR("Failed to allocate shader memory.\n");
1580 return E_OUTOFMEMORY;
1583 hr = geometryshader_init(object, This, byte_code, output_signature, parent, parent_ops);
1584 if (FAILED(hr))
1586 WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
1587 HeapFree(GetProcessHeap(), 0, object);
1588 return hr;
1591 TRACE("Created geometry shader %p.\n", object);
1592 *shader = object;
1594 return WINED3D_OK;
1597 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1598 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1599 void *parent, const struct wined3d_parent_ops *parent_ops,
1600 struct wined3d_shader **shader)
1602 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1603 struct wined3d_shader *object;
1604 HRESULT hr;
1606 if (This->ps_selected_mode == SHADER_NONE)
1607 return WINED3DERR_INVALIDCALL;
1609 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1610 if (!object)
1612 ERR("Failed to allocate shader memory.\n");
1613 return E_OUTOFMEMORY;
1616 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1617 if (FAILED(hr))
1619 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1620 HeapFree(GetProcessHeap(), 0, object);
1621 return hr;
1624 TRACE("Created pixel shader %p.\n", object);
1625 *shader = object;
1627 return WINED3D_OK;
1630 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD flags,
1631 const PALETTEENTRY *entries, void *parent, struct wined3d_palette **palette)
1633 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1634 struct wined3d_palette *object;
1635 HRESULT hr;
1637 TRACE("iface %p, flags %#x, entries %p, palette %p, parent %p.\n",
1638 iface, flags, entries, palette, parent);
1640 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1641 if (!object)
1643 ERR("Failed to allocate palette memory.\n");
1644 return E_OUTOFMEMORY;
1647 hr = wined3d_palette_init(object, This, flags, entries, parent);
1648 if (FAILED(hr))
1650 WARN("Failed to initialize palette, hr %#x.\n", hr);
1651 HeapFree(GetProcessHeap(), 0, object);
1652 return hr;
1655 TRACE("Created palette %p.\n", object);
1656 *palette = object;
1658 return WINED3D_OK;
1661 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1662 HBITMAP hbm;
1663 BITMAP bm;
1664 HRESULT hr;
1665 HDC dcb = NULL, dcs = NULL;
1666 WINEDDCOLORKEY colorkey;
1668 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1669 if(hbm)
1671 GetObjectA(hbm, sizeof(BITMAP), &bm);
1672 dcb = CreateCompatibleDC(NULL);
1673 if(!dcb) goto out;
1674 SelectObject(dcb, hbm);
1676 else
1678 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1679 * couldn't be loaded
1681 memset(&bm, 0, sizeof(bm));
1682 bm.bmWidth = 32;
1683 bm.bmHeight = 32;
1686 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1687 FALSE, 0, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL, NULL,
1688 &wined3d_null_parent_ops, &This->logo_surface);
1689 if (FAILED(hr))
1691 ERR("Wine logo requested, but failed to create surface, hr %#x.\n", hr);
1692 goto out;
1695 if (dcb)
1697 if (FAILED(hr = wined3d_surface_getdc(This->logo_surface, &dcs)))
1698 goto out;
1699 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1700 wined3d_surface_releasedc(This->logo_surface, dcs);
1702 colorkey.dwColorSpaceLowValue = 0;
1703 colorkey.dwColorSpaceHighValue = 0;
1704 wined3d_surface_set_color_key(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1706 else
1708 const WINED3DCOLORVALUE c = {1.0f, 1.0f, 1.0f, 1.0f};
1709 /* Fill the surface with a white color to show that wined3d is there */
1710 IWineD3DDevice_ColorFill((IWineD3DDevice *)This, This->logo_surface, NULL, &c);
1713 out:
1714 if (dcb) DeleteDC(dcb);
1715 if (hbm) DeleteObject(hbm);
1718 /* Context activation is done by the caller. */
1719 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1721 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1722 unsigned int i;
1723 /* Under DirectX you can have texture stage operations even if no texture is
1724 bound, whereas opengl will only do texture operations when a valid texture is
1725 bound. We emulate this by creating dummy textures and binding them to each
1726 texture stage, but disable all stages by default. Hence if a stage is enabled
1727 then the default texture will kick in until replaced by a SetTexture call */
1728 ENTER_GL();
1730 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1732 /* The dummy texture does not have client storage backing */
1733 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1734 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1737 for (i = 0; i < gl_info->limits.textures; ++i)
1739 GLubyte white = 255;
1741 /* Make appropriate texture active */
1742 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1743 checkGLcall("glActiveTextureARB");
1745 /* Generate an opengl texture name */
1746 glGenTextures(1, &This->dummyTextureName[i]);
1747 checkGLcall("glGenTextures");
1748 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1750 /* Generate a dummy 2d texture (not using 1d because they cause many
1751 * DRI drivers fall back to sw) */
1752 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1753 checkGLcall("glBindTexture");
1755 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1756 checkGLcall("glTexImage2D");
1759 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1761 /* Reenable because if supported it is enabled by default */
1762 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1763 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1766 LEAVE_GL();
1769 /* Context activation is done by the caller. */
1770 static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1772 ENTER_GL();
1773 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1774 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1775 LEAVE_GL();
1777 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1780 static LONG fullscreen_style(LONG style)
1782 /* Make sure the window is managed, otherwise we won't get keyboard input. */
1783 style |= WS_POPUP | WS_SYSMENU;
1784 style &= ~(WS_CAPTION | WS_THICKFRAME);
1786 return style;
1789 static LONG fullscreen_exstyle(LONG exstyle)
1791 /* Filter out window decorations. */
1792 exstyle &= ~(WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE);
1794 return exstyle;
1797 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h)
1799 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1800 BOOL filter_messages;
1801 LONG style, exstyle;
1803 TRACE("Setting up window %p for fullscreen mode.\n", window);
1805 if (device->style || device->exStyle)
1807 ERR("Changing the window style for window %p, but another style (%08x, %08x) is already stored.\n",
1808 window, device->style, device->exStyle);
1811 device->style = GetWindowLongW(window, GWL_STYLE);
1812 device->exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1814 style = fullscreen_style(device->style);
1815 exstyle = fullscreen_exstyle(device->exStyle);
1817 TRACE("Old style was %08x, %08x, setting to %08x, %08x.\n",
1818 device->style, device->exStyle, style, exstyle);
1820 filter_messages = device->filter_messages;
1821 device->filter_messages = TRUE;
1823 SetWindowLongW(window, GWL_STYLE, style);
1824 SetWindowLongW(window, GWL_EXSTYLE, exstyle);
1825 SetWindowPos(window, HWND_TOP, 0, 0, w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOACTIVATE);
1827 device->filter_messages = filter_messages;
1830 static void WINAPI IWineD3DDeviceImpl_RestoreFullscreenWindow(IWineD3DDevice *iface, HWND window)
1832 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1833 BOOL filter_messages;
1834 LONG style, exstyle;
1836 if (!device->style && !device->exStyle) return;
1838 TRACE("Restoring window style of window %p to %08x, %08x.\n",
1839 window, device->style, device->exStyle);
1841 style = GetWindowLongW(window, GWL_STYLE);
1842 exstyle = GetWindowLongW(window, GWL_EXSTYLE);
1844 filter_messages = device->filter_messages;
1845 device->filter_messages = TRUE;
1847 /* Only restore the style if the application didn't modify it during the
1848 * fullscreen phase. Some applications change it before calling Reset()
1849 * when switching between windowed and fullscreen modes (HL2), some
1850 * depend on the original style (Eve Online). */
1851 if (style == fullscreen_style(device->style) && exstyle == fullscreen_exstyle(device->exStyle))
1853 SetWindowLongW(window, GWL_STYLE, device->style);
1854 SetWindowLongW(window, GWL_EXSTYLE, device->exStyle);
1856 SetWindowPos(window, 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
1858 device->filter_messages = filter_messages;
1860 /* Delete the old values. */
1861 device->style = 0;
1862 device->exStyle = 0;
1865 static HRESULT WINAPI IWineD3DDeviceImpl_AcquireFocusWindow(IWineD3DDevice *iface, HWND window)
1867 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1869 TRACE("iface %p, window %p.\n", iface, window);
1871 if (!wined3d_register_window(window, device))
1873 ERR("Failed to register window %p.\n", window);
1874 return E_FAIL;
1877 device->focus_window = window;
1878 SetWindowPos(window, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
1880 return WINED3D_OK;
1883 static void WINAPI IWineD3DDeviceImpl_ReleaseFocusWindow(IWineD3DDevice *iface)
1885 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1887 TRACE("iface %p.\n", iface);
1889 if (device->focus_window) wined3d_unregister_window(device->focus_window);
1890 device->focus_window = NULL;
1893 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1894 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1896 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1897 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1898 struct wined3d_swapchain *swapchain = NULL;
1899 struct wined3d_context *context;
1900 HRESULT hr;
1901 DWORD state;
1902 unsigned int i;
1904 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1906 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1907 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1909 TRACE("(%p) : Creating stateblock\n", This);
1910 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, &This->stateBlock);
1911 if (FAILED(hr))
1913 WARN("Failed to create stateblock\n");
1914 goto err_out;
1916 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1917 This->updateStateBlock = This->stateBlock;
1918 wined3d_stateblock_incref(This->updateStateBlock);
1920 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1921 sizeof(*This->render_targets) * gl_info->limits.buffers);
1923 This->palette_count = 1;
1924 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1925 if (!This->palettes || !This->render_targets)
1927 ERR("Out of memory!\n");
1928 hr = E_OUTOFMEMORY;
1929 goto err_out;
1931 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1932 if(!This->palettes[0]) {
1933 ERR("Out of memory!\n");
1934 hr = E_OUTOFMEMORY;
1935 goto err_out;
1937 for (i = 0; i < 256; ++i) {
1938 This->palettes[0][i].peRed = 0xFF;
1939 This->palettes[0][i].peGreen = 0xFF;
1940 This->palettes[0][i].peBlue = 0xFF;
1941 This->palettes[0][i].peFlags = 0xFF;
1943 This->currentPalette = 0;
1945 /* Initialize the texture unit mapping to a 1:1 mapping */
1946 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1948 if (state < gl_info->limits.fragment_samplers)
1950 This->texUnitMap[state] = state;
1951 This->rev_tex_unit_map[state] = state;
1952 } else {
1953 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1954 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1958 /* Setup the implicit swapchain. This also initializes a context. */
1959 TRACE("Creating implicit swapchain\n");
1960 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1961 pPresentationParameters, &swapchain);
1962 if (FAILED(hr))
1964 WARN("Failed to create implicit swapchain\n");
1965 goto err_out;
1968 This->swapchain_count = 1;
1969 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->swapchain_count * sizeof(*This->swapchains));
1970 if (!This->swapchains)
1972 ERR("Out of memory!\n");
1973 goto err_out;
1975 This->swapchains[0] = swapchain;
1977 if (swapchain->back_buffers && swapchain->back_buffers[0])
1979 TRACE("Setting rendertarget to %p.\n", swapchain->back_buffers);
1980 This->render_targets[0] = swapchain->back_buffers[0];
1982 else
1984 TRACE("Setting rendertarget to %p.\n", swapchain->front_buffer);
1985 This->render_targets[0] = swapchain->front_buffer;
1987 wined3d_surface_incref(This->render_targets[0]);
1989 /* Depth Stencil support */
1990 This->depth_stencil = This->auto_depth_stencil;
1991 if (This->depth_stencil)
1992 wined3d_surface_incref(This->depth_stencil);
1994 hr = This->shader_backend->shader_alloc_private(This);
1995 if(FAILED(hr)) {
1996 TRACE("Shader private data couldn't be allocated\n");
1997 goto err_out;
1999 hr = This->frag_pipe->alloc_private(This);
2000 if(FAILED(hr)) {
2001 TRACE("Fragment pipeline private data couldn't be allocated\n");
2002 goto err_out;
2004 hr = This->blitter->alloc_private(This);
2005 if(FAILED(hr)) {
2006 TRACE("Blitter private data couldn't be allocated\n");
2007 goto err_out;
2010 /* Set up some starting GL setup */
2012 /* Setup all the devices defaults */
2013 stateblock_init_default_state(This->stateBlock);
2015 context = context_acquire(This, swapchain->front_buffer);
2017 create_dummy_textures(This);
2019 ENTER_GL();
2021 /* Initialize the current view state */
2022 This->view_ident = 1;
2023 This->contexts[0]->last_was_rhw = 0;
2024 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2025 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2027 switch(wined3d_settings.offscreen_rendering_mode) {
2028 case ORM_FBO:
2029 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
2030 break;
2032 case ORM_BACKBUFFER:
2034 if (context_get_current()->aux_buffers > 0)
2036 TRACE("Using auxilliary buffer for offscreen rendering\n");
2037 This->offscreenBuffer = GL_AUX0;
2038 } else {
2039 TRACE("Using back buffer for offscreen rendering\n");
2040 This->offscreenBuffer = GL_BACK;
2045 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2046 LEAVE_GL();
2048 context_release(context);
2050 /* Clear the screen */
2051 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2052 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2053 0x00, 1.0f, 0);
2055 This->d3d_initialized = TRUE;
2057 if(wined3d_settings.logo) {
2058 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2060 This->highest_dirty_ps_const = 0;
2061 This->highest_dirty_vs_const = 0;
2062 return WINED3D_OK;
2064 err_out:
2065 HeapFree(GetProcessHeap(), 0, This->render_targets);
2066 HeapFree(GetProcessHeap(), 0, This->swapchains);
2067 This->swapchain_count = 0;
2068 if (This->palettes)
2070 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2071 HeapFree(GetProcessHeap(), 0, This->palettes);
2073 This->palette_count = 0;
2074 if (swapchain)
2075 wined3d_swapchain_decref(swapchain);
2076 if (This->stateBlock)
2078 wined3d_stateblock_decref(This->stateBlock);
2079 This->stateBlock = NULL;
2081 if (This->blit_priv) {
2082 This->blitter->free_private(This);
2084 if (This->fragment_priv) {
2085 This->frag_pipe->free_private(This);
2087 if (This->shader_priv) {
2088 This->shader_backend->shader_free_private(This);
2090 return hr;
2093 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
2094 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2096 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2097 struct wined3d_swapchain *swapchain = NULL;
2098 HRESULT hr;
2100 /* Setup the implicit swapchain */
2101 TRACE("Creating implicit swapchain\n");
2102 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2103 pPresentationParameters, &swapchain);
2104 if (FAILED(hr))
2106 WARN("Failed to create implicit swapchain\n");
2107 goto err_out;
2110 This->swapchain_count = 1;
2111 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->swapchain_count * sizeof(*This->swapchains));
2112 if (!This->swapchains)
2114 ERR("Out of memory!\n");
2115 goto err_out;
2117 This->swapchains[0] = swapchain;
2118 return WINED3D_OK;
2120 err_out:
2121 wined3d_swapchain_decref(swapchain);
2122 return hr;
2125 static HRESULT WINAPI device_unload_resource(struct wined3d_resource *resource, void *data)
2127 TRACE("Unloading resource %p.\n", resource);
2129 resource->resource_ops->resource_unload(resource);
2131 return S_OK;
2134 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface)
2136 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2137 const struct wined3d_gl_info *gl_info;
2138 struct wined3d_context *context;
2139 struct wined3d_surface *surface;
2140 UINT i;
2141 TRACE("(%p)\n", This);
2143 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2145 /* Force making the context current again, to verify it is still valid
2146 * (workaround for broken drivers) */
2147 context_set_current(NULL);
2148 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2149 * it was created. Thus make sure a context is active for the glDelete* calls
2151 context = context_acquire(This, NULL);
2152 gl_info = context->gl_info;
2154 if (This->logo_surface)
2155 wined3d_surface_decref(This->logo_surface);
2157 /* Unload resources */
2158 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2160 TRACE("Deleting high order patches\n");
2161 for(i = 0; i < PATCHMAP_SIZE; i++) {
2162 struct list *e1, *e2;
2163 struct WineD3DRectPatch *patch;
2164 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2165 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2166 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2170 /* Delete the mouse cursor texture */
2171 if(This->cursorTexture) {
2172 ENTER_GL();
2173 glDeleteTextures(1, &This->cursorTexture);
2174 LEAVE_GL();
2175 This->cursorTexture = 0;
2178 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2179 * private data, it might contain opengl pointers
2181 if(This->depth_blt_texture) {
2182 ENTER_GL();
2183 glDeleteTextures(1, &This->depth_blt_texture);
2184 LEAVE_GL();
2185 This->depth_blt_texture = 0;
2187 if (This->depth_blt_rb) {
2188 ENTER_GL();
2189 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
2190 LEAVE_GL();
2191 This->depth_blt_rb = 0;
2192 This->depth_blt_rb_w = 0;
2193 This->depth_blt_rb_h = 0;
2196 /* Release the update stateblock */
2197 if (wined3d_stateblock_decref(This->updateStateBlock))
2199 if (This->updateStateBlock != This->stateBlock)
2200 FIXME("Something's still holding the update stateblock.\n");
2202 This->updateStateBlock = NULL;
2205 struct wined3d_stateblock *stateblock = This->stateBlock;
2206 This->stateBlock = NULL;
2208 /* Release the stateblock */
2209 if (wined3d_stateblock_decref(stateblock))
2210 FIXME("Something's still holding the stateblock.\n");
2213 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2214 This->blitter->free_private(This);
2215 This->frag_pipe->free_private(This);
2216 This->shader_backend->shader_free_private(This);
2218 /* Release the buffers (with sanity checks)*/
2219 if (This->onscreen_depth_stencil)
2221 surface = This->onscreen_depth_stencil;
2222 This->onscreen_depth_stencil = NULL;
2223 wined3d_surface_decref(surface);
2226 if (This->depth_stencil)
2228 surface = This->depth_stencil;
2230 TRACE("Releasing depth/stencil buffer %p.\n", surface);
2232 This->depth_stencil = NULL;
2233 if (wined3d_surface_decref(surface)
2234 && surface != This->auto_depth_stencil)
2236 ERR("Something is still holding a reference to depth/stencil buffer %p.\n", surface);
2240 if (This->auto_depth_stencil)
2242 surface = This->auto_depth_stencil;
2243 This->auto_depth_stencil = NULL;
2244 if (wined3d_surface_decref(surface))
2246 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2250 for (i = 1; i < gl_info->limits.buffers; ++i)
2252 IWineD3DDevice_SetRenderTarget(iface, i, NULL, FALSE);
2255 surface = This->render_targets[0];
2256 TRACE("Setting rendertarget 0 to NULL\n");
2257 This->render_targets[0] = NULL;
2258 TRACE("Releasing the render target at %p\n", surface);
2259 wined3d_surface_decref(surface);
2261 context_release(context);
2263 for (i = 0; i < This->swapchain_count; ++i)
2265 TRACE("Releasing the implicit swapchain %u.\n", i);
2266 if (wined3d_swapchain_decref(This->swapchains[i]))
2267 FIXME("Something's still holding the implicit swapchain.\n");
2270 HeapFree(GetProcessHeap(), 0, This->swapchains);
2271 This->swapchains = NULL;
2272 This->swapchain_count = 0;
2274 for (i = 0; i < This->palette_count; ++i)
2275 HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2276 HeapFree(GetProcessHeap(), 0, This->palettes);
2277 This->palettes = NULL;
2278 This->palette_count = 0;
2280 HeapFree(GetProcessHeap(), 0, This->render_targets);
2281 This->render_targets = NULL;
2283 This->d3d_initialized = FALSE;
2285 return WINED3D_OK;
2288 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface)
2290 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2291 unsigned int i;
2293 for (i = 0; i < This->swapchain_count; ++i)
2295 TRACE("Releasing the implicit swapchain %u.\n", i);
2296 if (wined3d_swapchain_decref(This->swapchains[i]))
2297 FIXME("Something's still holding the implicit swapchain.\n");
2300 HeapFree(GetProcessHeap(), 0, This->swapchains);
2301 This->swapchains = NULL;
2302 This->swapchain_count = 0;
2303 return WINED3D_OK;
2306 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2307 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2308 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2310 * There is no way to deactivate thread safety once it is enabled.
2312 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2313 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2315 /*For now just store the flag(needed in case of ddraw) */
2316 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2319 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2320 const WINED3DDISPLAYMODE* pMode) {
2321 DEVMODEW devmode;
2322 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2323 const struct wined3d_format *format = wined3d_get_format(&This->adapter->gl_info, pMode->Format);
2324 LONG ret;
2325 RECT clip_rc;
2327 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2329 /* Resize the screen even without a window:
2330 * The app could have unset it with SetCooperativeLevel, but not called
2331 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2332 * but we don't have any hwnd
2335 memset(&devmode, 0, sizeof(devmode));
2336 devmode.dmSize = sizeof(devmode);
2337 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2338 devmode.dmBitsPerPel = format->byte_count * CHAR_BIT;
2339 devmode.dmPelsWidth = pMode->Width;
2340 devmode.dmPelsHeight = pMode->Height;
2342 devmode.dmDisplayFrequency = pMode->RefreshRate;
2343 if (pMode->RefreshRate)
2344 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2346 /* Only change the mode if necessary */
2347 if (This->ddraw_width == pMode->Width && This->ddraw_height == pMode->Height
2348 && This->ddraw_format == pMode->Format && !pMode->RefreshRate)
2349 return WINED3D_OK;
2351 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2352 if (ret != DISP_CHANGE_SUCCESSFUL)
2354 if (devmode.dmDisplayFrequency)
2356 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2357 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2358 devmode.dmDisplayFrequency = 0;
2359 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2361 if(ret != DISP_CHANGE_SUCCESSFUL) {
2362 return WINED3DERR_NOTAVAILABLE;
2366 /* Store the new values */
2367 This->ddraw_width = pMode->Width;
2368 This->ddraw_height = pMode->Height;
2369 This->ddraw_format = pMode->Format;
2371 /* And finally clip mouse to our screen */
2372 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2373 ClipCursor(&clip_rc);
2375 return WINED3D_OK;
2378 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, struct wined3d **wined3d)
2380 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2382 TRACE("iface %p, wined3d %p.\n", iface, wined3d);
2384 *wined3d = device->wined3d;
2385 wined3d_incref(*wined3d);
2387 TRACE("Returning %p.\n", *wined3d);
2389 return WINED3D_OK;
2392 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2393 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2395 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2396 (This->adapter->TextureRam/(1024*1024)),
2397 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2398 /* return simulated texture memory left */
2399 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2402 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2403 struct wined3d_buffer *buffer, UINT OffsetInBytes, UINT Stride)
2405 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2406 struct wined3d_stream_state *stream;
2407 struct wined3d_buffer *prev_buffer;
2409 TRACE("iface %p, stream_idx %u, buffer %p, offset %u, stride %u.\n",
2410 iface, StreamNumber, buffer, OffsetInBytes, Stride);
2412 if (StreamNumber >= MAX_STREAMS) {
2413 WARN("Stream out of range %d\n", StreamNumber);
2414 return WINED3DERR_INVALIDCALL;
2415 } else if(OffsetInBytes & 0x3) {
2416 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2417 return WINED3DERR_INVALIDCALL;
2420 stream = &This->updateStateBlock->state.streams[StreamNumber];
2421 prev_buffer = stream->buffer;
2423 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2425 if (prev_buffer == buffer
2426 && stream->stride == Stride
2427 && stream->offset == OffsetInBytes)
2429 TRACE("Application is setting the old values over, nothing to do\n");
2430 return WINED3D_OK;
2433 stream->buffer = buffer;
2434 if (buffer)
2436 stream->stride = Stride;
2437 stream->offset = OffsetInBytes;
2440 /* Handle recording of state blocks */
2441 if (This->isRecordingState) {
2442 TRACE("Recording... not performing anything\n");
2443 if (buffer)
2444 wined3d_buffer_incref(buffer);
2445 if (prev_buffer)
2446 wined3d_buffer_decref(prev_buffer);
2447 return WINED3D_OK;
2450 if (buffer)
2452 InterlockedIncrement(&buffer->bind_count);
2453 wined3d_buffer_incref(buffer);
2455 if (prev_buffer)
2457 InterlockedDecrement(&prev_buffer->bind_count);
2458 wined3d_buffer_decref(prev_buffer);
2461 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2463 return WINED3D_OK;
2466 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2467 UINT StreamNumber, struct wined3d_buffer **buffer, UINT *pOffset, UINT *pStride)
2469 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2470 struct wined3d_stream_state *stream;
2472 TRACE("iface %p, stream_idx %u, buffer %p, offset %p, stride %p.\n",
2473 iface, StreamNumber, buffer, pOffset, pStride);
2475 if (StreamNumber >= MAX_STREAMS)
2477 WARN("Stream out of range %d\n", StreamNumber);
2478 return WINED3DERR_INVALIDCALL;
2481 stream = &This->stateBlock->state.streams[StreamNumber];
2482 *buffer = stream->buffer;
2483 *pStride = stream->stride;
2484 if (pOffset) *pOffset = stream->offset;
2486 if (*buffer)
2487 wined3d_buffer_incref(*buffer);
2489 return WINED3D_OK;
2492 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2493 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2494 struct wined3d_stream_state *stream;
2495 UINT old_flags, oldFreq;
2497 TRACE("iface %p, stream_idx %u, divider %#x.\n", iface, StreamNumber, Divider);
2499 /* Verify input at least in d3d9 this is invalid. */
2500 if ((Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA))
2502 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2503 return WINED3DERR_INVALIDCALL;
2505 if ((Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && !StreamNumber)
2507 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2508 return WINED3DERR_INVALIDCALL;
2510 if (!Divider)
2512 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2513 return WINED3DERR_INVALIDCALL;
2516 stream = &This->updateStateBlock->state.streams[StreamNumber];
2517 old_flags = stream->flags;
2518 oldFreq = stream->frequency;
2520 stream->flags = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA);
2521 stream->frequency = Divider & 0x7FFFFF;
2523 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2525 if (stream->frequency != oldFreq || stream->flags != old_flags)
2526 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2528 return WINED3D_OK;
2531 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2532 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2533 struct wined3d_stream_state *stream;
2535 TRACE("iface %p, stream_idx %u, divider %p.\n", iface, StreamNumber, Divider);
2537 stream = &This->updateStateBlock->state.streams[StreamNumber];
2538 *Divider = stream->flags | stream->frequency;
2540 TRACE("Returning %#x.\n", *Divider);
2542 return WINED3D_OK;
2545 /*****
2546 * Get / Set & Multiply Transform
2547 *****/
2548 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2549 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2551 /* Most of this routine, comments included copied from ddraw tree initially: */
2552 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2554 /* Handle recording of state blocks */
2555 if (This->isRecordingState) {
2556 TRACE("Recording... not performing anything\n");
2557 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2558 This->updateStateBlock->state.transforms[d3dts] = *lpmatrix;
2559 return WINED3D_OK;
2563 * If the new matrix is the same as the current one,
2564 * we cut off any further processing. this seems to be a reasonable
2565 * optimization because as was noticed, some apps (warcraft3 for example)
2566 * tend towards setting the same matrix repeatedly for some reason.
2568 * From here on we assume that the new matrix is different, wherever it matters.
2570 if (!memcmp(&This->stateBlock->state.transforms[d3dts].u.m[0][0], lpmatrix, sizeof(*lpmatrix)))
2572 TRACE("The app is setting the same matrix over again\n");
2573 return WINED3D_OK;
2575 else
2577 conv_mat(lpmatrix, &This->stateBlock->state.transforms[d3dts].u.m[0][0]);
2581 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2582 where ViewMat = Camera space, WorldMat = world space.
2584 In OpenGL, camera and world space is combined into GL_MODELVIEW
2585 matrix. The Projection matrix stay projection matrix.
2588 /* Capture the times we can just ignore the change for now */
2589 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2590 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2591 /* Handled by the state manager */
2594 if (d3dts < WINED3DTS_WORLDMATRIX(This->adapter->gl_info.limits.blends))
2595 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2597 return WINED3D_OK;
2601 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface,
2602 WINED3DTRANSFORMSTATETYPE state, WINED3DMATRIX *matrix)
2604 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2606 TRACE("iface %p, state %s, matrix %p.\n", iface, debug_d3dtstype(state), matrix);
2608 *matrix = device->stateBlock->state.transforms[state];
2610 return WINED3D_OK;
2613 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2614 const WINED3DMATRIX *mat = NULL;
2615 WINED3DMATRIX temp;
2617 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2618 * below means it will be recorded in a state block change, but it
2619 * works regardless where it is recorded.
2620 * If this is found to be wrong, change to StateBlock.
2622 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2623 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2625 if (State <= HIGHEST_TRANSFORMSTATE)
2627 mat = &This->updateStateBlock->state.transforms[State];
2629 else
2631 FIXME("Unhandled transform state!!\n");
2634 multiply_matrix(&temp, mat, pMatrix);
2636 /* Apply change via set transform - will reapply to eg. lights this way */
2637 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2640 /*****
2641 * Get / Set Light
2642 *****/
2643 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2644 you can reference any indexes you want as long as that number max are enabled at any
2645 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2646 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2647 but when recording, just build a chain pretty much of commands to be replayed. */
2649 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2650 float rho;
2651 struct wined3d_light_info *object = NULL;
2652 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2653 struct list *e;
2655 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2656 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2658 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2659 * the gl driver.
2661 if(!pLight) {
2662 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2663 return WINED3DERR_INVALIDCALL;
2666 switch(pLight->Type) {
2667 case WINED3DLIGHT_POINT:
2668 case WINED3DLIGHT_SPOT:
2669 case WINED3DLIGHT_PARALLELPOINT:
2670 case WINED3DLIGHT_GLSPOT:
2671 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2672 * most wanted
2674 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2676 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2677 return WINED3DERR_INVALIDCALL;
2679 break;
2681 case WINED3DLIGHT_DIRECTIONAL:
2682 /* Ignores attenuation */
2683 break;
2685 default:
2686 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2687 return WINED3DERR_INVALIDCALL;
2690 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2692 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2693 if(object->OriginalIndex == Index) break;
2694 object = NULL;
2697 if(!object) {
2698 TRACE("Adding new light\n");
2699 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2700 if(!object) {
2701 ERR("Out of memory error when allocating a light\n");
2702 return E_OUTOFMEMORY;
2704 list_add_head(&This->updateStateBlock->state.light_map[Hi], &object->entry);
2705 object->glIndex = -1;
2706 object->OriginalIndex = Index;
2709 /* Initialize the object */
2710 TRACE("Light %d setting to type %d, Diffuse(%f,%f,%f,%f), Specular(%f,%f,%f,%f), Ambient(%f,%f,%f,%f)\n", Index, pLight->Type,
2711 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2712 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2713 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2714 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2715 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2716 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2718 /* Save away the information */
2719 object->OriginalParms = *pLight;
2721 switch (pLight->Type) {
2722 case WINED3DLIGHT_POINT:
2723 /* Position */
2724 object->lightPosn[0] = pLight->Position.x;
2725 object->lightPosn[1] = pLight->Position.y;
2726 object->lightPosn[2] = pLight->Position.z;
2727 object->lightPosn[3] = 1.0f;
2728 object->cutoff = 180.0f;
2729 /* FIXME: Range */
2730 break;
2732 case WINED3DLIGHT_DIRECTIONAL:
2733 /* Direction */
2734 object->lightPosn[0] = -pLight->Direction.x;
2735 object->lightPosn[1] = -pLight->Direction.y;
2736 object->lightPosn[2] = -pLight->Direction.z;
2737 object->lightPosn[3] = 0.0f;
2738 object->exponent = 0.0f;
2739 object->cutoff = 180.0f;
2740 break;
2742 case WINED3DLIGHT_SPOT:
2743 /* Position */
2744 object->lightPosn[0] = pLight->Position.x;
2745 object->lightPosn[1] = pLight->Position.y;
2746 object->lightPosn[2] = pLight->Position.z;
2747 object->lightPosn[3] = 1.0f;
2749 /* Direction */
2750 object->lightDirn[0] = pLight->Direction.x;
2751 object->lightDirn[1] = pLight->Direction.y;
2752 object->lightDirn[2] = pLight->Direction.z;
2753 object->lightDirn[3] = 1.0f;
2756 * opengl-ish and d3d-ish spot lights use too different models for the
2757 * light "intensity" as a function of the angle towards the main light direction,
2758 * so we only can approximate very roughly.
2759 * however spot lights are rather rarely used in games (if ever used at all).
2760 * furthermore if still used, probably nobody pays attention to such details.
2762 if (!pLight->Falloff)
2764 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2765 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2766 * will always be 1.0 for both of them, and we don't have to care for the
2767 * rest of the rather complex calculation
2769 object->exponent = 0.0f;
2770 } else {
2771 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2772 if (rho < 0.0001f) rho = 0.0001f;
2773 object->exponent = -0.3f/logf(cosf(rho/2));
2775 if (object->exponent > 128.0f)
2777 object->exponent = 128.0f;
2779 object->cutoff = (float) (pLight->Phi*90/M_PI);
2781 /* FIXME: Range */
2782 break;
2784 default:
2785 FIXME("Unrecognized light type %d\n", pLight->Type);
2788 /* Update the live definitions if the light is currently assigned a glIndex */
2789 if (object->glIndex != -1 && !This->isRecordingState) {
2790 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2792 return WINED3D_OK;
2795 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2797 struct wined3d_light_info *lightInfo = NULL;
2798 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2799 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2800 struct list *e;
2801 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2803 LIST_FOR_EACH(e, &This->stateBlock->state.light_map[Hi])
2805 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2806 if(lightInfo->OriginalIndex == Index) break;
2807 lightInfo = NULL;
2810 if (!lightInfo)
2812 TRACE("Light information requested but light not defined\n");
2813 return WINED3DERR_INVALIDCALL;
2816 *pLight = lightInfo->OriginalParms;
2817 return WINED3D_OK;
2820 /*****
2821 * Get / Set Light Enable
2822 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2823 *****/
2824 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2826 struct wined3d_light_info *lightInfo = NULL;
2827 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2828 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2829 struct list *e;
2830 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2832 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2834 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2835 if(lightInfo->OriginalIndex == Index) break;
2836 lightInfo = NULL;
2838 TRACE("Found light: %p\n", lightInfo);
2840 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2841 if (!lightInfo)
2843 TRACE("Light enabled requested but light not defined, so defining one!\n");
2844 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2846 /* Search for it again! Should be fairly quick as near head of list */
2847 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2849 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2850 if(lightInfo->OriginalIndex == Index) break;
2851 lightInfo = NULL;
2853 if (!lightInfo)
2855 FIXME("Adding default lights has failed dismally\n");
2856 return WINED3DERR_INVALIDCALL;
2860 if(!Enable) {
2861 if(lightInfo->glIndex != -1) {
2862 if(!This->isRecordingState) {
2863 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2866 This->updateStateBlock->state.lights[lightInfo->glIndex] = NULL;
2867 lightInfo->glIndex = -1;
2868 } else {
2869 TRACE("Light already disabled, nothing to do\n");
2871 lightInfo->enabled = FALSE;
2872 } else {
2873 lightInfo->enabled = TRUE;
2874 if (lightInfo->glIndex != -1) {
2875 /* nop */
2876 TRACE("Nothing to do as light was enabled\n");
2877 } else {
2878 int i;
2879 /* Find a free gl light */
2880 for (i = 0; i < This->maxConcurrentLights; ++i)
2882 if (!This->updateStateBlock->state.lights[i])
2884 This->updateStateBlock->state.lights[i] = lightInfo;
2885 lightInfo->glIndex = i;
2886 break;
2889 if(lightInfo->glIndex == -1) {
2890 /* Our tests show that Windows returns D3D_OK in this situation, even with
2891 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2892 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2893 * as well for those lights.
2895 * TODO: Test how this affects rendering
2897 WARN("Too many concurrently active lights\n");
2898 return WINED3D_OK;
2901 /* i == lightInfo->glIndex */
2902 if(!This->isRecordingState) {
2903 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2908 return WINED3D_OK;
2911 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2913 struct wined3d_light_info *lightInfo = NULL;
2914 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2915 struct list *e;
2916 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2917 TRACE("(%p) : for idx(%d)\n", This, Index);
2919 LIST_FOR_EACH(e, &This->stateBlock->state.light_map[Hi])
2921 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2922 if(lightInfo->OriginalIndex == Index) break;
2923 lightInfo = NULL;
2926 if (!lightInfo)
2928 TRACE("Light enabled state requested but light not defined\n");
2929 return WINED3DERR_INVALIDCALL;
2931 /* true is 128 according to SetLightEnable */
2932 *pEnable = lightInfo->enabled ? 128 : 0;
2933 return WINED3D_OK;
2936 /*****
2937 * Get / Set Clip Planes
2938 *****/
2939 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2940 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2941 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2943 /* Validate Index */
2944 if (Index >= This->adapter->gl_info.limits.clipplanes)
2946 TRACE("Application has requested clipplane this device doesn't support\n");
2947 return WINED3DERR_INVALIDCALL;
2950 This->updateStateBlock->changed.clipplane |= 1 << Index;
2952 if (This->updateStateBlock->state.clip_planes[Index][0] == pPlane[0]
2953 && This->updateStateBlock->state.clip_planes[Index][1] == pPlane[1]
2954 && This->updateStateBlock->state.clip_planes[Index][2] == pPlane[2]
2955 && This->updateStateBlock->state.clip_planes[Index][3] == pPlane[3])
2957 TRACE("Application is setting old values over, nothing to do\n");
2958 return WINED3D_OK;
2961 This->updateStateBlock->state.clip_planes[Index][0] = pPlane[0];
2962 This->updateStateBlock->state.clip_planes[Index][1] = pPlane[1];
2963 This->updateStateBlock->state.clip_planes[Index][2] = pPlane[2];
2964 This->updateStateBlock->state.clip_planes[Index][3] = pPlane[3];
2966 /* Handle recording of state blocks */
2967 if (This->isRecordingState) {
2968 TRACE("Recording... not performing anything\n");
2969 return WINED3D_OK;
2972 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2974 return WINED3D_OK;
2977 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2978 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2979 TRACE("(%p) : for idx %d\n", This, Index);
2981 /* Validate Index */
2982 if (Index >= This->adapter->gl_info.limits.clipplanes)
2984 TRACE("Application has requested clipplane this device doesn't support\n");
2985 return WINED3DERR_INVALIDCALL;
2988 pPlane[0] = (float)This->stateBlock->state.clip_planes[Index][0];
2989 pPlane[1] = (float)This->stateBlock->state.clip_planes[Index][1];
2990 pPlane[2] = (float)This->stateBlock->state.clip_planes[Index][2];
2991 pPlane[3] = (float)This->stateBlock->state.clip_planes[Index][3];
2992 return WINED3D_OK;
2995 /*****
2996 * Get / Set Clip Plane Status
2997 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2998 *****/
2999 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3000 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3001 FIXME("(%p) : stub\n", This);
3003 if (!pClipStatus)
3004 return WINED3DERR_INVALIDCALL;
3006 This->updateStateBlock->state.clip_status.ClipUnion = pClipStatus->ClipUnion;
3007 This->updateStateBlock->state.clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3008 return WINED3D_OK;
3011 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3012 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3013 FIXME("(%p) : stub\n", This);
3015 if (!pClipStatus)
3016 return WINED3DERR_INVALIDCALL;
3018 pClipStatus->ClipUnion = This->updateStateBlock->state.clip_status.ClipUnion;
3019 pClipStatus->ClipIntersection = This->updateStateBlock->state.clip_status.ClipIntersection;
3020 return WINED3D_OK;
3023 /*****
3024 * Get / Set Material
3025 *****/
3026 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3027 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3029 This->updateStateBlock->changed.material = TRUE;
3030 This->updateStateBlock->state.material = *pMaterial;
3032 /* Handle recording of state blocks */
3033 if (This->isRecordingState) {
3034 TRACE("Recording... not performing anything\n");
3035 return WINED3D_OK;
3038 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3039 return WINED3D_OK;
3042 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3043 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3044 *pMaterial = This->updateStateBlock->state.material;
3045 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3046 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3047 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3048 pMaterial->Ambient.b, pMaterial->Ambient.a);
3049 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3050 pMaterial->Specular.b, pMaterial->Specular.a);
3051 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3052 pMaterial->Emissive.b, pMaterial->Emissive.a);
3053 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3055 return WINED3D_OK;
3058 /*****
3059 * Get / Set Indices
3060 *****/
3061 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
3062 struct wined3d_buffer *buffer, enum wined3d_format_id fmt)
3064 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3065 struct wined3d_buffer *prev_buffer;
3067 TRACE("iface %p, buffer %p, format %s.\n",
3068 iface, buffer, debug_d3dformat(fmt));
3070 prev_buffer = This->updateStateBlock->state.index_buffer;
3072 This->updateStateBlock->changed.indices = TRUE;
3073 This->updateStateBlock->state.index_buffer = buffer;
3074 This->updateStateBlock->state.index_format = fmt;
3076 /* Handle recording of state blocks */
3077 if (This->isRecordingState) {
3078 TRACE("Recording... not performing anything\n");
3079 if (buffer)
3080 wined3d_buffer_incref(buffer);
3081 if (prev_buffer)
3082 wined3d_buffer_decref(prev_buffer);
3083 return WINED3D_OK;
3086 if (prev_buffer != buffer)
3088 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3089 if (buffer)
3091 InterlockedIncrement(&buffer->bind_count);
3092 wined3d_buffer_incref(buffer);
3094 if (prev_buffer)
3096 InterlockedDecrement(&prev_buffer->bind_count);
3097 wined3d_buffer_decref(prev_buffer);
3101 return WINED3D_OK;
3104 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, struct wined3d_buffer **buffer)
3106 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3108 TRACE("iface %p, buffer %p.\n", iface, buffer);
3110 *buffer = This->stateBlock->state.index_buffer;
3112 if (*buffer)
3113 wined3d_buffer_incref(*buffer);
3115 TRACE("Returning %p.\n", *buffer);
3117 return WINED3D_OK;
3120 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3121 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3122 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3123 TRACE("(%p)->(%d)\n", This, BaseIndex);
3125 if (This->updateStateBlock->state.base_vertex_index == BaseIndex)
3127 TRACE("Application is setting the old value over, nothing to do\n");
3128 return WINED3D_OK;
3131 This->updateStateBlock->state.base_vertex_index = BaseIndex;
3133 if (This->isRecordingState) {
3134 TRACE("Recording... not performing anything\n");
3135 return WINED3D_OK;
3137 /* The base vertex index affects the stream sources */
3138 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3139 return WINED3D_OK;
3142 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3143 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3144 TRACE("(%p) : base_index %p\n", This, base_index);
3146 *base_index = This->stateBlock->state.base_vertex_index;
3148 TRACE("Returning %u\n", *base_index);
3150 return WINED3D_OK;
3153 /*****
3154 * Get / Set Viewports
3155 *****/
3156 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3157 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3159 TRACE("(%p)\n", This);
3160 This->updateStateBlock->changed.viewport = TRUE;
3161 This->updateStateBlock->state.viewport = *pViewport;
3163 /* Handle recording of state blocks */
3164 if (This->isRecordingState) {
3165 TRACE("Recording... not performing anything\n");
3166 return WINED3D_OK;
3169 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3170 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3172 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3173 return WINED3D_OK;
3177 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3178 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3179 TRACE("(%p)\n", This);
3180 *pViewport = This->stateBlock->state.viewport;
3181 return WINED3D_OK;
3184 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface,
3185 WINED3DRENDERSTATETYPE State, DWORD Value)
3187 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3188 DWORD oldValue = This->stateBlock->state.render_states[State];
3190 TRACE("iface %p, state %s (%#x), value %#x.\n", iface, debug_d3drenderstate(State), State, Value);
3192 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3193 This->updateStateBlock->state.render_states[State] = Value;
3195 /* Handle recording of state blocks */
3196 if (This->isRecordingState) {
3197 TRACE("Recording... not performing anything\n");
3198 return WINED3D_OK;
3201 /* Compared here and not before the assignment to allow proper stateblock recording */
3202 if(Value == oldValue) {
3203 TRACE("Application is setting the old value over, nothing to do\n");
3204 } else {
3205 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3208 return WINED3D_OK;
3211 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface,
3212 WINED3DRENDERSTATETYPE State, DWORD *pValue)
3214 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3216 TRACE("iface %p, state %s (%#x), value %p.\n", iface, debug_d3drenderstate(State), State, pValue);
3218 *pValue = This->stateBlock->state.render_states[State];
3219 return WINED3D_OK;
3222 /*****
3223 * Get / Set Sampler States
3224 * TODO: Verify against dx9 definitions
3225 *****/
3227 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3228 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3229 DWORD oldValue;
3231 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3232 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3234 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3235 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3238 if (Sampler >= sizeof(This->stateBlock->state.sampler_states) / sizeof(*This->stateBlock->state.sampler_states))
3240 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3241 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3244 oldValue = This->stateBlock->state.sampler_states[Sampler][Type];
3245 This->updateStateBlock->state.sampler_states[Sampler][Type] = Value;
3246 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3248 /* Handle recording of state blocks */
3249 if (This->isRecordingState) {
3250 TRACE("Recording... not performing anything\n");
3251 return WINED3D_OK;
3254 if(oldValue == Value) {
3255 TRACE("Application is setting the old value over, nothing to do\n");
3256 return WINED3D_OK;
3259 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3261 return WINED3D_OK;
3264 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3265 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3267 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3268 This, Sampler, debug_d3dsamplerstate(Type), Type);
3270 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3271 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3274 if (Sampler >= sizeof(This->stateBlock->state.sampler_states) / sizeof(*This->stateBlock->state.sampler_states))
3276 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3277 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3279 *Value = This->stateBlock->state.sampler_states[Sampler][Type];
3280 TRACE("(%p) : Returning %#x\n", This, *Value);
3282 return WINED3D_OK;
3285 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3286 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3288 This->updateStateBlock->changed.scissorRect = TRUE;
3289 if (EqualRect(&This->updateStateBlock->state.scissor_rect, pRect))
3291 TRACE("App is setting the old scissor rectangle over, nothing to do.\n");
3292 return WINED3D_OK;
3294 CopyRect(&This->updateStateBlock->state.scissor_rect, pRect);
3296 if(This->isRecordingState) {
3297 TRACE("Recording... not performing anything\n");
3298 return WINED3D_OK;
3301 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3303 return WINED3D_OK;
3306 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3307 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3309 *pRect = This->updateStateBlock->state.scissor_rect;
3310 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3311 return WINED3D_OK;
3314 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice *iface,
3315 struct wined3d_vertex_declaration *pDecl)
3317 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3318 struct wined3d_vertex_declaration *oldDecl = This->updateStateBlock->state.vertex_declaration;
3320 TRACE("iface %p, declaration %p.\n", iface, pDecl);
3322 if (pDecl)
3323 wined3d_vertex_declaration_incref(pDecl);
3324 if (oldDecl)
3325 wined3d_vertex_declaration_decref(oldDecl);
3327 This->updateStateBlock->state.vertex_declaration = pDecl;
3328 This->updateStateBlock->changed.vertexDecl = TRUE;
3330 if (This->isRecordingState) {
3331 TRACE("Recording... not performing anything\n");
3332 return WINED3D_OK;
3333 } else if(pDecl == oldDecl) {
3334 /* Checked after the assignment to allow proper stateblock recording */
3335 TRACE("Application is setting the old declaration over, nothing to do\n");
3336 return WINED3D_OK;
3339 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3340 return WINED3D_OK;
3343 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice *iface,
3344 struct wined3d_vertex_declaration **ppDecl)
3346 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3348 TRACE("iface %p, declaration %p.\n", iface, ppDecl);
3350 *ppDecl = This->stateBlock->state.vertex_declaration;
3351 if (*ppDecl)
3352 wined3d_vertex_declaration_incref(*ppDecl);
3354 return WINED3D_OK;
3357 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, struct wined3d_shader *shader)
3359 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3360 struct wined3d_shader *prev = device->updateStateBlock->state.vertex_shader;
3362 device->updateStateBlock->state.vertex_shader = shader;
3363 device->updateStateBlock->changed.vertexShader = TRUE;
3365 if (device->isRecordingState)
3367 if (shader)
3368 wined3d_shader_incref(shader);
3369 if (prev)
3370 wined3d_shader_decref(prev);
3371 TRACE("Recording... not performing anything.\n");
3372 return WINED3D_OK;
3374 else if(prev == shader)
3376 /* Checked here to allow proper stateblock recording */
3377 TRACE("App is setting the old shader over, nothing to do.\n");
3378 return WINED3D_OK;
3381 TRACE("(%p) : setting shader(%p)\n", device, shader);
3382 if (shader)
3383 wined3d_shader_incref(shader);
3384 if (prev)
3385 wined3d_shader_decref(prev);
3387 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_VSHADER);
3389 return WINED3D_OK;
3392 static struct wined3d_shader * WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface)
3394 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3395 struct wined3d_shader *shader;
3397 TRACE("iface %p.\n", iface);
3399 shader = device->stateBlock->state.vertex_shader;
3400 if (shader)
3401 wined3d_shader_incref(shader);
3403 TRACE("Returning %p.\n", shader);
3404 return shader;
3407 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3408 IWineD3DDevice *iface,
3409 UINT start,
3410 CONST BOOL *srcData,
3411 UINT count) {
3413 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3414 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3416 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3417 iface, srcData, start, count);
3419 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3421 memcpy(&This->updateStateBlock->state.vs_consts_b[start], srcData, cnt * sizeof(BOOL));
3422 for (i = 0; i < cnt; i++)
3423 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3425 for (i = start; i < cnt + start; ++i) {
3426 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3429 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3431 return WINED3D_OK;
3434 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3435 IWineD3DDevice *iface,
3436 UINT start,
3437 BOOL *dstData,
3438 UINT count) {
3440 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3441 int cnt = min(count, MAX_CONST_B - start);
3443 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3444 iface, dstData, start, count);
3446 if (!dstData || cnt < 0)
3447 return WINED3DERR_INVALIDCALL;
3449 memcpy(dstData, &This->stateBlock->state.vs_consts_b[start], cnt * sizeof(BOOL));
3450 return WINED3D_OK;
3453 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3454 IWineD3DDevice *iface,
3455 UINT start,
3456 CONST int *srcData,
3457 UINT count) {
3459 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3460 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3462 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3463 iface, srcData, start, count);
3465 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3467 memcpy(&This->updateStateBlock->state.vs_consts_i[start * 4], srcData, cnt * sizeof(int) * 4);
3468 for (i = 0; i < cnt; i++)
3469 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3470 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3472 for (i = start; i < cnt + start; ++i) {
3473 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3476 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3478 return WINED3D_OK;
3481 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3482 IWineD3DDevice *iface,
3483 UINT start,
3484 int *dstData,
3485 UINT count) {
3487 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3488 int cnt = min(count, MAX_CONST_I - start);
3490 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3491 iface, dstData, start, count);
3493 if (!dstData || ((signed int)MAX_CONST_I - (signed int)start) <= 0)
3494 return WINED3DERR_INVALIDCALL;
3496 memcpy(dstData, &This->stateBlock->state.vs_consts_i[start * 4], cnt * sizeof(int) * 4);
3497 return WINED3D_OK;
3500 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3501 IWineD3DDevice *iface,
3502 UINT start,
3503 CONST float *srcData,
3504 UINT count) {
3506 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3507 UINT i;
3509 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3510 iface, srcData, start, count);
3512 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3513 if (!srcData || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3514 return WINED3DERR_INVALIDCALL;
3516 memcpy(&This->updateStateBlock->state.vs_consts_f[start * 4], srcData, count * sizeof(float) * 4);
3517 if(TRACE_ON(d3d)) {
3518 for (i = 0; i < count; i++)
3519 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3520 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3523 if (!This->isRecordingState)
3525 This->shader_backend->shader_update_float_vertex_constants(This, start, count);
3526 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3529 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3530 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3532 return WINED3D_OK;
3535 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3536 IWineD3DDevice *iface,
3537 UINT start,
3538 float *dstData,
3539 UINT count) {
3541 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3542 int cnt = min(count, This->d3d_vshader_constantF - start);
3544 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3545 iface, dstData, start, count);
3547 if (!dstData || cnt < 0)
3548 return WINED3DERR_INVALIDCALL;
3550 memcpy(dstData, &This->stateBlock->state.vs_consts_f[start * 4], cnt * sizeof(float) * 4);
3551 return WINED3D_OK;
3554 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3555 DWORD i;
3556 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3558 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3562 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3564 DWORD i = This->rev_tex_unit_map[unit];
3565 DWORD j = This->texUnitMap[stage];
3567 This->texUnitMap[stage] = unit;
3568 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3570 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3573 This->rev_tex_unit_map[unit] = stage;
3574 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3576 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3580 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3581 int i;
3583 This->fixed_function_usage_map = 0;
3584 for (i = 0; i < MAX_TEXTURES; ++i)
3586 const struct wined3d_state *state = &This->stateBlock->state;
3587 WINED3DTEXTUREOP color_op = state->texture_states[i][WINED3DTSS_COLOROP];
3588 WINED3DTEXTUREOP alpha_op = state->texture_states[i][WINED3DTSS_ALPHAOP];
3589 DWORD color_arg1 = state->texture_states[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3590 DWORD color_arg2 = state->texture_states[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3591 DWORD color_arg3 = state->texture_states[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3592 DWORD alpha_arg1 = state->texture_states[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3593 DWORD alpha_arg2 = state->texture_states[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3594 DWORD alpha_arg3 = state->texture_states[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3596 if (color_op == WINED3DTOP_DISABLE) {
3597 /* Not used, and disable higher stages */
3598 break;
3601 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3602 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3603 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3604 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3605 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3606 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3607 This->fixed_function_usage_map |= (1 << i);
3610 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3611 This->fixed_function_usage_map |= (1 << (i + 1));
3616 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3618 unsigned int i, tex;
3619 WORD ffu_map;
3621 device_update_fixed_function_usage_map(This);
3622 ffu_map = This->fixed_function_usage_map;
3624 if (This->max_ffp_textures == gl_info->limits.texture_stages
3625 || This->stateBlock->state.lowest_disabled_stage <= This->max_ffp_textures)
3627 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3629 if (!(ffu_map & 1)) continue;
3631 if (This->texUnitMap[i] != i) {
3632 device_map_stage(This, i, i);
3633 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3634 markTextureStagesDirty(This, i);
3637 return;
3640 /* Now work out the mapping */
3641 tex = 0;
3642 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3644 if (!(ffu_map & 1)) continue;
3646 if (This->texUnitMap[i] != tex) {
3647 device_map_stage(This, i, tex);
3648 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3649 markTextureStagesDirty(This, i);
3652 ++tex;
3656 static void device_map_psamplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3658 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3659 This->stateBlock->state.pixel_shader->reg_maps.sampler_type;
3660 unsigned int i;
3662 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3663 if (sampler_type[i] && This->texUnitMap[i] != i)
3665 device_map_stage(This, i, i);
3666 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3667 if (i < gl_info->limits.texture_stages)
3669 markTextureStagesDirty(This, i);
3675 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_tokens,
3676 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_tokens, DWORD unit)
3678 DWORD current_mapping = This->rev_tex_unit_map[unit];
3680 /* Not currently used */
3681 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3683 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3684 /* Used by a fragment sampler */
3686 if (!pshader_sampler_tokens) {
3687 /* No pixel shader, check fixed function */
3688 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3691 /* Pixel shader, check the shader's sampler map */
3692 return !pshader_sampler_tokens[current_mapping];
3695 /* Used by a vertex sampler */
3696 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3699 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps, const struct wined3d_gl_info *gl_info)
3701 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3702 This->stateBlock->state.vertex_shader->reg_maps.sampler_type;
3703 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3704 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
3705 int i;
3707 if (ps)
3709 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3710 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3711 pshader_sampler_type = This->stateBlock->state.pixel_shader->reg_maps.sampler_type;
3714 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3715 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3716 if (vshader_sampler_type[i])
3718 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3720 /* Already mapped somewhere */
3721 continue;
3724 while (start >= 0) {
3725 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3727 device_map_stage(This, vsampler_idx, start);
3728 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3730 --start;
3731 break;
3734 --start;
3740 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This)
3742 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3743 const struct wined3d_state *state = &This->stateBlock->state;
3744 BOOL vs = use_vs(state);
3745 BOOL ps = use_ps(state);
3747 * Rules are:
3748 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3749 * that would be really messy and require shader recompilation
3750 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3751 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3753 if (ps) device_map_psamplers(This, gl_info);
3754 else device_map_fixed_function_samplers(This, gl_info);
3756 if (vs) device_map_vsamplers(This, ps, gl_info);
3759 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, struct wined3d_shader *shader)
3761 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3762 struct wined3d_shader *prev = device->updateStateBlock->state.pixel_shader;
3764 device->updateStateBlock->state.pixel_shader = shader;
3765 device->updateStateBlock->changed.pixelShader = TRUE;
3767 /* Handle recording of state blocks */
3768 if (device->isRecordingState)
3769 TRACE("Recording... not performing anything\n");
3771 if (device->isRecordingState)
3773 TRACE("Recording... not performing anything.\n");
3774 if (shader)
3775 wined3d_shader_incref(shader);
3776 if (prev)
3777 wined3d_shader_decref(prev);
3778 return WINED3D_OK;
3781 if (shader == prev)
3783 TRACE("App is setting the old pixel shader over, nothing to do.\n");
3784 return WINED3D_OK;
3787 if (shader)
3788 wined3d_shader_incref(shader);
3789 if (prev)
3790 wined3d_shader_decref(prev);
3792 TRACE("Setting shader %p.\n", shader);
3793 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_PIXELSHADER);
3795 return WINED3D_OK;
3798 static struct wined3d_shader * WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface)
3800 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3801 struct wined3d_shader *shader;
3803 TRACE("iface %p.\n", iface);
3805 shader = device->stateBlock->state.pixel_shader;
3806 if (shader)
3807 wined3d_shader_incref(shader);
3809 TRACE("Returning %p.\n", shader);
3810 return shader;
3813 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3814 IWineD3DDevice *iface,
3815 UINT start,
3816 CONST BOOL *srcData,
3817 UINT count) {
3819 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3820 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3822 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3823 iface, srcData, start, count);
3825 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3827 memcpy(&This->updateStateBlock->state.ps_consts_b[start], srcData, cnt * sizeof(BOOL));
3828 for (i = 0; i < cnt; i++)
3829 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3831 for (i = start; i < cnt + start; ++i) {
3832 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3835 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3837 return WINED3D_OK;
3840 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3841 IWineD3DDevice *iface,
3842 UINT start,
3843 BOOL *dstData,
3844 UINT count) {
3846 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3847 int cnt = min(count, MAX_CONST_B - start);
3849 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3850 iface, dstData, start, count);
3852 if (!dstData || cnt < 0)
3853 return WINED3DERR_INVALIDCALL;
3855 memcpy(dstData, &This->stateBlock->state.ps_consts_b[start], cnt * sizeof(BOOL));
3856 return WINED3D_OK;
3859 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3860 IWineD3DDevice *iface,
3861 UINT start,
3862 CONST int *srcData,
3863 UINT count) {
3865 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3866 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3868 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3869 iface, srcData, start, count);
3871 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3873 memcpy(&This->updateStateBlock->state.ps_consts_i[start * 4], srcData, cnt * sizeof(int) * 4);
3874 for (i = 0; i < cnt; i++)
3875 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3876 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3878 for (i = start; i < cnt + start; ++i) {
3879 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3882 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3884 return WINED3D_OK;
3887 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3888 IWineD3DDevice *iface,
3889 UINT start,
3890 int *dstData,
3891 UINT count) {
3893 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3894 int cnt = min(count, MAX_CONST_I - start);
3896 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3897 iface, dstData, start, count);
3899 if (!dstData || cnt < 0)
3900 return WINED3DERR_INVALIDCALL;
3902 memcpy(dstData, &This->stateBlock->state.ps_consts_i[start * 4], cnt * sizeof(int) * 4);
3903 return WINED3D_OK;
3906 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3907 IWineD3DDevice *iface,
3908 UINT start,
3909 CONST float *srcData,
3910 UINT count) {
3912 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3913 UINT i;
3915 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3916 iface, srcData, start, count);
3918 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3919 if (!srcData || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3920 return WINED3DERR_INVALIDCALL;
3922 memcpy(&This->updateStateBlock->state.ps_consts_f[start * 4], srcData, count * sizeof(float) * 4);
3923 if(TRACE_ON(d3d)) {
3924 for (i = 0; i < count; i++)
3925 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3926 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3929 if (!This->isRecordingState)
3931 This->shader_backend->shader_update_float_pixel_constants(This, start, count);
3932 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3935 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3936 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3938 return WINED3D_OK;
3941 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3942 IWineD3DDevice *iface,
3943 UINT start,
3944 float *dstData,
3945 UINT count) {
3947 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3948 int cnt = min(count, This->d3d_pshader_constantF - start);
3950 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3951 iface, dstData, start, count);
3953 if (!dstData || cnt < 0)
3954 return WINED3DERR_INVALIDCALL;
3956 memcpy(dstData, &This->stateBlock->state.ps_consts_f[start * 4], cnt * sizeof(float) * 4);
3957 return WINED3D_OK;
3960 /* Context activation is done by the caller. */
3961 /* Do not call while under the GL lock. */
3962 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3963 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3964 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD flags,
3965 DWORD DestFVF)
3967 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3968 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3969 unsigned int i;
3970 WINED3DVIEWPORT vp;
3971 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3972 BOOL doClip;
3973 DWORD numTextures;
3975 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3977 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3980 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3982 ERR("Source has no position mask\n");
3983 return WINED3DERR_INVALIDCALL;
3986 if (!dest->resource.allocatedMemory)
3987 buffer_get_sysmem(dest, gl_info);
3989 /* Get a pointer into the destination vbo(create one if none exists) and
3990 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3992 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3994 dest->flags |= WINED3D_BUFFER_CREATEBO;
3995 wined3d_buffer_preload(dest);
3998 if (dest->buffer_object)
4000 unsigned char extrabytes = 0;
4001 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4002 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4003 * this may write 4 extra bytes beyond the area that should be written
4005 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4006 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4007 if(!dest_conv_addr) {
4008 ERR("Out of memory\n");
4009 /* Continue without storing converted vertices */
4011 dest_conv = dest_conv_addr;
4014 if (This->stateBlock->state.render_states[WINED3DRS_CLIPPING])
4016 static BOOL warned = FALSE;
4018 * The clipping code is not quite correct. Some things need
4019 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4020 * so disable clipping for now.
4021 * (The graphics in Half-Life are broken, and my processvertices
4022 * test crashes with IDirect3DDevice3)
4023 doClip = TRUE;
4025 doClip = FALSE;
4026 if(!warned) {
4027 warned = TRUE;
4028 FIXME("Clipping is broken and disabled for now\n");
4030 } else doClip = FALSE;
4031 dest_ptr = ((char *)buffer_get_sysmem(dest, gl_info)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4033 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4034 WINED3DTS_VIEW,
4035 &view_mat);
4036 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4037 WINED3DTS_PROJECTION,
4038 &proj_mat);
4039 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4040 WINED3DTS_WORLDMATRIX(0),
4041 &world_mat);
4043 TRACE("View mat:\n");
4044 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);
4045 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);
4046 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);
4047 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);
4049 TRACE("Proj mat:\n");
4050 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);
4051 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);
4052 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);
4053 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);
4055 TRACE("World mat:\n");
4056 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);
4057 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);
4058 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);
4059 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);
4061 /* Get the viewport */
4062 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4063 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4064 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4066 multiply_matrix(&mat,&view_mat,&world_mat);
4067 multiply_matrix(&mat,&proj_mat,&mat);
4069 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4071 for (i = 0; i < dwCount; i+= 1) {
4072 unsigned int tex_index;
4074 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4075 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4076 /* The position first */
4077 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
4078 const float *p = (const float *)(element->data + i * element->stride);
4079 float x, y, z, rhw;
4080 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4082 /* Multiplication with world, view and projection matrix */
4083 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);
4084 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);
4085 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);
4086 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);
4088 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4090 /* WARNING: The following things are taken from d3d7 and were not yet checked
4091 * against d3d8 or d3d9!
4094 /* Clipping conditions: From msdn
4096 * A vertex is clipped if it does not match the following requirements
4097 * -rhw < x <= rhw
4098 * -rhw < y <= rhw
4099 * 0 < z <= rhw
4100 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4102 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4103 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4107 if( !doClip ||
4108 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4109 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4110 ( rhw > eps ) ) ) {
4112 /* "Normal" viewport transformation (not clipped)
4113 * 1) The values are divided by rhw
4114 * 2) The y axis is negative, so multiply it with -1
4115 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4116 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4117 * 4) Multiply x with Width/2 and add Width/2
4118 * 5) The same for the height
4119 * 6) Add the viewpoint X and Y to the 2D coordinates and
4120 * The minimum Z value to z
4121 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4123 * Well, basically it's simply a linear transformation into viewport
4124 * coordinates
4127 x /= rhw;
4128 y /= rhw;
4129 z /= rhw;
4131 y *= -1;
4133 x *= vp.Width / 2;
4134 y *= vp.Height / 2;
4135 z *= vp.MaxZ - vp.MinZ;
4137 x += vp.Width / 2 + vp.X;
4138 y += vp.Height / 2 + vp.Y;
4139 z += vp.MinZ;
4141 rhw = 1 / rhw;
4142 } else {
4143 /* That vertex got clipped
4144 * Contrary to OpenGL it is not dropped completely, it just
4145 * undergoes a different calculation.
4147 TRACE("Vertex got clipped\n");
4148 x += rhw;
4149 y += rhw;
4151 x /= 2;
4152 y /= 2;
4154 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4155 * outside of the main vertex buffer memory. That needs some more
4156 * investigation...
4160 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4163 ( (float *) dest_ptr)[0] = x;
4164 ( (float *) dest_ptr)[1] = y;
4165 ( (float *) dest_ptr)[2] = z;
4166 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4168 dest_ptr += 3 * sizeof(float);
4170 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4171 dest_ptr += sizeof(float);
4174 if(dest_conv) {
4175 float w = 1 / rhw;
4176 ( (float *) dest_conv)[0] = x * w;
4177 ( (float *) dest_conv)[1] = y * w;
4178 ( (float *) dest_conv)[2] = z * w;
4179 ( (float *) dest_conv)[3] = w;
4181 dest_conv += 3 * sizeof(float);
4183 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4184 dest_conv += sizeof(float);
4188 if (DestFVF & WINED3DFVF_PSIZE) {
4189 dest_ptr += sizeof(DWORD);
4190 if(dest_conv) dest_conv += sizeof(DWORD);
4192 if (DestFVF & WINED3DFVF_NORMAL) {
4193 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4194 const float *normal = (const float *)(element->data + i * element->stride);
4195 /* AFAIK this should go into the lighting information */
4196 FIXME("Didn't expect the destination to have a normal\n");
4197 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4198 if(dest_conv) {
4199 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4203 if (DestFVF & WINED3DFVF_DIFFUSE) {
4204 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4205 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4206 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
4208 static BOOL warned = FALSE;
4210 if(!warned) {
4211 ERR("No diffuse color in source, but destination has one\n");
4212 warned = TRUE;
4215 *( (DWORD *) dest_ptr) = 0xffffffff;
4216 dest_ptr += sizeof(DWORD);
4218 if(dest_conv) {
4219 *( (DWORD *) dest_conv) = 0xffffffff;
4220 dest_conv += sizeof(DWORD);
4223 else {
4224 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4225 if(dest_conv) {
4226 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4227 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4228 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4229 dest_conv += sizeof(DWORD);
4234 if (DestFVF & WINED3DFVF_SPECULAR)
4236 /* What's the color value in the feedback buffer? */
4237 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4238 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4239 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
4241 static BOOL warned = FALSE;
4243 if(!warned) {
4244 ERR("No specular color in source, but destination has one\n");
4245 warned = TRUE;
4248 *( (DWORD *) dest_ptr) = 0xFF000000;
4249 dest_ptr += sizeof(DWORD);
4251 if(dest_conv) {
4252 *( (DWORD *) dest_conv) = 0xFF000000;
4253 dest_conv += sizeof(DWORD);
4256 else {
4257 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4258 if(dest_conv) {
4259 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4260 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4261 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4262 dest_conv += sizeof(DWORD);
4267 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4268 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4269 const float *tex_coord = (const float *)(element->data + i * element->stride);
4270 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
4272 ERR("No source texture, but destination requests one\n");
4273 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4274 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4276 else {
4277 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4278 if(dest_conv) {
4279 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4285 if (dest_conv)
4287 ENTER_GL();
4289 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4290 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4291 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4292 dwCount * get_flexible_vertex_size(DestFVF),
4293 dest_conv_addr));
4294 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4296 LEAVE_GL();
4298 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4301 return WINED3D_OK;
4303 #undef copy_and_next
4305 /* Do not call while under the GL lock. */
4306 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface,
4307 UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, struct wined3d_buffer *dst_buffer,
4308 struct wined3d_vertex_declaration *pVertexDecl, DWORD flags, DWORD DestFVF)
4310 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4311 struct wined3d_stream_info stream_info;
4312 const struct wined3d_gl_info *gl_info;
4313 struct wined3d_context *context;
4314 BOOL vbo = FALSE, streamWasUP = This->stateBlock->state.user_stream;
4315 HRESULT hr;
4317 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, dst_buffer, pVertexDecl, flags);
4319 if(pVertexDecl) {
4320 ERR("Output vertex declaration not implemented yet\n");
4323 /* Need any context to write to the vbo. */
4324 context = context_acquire(This, NULL);
4325 gl_info = context->gl_info;
4327 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4328 * control the streamIsUP flag, thus restore it afterwards.
4330 This->stateBlock->state.user_stream = FALSE;
4331 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4332 This->stateBlock->state.user_stream = streamWasUP;
4334 if(vbo || SrcStartIndex) {
4335 unsigned int i;
4336 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4337 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4339 * Also get the start index in, but only loop over all elements if there's something to add at all.
4341 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4343 struct wined3d_stream_info_element *e;
4345 if (!(stream_info.use_map & (1 << i))) continue;
4347 e = &stream_info.elements[i];
4348 if (e->buffer_object)
4350 struct wined3d_buffer *vb = This->stateBlock->state.streams[e->stream_idx].buffer;
4351 e->buffer_object = 0;
4352 e->data = (BYTE *)((ULONG_PTR)e->data + (ULONG_PTR)buffer_get_sysmem(vb, gl_info));
4353 ENTER_GL();
4354 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4355 vb->buffer_object = 0;
4356 LEAVE_GL();
4358 if (e->data) e->data += e->stride * SrcStartIndex;
4362 hr = process_vertices_strided(This, DestIndex, VertexCount,
4363 &stream_info, dst_buffer, flags, DestFVF);
4365 context_release(context);
4367 return hr;
4370 /*****
4371 * Get / Set Texture Stage States
4372 * TODO: Verify against dx9 definitions
4373 *****/
4374 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value)
4376 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4377 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4378 DWORD oldValue;
4380 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4382 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4384 WARN("Invalid Type %d passed.\n", Type);
4385 return WINED3D_OK;
4388 if (Stage >= gl_info->limits.texture_stages)
4390 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
4391 Stage, gl_info->limits.texture_stages - 1);
4392 return WINED3D_OK;
4395 oldValue = This->updateStateBlock->state.texture_states[Stage][Type];
4396 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4397 This->updateStateBlock->state.texture_states[Stage][Type] = Value;
4399 if (This->isRecordingState) {
4400 TRACE("Recording... not performing anything\n");
4401 return WINED3D_OK;
4404 /* Checked after the assignments to allow proper stateblock recording */
4405 if(oldValue == Value) {
4406 TRACE("App is setting the old value over, nothing to do\n");
4407 return WINED3D_OK;
4410 if (Stage > This->stateBlock->state.lowest_disabled_stage
4411 && This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative
4412 == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP))
4414 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4415 * Changes in other states are important on disabled stages too
4417 return WINED3D_OK;
4420 if(Type == WINED3DTSS_COLOROP) {
4421 unsigned int i;
4423 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4424 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4425 * they have to be disabled
4427 * The current stage is dirtified below.
4429 for (i = Stage + 1; i < This->stateBlock->state.lowest_disabled_stage; ++i)
4431 TRACE("Additionally dirtifying stage %u\n", i);
4432 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4434 This->stateBlock->state.lowest_disabled_stage = Stage;
4435 TRACE("New lowest disabled: %u\n", Stage);
4436 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4437 /* Previously disabled stage enabled. Stages above it may need enabling
4438 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4439 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4441 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4444 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
4446 if (This->updateStateBlock->state.texture_states[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE)
4447 break;
4448 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4449 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4451 This->stateBlock->state.lowest_disabled_stage = i;
4452 TRACE("New lowest disabled: %u\n", i);
4456 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4458 return WINED3D_OK;
4461 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD *pValue)
4463 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4465 TRACE("iface %p, stage %u, state %s, value %p.\n",
4466 iface, Stage, debug_d3dtexturestate(Type), pValue);
4468 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4470 WARN("Invalid Type %d passed.\n", Type);
4471 return WINED3D_OK;
4474 *pValue = This->updateStateBlock->state.texture_states[Stage][Type];
4475 TRACE("Returning %#x.\n", *pValue);
4477 return WINED3D_OK;
4480 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4481 DWORD stage, struct wined3d_texture *texture)
4483 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4484 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4485 struct wined3d_texture *prev;
4487 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4489 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4490 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4492 /* Windows accepts overflowing this array... we do not. */
4493 if (stage >= sizeof(This->stateBlock->state.textures) / sizeof(*This->stateBlock->state.textures))
4495 WARN("Ignoring invalid stage %u.\n", stage);
4496 return WINED3D_OK;
4499 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4500 if (texture && texture->resource.pool == WINED3DPOOL_SCRATCH)
4502 WARN("Rejecting attempt to set scratch texture.\n");
4503 return WINED3DERR_INVALIDCALL;
4506 This->updateStateBlock->changed.textures |= 1 << stage;
4508 prev = This->updateStateBlock->state.textures[stage];
4509 TRACE("Previous texture %p.\n", prev);
4511 if (texture == prev)
4513 TRACE("App is setting the same texture again, nothing to do.\n");
4514 return WINED3D_OK;
4517 TRACE("Setting new texture to %p.\n", texture);
4518 This->updateStateBlock->state.textures[stage] = texture;
4520 if (This->isRecordingState)
4522 TRACE("Recording... not performing anything\n");
4524 if (texture) wined3d_texture_incref(texture);
4525 if (prev) wined3d_texture_decref(prev);
4527 return WINED3D_OK;
4530 if (texture)
4532 LONG bind_count = InterlockedIncrement(&texture->bind_count);
4534 wined3d_texture_incref(texture);
4536 if (!prev || texture->target != prev->target)
4537 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4539 if (!prev && stage < gl_info->limits.texture_stages)
4541 /* The source arguments for color and alpha ops have different
4542 * meanings when a NULL texture is bound, so the COLOROP and
4543 * ALPHAOP have to be dirtified. */
4544 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4545 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4548 if (bind_count == 1)
4549 texture->sampler = stage;
4552 if (prev)
4554 LONG bind_count = InterlockedDecrement(&prev->bind_count);
4556 wined3d_texture_decref(prev);
4558 if (!texture && stage < gl_info->limits.texture_stages)
4560 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4561 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4564 if (bind_count && prev->sampler == stage)
4566 unsigned int i;
4568 /* Search for other stages the texture is bound to. Shouldn't
4569 * happen if applications bind textures to a single stage only. */
4570 TRACE("Searching for other stages the texture is bound to.\n");
4571 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4573 if (This->updateStateBlock->state.textures[i] == prev)
4575 TRACE("Texture is also bound to stage %u.\n", i);
4576 prev->sampler = i;
4577 break;
4583 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4585 return WINED3D_OK;
4588 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface,
4589 DWORD stage, struct wined3d_texture **texture)
4591 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4593 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4595 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4596 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4598 if (stage >= sizeof(This->stateBlock->state.textures) / sizeof(*This->stateBlock->state.textures))
4600 WARN("Current stage overflows textures array (stage %u).\n", stage);
4601 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4604 *texture = This->stateBlock->state.textures[stage];
4605 if (*texture)
4606 wined3d_texture_incref(*texture);
4608 TRACE("Returning %p.\n", *texture);
4610 return WINED3D_OK;
4613 /*****
4614 * Get Back Buffer
4615 *****/
4616 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4617 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, struct wined3d_surface **backbuffer)
4619 struct wined3d_swapchain *swapchain;
4620 HRESULT hr;
4622 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4623 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4625 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4626 if (FAILED(hr))
4628 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4629 return hr;
4632 hr = wined3d_swapchain_get_back_buffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4633 wined3d_swapchain_decref(swapchain);
4634 if (FAILED(hr))
4636 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4637 return hr;
4640 return WINED3D_OK;
4643 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS *caps)
4645 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4647 TRACE("iface %p, caps %p.\n", iface, caps);
4649 return wined3d_get_device_caps(device->wined3d, device->adapter->ordinal, device->devType, caps);
4652 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface,
4653 UINT swapchain_idx, WINED3DDISPLAYMODE *mode)
4655 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4656 struct wined3d_swapchain *swapchain;
4657 HRESULT hr;
4659 TRACE("iface %p, swapchain_idx %u, mode %p.\n", iface, swapchain_idx, mode);
4661 if (swapchain_idx)
4663 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4664 if (SUCCEEDED(hr))
4666 hr = wined3d_swapchain_get_display_mode(swapchain, mode);
4667 wined3d_swapchain_decref(swapchain);
4670 else
4672 /* Don't read the real display mode, but return the stored mode
4673 * instead. X11 can't change the color depth, and some apps are
4674 * pretty angry if they SetDisplayMode from 24 to 16 bpp and find out
4675 * that GetDisplayMode still returns 24 bpp.
4677 * Also don't relay to the swapchain because with ddraw it's possible
4678 * that there isn't a swapchain at all. */
4679 mode->Width = device->ddraw_width;
4680 mode->Height = device->ddraw_height;
4681 mode->Format = device->ddraw_format;
4682 mode->RefreshRate = 0;
4683 hr = WINED3D_OK;
4686 return hr;
4689 /*****
4690 * Stateblock related functions
4691 *****/
4693 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface)
4695 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4696 struct wined3d_stateblock *stateblock;
4697 HRESULT hr;
4699 TRACE("(%p)\n", This);
4701 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4703 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock);
4704 if (FAILED(hr)) return hr;
4706 wined3d_stateblock_decref(This->updateStateBlock);
4707 This->updateStateBlock = stateblock;
4708 This->isRecordingState = TRUE;
4710 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4712 return WINED3D_OK;
4715 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface,
4716 struct wined3d_stateblock **stateblock)
4718 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4719 struct wined3d_stateblock *object = This->updateStateBlock;
4721 TRACE("iface %p, stateblock %p.\n", iface, stateblock);
4723 if (!This->isRecordingState) {
4724 WARN("(%p) not recording! returning error\n", This);
4725 *stateblock = NULL;
4726 return WINED3DERR_INVALIDCALL;
4729 stateblock_init_contained_states(object);
4731 *stateblock = object;
4732 This->isRecordingState = FALSE;
4733 This->updateStateBlock = This->stateBlock;
4734 wined3d_stateblock_incref(This->updateStateBlock);
4736 TRACE("Returning stateblock %p.\n", *stateblock);
4738 return WINED3D_OK;
4741 /*****
4742 * Scene related functions
4743 *****/
4744 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4745 /* At the moment we have no need for any functionality at the beginning
4746 of a scene */
4747 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4748 TRACE("(%p)\n", This);
4750 if(This->inScene) {
4751 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4752 return WINED3DERR_INVALIDCALL;
4754 This->inScene = TRUE;
4755 return WINED3D_OK;
4758 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4760 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4761 struct wined3d_context *context;
4763 TRACE("(%p)\n", This);
4765 if(!This->inScene) {
4766 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4767 return WINED3DERR_INVALIDCALL;
4770 context = context_acquire(This, NULL);
4771 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4772 wglFlush();
4773 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4774 * fails. */
4775 context_release(context);
4777 This->inScene = FALSE;
4778 return WINED3D_OK;
4781 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface, const RECT *src_rect,
4782 const RECT *dst_rect, HWND dst_window_override, const RGNDATA *dirty_region)
4784 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4785 UINT i;
4787 TRACE("iface %p, src_rect %s, dst_rect %s, dst_window_override %p, dirty_region %p.\n",
4788 iface, wine_dbgstr_rect(src_rect), wine_dbgstr_rect(dst_rect),
4789 dst_window_override, dirty_region);
4791 for (i = 0; i < device->swapchain_count; ++i)
4793 wined3d_swapchain_present(device->swapchains[i], src_rect,
4794 dst_rect, dst_window_override, dirty_region, 0);
4797 return WINED3D_OK;
4800 /* Do not call while under the GL lock. */
4801 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD rect_count,
4802 const RECT *rects, DWORD flags, WINED3DCOLOR color, float depth, DWORD stencil)
4804 const WINED3DCOLORVALUE c = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
4805 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4806 RECT draw_rect;
4808 TRACE("iface %p, rect_count %u, rects %p, flags %#x, color 0x%08x, depth %.8e, stencil %u.\n",
4809 iface, rect_count, rects, flags, color, depth, stencil);
4811 if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL))
4813 struct wined3d_surface *ds = device->depth_stencil;
4814 if (!ds)
4816 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4817 /* TODO: What about depth stencil buffers without stencil bits? */
4818 return WINED3DERR_INVALIDCALL;
4820 else if (flags & WINED3DCLEAR_TARGET)
4822 if(ds->resource.width < device->render_targets[0]->resource.width ||
4823 ds->resource.height < device->render_targets[0]->resource.height)
4825 WARN("Silently ignoring depth and target clear with mismatching sizes\n");
4826 return WINED3D_OK;
4831 device_get_draw_rect(device, &draw_rect);
4833 return device_clear_render_targets(device, device->adapter->gl_info.limits.buffers,
4834 device->render_targets, device->depth_stencil, rect_count, rects,
4835 &draw_rect, flags, &c, depth, stencil);
4838 /*****
4839 * Drawing functions
4840 *****/
4842 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4843 WINED3DPRIMITIVETYPE primitive_type)
4845 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4847 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4849 This->updateStateBlock->changed.primitive_type = TRUE;
4850 This->updateStateBlock->state.gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4853 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4854 WINED3DPRIMITIVETYPE *primitive_type)
4856 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4858 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4860 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->state.gl_primitive_type);
4862 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4865 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4867 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4869 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4871 if (!This->stateBlock->state.vertex_declaration)
4873 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4874 return WINED3DERR_INVALIDCALL;
4877 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4878 if (This->stateBlock->state.user_stream)
4880 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4881 This->stateBlock->state.user_stream = FALSE;
4884 if (This->stateBlock->state.load_base_vertex_index)
4886 This->stateBlock->state.load_base_vertex_index = 0;
4887 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4889 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4890 drawPrimitive(This, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4891 return WINED3D_OK;
4894 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4896 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4897 struct wined3d_buffer *index_buffer;
4898 UINT idxStride = 2;
4899 GLuint vbo;
4901 index_buffer = This->stateBlock->state.index_buffer;
4902 if (!index_buffer)
4904 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4905 * without an index buffer set. (The first time at least...)
4906 * D3D8 simply dies, but I doubt it can do much harm to return
4907 * D3DERR_INVALIDCALL there as well. */
4908 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4909 return WINED3DERR_INVALIDCALL;
4912 if (!This->stateBlock->state.vertex_declaration)
4914 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4915 return WINED3DERR_INVALIDCALL;
4918 if (This->stateBlock->state.user_stream)
4920 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4921 This->stateBlock->state.user_stream = FALSE;
4923 vbo = index_buffer->buffer_object;
4925 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4927 if (This->stateBlock->state.index_format == WINED3DFMT_R16_UINT)
4928 idxStride = 2;
4929 else
4930 idxStride = 4;
4932 if (This->stateBlock->state.load_base_vertex_index != This->stateBlock->state.base_vertex_index)
4934 This->stateBlock->state.load_base_vertex_index = This->stateBlock->state.base_vertex_index;
4935 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4938 drawPrimitive(This, index_count, startIndex, idxStride,
4939 vbo ? NULL : index_buffer->resource.allocatedMemory);
4941 return WINED3D_OK;
4944 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4945 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4947 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4948 struct wined3d_stream_state *stream;
4949 struct wined3d_buffer *vb;
4951 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4952 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4954 if (!This->stateBlock->state.vertex_declaration)
4956 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4957 return WINED3DERR_INVALIDCALL;
4960 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4961 stream = &This->stateBlock->state.streams[0];
4962 vb = stream->buffer;
4963 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4964 if (vb)
4965 wined3d_buffer_decref(vb);
4966 stream->offset = 0;
4967 stream->stride = VertexStreamZeroStride;
4968 This->stateBlock->state.user_stream = TRUE;
4969 This->stateBlock->state.load_base_vertex_index = 0;
4971 /* TODO: Only mark dirty if drawing from a different UP address */
4972 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4974 drawPrimitive(This, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4976 /* MSDN specifies stream zero settings must be set to NULL */
4977 stream->buffer = NULL;
4978 stream->stride = 0;
4980 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4981 * the new stream sources or use UP drawing again
4983 return WINED3D_OK;
4986 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4987 UINT index_count, const void *pIndexData, enum wined3d_format_id IndexDataFormat,
4988 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4990 int idxStride;
4991 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4992 struct wined3d_stream_state *stream;
4993 struct wined3d_buffer *vb, *ib;
4995 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4996 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4998 if (!This->stateBlock->state.vertex_declaration)
5000 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5001 return WINED3DERR_INVALIDCALL;
5004 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
5005 idxStride = 2;
5006 } else {
5007 idxStride = 4;
5010 stream = &This->stateBlock->state.streams[0];
5011 vb = stream->buffer;
5012 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
5013 if (vb)
5014 wined3d_buffer_decref(vb);
5015 stream->offset = 0;
5016 stream->stride = VertexStreamZeroStride;
5017 This->stateBlock->state.user_stream = TRUE;
5019 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5020 This->stateBlock->state.base_vertex_index = 0;
5021 This->stateBlock->state.load_base_vertex_index = 0;
5022 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5023 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5024 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5026 drawPrimitive(This, index_count, 0 /* start_idx */, idxStride, pIndexData);
5028 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5029 stream->buffer = NULL;
5030 stream->stride = 0;
5031 ib = This->stateBlock->state.index_buffer;
5032 if (ib)
5034 wined3d_buffer_decref(ib);
5035 This->stateBlock->state.index_buffer = NULL;
5037 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5038 * SetStreamSource to specify a vertex buffer
5041 return WINED3D_OK;
5044 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5045 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
5047 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5049 /* Mark the state dirty until we have nicer tracking
5050 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5051 * that value.
5053 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5054 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5055 This->stateBlock->state.base_vertex_index = 0;
5056 This->up_strided = DrawPrimStrideData;
5057 drawPrimitive(This, vertex_count, 0, 0, NULL);
5058 This->up_strided = NULL;
5059 return WINED3D_OK;
5062 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5063 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
5064 UINT NumVertices, const void *pIndexData, enum wined3d_format_id IndexDataFormat)
5066 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5067 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
5069 /* Mark the state dirty until we have nicer tracking
5070 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5071 * that value.
5073 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5074 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5075 This->stateBlock->state.user_stream = TRUE;
5076 This->stateBlock->state.base_vertex_index = 0;
5077 This->up_strided = DrawPrimStrideData;
5078 drawPrimitive(This, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
5079 This->up_strided = NULL;
5080 return WINED3D_OK;
5083 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
5084 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
5085 struct wined3d_volume *src_volume, struct wined3d_volume *dst_volume)
5087 WINED3DLOCKED_BOX src;
5088 WINED3DLOCKED_BOX dst;
5089 HRESULT hr;
5091 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
5092 iface, src_volume, dst_volume);
5094 /* TODO: Implement direct loading into the gl volume instead of using
5095 * memcpy and dirtification to improve loading performance. */
5096 hr = wined3d_volume_map(src_volume, &src, NULL, WINED3DLOCK_READONLY);
5097 if (FAILED(hr)) return hr;
5098 hr = wined3d_volume_map(dst_volume, &dst, NULL, WINED3DLOCK_DISCARD);
5099 if (FAILED(hr))
5101 wined3d_volume_unmap(src_volume);
5102 return hr;
5105 memcpy(dst.pBits, src.pBits, dst_volume->resource.size);
5107 hr = wined3d_volume_unmap(dst_volume);
5108 if (FAILED(hr))
5109 wined3d_volume_unmap(src_volume);
5110 else
5111 hr = wined3d_volume_unmap(src_volume);
5113 return hr;
5116 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
5117 struct wined3d_texture *src_texture, struct wined3d_texture *dst_texture)
5119 unsigned int level_count, i;
5120 WINED3DRESOURCETYPE type;
5121 HRESULT hr;
5123 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
5125 /* Verify that the source and destination textures are non-NULL. */
5126 if (!src_texture || !dst_texture)
5128 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
5129 return WINED3DERR_INVALIDCALL;
5132 if (src_texture == dst_texture)
5134 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
5135 return WINED3DERR_INVALIDCALL;
5138 /* Verify that the source and destination textures are the same type. */
5139 type = wined3d_texture_get_type(src_texture);
5140 if (wined3d_texture_get_type(dst_texture) != type)
5142 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
5143 return WINED3DERR_INVALIDCALL;
5146 /* Check that both textures have the identical numbers of levels. */
5147 level_count = wined3d_texture_get_level_count(src_texture);
5148 if (wined3d_texture_get_level_count(dst_texture) != level_count)
5150 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
5151 return WINED3DERR_INVALIDCALL;
5154 /* Make sure that the destination texture is loaded. */
5155 dst_texture->texture_ops->texture_preload(dst_texture, SRGB_RGB);
5157 /* Update every surface level of the texture. */
5158 switch (type)
5160 case WINED3DRTYPE_TEXTURE:
5162 struct wined3d_surface *src_surface;
5163 struct wined3d_surface *dst_surface;
5165 for (i = 0; i < level_count; ++i)
5167 src_surface = surface_from_resource(wined3d_texture_get_sub_resource(src_texture, i));
5168 dst_surface = surface_from_resource(wined3d_texture_get_sub_resource(dst_texture, i));
5169 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5170 if (FAILED(hr))
5172 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5173 return hr;
5176 break;
5179 case WINED3DRTYPE_CUBETEXTURE:
5181 struct wined3d_surface *src_surface;
5182 struct wined3d_surface *dst_surface;
5184 for (i = 0; i < level_count * 6; ++i)
5186 src_surface = surface_from_resource(wined3d_texture_get_sub_resource(src_texture, i));
5187 dst_surface = surface_from_resource(wined3d_texture_get_sub_resource(dst_texture, i));
5188 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5189 if (FAILED(hr))
5191 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5192 return hr;
5195 break;
5198 case WINED3DRTYPE_VOLUMETEXTURE:
5200 for (i = 0; i < level_count; ++i)
5202 hr = IWineD3DDeviceImpl_UpdateVolume(iface,
5203 volume_from_resource(wined3d_texture_get_sub_resource(src_texture, i)),
5204 volume_from_resource(wined3d_texture_get_sub_resource(dst_texture, i)));
5205 if (FAILED(hr))
5207 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
5208 return hr;
5211 break;
5214 default:
5215 FIXME("Unsupported texture type %#x.\n", type);
5216 return WINED3DERR_INVALIDCALL;
5219 return WINED3D_OK;
5222 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,
5223 UINT swapchain_idx, struct wined3d_surface *dst_surface)
5225 struct wined3d_swapchain *swapchain;
5226 HRESULT hr;
5228 TRACE("iface %p, swapchain_idx %u, dst_surface %p.\n", iface, swapchain_idx, dst_surface);
5230 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5231 if (FAILED(hr)) return hr;
5233 hr = wined3d_swapchain_get_front_buffer_data(swapchain, dst_surface);
5234 wined3d_swapchain_decref(swapchain);
5236 return hr;
5239 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD *pNumPasses)
5241 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5242 const struct wined3d_state *state = &This->stateBlock->state;
5243 struct wined3d_texture *texture;
5244 DWORD i;
5246 TRACE("(%p) : %p\n", This, pNumPasses);
5248 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5250 if (state->sampler_states[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE)
5252 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5253 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5255 if (state->sampler_states[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE)
5257 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5258 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5261 texture = state->textures[i];
5262 if (!texture || texture->resource.format->flags & WINED3DFMT_FLAG_FILTERING) continue;
5264 if (state->sampler_states[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT)
5266 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5267 return E_FAIL;
5269 if (state->sampler_states[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT)
5271 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5272 return E_FAIL;
5274 if (state->sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE
5275 && state->sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT)
5277 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5278 return E_FAIL;
5282 if (state->render_states[WINED3DRS_ZENABLE] || state->render_states[WINED3DRS_ZWRITEENABLE] ||
5283 state->render_states[WINED3DRS_STENCILENABLE])
5285 struct wined3d_surface *ds = This->depth_stencil;
5286 struct wined3d_surface *target = This->render_targets[0];
5288 if(ds && target
5289 && (ds->resource.width < target->resource.width || ds->resource.height < target->resource.height))
5291 WARN("Depth stencil is smaller than the color buffer, returning D3DERR_CONFLICTINGRENDERSTATE\n");
5292 return WINED3DERR_CONFLICTINGRENDERSTATE;
5296 /* return a sensible default */
5297 *pNumPasses = 1;
5299 TRACE("returning D3D_OK\n");
5300 return WINED3D_OK;
5303 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5305 int i;
5307 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5309 struct wined3d_texture *texture = device->stateBlock->state.textures[i];
5310 if (texture && (texture->resource.format->id == WINED3DFMT_P8_UINT
5311 || texture->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM))
5313 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5318 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface,
5319 UINT PaletteNumber, const PALETTEENTRY *pEntries)
5321 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5322 int j;
5323 UINT NewSize;
5324 PALETTEENTRY **palettes;
5326 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5328 if (PaletteNumber >= MAX_PALETTES) {
5329 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5330 return WINED3DERR_INVALIDCALL;
5333 if (PaletteNumber >= This->palette_count)
5335 NewSize = This->palette_count;
5336 do {
5337 NewSize *= 2;
5338 } while(PaletteNumber >= NewSize);
5339 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5340 if (!palettes) {
5341 ERR("Out of memory!\n");
5342 return E_OUTOFMEMORY;
5344 This->palettes = palettes;
5345 This->palette_count = NewSize;
5348 if (!This->palettes[PaletteNumber]) {
5349 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5350 if (!This->palettes[PaletteNumber]) {
5351 ERR("Out of memory!\n");
5352 return E_OUTOFMEMORY;
5356 for (j = 0; j < 256; ++j) {
5357 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5358 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5359 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5360 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5362 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5363 TRACE("(%p) : returning\n", This);
5364 return WINED3D_OK;
5367 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface,
5368 UINT PaletteNumber, PALETTEENTRY *pEntries)
5370 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5371 int j;
5372 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5374 if (PaletteNumber >= This->palette_count || !This->palettes[PaletteNumber])
5376 /* What happens in such situation isn't documented; Native seems to silently abort
5377 on such conditions. Return Invalid Call. */
5378 ERR("(%p) : (%u) Nonexistent palette. Palette count %u.\n", This, PaletteNumber, This->palette_count);
5379 return WINED3DERR_INVALIDCALL;
5381 for (j = 0; j < 256; ++j) {
5382 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5383 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5384 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5385 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5387 TRACE("(%p) : returning\n", This);
5388 return WINED3D_OK;
5391 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber)
5393 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5394 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5395 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5396 (tested with reference rasterizer). Return Invalid Call. */
5397 if (PaletteNumber >= This->palette_count || !This->palettes[PaletteNumber])
5399 ERR("(%p) : (%u) Nonexistent palette. Palette count %u.\n", This, PaletteNumber, This->palette_count);
5400 return WINED3DERR_INVALIDCALL;
5402 /*TODO: stateblocks */
5403 if (This->currentPalette != PaletteNumber) {
5404 This->currentPalette = PaletteNumber;
5405 dirtify_p8_texture_samplers(This);
5407 TRACE("(%p) : returning\n", This);
5408 return WINED3D_OK;
5411 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5412 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5414 if (!PaletteNumber)
5416 WARN("(%p) : returning Invalid Call\n", This);
5417 return WINED3DERR_INVALIDCALL;
5419 /*TODO: stateblocks */
5420 *PaletteNumber = This->currentPalette;
5421 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5422 return WINED3D_OK;
5425 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5426 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5427 static BOOL warned;
5428 if (!warned)
5430 FIXME("(%p) : stub\n", This);
5431 warned = TRUE;
5434 This->softwareVertexProcessing = bSoftware;
5435 return WINED3D_OK;
5439 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5440 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5441 static BOOL warned;
5442 if (!warned)
5444 FIXME("(%p) : stub\n", This);
5445 warned = TRUE;
5447 return This->softwareVertexProcessing;
5450 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5451 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5453 struct wined3d_swapchain *swapchain;
5454 HRESULT hr;
5456 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5457 iface, swapchain_idx, raster_status);
5459 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5460 if (FAILED(hr))
5462 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5463 return hr;
5466 hr = wined3d_swapchain_get_raster_status(swapchain, raster_status);
5467 wined3d_swapchain_decref(swapchain);
5468 if (FAILED(hr))
5470 WARN("Failed to get raster status, hr %#x.\n", hr);
5471 return hr;
5474 return WINED3D_OK;
5477 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5479 static BOOL warned;
5480 if(nSegments != 0.0f) {
5481 if (!warned)
5483 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5484 warned = TRUE;
5487 return WINED3D_OK;
5490 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5492 static BOOL warned;
5493 if (!warned)
5495 FIXME("iface %p stub!\n", iface);
5496 warned = TRUE;
5498 return 0.0f;
5501 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface,
5502 struct wined3d_surface *src_surface, const RECT *src_rect,
5503 struct wined3d_surface *dst_surface, const POINT *dst_point)
5505 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5506 const struct wined3d_format *src_format;
5507 const struct wined3d_format *dst_format;
5508 const struct wined3d_gl_info *gl_info;
5509 struct wined3d_context *context;
5510 const unsigned char *data;
5511 UINT update_w, update_h;
5512 CONVERT_TYPES convert;
5513 UINT src_w, src_h;
5514 UINT dst_x, dst_y;
5515 DWORD sampler;
5516 struct wined3d_format format;
5518 TRACE("iface %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s.\n",
5519 iface, src_surface, wine_dbgstr_rect(src_rect),
5520 dst_surface, wine_dbgstr_point(dst_point));
5522 if (src_surface->resource.pool != WINED3DPOOL_SYSTEMMEM || dst_surface->resource.pool != WINED3DPOOL_DEFAULT)
5524 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
5525 src_surface, dst_surface);
5526 return WINED3DERR_INVALIDCALL;
5529 src_format = src_surface->resource.format;
5530 dst_format = dst_surface->resource.format;
5532 if (src_format->id != dst_format->id)
5534 WARN("Source and destination surfaces should have the same format.\n");
5535 return WINED3DERR_INVALIDCALL;
5538 dst_x = dst_point ? dst_point->x : 0;
5539 dst_y = dst_point ? dst_point->y : 0;
5541 /* This call loads the OpenGL surface directly, instead of copying the
5542 * surface to the destination's sysmem copy. If surface conversion is
5543 * needed, use BltFast instead to copy in sysmem and use regular surface
5544 * loading. */
5545 d3dfmt_get_conv(dst_surface, FALSE, TRUE, &format, &convert);
5546 if (convert != NO_CONVERSION || format.convert)
5547 return wined3d_surface_bltfast(dst_surface, dst_x, dst_y, src_surface, src_rect, 0);
5549 context = context_acquire(This, NULL);
5550 gl_info = context->gl_info;
5552 ENTER_GL();
5553 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5554 checkGLcall("glActiveTextureARB");
5555 LEAVE_GL();
5557 /* Make sure the surface is loaded and up to date */
5558 surface_internal_preload(dst_surface, SRGB_RGB);
5559 surface_bind(dst_surface, gl_info, FALSE);
5561 src_w = src_surface->resource.width;
5562 src_h = src_surface->resource.height;
5563 update_w = src_rect ? src_rect->right - src_rect->left : src_w;
5564 update_h = src_rect ? src_rect->bottom - src_rect->top : src_h;
5566 data = src_surface->resource.allocatedMemory;
5567 if (!data) ERR("Source surface has no allocated memory, but should be a sysmem surface.\n");
5569 ENTER_GL();
5571 if (dst_format->flags & WINED3DFMT_FLAG_COMPRESSED)
5573 UINT row_length = wined3d_format_calculate_size(src_format, 1, update_w, 1);
5574 UINT row_count = (update_h + src_format->block_height - 1) / src_format->block_height;
5575 UINT src_pitch = wined3d_format_calculate_size(src_format, 1, src_w, 1);
5577 if (src_rect)
5579 data += (src_rect->top / src_format->block_height) * src_pitch;
5580 data += (src_rect->left / src_format->block_width) * src_format->block_byte_count;
5583 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
5584 "format %#x, image_size %#x, data %p.\n", dst_surface->texture_target, dst_surface->texture_level,
5585 dst_x, dst_y, update_w, update_h, dst_format->glFormat, row_count * row_length, data);
5587 if (row_length == src_pitch)
5589 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_surface->texture_target, dst_surface->texture_level,
5590 dst_x, dst_y, update_w, update_h, dst_format->glInternal, row_count * row_length, data));
5592 else
5594 UINT row, y;
5596 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
5597 * can't use the unpack row length like below. */
5598 for (row = 0, y = dst_y; row < row_count; ++row)
5600 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_surface->texture_target, dst_surface->texture_level,
5601 dst_x, y, update_w, src_format->block_height, dst_format->glInternal, row_length, data));
5602 y += src_format->block_height;
5603 data += src_pitch;
5606 checkGLcall("glCompressedTexSubImage2DARB");
5608 else
5610 if (src_rect)
5612 data += src_rect->top * src_w * src_format->byte_count;
5613 data += src_rect->left * src_format->byte_count;
5616 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, data %p.\n",
5617 dst_surface->texture_target, dst_surface->texture_level, dst_x, dst_y,
5618 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5620 glPixelStorei(GL_UNPACK_ROW_LENGTH, src_w);
5621 glTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level, dst_x, dst_y,
5622 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5623 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
5624 checkGLcall("glTexSubImage2D");
5627 LEAVE_GL();
5628 context_release(context);
5630 surface_modify_location(dst_surface, SFLAG_INTEXTURE, TRUE);
5631 sampler = This->rev_tex_unit_map[0];
5632 if (sampler != WINED3D_UNMAPPED_STAGE)
5634 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5637 return WINED3D_OK;
5640 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5641 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5642 struct WineD3DRectPatch *patch;
5643 GLenum old_primitive_type;
5644 unsigned int i;
5645 struct list *e;
5646 BOOL found;
5647 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5649 if(!(Handle || pRectPatchInfo)) {
5650 /* TODO: Write a test for the return value, thus the FIXME */
5651 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5652 return WINED3DERR_INVALIDCALL;
5655 if(Handle) {
5656 i = PATCHMAP_HASHFUNC(Handle);
5657 found = FALSE;
5658 LIST_FOR_EACH(e, &This->patches[i]) {
5659 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5660 if(patch->Handle == Handle) {
5661 found = TRUE;
5662 break;
5666 if(!found) {
5667 TRACE("Patch does not exist. Creating a new one\n");
5668 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5669 patch->Handle = Handle;
5670 list_add_head(&This->patches[i], &patch->entry);
5671 } else {
5672 TRACE("Found existing patch %p\n", patch);
5674 } else {
5675 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5676 * attributes we have to tesselate, read back, and draw. This needs a patch
5677 * management structure instance. Create one.
5679 * A possible improvement is to check if a vertex shader is used, and if not directly
5680 * draw the patch.
5682 FIXME("Drawing an uncached patch. This is slow\n");
5683 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5686 if (pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1]
5687 || pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3]
5688 || (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo))))
5690 HRESULT hr;
5691 TRACE("Tesselation density or patch info changed, retesselating\n");
5693 if(pRectPatchInfo) {
5694 patch->RectPatchInfo = *pRectPatchInfo;
5696 patch->numSegs[0] = pNumSegs[0];
5697 patch->numSegs[1] = pNumSegs[1];
5698 patch->numSegs[2] = pNumSegs[2];
5699 patch->numSegs[3] = pNumSegs[3];
5701 hr = tesselate_rectpatch(This, patch);
5702 if(FAILED(hr)) {
5703 WARN("Patch tesselation failed\n");
5705 /* Do not release the handle to store the params of the patch */
5706 if(!Handle) {
5707 HeapFree(GetProcessHeap(), 0, patch);
5709 return hr;
5713 This->currentPatch = patch;
5714 old_primitive_type = This->stateBlock->state.gl_primitive_type;
5715 This->stateBlock->state.gl_primitive_type = GL_TRIANGLES;
5716 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5717 This->stateBlock->state.gl_primitive_type = old_primitive_type;
5718 This->currentPatch = NULL;
5720 /* Destroy uncached patches */
5721 if(!Handle) {
5722 HeapFree(GetProcessHeap(), 0, patch->mem);
5723 HeapFree(GetProcessHeap(), 0, patch);
5725 return WINED3D_OK;
5728 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5729 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5731 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5732 iface, handle, segment_count, patch_info);
5734 return WINED3D_OK;
5737 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5738 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5739 int i;
5740 struct WineD3DRectPatch *patch;
5741 struct list *e;
5742 TRACE("(%p) Handle(%d)\n", This, Handle);
5744 i = PATCHMAP_HASHFUNC(Handle);
5745 LIST_FOR_EACH(e, &This->patches[i]) {
5746 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5747 if(patch->Handle == Handle) {
5748 TRACE("Deleting patch %p\n", patch);
5749 list_remove(&patch->entry);
5750 HeapFree(GetProcessHeap(), 0, patch->mem);
5751 HeapFree(GetProcessHeap(), 0, patch);
5752 return WINED3D_OK;
5756 /* TODO: Write a test for the return value */
5757 FIXME("Attempt to destroy nonexistent patch\n");
5758 return WINED3DERR_INVALIDCALL;
5761 /* Do not call while under the GL lock. */
5762 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5763 struct wined3d_surface *surface, const RECT *rect, const WINED3DCOLORVALUE *color)
5765 TRACE("iface %p, surface %p, rect %s, color {%.8e, %.8e, %.8e, %.8e}.\n",
5766 iface, surface, wine_dbgstr_rect(rect),
5767 color->r, color->g, color->b, color->a);
5769 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM)
5771 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5772 return WINED3DERR_INVALIDCALL;
5775 return surface_color_fill(surface, rect, color);
5778 /* Do not call while under the GL lock. */
5779 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5780 struct wined3d_rendertarget_view *rendertarget_view, const WINED3DCOLORVALUE *color)
5782 struct wined3d_resource *resource;
5783 HRESULT hr;
5785 resource = rendertarget_view->resource;
5786 if (resource->resourceType != WINED3DRTYPE_SURFACE)
5788 FIXME("Only supported on surface resources\n");
5789 return;
5792 hr = surface_color_fill(surface_from_resource(resource), NULL, color);
5793 if (FAILED(hr)) ERR("Color fill failed, hr %#x.\n", hr);
5796 /* rendertarget and depth stencil functions */
5797 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice *iface,
5798 DWORD render_target_idx, struct wined3d_surface **render_target)
5800 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5802 TRACE("iface %p, render_target_idx %u, render_target %p.\n",
5803 iface, render_target_idx, render_target);
5805 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5807 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5808 return WINED3DERR_INVALIDCALL;
5811 *render_target = device->render_targets[render_target_idx];
5812 if (*render_target)
5813 wined3d_surface_incref(*render_target);
5815 TRACE("Returning render target %p.\n", *render_target);
5817 return WINED3D_OK;
5820 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice *iface,
5821 struct wined3d_surface **depth_stencil)
5823 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5825 TRACE("iface %p, depth_stencil %p.\n", iface, depth_stencil);
5827 *depth_stencil = device->depth_stencil;
5828 TRACE("Returning depth/stencil surface %p.\n", *depth_stencil);
5829 if (!*depth_stencil) return WINED3DERR_NOTFOUND;
5830 wined3d_surface_incref(*depth_stencil);
5832 return WINED3D_OK;
5835 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface,
5836 DWORD render_target_idx, struct wined3d_surface *render_target, BOOL set_viewport)
5838 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5839 struct wined3d_surface *prev;
5841 TRACE("iface %p, render_target_idx %u, render_target %p, set_viewport %#x.\n",
5842 iface, render_target_idx, render_target, set_viewport);
5844 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5846 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5847 return WINED3DERR_INVALIDCALL;
5850 prev = device->render_targets[render_target_idx];
5851 if (render_target == prev)
5853 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5854 return WINED3D_OK;
5857 /* Render target 0 can't be set to NULL. */
5858 if (!render_target && !render_target_idx)
5860 WARN("Trying to set render target 0 to NULL.\n");
5861 return WINED3DERR_INVALIDCALL;
5864 if (render_target && !(render_target->resource.usage & WINED3DUSAGE_RENDERTARGET))
5866 FIXME("Surface %p doesn't have render target usage.\n", render_target);
5867 return WINED3DERR_INVALIDCALL;
5870 if (render_target)
5871 wined3d_surface_incref(render_target);
5872 device->render_targets[render_target_idx] = render_target;
5873 /* Release after the assignment, to prevent device_resource_released()
5874 * from seeing the surface as still in use. */
5875 if (prev)
5876 wined3d_surface_decref(prev);
5878 /* Render target 0 is special. */
5879 if (!render_target_idx && set_viewport)
5881 /* Set the viewport and scissor rectangles, if requested. Tests show
5882 * that stateblock recording is ignored, the change goes directly
5883 * into the primary stateblock. */
5884 device->stateBlock->state.viewport.Height = device->render_targets[0]->resource.height;
5885 device->stateBlock->state.viewport.Width = device->render_targets[0]->resource.width;
5886 device->stateBlock->state.viewport.X = 0;
5887 device->stateBlock->state.viewport.Y = 0;
5888 device->stateBlock->state.viewport.MaxZ = 1.0f;
5889 device->stateBlock->state.viewport.MinZ = 0.0f;
5890 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_VIEWPORT);
5892 device->stateBlock->state.scissor_rect.top = 0;
5893 device->stateBlock->state.scissor_rect.left = 0;
5894 device->stateBlock->state.scissor_rect.right = device->stateBlock->state.viewport.Width;
5895 device->stateBlock->state.scissor_rect.bottom = device->stateBlock->state.viewport.Height;
5896 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SCISSORRECT);
5899 return WINED3D_OK;
5902 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface,
5903 struct wined3d_surface *depth_stencil)
5905 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5906 struct wined3d_surface *tmp;
5908 TRACE("device %p, depth_stencil %p, old depth_stencil %p.\n", This, depth_stencil, This->depth_stencil);
5910 if (This->depth_stencil == depth_stencil)
5912 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5913 return WINED3D_OK;
5916 if (This->depth_stencil)
5918 if (This->swapchains[0]->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5919 || This->depth_stencil->flags & SFLAG_DISCARD)
5921 surface_modify_ds_location(This->depth_stencil, SFLAG_DS_DISCARDED,
5922 This->depth_stencil->resource.width,
5923 This->depth_stencil->resource.height);
5924 if (This->depth_stencil == This->onscreen_depth_stencil)
5926 wined3d_surface_decref(This->onscreen_depth_stencil);
5927 This->onscreen_depth_stencil = NULL;
5932 tmp = This->depth_stencil;
5933 This->depth_stencil = depth_stencil;
5934 if (This->depth_stencil)
5935 wined3d_surface_incref(This->depth_stencil);
5936 if (tmp)
5937 wined3d_surface_decref(tmp);
5939 if ((!tmp && depth_stencil) || (!depth_stencil && tmp))
5941 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5942 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5943 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5944 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5945 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_DEPTHBIAS));
5947 else if (tmp && tmp->resource.format->depth_size != This->depth_stencil->resource.format->depth_size)
5949 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_DEPTHBIAS));
5952 return WINED3D_OK;
5955 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice *iface,
5956 UINT XHotSpot, UINT YHotSpot, struct wined3d_surface *cursor_image)
5958 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5959 WINED3DLOCKED_RECT lockedRect;
5961 TRACE("iface %p, hotspot_x %u, hotspot_y %u, cursor_image %p.\n",
5962 iface, XHotSpot, YHotSpot, cursor_image);
5964 /* some basic validation checks */
5965 if (This->cursorTexture)
5967 struct wined3d_context *context = context_acquire(This, NULL);
5968 ENTER_GL();
5969 glDeleteTextures(1, &This->cursorTexture);
5970 LEAVE_GL();
5971 context_release(context);
5972 This->cursorTexture = 0;
5975 if (cursor_image->resource.width == 32 && cursor_image->resource.height == 32)
5976 This->haveHardwareCursor = TRUE;
5977 else
5978 This->haveHardwareCursor = FALSE;
5980 if (cursor_image)
5982 WINED3DLOCKED_RECT rect;
5984 /* MSDN: Cursor must be A8R8G8B8 */
5985 if (cursor_image->resource.format->id != WINED3DFMT_B8G8R8A8_UNORM)
5987 WARN("surface %p has an invalid format.\n", cursor_image);
5988 return WINED3DERR_INVALIDCALL;
5991 /* MSDN: Cursor must be smaller than the display mode */
5992 if (cursor_image->resource.width > This->ddraw_width
5993 || cursor_image->resource.height > This->ddraw_height)
5995 WARN("Surface %p dimensions are %ux%u, but screen dimensions are %ux%u.\n",
5996 cursor_image, cursor_image->resource.width, cursor_image->resource.height,
5997 This->ddraw_width, This->ddraw_height);
5998 return WINED3DERR_INVALIDCALL;
6001 if (!This->haveHardwareCursor) {
6002 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6004 /* Do not store the surface's pointer because the application may
6005 * release it after setting the cursor image. Windows doesn't
6006 * addref the set surface, so we can't do this either without
6007 * creating circular refcount dependencies. Copy out the gl texture
6008 * instead. */
6009 This->cursorWidth = cursor_image->resource.width;
6010 This->cursorHeight = cursor_image->resource.height;
6011 if (SUCCEEDED(wined3d_surface_map(cursor_image, &rect, NULL, WINED3DLOCK_READONLY)))
6013 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
6014 const struct wined3d_format *format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM);
6015 struct wined3d_context *context;
6016 char *mem, *bits = rect.pBits;
6017 GLint intfmt = format->glInternal;
6018 GLint gl_format = format->glFormat;
6019 GLint type = format->glType;
6020 INT height = This->cursorHeight;
6021 INT width = This->cursorWidth;
6022 INT bpp = format->byte_count;
6023 DWORD sampler;
6024 INT i;
6026 /* Reformat the texture memory (pitch and width can be
6027 * different) */
6028 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6029 for(i = 0; i < height; i++)
6030 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6031 wined3d_surface_unmap(cursor_image);
6033 context = context_acquire(This, NULL);
6035 ENTER_GL();
6037 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6039 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6040 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6043 /* Make sure that a proper texture unit is selected */
6044 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6045 checkGLcall("glActiveTextureARB");
6046 sampler = This->rev_tex_unit_map[0];
6047 if (sampler != WINED3D_UNMAPPED_STAGE)
6049 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6051 /* Create a new cursor texture */
6052 glGenTextures(1, &This->cursorTexture);
6053 checkGLcall("glGenTextures");
6054 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6055 checkGLcall("glBindTexture");
6056 /* Copy the bitmap memory into the cursor texture */
6057 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, gl_format, type, mem);
6058 checkGLcall("glTexImage2D");
6059 HeapFree(GetProcessHeap(), 0, mem);
6061 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6063 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6064 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6067 LEAVE_GL();
6069 context_release(context);
6071 else
6073 FIXME("A cursor texture was not returned.\n");
6074 This->cursorTexture = 0;
6077 else
6079 /* Draw a hardware cursor */
6080 ICONINFO cursorInfo;
6081 HCURSOR cursor;
6082 /* Create and clear maskBits because it is not needed for
6083 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6084 * chunks. */
6085 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6086 (cursor_image->resource.width * cursor_image->resource.height / 8));
6087 wined3d_surface_map(cursor_image, &lockedRect, NULL,
6088 WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY);
6089 TRACE("width: %u height: %u.\n", cursor_image->resource.width, cursor_image->resource.height);
6091 cursorInfo.fIcon = FALSE;
6092 cursorInfo.xHotspot = XHotSpot;
6093 cursorInfo.yHotspot = YHotSpot;
6094 cursorInfo.hbmMask = CreateBitmap(cursor_image->resource.width, cursor_image->resource.height,
6095 1, 1, maskBits);
6096 cursorInfo.hbmColor = CreateBitmap(cursor_image->resource.width, cursor_image->resource.height,
6097 1, 32, lockedRect.pBits);
6098 wined3d_surface_unmap(cursor_image);
6099 /* Create our cursor and clean up. */
6100 cursor = CreateIconIndirect(&cursorInfo);
6101 SetCursor(cursor);
6102 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6103 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6104 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6105 This->hardwareCursor = cursor;
6106 HeapFree(GetProcessHeap(), 0, maskBits);
6110 This->xHotSpot = XHotSpot;
6111 This->yHotSpot = YHotSpot;
6112 return WINED3D_OK;
6115 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice *iface,
6116 int XScreenSpace, int YScreenSpace, DWORD flags)
6118 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6120 TRACE("iface %p, x %d, y %d, flags %#x.\n",
6121 iface, XScreenSpace, YScreenSpace, flags);
6123 This->xScreenSpace = XScreenSpace;
6124 This->yScreenSpace = YScreenSpace;
6127 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6128 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6129 BOOL oldVisible = This->bCursorVisible;
6130 POINT pt;
6132 TRACE("(%p) : visible(%d)\n", This, bShow);
6135 * When ShowCursor is first called it should make the cursor appear at the OS's last
6136 * known cursor position. Because of this, some applications just repetitively call
6137 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6139 GetCursorPos(&pt);
6140 This->xScreenSpace = pt.x;
6141 This->yScreenSpace = pt.y;
6143 if (This->haveHardwareCursor) {
6144 This->bCursorVisible = bShow;
6145 if (bShow)
6146 SetCursor(This->hardwareCursor);
6147 else
6148 SetCursor(NULL);
6150 else
6152 if (This->cursorTexture)
6153 This->bCursorVisible = bShow;
6156 return oldVisible;
6159 static HRESULT WINAPI evict_managed_resource(struct wined3d_resource *resource, void *data)
6161 TRACE("checking resource %p for eviction\n", resource);
6163 if (resource->pool == WINED3DPOOL_MANAGED)
6165 TRACE("Evicting %p.\n", resource);
6166 resource->resource_ops->resource_unload(resource);
6169 return S_OK;
6172 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6174 TRACE("iface %p.\n", iface);
6176 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6177 /* Invalidate stream sources, the buffer(s) may have been evicted. */
6178 IWineD3DDeviceImpl_MarkStateDirty((IWineD3DDeviceImpl *)iface, STATE_STREAMSRC);
6180 return WINED3D_OK;
6183 static HRESULT updateSurfaceDesc(struct wined3d_surface *surface,
6184 const WINED3DPRESENT_PARAMETERS *pPresentationParameters)
6186 IWineD3DDeviceImpl *device = surface->resource.device;
6187 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6189 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6190 if (surface->flags & SFLAG_DIBSECTION)
6192 /* Release the DC */
6193 SelectObject(surface->hDC, surface->dib.holdbitmap);
6194 DeleteDC(surface->hDC);
6195 /* Release the DIB section */
6196 DeleteObject(surface->dib.DIBsection);
6197 surface->dib.bitmap_data = NULL;
6198 surface->resource.allocatedMemory = NULL;
6199 surface->flags &= ~SFLAG_DIBSECTION;
6201 surface->resource.width = pPresentationParameters->BackBufferWidth;
6202 surface->resource.height = pPresentationParameters->BackBufferHeight;
6203 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6204 || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
6206 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6207 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6208 } else {
6209 surface->pow2Width = surface->pow2Height = 1;
6210 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6211 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6214 if (surface->texture_name)
6216 struct wined3d_context *context = context_acquire(device, NULL);
6217 ENTER_GL();
6218 glDeleteTextures(1, &surface->texture_name);
6219 LEAVE_GL();
6220 context_release(context);
6221 surface->texture_name = 0;
6222 surface->flags &= ~SFLAG_CLIENT;
6224 if (surface->pow2Width != pPresentationParameters->BackBufferWidth
6225 || surface->pow2Height != pPresentationParameters->BackBufferHeight)
6227 surface->flags |= SFLAG_NONPOW2;
6229 else
6231 surface->flags &= ~SFLAG_NONPOW2;
6233 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6234 surface->resource.allocatedMemory = NULL;
6235 surface->resource.heapMemory = NULL;
6236 surface->resource.size = wined3d_surface_get_pitch(surface) * surface->pow2Width;
6238 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6239 * to a FBO */
6240 if (!surface_init_sysmem(surface))
6242 return E_OUTOFMEMORY;
6244 return WINED3D_OK;
6247 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6249 UINT i, count;
6250 WINED3DDISPLAYMODE m;
6251 HRESULT hr;
6253 /* All Windowed modes are supported, as is leaving the current mode */
6254 if(pp->Windowed) return TRUE;
6255 if(!pp->BackBufferWidth) return TRUE;
6256 if(!pp->BackBufferHeight) return TRUE;
6258 count = wined3d_get_adapter_mode_count(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6259 for (i = 0; i < count; ++i)
6261 memset(&m, 0, sizeof(m));
6262 hr = wined3d_enum_adapter_modes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6263 if (FAILED(hr))
6264 ERR("Failed to enumerate adapter mode.\n");
6265 if (m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight)
6266 /* Mode found, it is supported. */
6267 return TRUE;
6269 /* Mode not found -> not supported */
6270 return FALSE;
6273 /* Do not call while under the GL lock. */
6274 static void delete_opengl_contexts(IWineD3DDeviceImpl *device, struct wined3d_swapchain *swapchain)
6276 const struct wined3d_gl_info *gl_info;
6277 struct wined3d_context *context;
6278 struct wined3d_shader *shader;
6280 context = context_acquire(device, NULL);
6281 gl_info = context->gl_info;
6283 IWineD3DDevice_EnumResources((IWineD3DDevice *)device, device_unload_resource, NULL);
6284 LIST_FOR_EACH_ENTRY(shader, &device->shaders, struct wined3d_shader, shader_list_entry)
6286 device->shader_backend->shader_destroy(shader);
6289 ENTER_GL();
6290 if (device->depth_blt_texture)
6292 glDeleteTextures(1, &device->depth_blt_texture);
6293 device->depth_blt_texture = 0;
6295 if (device->depth_blt_rb)
6297 gl_info->fbo_ops.glDeleteRenderbuffers(1, &device->depth_blt_rb);
6298 device->depth_blt_rb = 0;
6299 device->depth_blt_rb_w = 0;
6300 device->depth_blt_rb_h = 0;
6302 LEAVE_GL();
6304 device->blitter->free_private(device);
6305 device->frag_pipe->free_private(device);
6306 device->shader_backend->shader_free_private(device);
6307 destroy_dummy_textures(device, gl_info);
6309 context_release(context);
6311 while (device->context_count)
6313 context_destroy(device, device->contexts[0]);
6315 HeapFree(GetProcessHeap(), 0, swapchain->context);
6316 swapchain->context = NULL;
6317 swapchain->num_contexts = 0;
6320 /* Do not call while under the GL lock. */
6321 static HRESULT create_primary_opengl_context(IWineD3DDeviceImpl *device, struct wined3d_swapchain *swapchain)
6323 struct wined3d_context *context;
6324 struct wined3d_surface *target;
6325 HRESULT hr;
6327 /* Recreate the primary swapchain's context */
6328 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6329 if (!swapchain->context)
6331 ERR("Failed to allocate memory for swapchain context array.\n");
6332 return E_OUTOFMEMORY;
6335 target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer;
6336 if (!(context = context_create(swapchain, target, swapchain->ds_format)))
6338 WARN("Failed to create context.\n");
6339 HeapFree(GetProcessHeap(), 0, swapchain->context);
6340 return E_FAIL;
6343 swapchain->context[0] = context;
6344 swapchain->num_contexts = 1;
6345 create_dummy_textures(device);
6346 context_release(context);
6348 hr = device->shader_backend->shader_alloc_private(device);
6349 if (FAILED(hr))
6351 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6352 goto err;
6355 hr = device->frag_pipe->alloc_private(device);
6356 if (FAILED(hr))
6358 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6359 device->shader_backend->shader_free_private(device);
6360 goto err;
6363 hr = device->blitter->alloc_private(device);
6364 if (FAILED(hr))
6366 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6367 device->frag_pipe->free_private(device);
6368 device->shader_backend->shader_free_private(device);
6369 goto err;
6372 return WINED3D_OK;
6374 err:
6375 context_acquire(device, NULL);
6376 destroy_dummy_textures(device, context->gl_info);
6377 context_release(context);
6378 context_destroy(device, context);
6379 HeapFree(GetProcessHeap(), 0, swapchain->context);
6380 swapchain->num_contexts = 0;
6381 return hr;
6384 /* Do not call while under the GL lock. */
6385 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice *iface,
6386 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
6388 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6389 struct wined3d_swapchain *swapchain;
6390 HRESULT hr;
6391 BOOL DisplayModeChanged = FALSE;
6392 WINED3DDISPLAYMODE mode;
6393 TRACE("(%p)\n", This);
6395 hr = IWineD3DDevice_GetSwapChain(iface, 0, &swapchain);
6396 if (FAILED(hr))
6398 ERR("Failed to get the first implicit swapchain\n");
6399 return hr;
6402 if(!is_display_mode_supported(This, pPresentationParameters)) {
6403 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6404 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6405 pPresentationParameters->BackBufferHeight);
6406 wined3d_swapchain_decref(swapchain);
6407 return WINED3DERR_INVALIDCALL;
6410 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6411 * on an existing gl context, so there's no real need for recreation.
6413 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6415 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6417 TRACE("New params:\n");
6418 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6419 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6420 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6421 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6422 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6423 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6424 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6425 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6426 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6427 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6428 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6429 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6430 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6432 /* No special treatment of these parameters. Just store them */
6433 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6434 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6435 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6436 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6438 /* What to do about these? */
6439 if (pPresentationParameters->BackBufferCount
6440 && pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount)
6441 ERR("Cannot change the back buffer count yet\n");
6443 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6444 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6445 ERR("Cannot change the back buffer format yet\n");
6448 if (pPresentationParameters->hDeviceWindow
6449 && pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow)
6450 ERR("Cannot change the device window yet\n");
6452 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil)
6454 HRESULT hrc;
6456 TRACE("Creating the depth stencil buffer\n");
6458 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6459 pPresentationParameters->BackBufferWidth,
6460 pPresentationParameters->BackBufferHeight,
6461 pPresentationParameters->AutoDepthStencilFormat,
6462 pPresentationParameters->MultiSampleType,
6463 pPresentationParameters->MultiSampleQuality,
6464 FALSE,
6465 &This->auto_depth_stencil);
6466 if (FAILED(hrc))
6468 ERR("Failed to create the depth stencil buffer.\n");
6469 wined3d_swapchain_decref(swapchain);
6470 return WINED3DERR_INVALIDCALL;
6474 if (This->onscreen_depth_stencil)
6476 wined3d_surface_decref(This->onscreen_depth_stencil);
6477 This->onscreen_depth_stencil = NULL;
6480 /* Reset the depth stencil */
6481 if (pPresentationParameters->EnableAutoDepthStencil)
6482 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil);
6483 else
6484 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6486 TRACE("Resetting stateblock\n");
6487 wined3d_stateblock_decref(This->updateStateBlock);
6488 wined3d_stateblock_decref(This->stateBlock);
6490 delete_opengl_contexts(This, swapchain);
6492 if(pPresentationParameters->Windowed) {
6493 mode.Width = swapchain->orig_width;
6494 mode.Height = swapchain->orig_height;
6495 mode.RefreshRate = 0;
6496 mode.Format = swapchain->presentParms.BackBufferFormat;
6497 } else {
6498 mode.Width = pPresentationParameters->BackBufferWidth;
6499 mode.Height = pPresentationParameters->BackBufferHeight;
6500 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6501 mode.Format = swapchain->presentParms.BackBufferFormat;
6504 /* Should Width == 800 && Height == 0 set 800x600? */
6505 if (pPresentationParameters->BackBufferWidth && pPresentationParameters->BackBufferHeight
6506 && (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth
6507 || pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6509 UINT i;
6511 if(!pPresentationParameters->Windowed) {
6512 DisplayModeChanged = TRUE;
6514 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6515 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6517 hr = updateSurfaceDesc(swapchain->front_buffer, pPresentationParameters);
6518 if(FAILED(hr))
6520 wined3d_swapchain_decref(swapchain);
6521 return hr;
6524 for (i = 0; i < swapchain->presentParms.BackBufferCount; ++i)
6526 hr = updateSurfaceDesc(swapchain->back_buffers[i], pPresentationParameters);
6527 if(FAILED(hr))
6529 wined3d_swapchain_decref(swapchain);
6530 return hr;
6533 if (This->auto_depth_stencil)
6535 hr = updateSurfaceDesc(This->auto_depth_stencil, pPresentationParameters);
6536 if(FAILED(hr))
6538 wined3d_swapchain_decref(swapchain);
6539 return hr;
6544 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
6545 || DisplayModeChanged)
6547 BOOL filter = This->filter_messages;
6548 This->filter_messages = TRUE;
6550 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6552 if (!pPresentationParameters->Windowed)
6554 if (swapchain->presentParms.Windowed)
6556 HWND focus_window = This->createParms.hFocusWindow;
6557 if (!focus_window) focus_window = pPresentationParameters->hDeviceWindow;
6558 if (FAILED(hr = IWineD3DDevice_AcquireFocusWindow(iface, focus_window)))
6560 ERR("Failed to acquire focus window, hr %#x.\n", hr);
6561 wined3d_swapchain_decref(swapchain);
6562 This->filter_messages = filter;
6563 return hr;
6566 /* switch from windowed to fs */
6567 IWineD3DDevice_SetupFullscreenWindow(iface, swapchain->device_window,
6568 pPresentationParameters->BackBufferWidth,
6569 pPresentationParameters->BackBufferHeight);
6571 else
6573 /* Fullscreen -> fullscreen mode change */
6574 MoveWindow(swapchain->device_window, 0, 0,
6575 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6576 TRUE);
6579 else if (!swapchain->presentParms.Windowed)
6581 /* Fullscreen -> windowed switch */
6582 IWineD3DDevice_RestoreFullscreenWindow(iface, swapchain->device_window);
6583 IWineD3DDevice_ReleaseFocusWindow(iface);
6585 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6587 This->filter_messages = filter;
6589 else if (!pPresentationParameters->Windowed)
6591 DWORD style = This->style, exStyle = This->exStyle;
6592 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6593 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6594 * Reset to clear up their mess. Guild Wars also loses the device during that.
6596 This->style = 0;
6597 This->exStyle = 0;
6598 IWineD3DDevice_SetupFullscreenWindow(iface, swapchain->device_window,
6599 pPresentationParameters->BackBufferWidth,
6600 pPresentationParameters->BackBufferHeight);
6601 This->style = style;
6602 This->exStyle = exStyle;
6605 /* Note: No parent needed for initial internal stateblock */
6606 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, &This->stateBlock);
6607 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6608 else TRACE("Created stateblock %p\n", This->stateBlock);
6609 This->updateStateBlock = This->stateBlock;
6610 wined3d_stateblock_incref(This->updateStateBlock);
6612 stateblock_init_default_state(This->stateBlock);
6614 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6616 RECT client_rect;
6617 GetClientRect(swapchain->win_handle, &client_rect);
6619 if(!swapchain->presentParms.BackBufferCount)
6621 TRACE("Single buffered rendering\n");
6622 swapchain->render_to_fbo = FALSE;
6624 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6625 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6627 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6628 swapchain->presentParms.BackBufferWidth,
6629 swapchain->presentParms.BackBufferHeight,
6630 client_rect.right, client_rect.bottom);
6631 swapchain->render_to_fbo = TRUE;
6633 else
6635 TRACE("Rendering directly to GL_BACK\n");
6636 swapchain->render_to_fbo = FALSE;
6640 hr = create_primary_opengl_context(This, swapchain);
6641 wined3d_swapchain_decref(swapchain);
6643 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6644 * first use
6646 return hr;
6649 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6651 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6653 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6655 return WINED3D_OK;
6659 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6660 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6661 TRACE("(%p) : pParameters %p\n", This, pParameters);
6663 *pParameters = This->createParms;
6664 return WINED3D_OK;
6667 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice *iface,
6668 UINT iSwapChain, DWORD flags, const WINED3DGAMMARAMP *pRamp)
6670 struct wined3d_swapchain *swapchain;
6672 TRACE("Relaying to swapchain\n");
6674 if (SUCCEEDED(IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)))
6676 wined3d_swapchain_set_gamma_ramp(swapchain, flags, pRamp);
6677 wined3d_swapchain_decref(swapchain);
6681 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp)
6683 struct wined3d_swapchain *swapchain;
6685 TRACE("Relaying to swapchain\n");
6687 if (SUCCEEDED(IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)))
6689 wined3d_swapchain_get_gamma_ramp(swapchain, pRamp);
6690 wined3d_swapchain_decref(swapchain);
6694 void device_resource_add(struct IWineD3DDeviceImpl *device, struct wined3d_resource *resource)
6696 TRACE("device %p, resource %p.\n", device, resource);
6698 list_add_head(&device->resources, &resource->resource_list_entry);
6701 static void device_resource_remove(struct IWineD3DDeviceImpl *device, struct wined3d_resource *resource)
6703 TRACE("device %p, resource %p.\n", device, resource);
6705 list_remove(&resource->resource_list_entry);
6708 void device_resource_released(struct IWineD3DDeviceImpl *device, struct wined3d_resource *resource)
6710 WINED3DRESOURCETYPE type = resource->resourceType;
6711 unsigned int i;
6713 TRACE("device %p, resource %p, type %s.\n", device, resource, debug_d3dresourcetype(type));
6715 context_resource_released(device, resource, type);
6717 switch (type)
6719 case WINED3DRTYPE_SURFACE:
6721 struct wined3d_surface *surface = surface_from_resource(resource);
6723 if (!device->d3d_initialized) break;
6725 for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i)
6727 if (device->render_targets[i] == surface)
6729 ERR("Surface %p is still in use as render target %u.\n", surface, i);
6730 device->render_targets[i] = NULL;
6734 if (device->depth_stencil == surface)
6736 ERR("Surface %p is still in use as depth/stencil buffer.\n", surface);
6737 device->depth_stencil = NULL;
6740 break;
6742 case WINED3DRTYPE_TEXTURE:
6743 case WINED3DRTYPE_CUBETEXTURE:
6744 case WINED3DRTYPE_VOLUMETEXTURE:
6745 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
6747 struct wined3d_texture *texture = wined3d_texture_from_resource(resource);
6749 if (device->stateBlock && device->stateBlock->state.textures[i] == texture)
6751 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6752 texture, device->stateBlock, i);
6753 device->stateBlock->state.textures[i] = NULL;
6756 if (device->updateStateBlock != device->stateBlock
6757 && device->updateStateBlock->state.textures[i] == texture)
6759 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6760 texture, device->updateStateBlock, i);
6761 device->updateStateBlock->state.textures[i] = NULL;
6764 break;
6766 case WINED3DRTYPE_BUFFER:
6768 struct wined3d_buffer *buffer = buffer_from_resource(resource);
6770 for (i = 0; i < MAX_STREAMS; ++i)
6772 if (device->stateBlock && device->stateBlock->state.streams[i].buffer == buffer)
6774 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6775 buffer, device->stateBlock, i);
6776 device->stateBlock->state.streams[i].buffer = NULL;
6779 if (device->updateStateBlock != device->stateBlock
6780 && device->updateStateBlock->state.streams[i].buffer == buffer)
6782 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6783 buffer, device->updateStateBlock, i);
6784 device->updateStateBlock->state.streams[i].buffer = NULL;
6789 if (device->stateBlock && device->stateBlock->state.index_buffer == buffer)
6791 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6792 buffer, device->stateBlock);
6793 device->stateBlock->state.index_buffer = NULL;
6796 if (device->updateStateBlock != device->stateBlock
6797 && device->updateStateBlock->state.index_buffer == buffer)
6799 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6800 buffer, device->updateStateBlock);
6801 device->updateStateBlock->state.index_buffer = NULL;
6804 break;
6806 default:
6807 break;
6810 /* Remove the resource from the resourceStore */
6811 device_resource_remove(device, resource);
6813 TRACE("Resource released.\n");
6816 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface,
6817 D3DCB_ENUMRESOURCES callback, void *data)
6819 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6820 struct wined3d_resource *resource, *cursor;
6822 TRACE("iface %p, callback %p, data %p.\n", iface, callback, data);
6824 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, struct wined3d_resource, resource_list_entry)
6826 TRACE("enumerating resource %p.\n", resource);
6827 if (callback(resource, data) == S_FALSE)
6829 TRACE("Canceling enumeration.\n");
6830 break;
6834 return WINED3D_OK;
6837 static HRESULT WINAPI IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice *iface,
6838 HDC dc, struct wined3d_surface **surface)
6840 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6841 struct wined3d_resource *resource;
6843 LIST_FOR_EACH_ENTRY(resource, &This->resources, struct wined3d_resource, resource_list_entry)
6845 if (resource->resourceType == WINED3DRTYPE_SURFACE)
6847 struct wined3d_surface *s = surface_from_resource(resource);
6849 if (s->hDC == dc)
6851 TRACE("Found surface %p for dc %p.\n", s, dc);
6852 *surface = s;
6853 return WINED3D_OK;
6858 return WINED3DERR_INVALIDCALL;
6861 /**********************************************************
6862 * IWineD3DDevice VTbl follows
6863 **********************************************************/
6865 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6867 /*** IUnknown methods ***/
6868 IWineD3DDeviceImpl_QueryInterface,
6869 IWineD3DDeviceImpl_AddRef,
6870 IWineD3DDeviceImpl_Release,
6871 /*** IWineD3DDevice methods ***/
6872 /*** Creation methods**/
6873 IWineD3DDeviceImpl_CreateBuffer,
6874 IWineD3DDeviceImpl_CreateVertexBuffer,
6875 IWineD3DDeviceImpl_CreateIndexBuffer,
6876 IWineD3DDeviceImpl_CreateStateBlock,
6877 IWineD3DDeviceImpl_CreateSurface,
6878 IWineD3DDeviceImpl_CreateRendertargetView,
6879 IWineD3DDeviceImpl_CreateTexture,
6880 IWineD3DDeviceImpl_CreateVolumeTexture,
6881 IWineD3DDeviceImpl_CreateVolume,
6882 IWineD3DDeviceImpl_CreateCubeTexture,
6883 IWineD3DDeviceImpl_CreateQuery,
6884 IWineD3DDeviceImpl_CreateSwapChain,
6885 IWineD3DDeviceImpl_CreateVertexDeclaration,
6886 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6887 IWineD3DDeviceImpl_CreateVertexShader,
6888 IWineD3DDeviceImpl_CreateGeometryShader,
6889 IWineD3DDeviceImpl_CreatePixelShader,
6890 IWineD3DDeviceImpl_CreatePalette,
6891 /*** Odd functions **/
6892 IWineD3DDeviceImpl_Init3D,
6893 IWineD3DDeviceImpl_InitGDI,
6894 IWineD3DDeviceImpl_Uninit3D,
6895 IWineD3DDeviceImpl_UninitGDI,
6896 IWineD3DDeviceImpl_SetMultithreaded,
6897 IWineD3DDeviceImpl_EvictManagedResources,
6898 IWineD3DDeviceImpl_GetAvailableTextureMem,
6899 IWineD3DDeviceImpl_GetBackBuffer,
6900 IWineD3DDeviceImpl_GetCreationParameters,
6901 IWineD3DDeviceImpl_GetDeviceCaps,
6902 IWineD3DDeviceImpl_GetDirect3D,
6903 IWineD3DDeviceImpl_GetDisplayMode,
6904 IWineD3DDeviceImpl_SetDisplayMode,
6905 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6906 IWineD3DDeviceImpl_GetRasterStatus,
6907 IWineD3DDeviceImpl_GetSwapChain,
6908 IWineD3DDeviceImpl_Reset,
6909 IWineD3DDeviceImpl_SetDialogBoxMode,
6910 IWineD3DDeviceImpl_SetCursorProperties,
6911 IWineD3DDeviceImpl_SetCursorPosition,
6912 IWineD3DDeviceImpl_ShowCursor,
6913 /*** Getters and setters **/
6914 IWineD3DDeviceImpl_SetClipPlane,
6915 IWineD3DDeviceImpl_GetClipPlane,
6916 IWineD3DDeviceImpl_SetClipStatus,
6917 IWineD3DDeviceImpl_GetClipStatus,
6918 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6919 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6920 IWineD3DDeviceImpl_SetDepthStencilSurface,
6921 IWineD3DDeviceImpl_GetDepthStencilSurface,
6922 IWineD3DDeviceImpl_SetGammaRamp,
6923 IWineD3DDeviceImpl_GetGammaRamp,
6924 IWineD3DDeviceImpl_SetIndexBuffer,
6925 IWineD3DDeviceImpl_GetIndexBuffer,
6926 IWineD3DDeviceImpl_SetBaseVertexIndex,
6927 IWineD3DDeviceImpl_GetBaseVertexIndex,
6928 IWineD3DDeviceImpl_SetLight,
6929 IWineD3DDeviceImpl_GetLight,
6930 IWineD3DDeviceImpl_SetLightEnable,
6931 IWineD3DDeviceImpl_GetLightEnable,
6932 IWineD3DDeviceImpl_SetMaterial,
6933 IWineD3DDeviceImpl_GetMaterial,
6934 IWineD3DDeviceImpl_SetNPatchMode,
6935 IWineD3DDeviceImpl_GetNPatchMode,
6936 IWineD3DDeviceImpl_SetPaletteEntries,
6937 IWineD3DDeviceImpl_GetPaletteEntries,
6938 IWineD3DDeviceImpl_SetPixelShader,
6939 IWineD3DDeviceImpl_GetPixelShader,
6940 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6941 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6942 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6943 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6944 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6945 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6946 IWineD3DDeviceImpl_SetRenderState,
6947 IWineD3DDeviceImpl_GetRenderState,
6948 IWineD3DDeviceImpl_SetRenderTarget,
6949 IWineD3DDeviceImpl_GetRenderTarget,
6950 IWineD3DDeviceImpl_SetSamplerState,
6951 IWineD3DDeviceImpl_GetSamplerState,
6952 IWineD3DDeviceImpl_SetScissorRect,
6953 IWineD3DDeviceImpl_GetScissorRect,
6954 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6955 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6956 IWineD3DDeviceImpl_SetStreamSource,
6957 IWineD3DDeviceImpl_GetStreamSource,
6958 IWineD3DDeviceImpl_SetStreamSourceFreq,
6959 IWineD3DDeviceImpl_GetStreamSourceFreq,
6960 IWineD3DDeviceImpl_SetTexture,
6961 IWineD3DDeviceImpl_GetTexture,
6962 IWineD3DDeviceImpl_SetTextureStageState,
6963 IWineD3DDeviceImpl_GetTextureStageState,
6964 IWineD3DDeviceImpl_SetTransform,
6965 IWineD3DDeviceImpl_GetTransform,
6966 IWineD3DDeviceImpl_SetVertexDeclaration,
6967 IWineD3DDeviceImpl_GetVertexDeclaration,
6968 IWineD3DDeviceImpl_SetVertexShader,
6969 IWineD3DDeviceImpl_GetVertexShader,
6970 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6971 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6972 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6973 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6974 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6975 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6976 IWineD3DDeviceImpl_SetViewport,
6977 IWineD3DDeviceImpl_GetViewport,
6978 IWineD3DDeviceImpl_MultiplyTransform,
6979 IWineD3DDeviceImpl_ValidateDevice,
6980 IWineD3DDeviceImpl_ProcessVertices,
6981 /*** State block ***/
6982 IWineD3DDeviceImpl_BeginStateBlock,
6983 IWineD3DDeviceImpl_EndStateBlock,
6984 /*** Scene management ***/
6985 IWineD3DDeviceImpl_BeginScene,
6986 IWineD3DDeviceImpl_EndScene,
6987 IWineD3DDeviceImpl_Present,
6988 IWineD3DDeviceImpl_Clear,
6989 IWineD3DDeviceImpl_ClearRendertargetView,
6990 /*** Drawing ***/
6991 IWineD3DDeviceImpl_SetPrimitiveType,
6992 IWineD3DDeviceImpl_GetPrimitiveType,
6993 IWineD3DDeviceImpl_DrawPrimitive,
6994 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6995 IWineD3DDeviceImpl_DrawPrimitiveUP,
6996 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6997 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6998 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6999 IWineD3DDeviceImpl_DrawRectPatch,
7000 IWineD3DDeviceImpl_DrawTriPatch,
7001 IWineD3DDeviceImpl_DeletePatch,
7002 IWineD3DDeviceImpl_ColorFill,
7003 IWineD3DDeviceImpl_UpdateTexture,
7004 IWineD3DDeviceImpl_UpdateSurface,
7005 IWineD3DDeviceImpl_GetFrontBufferData,
7006 /*** object tracking ***/
7007 IWineD3DDeviceImpl_EnumResources,
7008 IWineD3DDeviceImpl_GetSurfaceFromDC,
7009 IWineD3DDeviceImpl_AcquireFocusWindow,
7010 IWineD3DDeviceImpl_ReleaseFocusWindow,
7011 IWineD3DDeviceImpl_SetupFullscreenWindow,
7012 IWineD3DDeviceImpl_RestoreFullscreenWindow,
7015 HRESULT device_init(IWineD3DDeviceImpl *device, struct wined3d *wined3d,
7016 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
7017 IWineD3DDeviceParent *device_parent)
7019 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
7020 const struct fragment_pipeline *fragment_pipeline;
7021 struct shader_caps shader_caps;
7022 struct fragment_caps ffp_caps;
7023 WINED3DDISPLAYMODE mode;
7024 unsigned int i;
7025 HRESULT hr;
7027 device->lpVtbl = &IWineD3DDevice_Vtbl;
7028 device->ref = 1;
7029 device->wined3d = wined3d;
7030 wined3d_incref(device->wined3d);
7031 device->adapter = wined3d->adapter_count ? adapter : NULL;
7032 device->device_parent = device_parent;
7033 list_init(&device->resources);
7034 list_init(&device->shaders);
7036 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
7038 /* Get the initial screen setup for ddraw. */
7039 hr = wined3d_get_adapter_display_mode(wined3d, adapter_idx, &mode);
7040 if (FAILED(hr))
7042 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
7043 wined3d_decref(device->wined3d);
7044 return hr;
7046 device->ddraw_width = mode.Width;
7047 device->ddraw_height = mode.Height;
7048 device->ddraw_format = mode.Format;
7050 /* Save the creation parameters. */
7051 device->createParms.AdapterOrdinal = adapter_idx;
7052 device->createParms.DeviceType = device_type;
7053 device->createParms.hFocusWindow = focus_window;
7054 device->createParms.BehaviorFlags = flags;
7056 device->devType = device_type;
7057 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
7059 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
7060 device->shader_backend = adapter->shader_backend;
7062 if (device->shader_backend)
7064 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
7065 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
7066 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
7067 device->vs_clipping = shader_caps.VSClipping;
7069 fragment_pipeline = adapter->fragment_pipe;
7070 device->frag_pipe = fragment_pipeline;
7071 if (fragment_pipeline)
7073 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
7074 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
7076 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
7077 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
7078 if (FAILED(hr))
7080 ERR("Failed to compile state table, hr %#x.\n", hr);
7081 wined3d_decref(device->wined3d);
7082 return hr;
7085 device->blitter = adapter->blitter;
7087 return WINED3D_OK;
7091 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7092 DWORD rep = This->StateTable[state].representative;
7093 struct wined3d_context *context;
7094 DWORD idx;
7095 BYTE shift;
7096 UINT i;
7098 for (i = 0; i < This->context_count; ++i)
7100 context = This->contexts[i];
7101 if(isStateDirty(context, rep)) continue;
7103 context->dirtyArray[context->numDirtyEntries++] = rep;
7104 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
7105 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
7106 context->isStateDirty[idx] |= (1 << shift);
7110 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7112 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7113 *width = context->current_rt->pow2Width;
7114 *height = context->current_rt->pow2Height;
7117 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7119 struct wined3d_swapchain *swapchain = context->swapchain;
7120 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7121 * current context's drawable, which is the size of the back buffer of the swapchain
7122 * the active context belongs to. */
7123 *width = swapchain->presentParms.BackBufferWidth;
7124 *height = swapchain->presentParms.BackBufferHeight;
7127 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window, BOOL unicode,
7128 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
7130 if (device->filter_messages)
7132 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
7133 window, message, wparam, lparam);
7134 if (unicode)
7135 return DefWindowProcW(window, message, wparam, lparam);
7136 else
7137 return DefWindowProcA(window, message, wparam, lparam);
7140 if (message == WM_DESTROY)
7142 TRACE("unregister window %p.\n", window);
7143 wined3d_unregister_window(window);
7145 if (device->focus_window == window) device->focus_window = NULL;
7146 else ERR("Window %p is not the focus window for device %p.\n", window, device);
7149 if (unicode)
7150 return CallWindowProcW(proc, window, message, wparam, lparam);
7151 else
7152 return CallWindowProcA(proc, window, message, wparam, lparam);