wined3d: Get rid of IWineD3DBaseTextureClass.
[wine/wine-gecko.git] / dlls / wined3d / device.c
blob6e43577b9c9d388a932ef52ebf4b45f4ef5c11c2
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-2010 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->baseShader.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->baseShader.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, sizeof(*new_array) * (device->numContexts + 1));
509 if (!new_array)
511 ERR("Failed to grow the context array.\n");
512 return FALSE;
515 new_array[device->numContexts++] = context;
516 device->contexts = new_array;
517 return TRUE;
520 void device_context_remove(IWineD3DDeviceImpl *device, struct wined3d_context *context)
522 struct wined3d_context **new_array;
523 BOOL found = FALSE;
524 UINT i;
526 TRACE("Removing context %p.\n", context);
528 for (i = 0; i < device->numContexts; ++i)
530 if (device->contexts[i] == context)
532 found = TRUE;
533 break;
537 if (!found)
539 ERR("Context %p doesn't exist in context array.\n", context);
540 return;
543 if (!--device->numContexts)
545 HeapFree(GetProcessHeap(), 0, device->contexts);
546 device->contexts = NULL;
547 return;
550 memmove(&device->contexts[i], &device->contexts[i + 1], (device->numContexts - i) * sizeof(*device->contexts));
551 new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, device->numContexts * sizeof(*device->contexts));
552 if (!new_array)
554 ERR("Failed to shrink context array. Oh well.\n");
555 return;
558 device->contexts = new_array;
561 void device_get_draw_rect(IWineD3DDeviceImpl *device, RECT *rect)
563 struct wined3d_stateblock *stateblock = device->stateBlock;
564 WINED3DVIEWPORT *vp = &stateblock->state.viewport;
566 SetRect(rect, vp->X, vp->Y, vp->X + vp->Width, vp->Y + vp->Height);
568 if (stateblock->state.render_states[WINED3DRS_SCISSORTESTENABLE])
570 IntersectRect(rect, rect, &stateblock->state.scissor_rect);
574 /* Do not call while under the GL lock. */
575 void device_switch_onscreen_ds(IWineD3DDeviceImpl *device,
576 struct wined3d_context *context, IWineD3DSurfaceImpl *depth_stencil)
578 if (device->onscreen_depth_stencil)
580 surface_load_ds_location(device->onscreen_depth_stencil, context, SFLAG_DS_OFFSCREEN);
581 surface_modify_ds_location(device->onscreen_depth_stencil, SFLAG_DS_OFFSCREEN,
582 device->onscreen_depth_stencil->ds_current_size.cx,
583 device->onscreen_depth_stencil->ds_current_size.cy);
584 IWineD3DSurface_Release((IWineD3DSurface *)device->onscreen_depth_stencil);
586 device->onscreen_depth_stencil = depth_stencil;
587 IWineD3DSurface_AddRef((IWineD3DSurface *)device->onscreen_depth_stencil);
590 static BOOL is_full_clear(IWineD3DSurfaceImpl *target, const RECT *draw_rect, const RECT *clear_rect)
592 /* partial draw rect */
593 if (draw_rect->left || draw_rect->top
594 || draw_rect->right < target->resource.width
595 || draw_rect->bottom < target->resource.height)
596 return FALSE;
598 /* partial clear rect */
599 if (clear_rect && (clear_rect->left > 0 || clear_rect->top > 0
600 || clear_rect->right < target->resource.width
601 || clear_rect->bottom < target->resource.height))
602 return FALSE;
604 return TRUE;
607 static void prepare_ds_clear(IWineD3DSurfaceImpl *ds, struct wined3d_context *context,
608 DWORD location, const RECT *draw_rect, UINT rect_count, const RECT *clear_rect)
610 RECT current_rect, r;
612 if (ds->flags & location)
613 SetRect(&current_rect, 0, 0,
614 ds->ds_current_size.cx,
615 ds->ds_current_size.cy);
616 else
617 SetRectEmpty(&current_rect);
619 IntersectRect(&r, draw_rect, &current_rect);
620 if (EqualRect(&r, draw_rect))
622 /* current_rect ⊇ draw_rect, modify only. */
623 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
624 return;
627 if (EqualRect(&r, &current_rect))
629 /* draw_rect ⊇ current_rect, test if we're doing a full clear. */
631 if (!clear_rect)
633 /* Full clear, modify only. */
634 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
635 return;
638 IntersectRect(&r, draw_rect, clear_rect);
639 if (EqualRect(&r, draw_rect))
641 /* clear_rect ⊇ draw_rect, modify only. */
642 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
643 return;
647 /* Full load. */
648 surface_load_ds_location(ds, context, location);
649 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
652 /* Do not call while under the GL lock. */
653 HRESULT device_clear_render_targets(IWineD3DDeviceImpl *device, UINT rt_count, IWineD3DSurfaceImpl **rts,
654 UINT rect_count, const RECT *rects, const RECT *draw_rect, DWORD flags,
655 const WINED3DCOLORVALUE *color, float depth, DWORD stencil)
657 const RECT *clear_rect = (rect_count > 0 && rects) ? (const RECT *)rects : NULL;
658 IWineD3DSurfaceImpl *depth_stencil = device->depth_stencil;
659 IWineD3DSurfaceImpl *target = rts[0];
660 UINT drawable_width, drawable_height;
661 struct wined3d_context *context;
662 GLbitfield clear_mask = 0;
663 unsigned int i;
665 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
666 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
667 * for the cleared parts, and the untouched parts.
669 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
670 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
671 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
672 * checking all this if the dest surface is in the drawable anyway. */
673 if (flags & WINED3DCLEAR_TARGET && !is_full_clear(target, draw_rect, clear_rect))
675 for (i = 0; i < rt_count; ++i)
677 if (rts[i]) surface_load_location(rts[i], SFLAG_INDRAWABLE, NULL);
681 context = context_acquire(device, target);
682 if (!context->valid)
684 context_release(context);
685 WARN("Invalid context, skipping clear.\n");
686 return WINED3D_OK;
689 if (!context_apply_clear_state(context, device, rt_count, rts, depth_stencil))
691 context_release(context);
692 WARN("Failed to apply clear state, skipping clear.\n");
693 return WINED3D_OK;
696 target->get_drawable_size(context, &drawable_width, &drawable_height);
698 ENTER_GL();
700 /* Only set the values up once, as they are not changing. */
701 if (flags & WINED3DCLEAR_STENCIL)
703 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
705 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
706 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_TWOSIDEDSTENCILMODE));
708 glStencilMask(~0U);
709 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
710 glClearStencil(stencil);
711 checkGLcall("glClearStencil");
712 clear_mask = clear_mask | GL_STENCIL_BUFFER_BIT;
715 if (flags & WINED3DCLEAR_ZBUFFER)
717 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
719 if (location == SFLAG_DS_ONSCREEN && depth_stencil != device->onscreen_depth_stencil)
721 LEAVE_GL();
722 device_switch_onscreen_ds(device, context, depth_stencil);
723 ENTER_GL();
725 prepare_ds_clear(depth_stencil, context, location, draw_rect, rect_count, clear_rect);
726 surface_modify_location(depth_stencil, SFLAG_INDRAWABLE, TRUE);
728 glDepthMask(GL_TRUE);
729 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
730 glClearDepth(depth);
731 checkGLcall("glClearDepth");
732 clear_mask = clear_mask | GL_DEPTH_BUFFER_BIT;
735 if (flags & WINED3DCLEAR_TARGET)
737 for (i = 0; i < rt_count; ++i)
739 if (rts[i]) surface_modify_location(rts[i], SFLAG_INDRAWABLE, TRUE);
742 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
743 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
744 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
745 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
746 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
747 glClearColor(color->r, color->g, color->b, color->a);
748 checkGLcall("glClearColor");
749 clear_mask = clear_mask | GL_COLOR_BUFFER_BIT;
752 if (!clear_rect)
754 if (context->render_offscreen)
756 glScissor(draw_rect->left, draw_rect->top,
757 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
759 else
761 glScissor(draw_rect->left, drawable_height - draw_rect->bottom,
762 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
764 checkGLcall("glScissor");
765 glClear(clear_mask);
766 checkGLcall("glClear");
768 else
770 RECT current_rect;
772 /* Now process each rect in turn. */
773 for (i = 0; i < rect_count; ++i)
775 /* Note that GL uses lower left, width/height. */
776 IntersectRect(&current_rect, draw_rect, &clear_rect[i]);
778 TRACE("clear_rect[%u] %s, current_rect %s.\n", i,
779 wine_dbgstr_rect(&clear_rect[i]),
780 wine_dbgstr_rect(&current_rect));
782 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
783 * The rectangle is not cleared, no error is returned, but further rectanlges are
784 * still cleared if they are valid. */
785 if (current_rect.left > current_rect.right || current_rect.top > current_rect.bottom)
787 TRACE("Rectangle with negative dimensions, ignoring.\n");
788 continue;
791 if (context->render_offscreen)
793 glScissor(current_rect.left, current_rect.top,
794 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
796 else
798 glScissor(current_rect.left, drawable_height - current_rect.bottom,
799 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
801 checkGLcall("glScissor");
803 glClear(clear_mask);
804 checkGLcall("glClear");
808 LEAVE_GL();
810 if (wined3d_settings.strict_draw_ordering || (target->container.type == WINED3D_CONTAINER_SWAPCHAIN
811 && target->container.u.swapchain->front_buffer == target))
812 wglFlush(); /* Flush to ensure ordering across contexts. */
814 context_release(context);
816 return WINED3D_OK;
820 /**********************************************************
821 * IUnknown parts follows
822 **********************************************************/
824 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface, REFIID riid, void **object)
826 TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
828 if (IsEqualGUID(riid, &IID_IWineD3DDevice)
829 || IsEqualGUID(riid, &IID_IUnknown))
831 IUnknown_AddRef(iface);
832 *object = iface;
833 return S_OK;
836 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
838 *object = NULL;
839 return E_NOINTERFACE;
842 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
843 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
844 ULONG refCount = InterlockedIncrement(&This->ref);
846 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
847 return refCount;
850 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
851 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
852 ULONG refCount = InterlockedDecrement(&This->ref);
854 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
856 if (!refCount) {
857 UINT i;
859 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
860 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
861 This->multistate_funcs[i] = NULL;
864 /* TODO: Clean up all the surfaces and textures! */
865 /* NOTE: You must release the parent if the object was created via a callback
866 ** ***************************/
868 if (!list_empty(&This->resources))
870 struct wined3d_resource *resource;
871 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
873 LIST_FOR_EACH_ENTRY(resource, &This->resources, struct wined3d_resource, resource_list_entry)
875 FIXME("Leftover resource %p with type %s (%#x).\n",
876 resource, debug_d3dresourcetype(resource->resourceType), resource->resourceType);
880 if(This->contexts) ERR("Context array not freed!\n");
881 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
882 This->haveHardwareCursor = FALSE;
884 wined3d_decref(This->wined3d);
885 This->wined3d = NULL;
886 HeapFree(GetProcessHeap(), 0, This);
887 TRACE("Freed device %p\n", This);
888 This = NULL;
890 return refCount;
893 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
894 const void *data, void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_buffer **buffer)
896 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
897 struct wined3d_buffer *object;
898 HRESULT hr;
900 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
902 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
903 if (!object)
905 ERR("Failed to allocate memory\n");
906 return E_OUTOFMEMORY;
909 FIXME("Ignoring access flags (pool)\n");
911 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
912 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
913 if (FAILED(hr))
915 WARN("Failed to initialize buffer, hr %#x.\n", hr);
916 HeapFree(GetProcessHeap(), 0, object);
917 return hr;
919 object->desc = *desc;
921 TRACE("Created buffer %p.\n", object);
923 *buffer = object;
925 return WINED3D_OK;
928 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
929 WINED3DPOOL Pool, void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_buffer **buffer)
931 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
932 struct wined3d_buffer *object;
933 HRESULT hr;
935 TRACE("iface %p, size %u, usage %#x, pool %#x, parent %p, parent_ops %p, buffer %p.\n",
936 iface, Size, Usage, Pool, parent, parent_ops, buffer);
938 if (Pool == WINED3DPOOL_SCRATCH)
940 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
941 * anyway, SCRATCH vertex buffers aren't usable anywhere
943 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
944 *buffer = NULL;
945 return WINED3DERR_INVALIDCALL;
948 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
949 if (!object)
951 ERR("Out of memory\n");
952 *buffer = NULL;
953 return WINED3DERR_OUTOFVIDEOMEMORY;
956 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
957 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
958 if (FAILED(hr))
960 WARN("Failed to initialize buffer, hr %#x.\n", hr);
961 HeapFree(GetProcessHeap(), 0, object);
962 return hr;
965 TRACE("Created buffer %p.\n", object);
966 *buffer = object;
968 return WINED3D_OK;
971 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
972 WINED3DPOOL Pool, void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_buffer **buffer)
974 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
975 struct wined3d_buffer *object;
976 HRESULT hr;
978 TRACE("iface %p, size %u, usage %#x, pool %#x, parent %p, parent_ops %p, buffer %p.\n",
979 iface, Length, Usage, Pool, parent, parent_ops, buffer);
981 /* Allocate the storage for the device */
982 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
983 if (!object)
985 ERR("Out of memory\n");
986 *buffer = NULL;
987 return WINED3DERR_OUTOFVIDEOMEMORY;
990 hr = buffer_init(object, This, Length, Usage | WINED3DUSAGE_STATICDECL,
991 WINED3DFMT_UNKNOWN, Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL,
992 parent, parent_ops);
993 if (FAILED(hr))
995 WARN("Failed to initialize buffer, hr %#x\n", hr);
996 HeapFree(GetProcessHeap(), 0, object);
997 return hr;
1000 TRACE("Created buffer %p.\n", object);
1002 *buffer = object;
1004 return WINED3D_OK;
1007 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
1008 WINED3DSTATEBLOCKTYPE type, struct wined3d_stateblock **stateblock)
1010 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1011 struct wined3d_stateblock *object;
1012 HRESULT hr;
1014 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1015 if(!object)
1017 ERR("Failed to allocate stateblock memory.\n");
1018 return E_OUTOFMEMORY;
1021 hr = stateblock_init(object, This, type);
1022 if (FAILED(hr))
1024 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
1025 HeapFree(GetProcessHeap(), 0, object);
1026 return hr;
1029 TRACE("Created stateblock %p.\n", object);
1030 *stateblock = object;
1032 return WINED3D_OK;
1035 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
1036 enum wined3d_format_id Format, BOOL Lockable, BOOL Discard, UINT Level, DWORD Usage, WINED3DPOOL Pool,
1037 WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, WINED3DSURFTYPE Impl,
1038 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DSurface **surface)
1040 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1041 IWineD3DSurfaceImpl *object;
1042 HRESULT hr;
1044 TRACE("iface %p, width %u, height %u, format %s (%#x), lockable %#x, discard %#x, level %u\n",
1045 iface, Width, Height, debug_d3dformat(Format), Format, Lockable, Discard, Level);
1046 TRACE("surface %p, usage %s (%#x), pool %s (%#x), multisample_type %#x, multisample_quality %u\n",
1047 surface, debug_d3dusage(Usage), Usage, debug_d3dpool(Pool), Pool, MultiSample, MultisampleQuality);
1048 TRACE("surface_type %#x, parent %p, parent_ops %p.\n", Impl, parent, parent_ops);
1050 if (Impl == SURFACE_OPENGL && !This->adapter)
1052 ERR("OpenGL surfaces are not available without OpenGL.\n");
1053 return WINED3DERR_NOTAVAILABLE;
1056 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1057 if (!object)
1059 ERR("Failed to allocate surface memory.\n");
1060 return WINED3DERR_OUTOFVIDEOMEMORY;
1063 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
1064 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
1065 if (FAILED(hr))
1067 WARN("Failed to initialize surface, returning %#x.\n", hr);
1068 HeapFree(GetProcessHeap(), 0, object);
1069 return hr;
1072 TRACE("(%p) : Created surface %p\n", This, object);
1074 *surface = (IWineD3DSurface *)object;
1076 return hr;
1079 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
1080 struct wined3d_resource *resource, void *parent, IWineD3DRendertargetView **rendertarget_view)
1082 struct wined3d_rendertarget_view *object;
1084 TRACE("iface %p, resource %p, parent %p, rendertarget_view %p.\n",
1085 iface, resource, parent, rendertarget_view);
1087 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1088 if (!object)
1090 ERR("Failed to allocate memory\n");
1091 return E_OUTOFMEMORY;
1094 wined3d_rendertarget_view_init(object, resource, parent);
1096 TRACE("Created render target view %p.\n", object);
1097 *rendertarget_view = (IWineD3DRendertargetView *)object;
1099 return WINED3D_OK;
1102 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
1103 UINT Width, UINT Height, UINT Levels, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool,
1104 void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_texture **texture)
1106 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1107 struct wined3d_texture *object;
1108 HRESULT hr;
1110 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
1111 TRACE("Format %#x (%s), Pool %#x, texture %p, parent %p\n",
1112 Format, debug_d3dformat(Format), Pool, texture, parent);
1114 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1115 if (!object)
1117 ERR("Out of memory\n");
1118 *texture = NULL;
1119 return WINED3DERR_OUTOFVIDEOMEMORY;
1122 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
1123 if (FAILED(hr))
1125 WARN("Failed to initialize texture, returning %#x\n", hr);
1126 HeapFree(GetProcessHeap(), 0, object);
1127 *texture = NULL;
1128 return hr;
1131 *texture = object;
1133 TRACE("(%p) : Created texture %p\n", This, object);
1135 return WINED3D_OK;
1138 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1139 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool,
1140 void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_texture **texture)
1142 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1143 struct wined3d_texture *object;
1144 HRESULT hr;
1146 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1147 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1149 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1150 if (!object)
1152 ERR("Out of memory\n");
1153 *texture = NULL;
1154 return WINED3DERR_OUTOFVIDEOMEMORY;
1157 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
1158 if (FAILED(hr))
1160 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
1161 HeapFree(GetProcessHeap(), 0, object);
1162 *texture = NULL;
1163 return hr;
1166 TRACE("(%p) : Created volume texture %p.\n", This, object);
1167 *texture = object;
1169 return WINED3D_OK;
1172 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
1173 UINT Depth, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool, void *parent,
1174 const struct wined3d_parent_ops *parent_ops, IWineD3DVolume **ppVolume)
1176 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1177 IWineD3DVolumeImpl *object;
1178 HRESULT hr;
1180 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1181 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1183 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1184 if (!object)
1186 ERR("Out of memory\n");
1187 *ppVolume = NULL;
1188 return WINED3DERR_OUTOFVIDEOMEMORY;
1191 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
1192 if (FAILED(hr))
1194 WARN("Failed to initialize volume, returning %#x.\n", hr);
1195 HeapFree(GetProcessHeap(), 0, object);
1196 return hr;
1199 TRACE("(%p) : Created volume %p.\n", This, object);
1200 *ppVolume = (IWineD3DVolume *)object;
1202 return WINED3D_OK;
1205 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
1206 DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool, void *parent,
1207 const struct wined3d_parent_ops *parent_ops, struct wined3d_texture **texture)
1209 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1210 struct wined3d_texture *object;
1211 HRESULT hr;
1213 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1214 if (!object)
1216 ERR("Out of memory\n");
1217 *texture = NULL;
1218 return WINED3DERR_OUTOFVIDEOMEMORY;
1221 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
1222 if (FAILED(hr))
1224 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
1225 HeapFree(GetProcessHeap(), 0, object);
1226 *texture = NULL;
1227 return hr;
1230 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1231 *texture = object;
1233 return WINED3D_OK;
1236 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface,
1237 WINED3DQUERYTYPE type, struct wined3d_query **query)
1239 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1240 struct wined3d_query *object;
1241 HRESULT hr;
1243 TRACE("iface %p, type %#x, query %p.\n", iface, type, query);
1245 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1246 if (!object)
1248 ERR("Failed to allocate query memory.\n");
1249 return E_OUTOFMEMORY;
1252 hr = query_init(object, This, type);
1253 if (FAILED(hr))
1255 WARN("Failed to initialize query, hr %#x.\n", hr);
1256 HeapFree(GetProcessHeap(), 0, object);
1257 return hr;
1260 TRACE("Created query %p.\n", object);
1261 *query = object;
1263 return WINED3D_OK;
1266 /* Do not call while under the GL lock. */
1267 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1268 WINED3DPRESENT_PARAMETERS *present_parameters, WINED3DSURFTYPE surface_type,
1269 void *parent, IWineD3DSwapChain **swapchain)
1271 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1272 IWineD3DSwapChainImpl *object;
1273 HRESULT hr;
1275 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
1276 iface, present_parameters, swapchain, parent, surface_type);
1278 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1279 if (!object)
1281 ERR("Failed to allocate swapchain memory.\n");
1282 return E_OUTOFMEMORY;
1285 hr = swapchain_init(object, surface_type, This, present_parameters, parent);
1286 if (FAILED(hr))
1288 WARN("Failed to initialize swapchain, hr %#x.\n", hr);
1289 HeapFree(GetProcessHeap(), 0, object);
1290 return hr;
1293 TRACE("Created swapchain %p.\n", object);
1294 *swapchain = (IWineD3DSwapChain *)object;
1296 return WINED3D_OK;
1299 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1300 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1301 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1302 TRACE("(%p)\n", This);
1304 return This->NumberOfSwapChains;
1307 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1308 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1309 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1311 if (iSwapChain < This->NumberOfSwapChains)
1313 *pSwapChain = (IWineD3DSwapChain *)This->swapchains[iSwapChain];
1314 IWineD3DSwapChain_AddRef(*pSwapChain);
1315 TRACE("(%p) returning %p\n", This, *pSwapChain);
1316 return WINED3D_OK;
1317 } else {
1318 TRACE("Swapchain out of range\n");
1319 *pSwapChain = NULL;
1320 return WINED3DERR_INVALIDCALL;
1324 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
1325 const WINED3DVERTEXELEMENT *elements, UINT element_count, void *parent,
1326 const struct wined3d_parent_ops *parent_ops, struct wined3d_vertex_declaration **declaration)
1328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1329 struct wined3d_vertex_declaration *object;
1330 HRESULT hr;
1332 TRACE("iface %p, elements %p, element_count %u, parent %p, parent_ops %p, declaration %p.\n",
1333 iface, elements, element_count, parent, parent_ops, declaration);
1335 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1336 if(!object)
1338 ERR("Failed to allocate vertex declaration memory.\n");
1339 return E_OUTOFMEMORY;
1342 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1343 if (FAILED(hr))
1345 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1346 HeapFree(GetProcessHeap(), 0, object);
1347 return hr;
1350 TRACE("Created vertex declaration %p.\n", object);
1351 *declaration = object;
1353 return WINED3D_OK;
1356 struct wined3d_fvf_convert_state
1358 const struct wined3d_gl_info *gl_info;
1359 WINED3DVERTEXELEMENT *elements;
1360 UINT offset;
1361 UINT idx;
1364 static void append_decl_element(struct wined3d_fvf_convert_state *state,
1365 enum wined3d_format_id format_id, WINED3DDECLUSAGE usage, UINT usage_idx)
1367 WINED3DVERTEXELEMENT *elements = state->elements;
1368 const struct wined3d_format *format;
1369 UINT offset = state->offset;
1370 UINT idx = state->idx;
1372 elements[idx].format = format_id;
1373 elements[idx].input_slot = 0;
1374 elements[idx].offset = offset;
1375 elements[idx].output_slot = 0;
1376 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1377 elements[idx].usage = usage;
1378 elements[idx].usage_idx = usage_idx;
1380 format = wined3d_get_format(state->gl_info, format_id);
1381 state->offset += format->component_count * format->component_size;
1382 ++state->idx;
1385 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1386 DWORD fvf, WINED3DVERTEXELEMENT **ppVertexElements)
1388 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1389 BOOL has_pos = !!(fvf & WINED3DFVF_POSITION_MASK);
1390 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1391 BOOL has_blend_idx = has_blend &&
1392 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1393 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1394 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1395 BOOL has_normal = !!(fvf & WINED3DFVF_NORMAL);
1396 BOOL has_psize = !!(fvf & WINED3DFVF_PSIZE);
1397 BOOL has_diffuse = !!(fvf & WINED3DFVF_DIFFUSE);
1398 BOOL has_specular = !!(fvf & WINED3DFVF_SPECULAR);
1400 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1401 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1402 struct wined3d_fvf_convert_state state;
1403 unsigned int size;
1404 unsigned int idx;
1405 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1406 if (has_blend_idx) num_blends--;
1408 /* Compute declaration size */
1409 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1410 has_psize + has_diffuse + has_specular + num_textures;
1412 state.gl_info = gl_info;
1413 state.elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*state.elements));
1414 if (!state.elements) return ~0U;
1415 state.offset = 0;
1416 state.idx = 0;
1418 if (has_pos)
1420 if (!has_blend && (fvf & WINED3DFVF_XYZRHW))
1421 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITIONT, 0);
1422 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW)
1423 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1424 else
1425 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1428 if (has_blend && (num_blends > 0))
1430 if ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1431 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1432 else
1434 switch (num_blends)
1436 case 1:
1437 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1438 break;
1439 case 2:
1440 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1441 break;
1442 case 3:
1443 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1444 break;
1445 case 4:
1446 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1447 break;
1448 default:
1449 ERR("Unexpected amount of blend values: %u\n", num_blends);
1454 if (has_blend_idx)
1456 if ((fvf & WINED3DFVF_LASTBETA_UBYTE4)
1457 || ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1458 append_decl_element(&state, WINED3DFMT_R8G8B8A8_UINT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1459 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1460 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDINDICES, 0);
1461 else
1462 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1465 if (has_normal) append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_NORMAL, 0);
1466 if (has_psize) append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_PSIZE, 0);
1467 if (has_diffuse) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 0);
1468 if (has_specular) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 1);
1470 for (idx = 0; idx < num_textures; ++idx)
1472 switch ((texcoords >> (idx * 2)) & 0x03)
1474 case WINED3DFVF_TEXTUREFORMAT1:
1475 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1476 break;
1477 case WINED3DFVF_TEXTUREFORMAT2:
1478 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1479 break;
1480 case WINED3DFVF_TEXTUREFORMAT3:
1481 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1482 break;
1483 case WINED3DFVF_TEXTUREFORMAT4:
1484 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1485 break;
1489 *ppVertexElements = state.elements;
1490 return size;
1493 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1494 DWORD fvf, void *parent, const struct wined3d_parent_ops *parent_ops,
1495 struct wined3d_vertex_declaration **declaration)
1497 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1498 WINED3DVERTEXELEMENT *elements;
1499 unsigned int size;
1500 DWORD hr;
1502 TRACE("iface %p, fvf %#x, parent %p, parent_ops %p, declaration %p.\n",
1503 iface, fvf, parent, parent_ops, declaration);
1505 size = ConvertFvfToDeclaration(This, fvf, &elements);
1506 if (size == ~0U) return E_OUTOFMEMORY;
1508 hr = IWineD3DDeviceImpl_CreateVertexDeclaration(iface, elements, size, parent, parent_ops, declaration);
1509 HeapFree(GetProcessHeap(), 0, elements);
1510 return hr;
1513 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1514 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1515 void *parent, const struct wined3d_parent_ops *parent_ops,
1516 IWineD3DVertexShader **ppVertexShader)
1518 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1519 IWineD3DVertexShaderImpl *object;
1520 HRESULT hr;
1522 if (This->vs_selected_mode == SHADER_NONE)
1523 return WINED3DERR_INVALIDCALL;
1525 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1526 if (!object)
1528 ERR("Failed to allocate shader memory.\n");
1529 return E_OUTOFMEMORY;
1532 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1533 if (FAILED(hr))
1535 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1536 HeapFree(GetProcessHeap(), 0, object);
1537 return hr;
1540 TRACE("Created vertex shader %p.\n", object);
1541 *ppVertexShader = (IWineD3DVertexShader *)object;
1543 return WINED3D_OK;
1546 static HRESULT WINAPI IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice *iface,
1547 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
1548 void *parent, const struct wined3d_parent_ops *parent_ops,
1549 IWineD3DGeometryShader **shader)
1551 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1552 struct wined3d_geometryshader *object;
1553 HRESULT hr;
1555 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1556 if (!object)
1558 ERR("Failed to allocate shader memory.\n");
1559 return E_OUTOFMEMORY;
1562 hr = geometryshader_init(object, This, byte_code, output_signature, parent, parent_ops);
1563 if (FAILED(hr))
1565 WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
1566 HeapFree(GetProcessHeap(), 0, object);
1567 return hr;
1570 TRACE("Created geometry shader %p.\n", object);
1571 *shader = (IWineD3DGeometryShader *)object;
1573 return WINED3D_OK;
1576 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1577 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1578 void *parent, const struct wined3d_parent_ops *parent_ops,
1579 IWineD3DPixelShader **ppPixelShader)
1581 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1582 IWineD3DPixelShaderImpl *object;
1583 HRESULT hr;
1585 if (This->ps_selected_mode == SHADER_NONE)
1586 return WINED3DERR_INVALIDCALL;
1588 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1589 if (!object)
1591 ERR("Failed to allocate shader memory.\n");
1592 return E_OUTOFMEMORY;
1595 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1596 if (FAILED(hr))
1598 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1599 HeapFree(GetProcessHeap(), 0, object);
1600 return hr;
1603 TRACE("Created pixel shader %p.\n", object);
1604 *ppPixelShader = (IWineD3DPixelShader *)object;
1606 return WINED3D_OK;
1609 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD flags,
1610 const PALETTEENTRY *entries, void *parent, struct wined3d_palette **palette)
1612 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1613 struct wined3d_palette *object;
1614 HRESULT hr;
1616 TRACE("iface %p, flags %#x, entries %p, palette %p, parent %p.\n",
1617 iface, flags, entries, palette, parent);
1619 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1620 if (!object)
1622 ERR("Failed to allocate palette memory.\n");
1623 return E_OUTOFMEMORY;
1626 hr = wined3d_palette_init(object, This, flags, entries, parent);
1627 if (FAILED(hr))
1629 WARN("Failed to initialize palette, hr %#x.\n", hr);
1630 HeapFree(GetProcessHeap(), 0, object);
1631 return hr;
1634 TRACE("Created palette %p.\n", object);
1635 *palette = object;
1637 return WINED3D_OK;
1640 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1641 HBITMAP hbm;
1642 BITMAP bm;
1643 HRESULT hr;
1644 HDC dcb = NULL, dcs = NULL;
1645 WINEDDCOLORKEY colorkey;
1647 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1648 if(hbm)
1650 GetObjectA(hbm, sizeof(BITMAP), &bm);
1651 dcb = CreateCompatibleDC(NULL);
1652 if(!dcb) goto out;
1653 SelectObject(dcb, hbm);
1655 else
1657 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1658 * couldn't be loaded
1660 memset(&bm, 0, sizeof(bm));
1661 bm.bmWidth = 32;
1662 bm.bmHeight = 32;
1665 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1666 FALSE, 0, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL, NULL,
1667 &wined3d_null_parent_ops, &This->logo_surface);
1668 if (FAILED(hr))
1670 ERR("Wine logo requested, but failed to create surface, hr %#x.\n", hr);
1671 goto out;
1674 if(dcb) {
1675 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1676 if(FAILED(hr)) goto out;
1677 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1678 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1680 colorkey.dwColorSpaceLowValue = 0;
1681 colorkey.dwColorSpaceHighValue = 0;
1682 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1684 else
1686 const WINED3DCOLORVALUE c = {1.0f, 1.0f, 1.0f, 1.0f};
1687 /* Fill the surface with a white color to show that wined3d is there */
1688 IWineD3DDevice_ColorFill((IWineD3DDevice *)This, This->logo_surface, NULL, &c);
1691 out:
1692 if (dcb) DeleteDC(dcb);
1693 if (hbm) DeleteObject(hbm);
1696 /* Context activation is done by the caller. */
1697 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1699 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1700 unsigned int i;
1701 /* Under DirectX you can have texture stage operations even if no texture is
1702 bound, whereas opengl will only do texture operations when a valid texture is
1703 bound. We emulate this by creating dummy textures and binding them to each
1704 texture stage, but disable all stages by default. Hence if a stage is enabled
1705 then the default texture will kick in until replaced by a SetTexture call */
1706 ENTER_GL();
1708 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1710 /* The dummy texture does not have client storage backing */
1711 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1712 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1715 for (i = 0; i < gl_info->limits.textures; ++i)
1717 GLubyte white = 255;
1719 /* Make appropriate texture active */
1720 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1721 checkGLcall("glActiveTextureARB");
1723 /* Generate an opengl texture name */
1724 glGenTextures(1, &This->dummyTextureName[i]);
1725 checkGLcall("glGenTextures");
1726 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1728 /* Generate a dummy 2d texture (not using 1d because they cause many
1729 * DRI drivers fall back to sw) */
1730 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1731 checkGLcall("glBindTexture");
1733 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1734 checkGLcall("glTexImage2D");
1737 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1739 /* Reenable because if supported it is enabled by default */
1740 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1741 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1744 LEAVE_GL();
1747 /* Context activation is done by the caller. */
1748 static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1750 ENTER_GL();
1751 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1752 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1753 LEAVE_GL();
1755 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1758 static LONG fullscreen_style(LONG style)
1760 /* Make sure the window is managed, otherwise we won't get keyboard input. */
1761 style |= WS_POPUP | WS_SYSMENU;
1762 style &= ~(WS_CAPTION | WS_THICKFRAME);
1764 return style;
1767 static LONG fullscreen_exstyle(LONG exstyle)
1769 /* Filter out window decorations. */
1770 exstyle &= ~(WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE);
1772 return exstyle;
1775 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h)
1777 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1778 BOOL filter_messages;
1779 LONG style, exstyle;
1781 TRACE("Setting up window %p for fullscreen mode.\n", window);
1783 if (device->style || device->exStyle)
1785 ERR("Changing the window style for window %p, but another style (%08x, %08x) is already stored.\n",
1786 window, device->style, device->exStyle);
1789 device->style = GetWindowLongW(window, GWL_STYLE);
1790 device->exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1792 style = fullscreen_style(device->style);
1793 exstyle = fullscreen_exstyle(device->exStyle);
1795 TRACE("Old style was %08x, %08x, setting to %08x, %08x.\n",
1796 device->style, device->exStyle, style, exstyle);
1798 filter_messages = device->filter_messages;
1799 device->filter_messages = TRUE;
1801 SetWindowLongW(window, GWL_STYLE, style);
1802 SetWindowLongW(window, GWL_EXSTYLE, exstyle);
1803 SetWindowPos(window, HWND_TOP, 0, 0, w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOACTIVATE);
1805 device->filter_messages = filter_messages;
1808 static void WINAPI IWineD3DDeviceImpl_RestoreFullscreenWindow(IWineD3DDevice *iface, HWND window)
1810 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1811 BOOL filter_messages;
1812 LONG style, exstyle;
1814 if (!device->style && !device->exStyle) return;
1816 TRACE("Restoring window style of window %p to %08x, %08x.\n",
1817 window, device->style, device->exStyle);
1819 style = GetWindowLongW(window, GWL_STYLE);
1820 exstyle = GetWindowLongW(window, GWL_EXSTYLE);
1822 filter_messages = device->filter_messages;
1823 device->filter_messages = TRUE;
1825 /* Only restore the style if the application didn't modify it during the
1826 * fullscreen phase. Some applications change it before calling Reset()
1827 * when switching between windowed and fullscreen modes (HL2), some
1828 * depend on the original style (Eve Online). */
1829 if (style == fullscreen_style(device->style) && exstyle == fullscreen_exstyle(device->exStyle))
1831 SetWindowLongW(window, GWL_STYLE, device->style);
1832 SetWindowLongW(window, GWL_EXSTYLE, device->exStyle);
1834 SetWindowPos(window, 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
1836 device->filter_messages = filter_messages;
1838 /* Delete the old values. */
1839 device->style = 0;
1840 device->exStyle = 0;
1843 static HRESULT WINAPI IWineD3DDeviceImpl_AcquireFocusWindow(IWineD3DDevice *iface, HWND window)
1845 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1847 TRACE("iface %p, window %p.\n", iface, window);
1849 if (!wined3d_register_window(window, device))
1851 ERR("Failed to register window %p.\n", window);
1852 return E_FAIL;
1855 device->focus_window = window;
1856 SetWindowPos(window, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
1858 return WINED3D_OK;
1861 static void WINAPI IWineD3DDeviceImpl_ReleaseFocusWindow(IWineD3DDevice *iface)
1863 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1865 TRACE("iface %p.\n", iface);
1867 if (device->focus_window) wined3d_unregister_window(device->focus_window);
1868 device->focus_window = NULL;
1871 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1872 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1874 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1875 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1876 IWineD3DSwapChainImpl *swapchain = NULL;
1877 struct wined3d_context *context;
1878 HRESULT hr;
1879 DWORD state;
1880 unsigned int i;
1882 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1884 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1885 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1887 TRACE("(%p) : Creating stateblock\n", This);
1888 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, &This->stateBlock);
1889 if (FAILED(hr))
1891 WARN("Failed to create stateblock\n");
1892 goto err_out;
1894 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1895 This->updateStateBlock = This->stateBlock;
1896 wined3d_stateblock_incref(This->updateStateBlock);
1898 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1899 sizeof(*This->render_targets) * gl_info->limits.buffers);
1901 This->NumberOfPalettes = 1;
1902 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1903 if (!This->palettes || !This->render_targets)
1905 ERR("Out of memory!\n");
1906 hr = E_OUTOFMEMORY;
1907 goto err_out;
1909 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1910 if(!This->palettes[0]) {
1911 ERR("Out of memory!\n");
1912 hr = E_OUTOFMEMORY;
1913 goto err_out;
1915 for (i = 0; i < 256; ++i) {
1916 This->palettes[0][i].peRed = 0xFF;
1917 This->palettes[0][i].peGreen = 0xFF;
1918 This->palettes[0][i].peBlue = 0xFF;
1919 This->palettes[0][i].peFlags = 0xFF;
1921 This->currentPalette = 0;
1923 /* Initialize the texture unit mapping to a 1:1 mapping */
1924 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1926 if (state < gl_info->limits.fragment_samplers)
1928 This->texUnitMap[state] = state;
1929 This->rev_tex_unit_map[state] = state;
1930 } else {
1931 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1932 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1936 /* Setup the implicit swapchain. This also initializes a context. */
1937 TRACE("Creating implicit swapchain\n");
1938 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1939 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1940 if (FAILED(hr))
1942 WARN("Failed to create implicit swapchain\n");
1943 goto err_out;
1946 This->NumberOfSwapChains = 1;
1947 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(*This->swapchains));
1948 if (!This->swapchains)
1950 ERR("Out of memory!\n");
1951 goto err_out;
1953 This->swapchains[0] = swapchain;
1955 if (swapchain->back_buffers && swapchain->back_buffers[0])
1957 TRACE("Setting rendertarget to %p.\n", swapchain->back_buffers);
1958 This->render_targets[0] = swapchain->back_buffers[0];
1960 else
1962 TRACE("Setting rendertarget to %p.\n", swapchain->front_buffer);
1963 This->render_targets[0] = swapchain->front_buffer;
1965 IWineD3DSurface_AddRef((IWineD3DSurface *)This->render_targets[0]);
1967 /* Depth Stencil support */
1968 This->depth_stencil = This->auto_depth_stencil;
1969 if (This->depth_stencil)
1970 IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
1972 hr = This->shader_backend->shader_alloc_private(This);
1973 if(FAILED(hr)) {
1974 TRACE("Shader private data couldn't be allocated\n");
1975 goto err_out;
1977 hr = This->frag_pipe->alloc_private(This);
1978 if(FAILED(hr)) {
1979 TRACE("Fragment pipeline private data couldn't be allocated\n");
1980 goto err_out;
1982 hr = This->blitter->alloc_private(This);
1983 if(FAILED(hr)) {
1984 TRACE("Blitter private data couldn't be allocated\n");
1985 goto err_out;
1988 /* Set up some starting GL setup */
1990 /* Setup all the devices defaults */
1991 stateblock_init_default_state(This->stateBlock);
1993 context = context_acquire(This, swapchain->front_buffer);
1995 create_dummy_textures(This);
1997 ENTER_GL();
1999 /* Initialize the current view state */
2000 This->view_ident = 1;
2001 This->contexts[0]->last_was_rhw = 0;
2002 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2003 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2005 switch(wined3d_settings.offscreen_rendering_mode) {
2006 case ORM_FBO:
2007 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
2008 break;
2010 case ORM_BACKBUFFER:
2012 if (context_get_current()->aux_buffers > 0)
2014 TRACE("Using auxilliary buffer for offscreen rendering\n");
2015 This->offscreenBuffer = GL_AUX0;
2016 } else {
2017 TRACE("Using back buffer for offscreen rendering\n");
2018 This->offscreenBuffer = GL_BACK;
2023 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2024 LEAVE_GL();
2026 context_release(context);
2028 /* Clear the screen */
2029 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2030 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2031 0x00, 1.0f, 0);
2033 This->d3d_initialized = TRUE;
2035 if(wined3d_settings.logo) {
2036 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2038 This->highest_dirty_ps_const = 0;
2039 This->highest_dirty_vs_const = 0;
2040 return WINED3D_OK;
2042 err_out:
2043 HeapFree(GetProcessHeap(), 0, This->render_targets);
2044 HeapFree(GetProcessHeap(), 0, This->swapchains);
2045 This->NumberOfSwapChains = 0;
2046 if(This->palettes) {
2047 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2048 HeapFree(GetProcessHeap(), 0, This->palettes);
2050 This->NumberOfPalettes = 0;
2051 if(swapchain) {
2052 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2054 if (This->stateBlock)
2056 wined3d_stateblock_decref(This->stateBlock);
2057 This->stateBlock = NULL;
2059 if (This->blit_priv) {
2060 This->blitter->free_private(This);
2062 if (This->fragment_priv) {
2063 This->frag_pipe->free_private(This);
2065 if (This->shader_priv) {
2066 This->shader_backend->shader_free_private(This);
2068 return hr;
2071 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
2072 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2074 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2075 IWineD3DSwapChainImpl *swapchain = NULL;
2076 HRESULT hr;
2078 /* Setup the implicit swapchain */
2079 TRACE("Creating implicit swapchain\n");
2080 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2081 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2082 if (FAILED(hr))
2084 WARN("Failed to create implicit swapchain\n");
2085 goto err_out;
2088 This->NumberOfSwapChains = 1;
2089 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(*This->swapchains));
2090 if (!This->swapchains)
2092 ERR("Out of memory!\n");
2093 goto err_out;
2095 This->swapchains[0] = swapchain;
2096 return WINED3D_OK;
2098 err_out:
2099 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2100 return hr;
2103 static HRESULT WINAPI device_unload_resource(struct wined3d_resource *resource, void *data)
2105 TRACE("Unloading resource %p.\n", resource);
2107 resource->resource_ops->resource_unload(resource);
2109 return S_OK;
2112 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
2113 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
2115 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2116 const struct wined3d_gl_info *gl_info;
2117 struct IWineD3DSurfaceImpl *surface;
2118 struct wined3d_context *context;
2119 int sampler;
2120 UINT i;
2121 TRACE("(%p)\n", This);
2123 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2125 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2126 * it was created. Thus make sure a context is active for the glDelete* calls
2128 context = context_acquire(This, NULL);
2129 gl_info = context->gl_info;
2131 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2133 /* Unload resources */
2134 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2136 TRACE("Deleting high order patches\n");
2137 for(i = 0; i < PATCHMAP_SIZE; i++) {
2138 struct list *e1, *e2;
2139 struct WineD3DRectPatch *patch;
2140 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2141 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2142 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2146 /* Delete the mouse cursor texture */
2147 if(This->cursorTexture) {
2148 ENTER_GL();
2149 glDeleteTextures(1, &This->cursorTexture);
2150 LEAVE_GL();
2151 This->cursorTexture = 0;
2154 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2155 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2157 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2158 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2161 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2162 * private data, it might contain opengl pointers
2164 if(This->depth_blt_texture) {
2165 ENTER_GL();
2166 glDeleteTextures(1, &This->depth_blt_texture);
2167 LEAVE_GL();
2168 This->depth_blt_texture = 0;
2170 if (This->depth_blt_rb) {
2171 ENTER_GL();
2172 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
2173 LEAVE_GL();
2174 This->depth_blt_rb = 0;
2175 This->depth_blt_rb_w = 0;
2176 This->depth_blt_rb_h = 0;
2179 /* Release the update stateblock */
2180 if (wined3d_stateblock_decref(This->updateStateBlock))
2182 if (This->updateStateBlock != This->stateBlock)
2183 FIXME("Something's still holding the update stateblock.\n");
2185 This->updateStateBlock = NULL;
2188 struct wined3d_stateblock *stateblock = This->stateBlock;
2189 This->stateBlock = NULL;
2191 /* Release the stateblock */
2192 if (wined3d_stateblock_decref(stateblock))
2193 FIXME("Something's still holding the stateblock.\n");
2196 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2197 This->blitter->free_private(This);
2198 This->frag_pipe->free_private(This);
2199 This->shader_backend->shader_free_private(This);
2201 /* Release the buffers (with sanity checks)*/
2202 if (This->onscreen_depth_stencil)
2204 surface = This->onscreen_depth_stencil;
2205 This->onscreen_depth_stencil = NULL;
2206 IWineD3DSurface_Release((IWineD3DSurface *)surface);
2209 if (This->depth_stencil)
2211 surface = This->depth_stencil;
2213 TRACE("Releasing depth/stencil buffer %p.\n", surface);
2215 This->depth_stencil = NULL;
2216 if (IWineD3DSurface_Release((IWineD3DSurface *)surface)
2217 && surface != This->auto_depth_stencil)
2219 ERR("Something is still holding a reference to depth/stencil buffer %p.\n", surface);
2223 if (This->auto_depth_stencil)
2225 surface = This->auto_depth_stencil;
2226 This->auto_depth_stencil = NULL;
2227 if (IWineD3DSurface_Release((IWineD3DSurface *)surface))
2229 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2233 for (i = 1; i < gl_info->limits.buffers; ++i)
2235 IWineD3DDevice_SetRenderTarget(iface, i, NULL, FALSE);
2238 surface = This->render_targets[0];
2239 TRACE("Setting rendertarget 0 to NULL\n");
2240 This->render_targets[0] = NULL;
2241 TRACE("Releasing the render target at %p\n", surface);
2242 IWineD3DSurface_Release((IWineD3DSurface *)surface);
2244 context_release(context);
2246 for (i = 0; i < This->NumberOfSwapChains; ++i)
2248 TRACE("Releasing the implicit swapchain %u.\n", i);
2249 if (D3DCB_DestroySwapChain((IWineD3DSwapChain *)This->swapchains[i]) > 0)
2251 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2255 HeapFree(GetProcessHeap(), 0, This->swapchains);
2256 This->swapchains = NULL;
2257 This->NumberOfSwapChains = 0;
2259 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2260 HeapFree(GetProcessHeap(), 0, This->palettes);
2261 This->palettes = NULL;
2262 This->NumberOfPalettes = 0;
2264 HeapFree(GetProcessHeap(), 0, This->render_targets);
2265 This->render_targets = NULL;
2267 This->d3d_initialized = FALSE;
2269 return WINED3D_OK;
2272 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2273 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2274 unsigned int i;
2276 for (i = 0; i < This->NumberOfSwapChains; ++i)
2278 TRACE("Releasing the implicit swapchain %u.\n", i);
2279 if (D3DCB_DestroySwapChain((IWineD3DSwapChain *)This->swapchains[i]) > 0)
2281 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2285 HeapFree(GetProcessHeap(), 0, This->swapchains);
2286 This->swapchains = NULL;
2287 This->NumberOfSwapChains = 0;
2288 return WINED3D_OK;
2291 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2292 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2293 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2295 * There is no way to deactivate thread safety once it is enabled.
2297 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2298 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2300 /*For now just store the flag(needed in case of ddraw) */
2301 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2304 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2305 const WINED3DDISPLAYMODE* pMode) {
2306 DEVMODEW devmode;
2307 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2308 const struct wined3d_format *format = wined3d_get_format(&This->adapter->gl_info, pMode->Format);
2309 LONG ret;
2310 RECT clip_rc;
2312 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2314 /* Resize the screen even without a window:
2315 * The app could have unset it with SetCooperativeLevel, but not called
2316 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2317 * but we don't have any hwnd
2320 memset(&devmode, 0, sizeof(devmode));
2321 devmode.dmSize = sizeof(devmode);
2322 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2323 devmode.dmBitsPerPel = format->byte_count * CHAR_BIT;
2324 devmode.dmPelsWidth = pMode->Width;
2325 devmode.dmPelsHeight = pMode->Height;
2327 devmode.dmDisplayFrequency = pMode->RefreshRate;
2328 if (pMode->RefreshRate)
2329 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2331 /* Only change the mode if necessary */
2332 if (This->ddraw_width == pMode->Width && This->ddraw_height == pMode->Height
2333 && This->ddraw_format == pMode->Format && !pMode->RefreshRate)
2334 return WINED3D_OK;
2336 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2337 if (ret != DISP_CHANGE_SUCCESSFUL)
2339 if (devmode.dmDisplayFrequency)
2341 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2342 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2343 devmode.dmDisplayFrequency = 0;
2344 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2346 if(ret != DISP_CHANGE_SUCCESSFUL) {
2347 return WINED3DERR_NOTAVAILABLE;
2351 /* Store the new values */
2352 This->ddraw_width = pMode->Width;
2353 This->ddraw_height = pMode->Height;
2354 This->ddraw_format = pMode->Format;
2356 /* And finally clip mouse to our screen */
2357 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2358 ClipCursor(&clip_rc);
2360 return WINED3D_OK;
2363 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, struct wined3d **wined3d)
2365 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2367 TRACE("iface %p, wined3d %p.\n", iface, wined3d);
2369 *wined3d = device->wined3d;
2370 wined3d_incref(*wined3d);
2372 TRACE("Returning %p.\n", *wined3d);
2374 return WINED3D_OK;
2377 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2378 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2380 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2381 (This->adapter->TextureRam/(1024*1024)),
2382 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2383 /* return simulated texture memory left */
2384 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2387 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2388 struct wined3d_buffer *buffer, UINT OffsetInBytes, UINT Stride)
2390 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2391 struct wined3d_stream_state *stream;
2392 struct wined3d_buffer *prev_buffer;
2394 TRACE("iface %p, stream_idx %u, buffer %p, offset %u, stride %u.\n",
2395 iface, StreamNumber, buffer, OffsetInBytes, Stride);
2397 if (StreamNumber >= MAX_STREAMS) {
2398 WARN("Stream out of range %d\n", StreamNumber);
2399 return WINED3DERR_INVALIDCALL;
2400 } else if(OffsetInBytes & 0x3) {
2401 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2402 return WINED3DERR_INVALIDCALL;
2405 stream = &This->updateStateBlock->state.streams[StreamNumber];
2406 prev_buffer = stream->buffer;
2408 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2410 if (prev_buffer == buffer
2411 && stream->stride == Stride
2412 && stream->offset == OffsetInBytes)
2414 TRACE("Application is setting the old values over, nothing to do\n");
2415 return WINED3D_OK;
2418 stream->buffer = buffer;
2419 if (buffer)
2421 stream->stride = Stride;
2422 stream->offset = OffsetInBytes;
2425 /* Handle recording of state blocks */
2426 if (This->isRecordingState) {
2427 TRACE("Recording... not performing anything\n");
2428 if (buffer)
2429 wined3d_buffer_incref(buffer);
2430 if (prev_buffer)
2431 wined3d_buffer_decref(prev_buffer);
2432 return WINED3D_OK;
2435 if (buffer)
2437 InterlockedIncrement(&buffer->bind_count);
2438 wined3d_buffer_incref(buffer);
2440 if (prev_buffer)
2442 InterlockedDecrement(&prev_buffer->bind_count);
2443 wined3d_buffer_decref(prev_buffer);
2446 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2448 return WINED3D_OK;
2451 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2452 UINT StreamNumber, struct wined3d_buffer **buffer, UINT *pOffset, UINT *pStride)
2454 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2455 struct wined3d_stream_state *stream;
2457 TRACE("iface %p, stream_idx %u, buffer %p, offset %p, stride %p.\n",
2458 iface, StreamNumber, buffer, pOffset, pStride);
2460 if (StreamNumber >= MAX_STREAMS)
2462 WARN("Stream out of range %d\n", StreamNumber);
2463 return WINED3DERR_INVALIDCALL;
2466 stream = &This->stateBlock->state.streams[StreamNumber];
2467 *buffer = stream->buffer;
2468 *pStride = stream->stride;
2469 if (pOffset) *pOffset = stream->offset;
2471 if (*buffer)
2472 wined3d_buffer_incref(*buffer);
2474 return WINED3D_OK;
2477 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2478 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2479 struct wined3d_stream_state *stream;
2480 UINT old_flags, oldFreq;
2482 TRACE("iface %p, stream_idx %u, divider %#x.\n", iface, StreamNumber, Divider);
2484 /* Verify input at least in d3d9 this is invalid. */
2485 if ((Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA))
2487 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2488 return WINED3DERR_INVALIDCALL;
2490 if ((Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && !StreamNumber)
2492 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2493 return WINED3DERR_INVALIDCALL;
2495 if (!Divider)
2497 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2498 return WINED3DERR_INVALIDCALL;
2501 stream = &This->updateStateBlock->state.streams[StreamNumber];
2502 old_flags = stream->flags;
2503 oldFreq = stream->frequency;
2505 stream->flags = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA);
2506 stream->frequency = Divider & 0x7FFFFF;
2508 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2510 if (stream->frequency != oldFreq || stream->flags != old_flags)
2511 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2513 return WINED3D_OK;
2516 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2517 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2518 struct wined3d_stream_state *stream;
2520 TRACE("iface %p, stream_idx %u, divider %p.\n", iface, StreamNumber, Divider);
2522 stream = &This->updateStateBlock->state.streams[StreamNumber];
2523 *Divider = stream->flags | stream->frequency;
2525 TRACE("Returning %#x.\n", *Divider);
2527 return WINED3D_OK;
2530 /*****
2531 * Get / Set & Multiply Transform
2532 *****/
2533 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2534 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2536 /* Most of this routine, comments included copied from ddraw tree initially: */
2537 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2539 /* Handle recording of state blocks */
2540 if (This->isRecordingState) {
2541 TRACE("Recording... not performing anything\n");
2542 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2543 This->updateStateBlock->state.transforms[d3dts] = *lpmatrix;
2544 return WINED3D_OK;
2548 * If the new matrix is the same as the current one,
2549 * we cut off any further processing. this seems to be a reasonable
2550 * optimization because as was noticed, some apps (warcraft3 for example)
2551 * tend towards setting the same matrix repeatedly for some reason.
2553 * From here on we assume that the new matrix is different, wherever it matters.
2555 if (!memcmp(&This->stateBlock->state.transforms[d3dts].u.m[0][0], lpmatrix, sizeof(*lpmatrix)))
2557 TRACE("The app is setting the same matrix over again\n");
2558 return WINED3D_OK;
2560 else
2562 conv_mat(lpmatrix, &This->stateBlock->state.transforms[d3dts].u.m[0][0]);
2566 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2567 where ViewMat = Camera space, WorldMat = world space.
2569 In OpenGL, camera and world space is combined into GL_MODELVIEW
2570 matrix. The Projection matrix stay projection matrix.
2573 /* Capture the times we can just ignore the change for now */
2574 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2575 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2576 /* Handled by the state manager */
2579 if (d3dts < WINED3DTS_WORLDMATRIX(This->adapter->gl_info.limits.blends))
2580 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2582 return WINED3D_OK;
2586 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface,
2587 WINED3DTRANSFORMSTATETYPE state, WINED3DMATRIX *matrix)
2589 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2591 TRACE("iface %p, state %s, matrix %p.\n", iface, debug_d3dtstype(state), matrix);
2593 *matrix = device->stateBlock->state.transforms[state];
2595 return WINED3D_OK;
2598 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2599 const WINED3DMATRIX *mat = NULL;
2600 WINED3DMATRIX temp;
2602 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2603 * below means it will be recorded in a state block change, but it
2604 * works regardless where it is recorded.
2605 * If this is found to be wrong, change to StateBlock.
2607 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2608 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2610 if (State <= HIGHEST_TRANSFORMSTATE)
2612 mat = &This->updateStateBlock->state.transforms[State];
2614 else
2616 FIXME("Unhandled transform state!!\n");
2619 multiply_matrix(&temp, mat, pMatrix);
2621 /* Apply change via set transform - will reapply to eg. lights this way */
2622 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2625 /*****
2626 * Get / Set Light
2627 *****/
2628 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2629 you can reference any indexes you want as long as that number max are enabled at any
2630 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2631 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2632 but when recording, just build a chain pretty much of commands to be replayed. */
2634 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2635 float rho;
2636 struct wined3d_light_info *object = NULL;
2637 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2638 struct list *e;
2640 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2641 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2643 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2644 * the gl driver.
2646 if(!pLight) {
2647 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2648 return WINED3DERR_INVALIDCALL;
2651 switch(pLight->Type) {
2652 case WINED3DLIGHT_POINT:
2653 case WINED3DLIGHT_SPOT:
2654 case WINED3DLIGHT_PARALLELPOINT:
2655 case WINED3DLIGHT_GLSPOT:
2656 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2657 * most wanted
2659 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2661 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2662 return WINED3DERR_INVALIDCALL;
2664 break;
2666 case WINED3DLIGHT_DIRECTIONAL:
2667 /* Ignores attenuation */
2668 break;
2670 default:
2671 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2672 return WINED3DERR_INVALIDCALL;
2675 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2677 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2678 if(object->OriginalIndex == Index) break;
2679 object = NULL;
2682 if(!object) {
2683 TRACE("Adding new light\n");
2684 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2685 if(!object) {
2686 ERR("Out of memory error when allocating a light\n");
2687 return E_OUTOFMEMORY;
2689 list_add_head(&This->updateStateBlock->state.light_map[Hi], &object->entry);
2690 object->glIndex = -1;
2691 object->OriginalIndex = Index;
2694 /* Initialize the object */
2695 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,
2696 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2697 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2698 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2699 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2700 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2701 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2703 /* Save away the information */
2704 object->OriginalParms = *pLight;
2706 switch (pLight->Type) {
2707 case WINED3DLIGHT_POINT:
2708 /* Position */
2709 object->lightPosn[0] = pLight->Position.x;
2710 object->lightPosn[1] = pLight->Position.y;
2711 object->lightPosn[2] = pLight->Position.z;
2712 object->lightPosn[3] = 1.0f;
2713 object->cutoff = 180.0f;
2714 /* FIXME: Range */
2715 break;
2717 case WINED3DLIGHT_DIRECTIONAL:
2718 /* Direction */
2719 object->lightPosn[0] = -pLight->Direction.x;
2720 object->lightPosn[1] = -pLight->Direction.y;
2721 object->lightPosn[2] = -pLight->Direction.z;
2722 object->lightPosn[3] = 0.0f;
2723 object->exponent = 0.0f;
2724 object->cutoff = 180.0f;
2725 break;
2727 case WINED3DLIGHT_SPOT:
2728 /* Position */
2729 object->lightPosn[0] = pLight->Position.x;
2730 object->lightPosn[1] = pLight->Position.y;
2731 object->lightPosn[2] = pLight->Position.z;
2732 object->lightPosn[3] = 1.0f;
2734 /* Direction */
2735 object->lightDirn[0] = pLight->Direction.x;
2736 object->lightDirn[1] = pLight->Direction.y;
2737 object->lightDirn[2] = pLight->Direction.z;
2738 object->lightDirn[3] = 1.0f;
2741 * opengl-ish and d3d-ish spot lights use too different models for the
2742 * light "intensity" as a function of the angle towards the main light direction,
2743 * so we only can approximate very roughly.
2744 * however spot lights are rather rarely used in games (if ever used at all).
2745 * furthermore if still used, probably nobody pays attention to such details.
2747 if (!pLight->Falloff)
2749 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2750 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2751 * will always be 1.0 for both of them, and we don't have to care for the
2752 * rest of the rather complex calculation
2754 object->exponent = 0.0f;
2755 } else {
2756 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2757 if (rho < 0.0001f) rho = 0.0001f;
2758 object->exponent = -0.3f/logf(cosf(rho/2));
2760 if (object->exponent > 128.0f)
2762 object->exponent = 128.0f;
2764 object->cutoff = (float) (pLight->Phi*90/M_PI);
2766 /* FIXME: Range */
2767 break;
2769 default:
2770 FIXME("Unrecognized light type %d\n", pLight->Type);
2773 /* Update the live definitions if the light is currently assigned a glIndex */
2774 if (object->glIndex != -1 && !This->isRecordingState) {
2775 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2777 return WINED3D_OK;
2780 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2782 struct wined3d_light_info *lightInfo = NULL;
2783 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2784 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2785 struct list *e;
2786 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2788 LIST_FOR_EACH(e, &This->stateBlock->state.light_map[Hi])
2790 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2791 if(lightInfo->OriginalIndex == Index) break;
2792 lightInfo = NULL;
2795 if (!lightInfo)
2797 TRACE("Light information requested but light not defined\n");
2798 return WINED3DERR_INVALIDCALL;
2801 *pLight = lightInfo->OriginalParms;
2802 return WINED3D_OK;
2805 /*****
2806 * Get / Set Light Enable
2807 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2808 *****/
2809 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2811 struct wined3d_light_info *lightInfo = NULL;
2812 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2813 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2814 struct list *e;
2815 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2817 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2819 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2820 if(lightInfo->OriginalIndex == Index) break;
2821 lightInfo = NULL;
2823 TRACE("Found light: %p\n", lightInfo);
2825 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2826 if (!lightInfo)
2828 TRACE("Light enabled requested but light not defined, so defining one!\n");
2829 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2831 /* Search for it again! Should be fairly quick as near head of list */
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 if (!lightInfo)
2840 FIXME("Adding default lights has failed dismally\n");
2841 return WINED3DERR_INVALIDCALL;
2845 if(!Enable) {
2846 if(lightInfo->glIndex != -1) {
2847 if(!This->isRecordingState) {
2848 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2851 This->updateStateBlock->state.lights[lightInfo->glIndex] = NULL;
2852 lightInfo->glIndex = -1;
2853 } else {
2854 TRACE("Light already disabled, nothing to do\n");
2856 lightInfo->enabled = FALSE;
2857 } else {
2858 lightInfo->enabled = TRUE;
2859 if (lightInfo->glIndex != -1) {
2860 /* nop */
2861 TRACE("Nothing to do as light was enabled\n");
2862 } else {
2863 int i;
2864 /* Find a free gl light */
2865 for (i = 0; i < This->maxConcurrentLights; ++i)
2867 if (!This->updateStateBlock->state.lights[i])
2869 This->updateStateBlock->state.lights[i] = lightInfo;
2870 lightInfo->glIndex = i;
2871 break;
2874 if(lightInfo->glIndex == -1) {
2875 /* Our tests show that Windows returns D3D_OK in this situation, even with
2876 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2877 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2878 * as well for those lights.
2880 * TODO: Test how this affects rendering
2882 WARN("Too many concurrently active lights\n");
2883 return WINED3D_OK;
2886 /* i == lightInfo->glIndex */
2887 if(!This->isRecordingState) {
2888 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2893 return WINED3D_OK;
2896 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2898 struct wined3d_light_info *lightInfo = NULL;
2899 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2900 struct list *e;
2901 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2902 TRACE("(%p) : for idx(%d)\n", This, Index);
2904 LIST_FOR_EACH(e, &This->stateBlock->state.light_map[Hi])
2906 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2907 if(lightInfo->OriginalIndex == Index) break;
2908 lightInfo = NULL;
2911 if (!lightInfo)
2913 TRACE("Light enabled state requested but light not defined\n");
2914 return WINED3DERR_INVALIDCALL;
2916 /* true is 128 according to SetLightEnable */
2917 *pEnable = lightInfo->enabled ? 128 : 0;
2918 return WINED3D_OK;
2921 /*****
2922 * Get / Set Clip Planes
2923 *****/
2924 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2925 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2926 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2928 /* Validate Index */
2929 if (Index >= This->adapter->gl_info.limits.clipplanes)
2931 TRACE("Application has requested clipplane this device doesn't support\n");
2932 return WINED3DERR_INVALIDCALL;
2935 This->updateStateBlock->changed.clipplane |= 1 << Index;
2937 if (This->updateStateBlock->state.clip_planes[Index][0] == pPlane[0]
2938 && This->updateStateBlock->state.clip_planes[Index][1] == pPlane[1]
2939 && This->updateStateBlock->state.clip_planes[Index][2] == pPlane[2]
2940 && This->updateStateBlock->state.clip_planes[Index][3] == pPlane[3])
2942 TRACE("Application is setting old values over, nothing to do\n");
2943 return WINED3D_OK;
2946 This->updateStateBlock->state.clip_planes[Index][0] = pPlane[0];
2947 This->updateStateBlock->state.clip_planes[Index][1] = pPlane[1];
2948 This->updateStateBlock->state.clip_planes[Index][2] = pPlane[2];
2949 This->updateStateBlock->state.clip_planes[Index][3] = pPlane[3];
2951 /* Handle recording of state blocks */
2952 if (This->isRecordingState) {
2953 TRACE("Recording... not performing anything\n");
2954 return WINED3D_OK;
2957 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2959 return WINED3D_OK;
2962 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2963 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2964 TRACE("(%p) : for idx %d\n", This, Index);
2966 /* Validate Index */
2967 if (Index >= This->adapter->gl_info.limits.clipplanes)
2969 TRACE("Application has requested clipplane this device doesn't support\n");
2970 return WINED3DERR_INVALIDCALL;
2973 pPlane[0] = (float)This->stateBlock->state.clip_planes[Index][0];
2974 pPlane[1] = (float)This->stateBlock->state.clip_planes[Index][1];
2975 pPlane[2] = (float)This->stateBlock->state.clip_planes[Index][2];
2976 pPlane[3] = (float)This->stateBlock->state.clip_planes[Index][3];
2977 return WINED3D_OK;
2980 /*****
2981 * Get / Set Clip Plane Status
2982 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2983 *****/
2984 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2985 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2986 FIXME("(%p) : stub\n", This);
2988 if (!pClipStatus)
2989 return WINED3DERR_INVALIDCALL;
2991 This->updateStateBlock->state.clip_status.ClipUnion = pClipStatus->ClipUnion;
2992 This->updateStateBlock->state.clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2993 return WINED3D_OK;
2996 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2997 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2998 FIXME("(%p) : stub\n", This);
3000 if (!pClipStatus)
3001 return WINED3DERR_INVALIDCALL;
3003 pClipStatus->ClipUnion = This->updateStateBlock->state.clip_status.ClipUnion;
3004 pClipStatus->ClipIntersection = This->updateStateBlock->state.clip_status.ClipIntersection;
3005 return WINED3D_OK;
3008 /*****
3009 * Get / Set Material
3010 *****/
3011 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3012 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3014 This->updateStateBlock->changed.material = TRUE;
3015 This->updateStateBlock->state.material = *pMaterial;
3017 /* Handle recording of state blocks */
3018 if (This->isRecordingState) {
3019 TRACE("Recording... not performing anything\n");
3020 return WINED3D_OK;
3023 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3024 return WINED3D_OK;
3027 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3028 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3029 *pMaterial = This->updateStateBlock->state.material;
3030 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3031 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3032 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3033 pMaterial->Ambient.b, pMaterial->Ambient.a);
3034 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3035 pMaterial->Specular.b, pMaterial->Specular.a);
3036 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3037 pMaterial->Emissive.b, pMaterial->Emissive.a);
3038 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3040 return WINED3D_OK;
3043 /*****
3044 * Get / Set Indices
3045 *****/
3046 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
3047 struct wined3d_buffer *buffer, enum wined3d_format_id fmt)
3049 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3050 struct wined3d_buffer *prev_buffer;
3052 TRACE("iface %p, buffer %p, format %s.\n",
3053 iface, buffer, debug_d3dformat(fmt));
3055 prev_buffer = This->updateStateBlock->state.index_buffer;
3057 This->updateStateBlock->changed.indices = TRUE;
3058 This->updateStateBlock->state.index_buffer = buffer;
3059 This->updateStateBlock->state.index_format = fmt;
3061 /* Handle recording of state blocks */
3062 if (This->isRecordingState) {
3063 TRACE("Recording... not performing anything\n");
3064 if (buffer)
3065 wined3d_buffer_incref(buffer);
3066 if (prev_buffer)
3067 wined3d_buffer_decref(prev_buffer);
3068 return WINED3D_OK;
3071 if (prev_buffer != buffer)
3073 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3074 if (buffer)
3076 InterlockedIncrement(&buffer->bind_count);
3077 wined3d_buffer_incref(buffer);
3079 if (prev_buffer)
3081 InterlockedDecrement(&prev_buffer->bind_count);
3082 wined3d_buffer_decref(prev_buffer);
3086 return WINED3D_OK;
3089 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, struct wined3d_buffer **buffer)
3091 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3093 TRACE("iface %p, buffer %p.\n", iface, buffer);
3095 *buffer = This->stateBlock->state.index_buffer;
3097 if (*buffer)
3098 wined3d_buffer_incref(*buffer);
3100 TRACE("Returning %p.\n", *buffer);
3102 return WINED3D_OK;
3105 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3106 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3107 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3108 TRACE("(%p)->(%d)\n", This, BaseIndex);
3110 if (This->updateStateBlock->state.base_vertex_index == BaseIndex)
3112 TRACE("Application is setting the old value over, nothing to do\n");
3113 return WINED3D_OK;
3116 This->updateStateBlock->state.base_vertex_index = BaseIndex;
3118 if (This->isRecordingState) {
3119 TRACE("Recording... not performing anything\n");
3120 return WINED3D_OK;
3122 /* The base vertex index affects the stream sources */
3123 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3124 return WINED3D_OK;
3127 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3128 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3129 TRACE("(%p) : base_index %p\n", This, base_index);
3131 *base_index = This->stateBlock->state.base_vertex_index;
3133 TRACE("Returning %u\n", *base_index);
3135 return WINED3D_OK;
3138 /*****
3139 * Get / Set Viewports
3140 *****/
3141 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3142 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3144 TRACE("(%p)\n", This);
3145 This->updateStateBlock->changed.viewport = TRUE;
3146 This->updateStateBlock->state.viewport = *pViewport;
3148 /* Handle recording of state blocks */
3149 if (This->isRecordingState) {
3150 TRACE("Recording... not performing anything\n");
3151 return WINED3D_OK;
3154 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3155 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3157 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3158 return WINED3D_OK;
3162 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3163 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3164 TRACE("(%p)\n", This);
3165 *pViewport = This->stateBlock->state.viewport;
3166 return WINED3D_OK;
3169 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface,
3170 WINED3DRENDERSTATETYPE State, DWORD Value)
3172 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3173 DWORD oldValue = This->stateBlock->state.render_states[State];
3175 TRACE("iface %p, state %s (%#x), value %#x.\n", iface, debug_d3drenderstate(State), State, Value);
3177 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3178 This->updateStateBlock->state.render_states[State] = Value;
3180 /* Handle recording of state blocks */
3181 if (This->isRecordingState) {
3182 TRACE("Recording... not performing anything\n");
3183 return WINED3D_OK;
3186 /* Compared here and not before the assignment to allow proper stateblock recording */
3187 if(Value == oldValue) {
3188 TRACE("Application is setting the old value over, nothing to do\n");
3189 } else {
3190 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3193 return WINED3D_OK;
3196 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface,
3197 WINED3DRENDERSTATETYPE State, DWORD *pValue)
3199 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3201 TRACE("iface %p, state %s (%#x), value %p.\n", iface, debug_d3drenderstate(State), State, pValue);
3203 *pValue = This->stateBlock->state.render_states[State];
3204 return WINED3D_OK;
3207 /*****
3208 * Get / Set Sampler States
3209 * TODO: Verify against dx9 definitions
3210 *****/
3212 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3213 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3214 DWORD oldValue;
3216 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3217 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3219 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3220 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3223 if (Sampler >= sizeof(This->stateBlock->state.sampler_states) / sizeof(*This->stateBlock->state.sampler_states))
3225 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3226 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3229 oldValue = This->stateBlock->state.sampler_states[Sampler][Type];
3230 This->updateStateBlock->state.sampler_states[Sampler][Type] = Value;
3231 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3233 /* Handle recording of state blocks */
3234 if (This->isRecordingState) {
3235 TRACE("Recording... not performing anything\n");
3236 return WINED3D_OK;
3239 if(oldValue == Value) {
3240 TRACE("Application is setting the old value over, nothing to do\n");
3241 return WINED3D_OK;
3244 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3246 return WINED3D_OK;
3249 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3250 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3252 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3253 This, Sampler, debug_d3dsamplerstate(Type), Type);
3255 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3256 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3259 if (Sampler >= sizeof(This->stateBlock->state.sampler_states) / sizeof(*This->stateBlock->state.sampler_states))
3261 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3262 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3264 *Value = This->stateBlock->state.sampler_states[Sampler][Type];
3265 TRACE("(%p) : Returning %#x\n", This, *Value);
3267 return WINED3D_OK;
3270 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3271 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3273 This->updateStateBlock->changed.scissorRect = TRUE;
3274 if (EqualRect(&This->updateStateBlock->state.scissor_rect, pRect))
3276 TRACE("App is setting the old scissor rectangle over, nothing to do.\n");
3277 return WINED3D_OK;
3279 CopyRect(&This->updateStateBlock->state.scissor_rect, pRect);
3281 if(This->isRecordingState) {
3282 TRACE("Recording... not performing anything\n");
3283 return WINED3D_OK;
3286 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3288 return WINED3D_OK;
3291 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3292 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3294 *pRect = This->updateStateBlock->state.scissor_rect;
3295 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3296 return WINED3D_OK;
3299 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice *iface,
3300 struct wined3d_vertex_declaration *pDecl)
3302 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3303 struct wined3d_vertex_declaration *oldDecl = This->updateStateBlock->state.vertex_declaration;
3305 TRACE("iface %p, declaration %p.\n", iface, pDecl);
3307 if (pDecl)
3308 wined3d_vertex_declaration_incref(pDecl);
3309 if (oldDecl)
3310 wined3d_vertex_declaration_decref(oldDecl);
3312 This->updateStateBlock->state.vertex_declaration = pDecl;
3313 This->updateStateBlock->changed.vertexDecl = TRUE;
3315 if (This->isRecordingState) {
3316 TRACE("Recording... not performing anything\n");
3317 return WINED3D_OK;
3318 } else if(pDecl == oldDecl) {
3319 /* Checked after the assignment to allow proper stateblock recording */
3320 TRACE("Application is setting the old declaration over, nothing to do\n");
3321 return WINED3D_OK;
3324 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3325 return WINED3D_OK;
3328 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice *iface,
3329 struct wined3d_vertex_declaration **ppDecl)
3331 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3333 TRACE("iface %p, declaration %p.\n", iface, ppDecl);
3335 *ppDecl = This->stateBlock->state.vertex_declaration;
3336 if (*ppDecl)
3337 wined3d_vertex_declaration_incref(*ppDecl);
3339 return WINED3D_OK;
3342 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader *pShader)
3344 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3345 IWineD3DVertexShader *oldShader = (IWineD3DVertexShader *)This->updateStateBlock->state.vertex_shader;
3347 This->updateStateBlock->state.vertex_shader = (IWineD3DVertexShaderImpl *)pShader;
3348 This->updateStateBlock->changed.vertexShader = TRUE;
3350 if (This->isRecordingState) {
3351 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3352 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3353 TRACE("Recording... not performing anything\n");
3354 return WINED3D_OK;
3355 } else if(oldShader == pShader) {
3356 /* Checked here to allow proper stateblock recording */
3357 TRACE("App is setting the old shader over, nothing to do\n");
3358 return WINED3D_OK;
3361 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3362 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3363 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3365 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3367 return WINED3D_OK;
3370 static IWineD3DVertexShader * WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface)
3372 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3373 IWineD3DVertexShader *shader;
3375 TRACE("iface %p.\n", iface);
3377 shader = (IWineD3DVertexShader *)device->stateBlock->state.vertex_shader;
3378 if (shader) IWineD3DVertexShader_AddRef(shader);
3380 TRACE("Returning %p.\n", shader);
3381 return shader;
3384 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3385 IWineD3DDevice *iface,
3386 UINT start,
3387 CONST BOOL *srcData,
3388 UINT count) {
3390 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3391 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3393 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3394 iface, srcData, start, count);
3396 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3398 memcpy(&This->updateStateBlock->state.vs_consts_b[start], srcData, cnt * sizeof(BOOL));
3399 for (i = 0; i < cnt; i++)
3400 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3402 for (i = start; i < cnt + start; ++i) {
3403 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3406 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3408 return WINED3D_OK;
3411 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3412 IWineD3DDevice *iface,
3413 UINT start,
3414 BOOL *dstData,
3415 UINT count) {
3417 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3418 int cnt = min(count, MAX_CONST_B - start);
3420 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3421 iface, dstData, start, count);
3423 if (!dstData || cnt < 0)
3424 return WINED3DERR_INVALIDCALL;
3426 memcpy(dstData, &This->stateBlock->state.vs_consts_b[start], cnt * sizeof(BOOL));
3427 return WINED3D_OK;
3430 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3431 IWineD3DDevice *iface,
3432 UINT start,
3433 CONST int *srcData,
3434 UINT count) {
3436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3437 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3439 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3440 iface, srcData, start, count);
3442 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3444 memcpy(&This->updateStateBlock->state.vs_consts_i[start * 4], srcData, cnt * sizeof(int) * 4);
3445 for (i = 0; i < cnt; i++)
3446 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3447 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3449 for (i = start; i < cnt + start; ++i) {
3450 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3453 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3455 return WINED3D_OK;
3458 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3459 IWineD3DDevice *iface,
3460 UINT start,
3461 int *dstData,
3462 UINT count) {
3464 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3465 int cnt = min(count, MAX_CONST_I - start);
3467 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3468 iface, dstData, start, count);
3470 if (!dstData || ((signed int)MAX_CONST_I - (signed int)start) <= 0)
3471 return WINED3DERR_INVALIDCALL;
3473 memcpy(dstData, &This->stateBlock->state.vs_consts_i[start * 4], cnt * sizeof(int) * 4);
3474 return WINED3D_OK;
3477 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3478 IWineD3DDevice *iface,
3479 UINT start,
3480 CONST float *srcData,
3481 UINT count) {
3483 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3484 UINT i;
3486 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3487 iface, srcData, start, count);
3489 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3490 if (!srcData || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3491 return WINED3DERR_INVALIDCALL;
3493 memcpy(&This->updateStateBlock->state.vs_consts_f[start * 4], srcData, count * sizeof(float) * 4);
3494 if(TRACE_ON(d3d)) {
3495 for (i = 0; i < count; i++)
3496 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3497 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3500 if (!This->isRecordingState)
3502 This->shader_backend->shader_update_float_vertex_constants(This, start, count);
3503 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3506 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3507 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3509 return WINED3D_OK;
3512 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3513 IWineD3DDevice *iface,
3514 UINT start,
3515 float *dstData,
3516 UINT count) {
3518 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3519 int cnt = min(count, This->d3d_vshader_constantF - start);
3521 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3522 iface, dstData, start, count);
3524 if (!dstData || cnt < 0)
3525 return WINED3DERR_INVALIDCALL;
3527 memcpy(dstData, &This->stateBlock->state.vs_consts_f[start * 4], cnt * sizeof(float) * 4);
3528 return WINED3D_OK;
3531 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3532 DWORD i;
3533 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3535 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3539 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3541 DWORD i = This->rev_tex_unit_map[unit];
3542 DWORD j = This->texUnitMap[stage];
3544 This->texUnitMap[stage] = unit;
3545 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3547 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3550 This->rev_tex_unit_map[unit] = stage;
3551 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3553 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3557 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3558 int i;
3560 This->fixed_function_usage_map = 0;
3561 for (i = 0; i < MAX_TEXTURES; ++i)
3563 const struct wined3d_state *state = &This->stateBlock->state;
3564 WINED3DTEXTUREOP color_op = state->texture_states[i][WINED3DTSS_COLOROP];
3565 WINED3DTEXTUREOP alpha_op = state->texture_states[i][WINED3DTSS_ALPHAOP];
3566 DWORD color_arg1 = state->texture_states[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3567 DWORD color_arg2 = state->texture_states[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3568 DWORD color_arg3 = state->texture_states[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3569 DWORD alpha_arg1 = state->texture_states[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3570 DWORD alpha_arg2 = state->texture_states[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3571 DWORD alpha_arg3 = state->texture_states[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3573 if (color_op == WINED3DTOP_DISABLE) {
3574 /* Not used, and disable higher stages */
3575 break;
3578 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3579 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3580 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3581 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3582 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3583 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3584 This->fixed_function_usage_map |= (1 << i);
3587 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3588 This->fixed_function_usage_map |= (1 << (i + 1));
3593 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3595 unsigned int i, tex;
3596 WORD ffu_map;
3598 device_update_fixed_function_usage_map(This);
3599 ffu_map = This->fixed_function_usage_map;
3601 if (This->max_ffp_textures == gl_info->limits.texture_stages
3602 || This->stateBlock->state.lowest_disabled_stage <= This->max_ffp_textures)
3604 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3606 if (!(ffu_map & 1)) continue;
3608 if (This->texUnitMap[i] != i) {
3609 device_map_stage(This, i, i);
3610 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3611 markTextureStagesDirty(This, i);
3614 return;
3617 /* Now work out the mapping */
3618 tex = 0;
3619 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3621 if (!(ffu_map & 1)) continue;
3623 if (This->texUnitMap[i] != tex) {
3624 device_map_stage(This, i, tex);
3625 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3626 markTextureStagesDirty(This, i);
3629 ++tex;
3633 static void device_map_psamplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3635 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3636 This->stateBlock->state.pixel_shader->baseShader.reg_maps.sampler_type;
3637 unsigned int i;
3639 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3640 if (sampler_type[i] && This->texUnitMap[i] != i)
3642 device_map_stage(This, i, i);
3643 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3644 if (i < gl_info->limits.texture_stages)
3646 markTextureStagesDirty(This, i);
3652 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_tokens,
3653 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_tokens, DWORD unit)
3655 DWORD current_mapping = This->rev_tex_unit_map[unit];
3657 /* Not currently used */
3658 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3660 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3661 /* Used by a fragment sampler */
3663 if (!pshader_sampler_tokens) {
3664 /* No pixel shader, check fixed function */
3665 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3668 /* Pixel shader, check the shader's sampler map */
3669 return !pshader_sampler_tokens[current_mapping];
3672 /* Used by a vertex sampler */
3673 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3676 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps, const struct wined3d_gl_info *gl_info)
3678 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3679 This->stateBlock->state.vertex_shader->baseShader.reg_maps.sampler_type;
3680 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3681 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
3682 int i;
3684 if (ps)
3686 IWineD3DPixelShaderImpl *pshader = This->stateBlock->state.pixel_shader;
3688 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3689 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3690 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3693 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3694 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3695 if (vshader_sampler_type[i])
3697 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3699 /* Already mapped somewhere */
3700 continue;
3703 while (start >= 0) {
3704 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3706 device_map_stage(This, vsampler_idx, start);
3707 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3709 --start;
3710 break;
3713 --start;
3719 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This)
3721 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3722 const struct wined3d_state *state = &This->stateBlock->state;
3723 BOOL vs = use_vs(state);
3724 BOOL ps = use_ps(state);
3726 * Rules are:
3727 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3728 * that would be really messy and require shader recompilation
3729 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3730 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3732 if (ps) device_map_psamplers(This, gl_info);
3733 else device_map_fixed_function_samplers(This, gl_info);
3735 if (vs) device_map_vsamplers(This, ps, gl_info);
3738 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader)
3740 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3741 IWineD3DPixelShader *oldShader = (IWineD3DPixelShader *)This->updateStateBlock->state.pixel_shader;
3742 This->updateStateBlock->state.pixel_shader = (IWineD3DPixelShaderImpl *)pShader;
3743 This->updateStateBlock->changed.pixelShader = TRUE;
3745 /* Handle recording of state blocks */
3746 if (This->isRecordingState) {
3747 TRACE("Recording... not performing anything\n");
3750 if (This->isRecordingState) {
3751 TRACE("Recording... not performing anything\n");
3752 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3753 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3754 return WINED3D_OK;
3757 if(pShader == oldShader) {
3758 TRACE("App is setting the old pixel shader over, nothing to do\n");
3759 return WINED3D_OK;
3762 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3763 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3765 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3766 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3768 return WINED3D_OK;
3771 static IWineD3DPixelShader * WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface)
3773 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3774 IWineD3DPixelShader *shader;
3776 TRACE("iface %p.\n", iface);
3778 shader = (IWineD3DPixelShader *)device->stateBlock->state.pixel_shader;
3779 if (shader) IWineD3DPixelShader_AddRef(shader);
3781 TRACE("Returning %p.\n", shader);
3782 return shader;
3785 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3786 IWineD3DDevice *iface,
3787 UINT start,
3788 CONST BOOL *srcData,
3789 UINT count) {
3791 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3792 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3794 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3795 iface, srcData, start, count);
3797 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3799 memcpy(&This->updateStateBlock->state.ps_consts_b[start], srcData, cnt * sizeof(BOOL));
3800 for (i = 0; i < cnt; i++)
3801 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3803 for (i = start; i < cnt + start; ++i) {
3804 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3807 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3809 return WINED3D_OK;
3812 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3813 IWineD3DDevice *iface,
3814 UINT start,
3815 BOOL *dstData,
3816 UINT count) {
3818 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3819 int cnt = min(count, MAX_CONST_B - start);
3821 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3822 iface, dstData, start, count);
3824 if (!dstData || cnt < 0)
3825 return WINED3DERR_INVALIDCALL;
3827 memcpy(dstData, &This->stateBlock->state.ps_consts_b[start], cnt * sizeof(BOOL));
3828 return WINED3D_OK;
3831 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3832 IWineD3DDevice *iface,
3833 UINT start,
3834 CONST int *srcData,
3835 UINT count) {
3837 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3838 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3840 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3841 iface, srcData, start, count);
3843 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3845 memcpy(&This->updateStateBlock->state.ps_consts_i[start * 4], srcData, cnt * sizeof(int) * 4);
3846 for (i = 0; i < cnt; i++)
3847 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3848 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3850 for (i = start; i < cnt + start; ++i) {
3851 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3854 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3856 return WINED3D_OK;
3859 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3860 IWineD3DDevice *iface,
3861 UINT start,
3862 int *dstData,
3863 UINT count) {
3865 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3866 int cnt = min(count, MAX_CONST_I - start);
3868 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3869 iface, dstData, start, count);
3871 if (!dstData || cnt < 0)
3872 return WINED3DERR_INVALIDCALL;
3874 memcpy(dstData, &This->stateBlock->state.ps_consts_i[start * 4], cnt * sizeof(int) * 4);
3875 return WINED3D_OK;
3878 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3879 IWineD3DDevice *iface,
3880 UINT start,
3881 CONST float *srcData,
3882 UINT count) {
3884 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3885 UINT i;
3887 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3888 iface, srcData, start, count);
3890 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3891 if (!srcData || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3892 return WINED3DERR_INVALIDCALL;
3894 memcpy(&This->updateStateBlock->state.ps_consts_f[start * 4], srcData, count * sizeof(float) * 4);
3895 if(TRACE_ON(d3d)) {
3896 for (i = 0; i < count; i++)
3897 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3898 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3901 if (!This->isRecordingState)
3903 This->shader_backend->shader_update_float_pixel_constants(This, start, count);
3904 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3907 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3908 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3910 return WINED3D_OK;
3913 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3914 IWineD3DDevice *iface,
3915 UINT start,
3916 float *dstData,
3917 UINT count) {
3919 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3920 int cnt = min(count, This->d3d_pshader_constantF - start);
3922 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3923 iface, dstData, start, count);
3925 if (!dstData || cnt < 0)
3926 return WINED3DERR_INVALIDCALL;
3928 memcpy(dstData, &This->stateBlock->state.ps_consts_f[start * 4], cnt * sizeof(float) * 4);
3929 return WINED3D_OK;
3932 /* Context activation is done by the caller. */
3933 /* Do not call while under the GL lock. */
3934 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3935 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3936 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD flags,
3937 DWORD DestFVF)
3939 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3940 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3941 unsigned int i;
3942 WINED3DVIEWPORT vp;
3943 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3944 BOOL doClip;
3945 DWORD numTextures;
3947 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3949 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3952 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3954 ERR("Source has no position mask\n");
3955 return WINED3DERR_INVALIDCALL;
3958 if (!dest->resource.allocatedMemory)
3959 buffer_get_sysmem(dest, gl_info);
3961 /* Get a pointer into the destination vbo(create one if none exists) and
3962 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3964 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3966 dest->flags |= WINED3D_BUFFER_CREATEBO;
3967 wined3d_buffer_preload(dest);
3970 if (dest->buffer_object)
3972 unsigned char extrabytes = 0;
3973 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3974 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3975 * this may write 4 extra bytes beyond the area that should be written
3977 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3978 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3979 if(!dest_conv_addr) {
3980 ERR("Out of memory\n");
3981 /* Continue without storing converted vertices */
3983 dest_conv = dest_conv_addr;
3986 if (This->stateBlock->state.render_states[WINED3DRS_CLIPPING])
3988 static BOOL warned = FALSE;
3990 * The clipping code is not quite correct. Some things need
3991 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3992 * so disable clipping for now.
3993 * (The graphics in Half-Life are broken, and my processvertices
3994 * test crashes with IDirect3DDevice3)
3995 doClip = TRUE;
3997 doClip = FALSE;
3998 if(!warned) {
3999 warned = TRUE;
4000 FIXME("Clipping is broken and disabled for now\n");
4002 } else doClip = FALSE;
4003 dest_ptr = ((char *)buffer_get_sysmem(dest, gl_info)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4005 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4006 WINED3DTS_VIEW,
4007 &view_mat);
4008 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4009 WINED3DTS_PROJECTION,
4010 &proj_mat);
4011 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4012 WINED3DTS_WORLDMATRIX(0),
4013 &world_mat);
4015 TRACE("View mat:\n");
4016 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);
4017 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);
4018 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);
4019 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);
4021 TRACE("Proj mat:\n");
4022 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);
4023 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);
4024 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);
4025 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);
4027 TRACE("World mat:\n");
4028 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);
4029 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);
4030 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);
4031 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);
4033 /* Get the viewport */
4034 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4035 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4036 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4038 multiply_matrix(&mat,&view_mat,&world_mat);
4039 multiply_matrix(&mat,&proj_mat,&mat);
4041 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4043 for (i = 0; i < dwCount; i+= 1) {
4044 unsigned int tex_index;
4046 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4047 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4048 /* The position first */
4049 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
4050 const float *p = (const float *)(element->data + i * element->stride);
4051 float x, y, z, rhw;
4052 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4054 /* Multiplication with world, view and projection matrix */
4055 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);
4056 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);
4057 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);
4058 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);
4060 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4062 /* WARNING: The following things are taken from d3d7 and were not yet checked
4063 * against d3d8 or d3d9!
4066 /* Clipping conditions: From msdn
4068 * A vertex is clipped if it does not match the following requirements
4069 * -rhw < x <= rhw
4070 * -rhw < y <= rhw
4071 * 0 < z <= rhw
4072 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4074 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4075 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4079 if( !doClip ||
4080 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4081 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4082 ( rhw > eps ) ) ) {
4084 /* "Normal" viewport transformation (not clipped)
4085 * 1) The values are divided by rhw
4086 * 2) The y axis is negative, so multiply it with -1
4087 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4088 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4089 * 4) Multiply x with Width/2 and add Width/2
4090 * 5) The same for the height
4091 * 6) Add the viewpoint X and Y to the 2D coordinates and
4092 * The minimum Z value to z
4093 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4095 * Well, basically it's simply a linear transformation into viewport
4096 * coordinates
4099 x /= rhw;
4100 y /= rhw;
4101 z /= rhw;
4103 y *= -1;
4105 x *= vp.Width / 2;
4106 y *= vp.Height / 2;
4107 z *= vp.MaxZ - vp.MinZ;
4109 x += vp.Width / 2 + vp.X;
4110 y += vp.Height / 2 + vp.Y;
4111 z += vp.MinZ;
4113 rhw = 1 / rhw;
4114 } else {
4115 /* That vertex got clipped
4116 * Contrary to OpenGL it is not dropped completely, it just
4117 * undergoes a different calculation.
4119 TRACE("Vertex got clipped\n");
4120 x += rhw;
4121 y += rhw;
4123 x /= 2;
4124 y /= 2;
4126 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4127 * outside of the main vertex buffer memory. That needs some more
4128 * investigation...
4132 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4135 ( (float *) dest_ptr)[0] = x;
4136 ( (float *) dest_ptr)[1] = y;
4137 ( (float *) dest_ptr)[2] = z;
4138 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4140 dest_ptr += 3 * sizeof(float);
4142 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4143 dest_ptr += sizeof(float);
4146 if(dest_conv) {
4147 float w = 1 / rhw;
4148 ( (float *) dest_conv)[0] = x * w;
4149 ( (float *) dest_conv)[1] = y * w;
4150 ( (float *) dest_conv)[2] = z * w;
4151 ( (float *) dest_conv)[3] = w;
4153 dest_conv += 3 * sizeof(float);
4155 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4156 dest_conv += sizeof(float);
4160 if (DestFVF & WINED3DFVF_PSIZE) {
4161 dest_ptr += sizeof(DWORD);
4162 if(dest_conv) dest_conv += sizeof(DWORD);
4164 if (DestFVF & WINED3DFVF_NORMAL) {
4165 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4166 const float *normal = (const float *)(element->data + i * element->stride);
4167 /* AFAIK this should go into the lighting information */
4168 FIXME("Didn't expect the destination to have a normal\n");
4169 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4170 if(dest_conv) {
4171 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4175 if (DestFVF & WINED3DFVF_DIFFUSE) {
4176 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4177 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4178 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
4180 static BOOL warned = FALSE;
4182 if(!warned) {
4183 ERR("No diffuse color in source, but destination has one\n");
4184 warned = TRUE;
4187 *( (DWORD *) dest_ptr) = 0xffffffff;
4188 dest_ptr += sizeof(DWORD);
4190 if(dest_conv) {
4191 *( (DWORD *) dest_conv) = 0xffffffff;
4192 dest_conv += sizeof(DWORD);
4195 else {
4196 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4197 if(dest_conv) {
4198 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4199 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4200 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4201 dest_conv += sizeof(DWORD);
4206 if (DestFVF & WINED3DFVF_SPECULAR)
4208 /* What's the color value in the feedback buffer? */
4209 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4210 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4211 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
4213 static BOOL warned = FALSE;
4215 if(!warned) {
4216 ERR("No specular color in source, but destination has one\n");
4217 warned = TRUE;
4220 *( (DWORD *) dest_ptr) = 0xFF000000;
4221 dest_ptr += sizeof(DWORD);
4223 if(dest_conv) {
4224 *( (DWORD *) dest_conv) = 0xFF000000;
4225 dest_conv += sizeof(DWORD);
4228 else {
4229 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4230 if(dest_conv) {
4231 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4232 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4233 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4234 dest_conv += sizeof(DWORD);
4239 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4240 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4241 const float *tex_coord = (const float *)(element->data + i * element->stride);
4242 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
4244 ERR("No source texture, but destination requests one\n");
4245 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4246 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4248 else {
4249 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4250 if(dest_conv) {
4251 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4257 if (dest_conv)
4259 ENTER_GL();
4261 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4262 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4263 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4264 dwCount * get_flexible_vertex_size(DestFVF),
4265 dest_conv_addr));
4266 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4268 LEAVE_GL();
4270 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4273 return WINED3D_OK;
4275 #undef copy_and_next
4277 /* Do not call while under the GL lock. */
4278 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface,
4279 UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, struct wined3d_buffer *dst_buffer,
4280 struct wined3d_vertex_declaration *pVertexDecl, DWORD flags, DWORD DestFVF)
4282 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4283 struct wined3d_stream_info stream_info;
4284 const struct wined3d_gl_info *gl_info;
4285 struct wined3d_context *context;
4286 BOOL vbo = FALSE, streamWasUP = This->stateBlock->state.user_stream;
4287 HRESULT hr;
4289 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, dst_buffer, pVertexDecl, flags);
4291 if(pVertexDecl) {
4292 ERR("Output vertex declaration not implemented yet\n");
4295 /* Need any context to write to the vbo. */
4296 context = context_acquire(This, NULL);
4297 gl_info = context->gl_info;
4299 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4300 * control the streamIsUP flag, thus restore it afterwards.
4302 This->stateBlock->state.user_stream = FALSE;
4303 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4304 This->stateBlock->state.user_stream = streamWasUP;
4306 if(vbo || SrcStartIndex) {
4307 unsigned int i;
4308 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4309 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4311 * Also get the start index in, but only loop over all elements if there's something to add at all.
4313 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4315 struct wined3d_stream_info_element *e;
4317 if (!(stream_info.use_map & (1 << i))) continue;
4319 e = &stream_info.elements[i];
4320 if (e->buffer_object)
4322 struct wined3d_buffer *vb = This->stateBlock->state.streams[e->stream_idx].buffer;
4323 e->buffer_object = 0;
4324 e->data = (BYTE *)((ULONG_PTR)e->data + (ULONG_PTR)buffer_get_sysmem(vb, gl_info));
4325 ENTER_GL();
4326 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4327 vb->buffer_object = 0;
4328 LEAVE_GL();
4330 if (e->data) e->data += e->stride * SrcStartIndex;
4334 hr = process_vertices_strided(This, DestIndex, VertexCount,
4335 &stream_info, dst_buffer, flags, DestFVF);
4337 context_release(context);
4339 return hr;
4342 /*****
4343 * Get / Set Texture Stage States
4344 * TODO: Verify against dx9 definitions
4345 *****/
4346 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value)
4348 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4349 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4350 DWORD oldValue;
4352 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4354 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4356 WARN("Invalid Type %d passed.\n", Type);
4357 return WINED3D_OK;
4360 if (Stage >= gl_info->limits.texture_stages)
4362 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
4363 Stage, gl_info->limits.texture_stages - 1);
4364 return WINED3D_OK;
4367 oldValue = This->updateStateBlock->state.texture_states[Stage][Type];
4368 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4369 This->updateStateBlock->state.texture_states[Stage][Type] = Value;
4371 if (This->isRecordingState) {
4372 TRACE("Recording... not performing anything\n");
4373 return WINED3D_OK;
4376 /* Checked after the assignments to allow proper stateblock recording */
4377 if(oldValue == Value) {
4378 TRACE("App is setting the old value over, nothing to do\n");
4379 return WINED3D_OK;
4382 if (Stage > This->stateBlock->state.lowest_disabled_stage
4383 && This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative
4384 == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP))
4386 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4387 * Changes in other states are important on disabled stages too
4389 return WINED3D_OK;
4392 if(Type == WINED3DTSS_COLOROP) {
4393 unsigned int i;
4395 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4396 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4397 * they have to be disabled
4399 * The current stage is dirtified below.
4401 for (i = Stage + 1; i < This->stateBlock->state.lowest_disabled_stage; ++i)
4403 TRACE("Additionally dirtifying stage %u\n", i);
4404 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4406 This->stateBlock->state.lowest_disabled_stage = Stage;
4407 TRACE("New lowest disabled: %u\n", Stage);
4408 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4409 /* Previously disabled stage enabled. Stages above it may need enabling
4410 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4411 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4413 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4416 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
4418 if (This->updateStateBlock->state.texture_states[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE)
4419 break;
4420 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4421 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4423 This->stateBlock->state.lowest_disabled_stage = i;
4424 TRACE("New lowest disabled: %u\n", i);
4428 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4430 return WINED3D_OK;
4433 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD *pValue)
4435 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4437 TRACE("iface %p, stage %u, state %s, value %p.\n",
4438 iface, Stage, debug_d3dtexturestate(Type), pValue);
4440 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4442 WARN("Invalid Type %d passed.\n", Type);
4443 return WINED3D_OK;
4446 *pValue = This->updateStateBlock->state.texture_states[Stage][Type];
4447 TRACE("Returning %#x.\n", *pValue);
4449 return WINED3D_OK;
4452 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4453 DWORD stage, struct wined3d_texture *texture)
4455 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4456 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4457 struct wined3d_texture *prev;
4459 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4461 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4462 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4464 /* Windows accepts overflowing this array... we do not. */
4465 if (stage >= sizeof(This->stateBlock->state.textures) / sizeof(*This->stateBlock->state.textures))
4467 WARN("Ignoring invalid stage %u.\n", stage);
4468 return WINED3D_OK;
4471 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4472 if (texture && texture->resource.pool == WINED3DPOOL_SCRATCH)
4474 WARN("Rejecting attempt to set scratch texture.\n");
4475 return WINED3DERR_INVALIDCALL;
4478 This->updateStateBlock->changed.textures |= 1 << stage;
4480 prev = This->updateStateBlock->state.textures[stage];
4481 TRACE("Previous texture %p.\n", prev);
4483 if (texture == prev)
4485 TRACE("App is setting the same texture again, nothing to do.\n");
4486 return WINED3D_OK;
4489 TRACE("Setting new texture to %p.\n", texture);
4490 This->updateStateBlock->state.textures[stage] = texture;
4492 if (This->isRecordingState)
4494 TRACE("Recording... not performing anything\n");
4496 if (texture) wined3d_texture_incref(texture);
4497 if (prev) wined3d_texture_decref(prev);
4499 return WINED3D_OK;
4502 if (texture)
4504 LONG bind_count = InterlockedIncrement(&texture->bind_count);
4506 wined3d_texture_incref(texture);
4508 if (!prev || texture->target != prev->target)
4509 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4511 if (!prev && stage < gl_info->limits.texture_stages)
4513 /* The source arguments for color and alpha ops have different
4514 * meanings when a NULL texture is bound, so the COLOROP and
4515 * ALPHAOP have to be dirtified. */
4516 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4517 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4520 if (bind_count == 1)
4521 texture->sampler = stage;
4524 if (prev)
4526 LONG bind_count = InterlockedDecrement(&prev->bind_count);
4528 wined3d_texture_decref(prev);
4530 if (!texture && stage < gl_info->limits.texture_stages)
4532 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4533 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4536 if (bind_count && prev->sampler == stage)
4538 unsigned int i;
4540 /* Search for other stages the texture is bound to. Shouldn't
4541 * happen if applications bind textures to a single stage only. */
4542 TRACE("Searching for other stages the texture is bound to.\n");
4543 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4545 if (This->updateStateBlock->state.textures[i] == prev)
4547 TRACE("Texture is also bound to stage %u.\n", i);
4548 prev->sampler = i;
4549 break;
4555 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4557 return WINED3D_OK;
4560 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface,
4561 DWORD stage, struct wined3d_texture **texture)
4563 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4565 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4567 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4568 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4570 if (stage >= sizeof(This->stateBlock->state.textures) / sizeof(*This->stateBlock->state.textures))
4572 WARN("Current stage overflows textures array (stage %u).\n", stage);
4573 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4576 *texture = This->stateBlock->state.textures[stage];
4577 if (*texture)
4578 wined3d_texture_incref(*texture);
4580 TRACE("Returning %p.\n", *texture);
4582 return WINED3D_OK;
4585 /*****
4586 * Get Back Buffer
4587 *****/
4588 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4589 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4591 IWineD3DSwapChain *swapchain;
4592 HRESULT hr;
4594 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4595 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4597 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4598 if (FAILED(hr))
4600 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4601 return hr;
4604 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4605 IWineD3DSwapChain_Release(swapchain);
4606 if (FAILED(hr))
4608 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4609 return hr;
4612 return WINED3D_OK;
4615 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS *caps)
4617 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4619 TRACE("iface %p, caps %p.\n", iface, caps);
4621 return wined3d_get_device_caps(device->wined3d, device->adapter->ordinal, device->devType, caps);
4624 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4625 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4626 IWineD3DSwapChain *swapChain;
4627 HRESULT hr;
4629 if(iSwapChain > 0) {
4630 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4631 if (hr == WINED3D_OK) {
4632 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4633 IWineD3DSwapChain_Release(swapChain);
4634 } else {
4635 FIXME("(%p) Error getting display mode\n", This);
4637 } else {
4638 /* Don't read the real display mode,
4639 but return the stored mode instead. X11 can't change the color
4640 depth, and some apps are pretty angry if they SetDisplayMode from
4641 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4643 Also don't relay to the swapchain because with ddraw it's possible
4644 that there isn't a swapchain at all */
4645 pMode->Width = This->ddraw_width;
4646 pMode->Height = This->ddraw_height;
4647 pMode->Format = This->ddraw_format;
4648 pMode->RefreshRate = 0;
4649 hr = WINED3D_OK;
4652 return hr;
4655 /*****
4656 * Stateblock related functions
4657 *****/
4659 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface)
4661 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4662 struct wined3d_stateblock *stateblock;
4663 HRESULT hr;
4665 TRACE("(%p)\n", This);
4667 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4669 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock);
4670 if (FAILED(hr)) return hr;
4672 wined3d_stateblock_decref(This->updateStateBlock);
4673 This->updateStateBlock = stateblock;
4674 This->isRecordingState = TRUE;
4676 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4678 return WINED3D_OK;
4681 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface,
4682 struct wined3d_stateblock **stateblock)
4684 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4685 struct wined3d_stateblock *object = This->updateStateBlock;
4687 TRACE("iface %p, stateblock %p.\n", iface, stateblock);
4689 if (!This->isRecordingState) {
4690 WARN("(%p) not recording! returning error\n", This);
4691 *stateblock = NULL;
4692 return WINED3DERR_INVALIDCALL;
4695 stateblock_init_contained_states(object);
4697 *stateblock = object;
4698 This->isRecordingState = FALSE;
4699 This->updateStateBlock = This->stateBlock;
4700 wined3d_stateblock_incref(This->updateStateBlock);
4702 TRACE("Returning stateblock %p.\n", *stateblock);
4704 return WINED3D_OK;
4707 /*****
4708 * Scene related functions
4709 *****/
4710 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4711 /* At the moment we have no need for any functionality at the beginning
4712 of a scene */
4713 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4714 TRACE("(%p)\n", This);
4716 if(This->inScene) {
4717 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4718 return WINED3DERR_INVALIDCALL;
4720 This->inScene = TRUE;
4721 return WINED3D_OK;
4724 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4726 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4727 struct wined3d_context *context;
4729 TRACE("(%p)\n", This);
4731 if(!This->inScene) {
4732 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4733 return WINED3DERR_INVALIDCALL;
4736 context = context_acquire(This, NULL);
4737 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4738 wglFlush();
4739 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4740 * fails. */
4741 context_release(context);
4743 This->inScene = FALSE;
4744 return WINED3D_OK;
4747 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4748 const RECT *pSourceRect, const RECT *pDestRect,
4749 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4751 IWineD3DSwapChain *swapChain = NULL;
4752 int i;
4753 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4755 TRACE("iface %p.\n", iface);
4757 for(i = 0 ; i < swapchains ; i ++) {
4759 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4760 TRACE("Presenting chain %d, %p.\n", i, swapChain);
4761 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4762 IWineD3DSwapChain_Release(swapChain);
4765 return WINED3D_OK;
4768 /* Do not call while under the GL lock. */
4769 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD rect_count,
4770 const RECT *rects, DWORD flags, WINED3DCOLOR color, float depth, DWORD stencil)
4772 const WINED3DCOLORVALUE c = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
4773 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4774 RECT draw_rect;
4776 TRACE("iface %p, rect_count %u, rects %p, flags %#x, color 0x%08x, depth %.8e, stencil %u.\n",
4777 iface, rect_count, rects, flags, color, depth, stencil);
4779 if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL))
4781 IWineD3DSurfaceImpl *ds = device->depth_stencil;
4782 if (!ds)
4784 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4785 /* TODO: What about depth stencil buffers without stencil bits? */
4786 return WINED3DERR_INVALIDCALL;
4788 else if (flags & WINED3DCLEAR_TARGET)
4790 if(ds->resource.width < device->render_targets[0]->resource.width ||
4791 ds->resource.height < device->render_targets[0]->resource.height)
4793 WARN("Silently ignoring depth and target clear with mismatching sizes\n");
4794 return WINED3D_OK;
4799 device_get_draw_rect(device, &draw_rect);
4801 return device_clear_render_targets(device, device->adapter->gl_info.limits.buffers,
4802 device->render_targets, rect_count, rects, &draw_rect, flags, &c, depth, stencil);
4805 /*****
4806 * Drawing functions
4807 *****/
4809 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4810 WINED3DPRIMITIVETYPE primitive_type)
4812 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4814 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4816 This->updateStateBlock->changed.primitive_type = TRUE;
4817 This->updateStateBlock->state.gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4820 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4821 WINED3DPRIMITIVETYPE *primitive_type)
4823 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4825 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4827 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->state.gl_primitive_type);
4829 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4832 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4834 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4836 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4838 if (!This->stateBlock->state.vertex_declaration)
4840 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4841 return WINED3DERR_INVALIDCALL;
4844 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4845 if (This->stateBlock->state.user_stream)
4847 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4848 This->stateBlock->state.user_stream = FALSE;
4851 if (This->stateBlock->state.load_base_vertex_index)
4853 This->stateBlock->state.load_base_vertex_index = 0;
4854 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4856 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4857 drawPrimitive(This, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4858 return WINED3D_OK;
4861 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4863 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4864 struct wined3d_buffer *index_buffer;
4865 UINT idxStride = 2;
4866 GLuint vbo;
4868 index_buffer = This->stateBlock->state.index_buffer;
4869 if (!index_buffer)
4871 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4872 * without an index buffer set. (The first time at least...)
4873 * D3D8 simply dies, but I doubt it can do much harm to return
4874 * D3DERR_INVALIDCALL there as well. */
4875 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4876 return WINED3DERR_INVALIDCALL;
4879 if (!This->stateBlock->state.vertex_declaration)
4881 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4882 return WINED3DERR_INVALIDCALL;
4885 if (This->stateBlock->state.user_stream)
4887 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4888 This->stateBlock->state.user_stream = FALSE;
4890 vbo = index_buffer->buffer_object;
4892 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4894 if (This->stateBlock->state.index_format == WINED3DFMT_R16_UINT)
4895 idxStride = 2;
4896 else
4897 idxStride = 4;
4899 if (This->stateBlock->state.load_base_vertex_index != This->stateBlock->state.base_vertex_index)
4901 This->stateBlock->state.load_base_vertex_index = This->stateBlock->state.base_vertex_index;
4902 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4905 drawPrimitive(This, index_count, startIndex, idxStride,
4906 vbo ? NULL : index_buffer->resource.allocatedMemory);
4908 return WINED3D_OK;
4911 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4912 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4914 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4915 struct wined3d_stream_state *stream;
4916 struct wined3d_buffer *vb;
4918 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4919 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4921 if (!This->stateBlock->state.vertex_declaration)
4923 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4924 return WINED3DERR_INVALIDCALL;
4927 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4928 stream = &This->stateBlock->state.streams[0];
4929 vb = stream->buffer;
4930 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4931 if (vb)
4932 wined3d_buffer_decref(vb);
4933 stream->offset = 0;
4934 stream->stride = VertexStreamZeroStride;
4935 This->stateBlock->state.user_stream = TRUE;
4936 This->stateBlock->state.load_base_vertex_index = 0;
4938 /* TODO: Only mark dirty if drawing from a different UP address */
4939 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4941 drawPrimitive(This, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4943 /* MSDN specifies stream zero settings must be set to NULL */
4944 stream->buffer = NULL;
4945 stream->stride = 0;
4947 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4948 * the new stream sources or use UP drawing again
4950 return WINED3D_OK;
4953 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4954 UINT index_count, const void *pIndexData, enum wined3d_format_id IndexDataFormat,
4955 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4957 int idxStride;
4958 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4959 struct wined3d_stream_state *stream;
4960 struct wined3d_buffer *vb, *ib;
4962 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4963 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4965 if (!This->stateBlock->state.vertex_declaration)
4967 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4968 return WINED3DERR_INVALIDCALL;
4971 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4972 idxStride = 2;
4973 } else {
4974 idxStride = 4;
4977 stream = &This->stateBlock->state.streams[0];
4978 vb = stream->buffer;
4979 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4980 if (vb)
4981 wined3d_buffer_decref(vb);
4982 stream->offset = 0;
4983 stream->stride = VertexStreamZeroStride;
4984 This->stateBlock->state.user_stream = TRUE;
4986 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4987 This->stateBlock->state.base_vertex_index = 0;
4988 This->stateBlock->state.load_base_vertex_index = 0;
4989 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4990 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4991 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4993 drawPrimitive(This, index_count, 0 /* start_idx */, idxStride, pIndexData);
4995 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4996 stream->buffer = NULL;
4997 stream->stride = 0;
4998 ib = This->stateBlock->state.index_buffer;
4999 if (ib)
5001 wined3d_buffer_decref(ib);
5002 This->stateBlock->state.index_buffer = NULL;
5004 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5005 * SetStreamSource to specify a vertex buffer
5008 return WINED3D_OK;
5011 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5012 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
5014 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5016 /* Mark the state dirty until we have nicer tracking
5017 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5018 * that value.
5020 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5021 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5022 This->stateBlock->state.base_vertex_index = 0;
5023 This->up_strided = DrawPrimStrideData;
5024 drawPrimitive(This, vertex_count, 0, 0, NULL);
5025 This->up_strided = NULL;
5026 return WINED3D_OK;
5029 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5030 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
5031 UINT NumVertices, const void *pIndexData, enum wined3d_format_id IndexDataFormat)
5033 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5034 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
5036 /* Mark the state dirty until we have nicer tracking
5037 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5038 * that value.
5040 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5041 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5042 This->stateBlock->state.user_stream = TRUE;
5043 This->stateBlock->state.base_vertex_index = 0;
5044 This->up_strided = DrawPrimStrideData;
5045 drawPrimitive(This, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
5046 This->up_strided = NULL;
5047 return WINED3D_OK;
5050 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
5051 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
5052 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
5054 WINED3DLOCKED_BOX src;
5055 WINED3DLOCKED_BOX dst;
5056 HRESULT hr;
5058 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
5059 iface, pSourceVolume, pDestinationVolume);
5061 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5062 * dirtification to improve loading performance.
5064 hr = IWineD3DVolume_Map(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5065 if (FAILED(hr)) return hr;
5066 hr = IWineD3DVolume_Map(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5067 if (FAILED(hr))
5069 IWineD3DVolume_Unmap(pSourceVolume);
5070 return hr;
5073 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5075 hr = IWineD3DVolume_Unmap(pDestinationVolume);
5076 if (FAILED(hr))
5077 IWineD3DVolume_Unmap(pSourceVolume);
5078 else
5079 hr = IWineD3DVolume_Unmap(pSourceVolume);
5081 return hr;
5084 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
5085 struct wined3d_texture *src_texture, struct wined3d_texture *dst_texture)
5087 unsigned int level_count, i;
5088 WINED3DRESOURCETYPE type;
5089 HRESULT hr;
5091 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
5093 /* Verify that the source and destination textures are non-NULL. */
5094 if (!src_texture || !dst_texture)
5096 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
5097 return WINED3DERR_INVALIDCALL;
5100 if (src_texture == dst_texture)
5102 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
5103 return WINED3DERR_INVALIDCALL;
5106 /* Verify that the source and destination textures are the same type. */
5107 type = wined3d_texture_get_type(src_texture);
5108 if (wined3d_texture_get_type(dst_texture) != type)
5110 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
5111 return WINED3DERR_INVALIDCALL;
5114 /* Check that both textures have the identical numbers of levels. */
5115 level_count = wined3d_texture_get_level_count(src_texture);
5116 if (wined3d_texture_get_level_count(dst_texture) != level_count)
5118 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
5119 return WINED3DERR_INVALIDCALL;
5122 /* Make sure that the destination texture is loaded. */
5123 dst_texture->texture_ops->texture_preload(dst_texture, SRGB_RGB);
5125 /* Update every surface level of the texture. */
5126 switch (type)
5128 case WINED3DRTYPE_TEXTURE:
5130 IWineD3DSurface *src_surface;
5131 IWineD3DSurface *dst_surface;
5133 for (i = 0; i < level_count; ++i)
5135 src_surface = (IWineD3DSurface *)surface_from_resource(wined3d_texture_get_sub_resource(
5136 src_texture, i));
5137 dst_surface = (IWineD3DSurface *)surface_from_resource(wined3d_texture_get_sub_resource(
5138 dst_texture, i));
5139 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5140 if (FAILED(hr))
5142 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5143 return hr;
5146 break;
5149 case WINED3DRTYPE_CUBETEXTURE:
5151 IWineD3DSurface *src_surface;
5152 IWineD3DSurface *dst_surface;
5154 for (i = 0; i < level_count * 6; ++i)
5156 src_surface = (IWineD3DSurface *)surface_from_resource(wined3d_texture_get_sub_resource(
5157 src_texture, i));
5158 dst_surface = (IWineD3DSurface *)surface_from_resource(wined3d_texture_get_sub_resource(
5159 dst_texture, i));
5160 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5161 if (FAILED(hr))
5163 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5164 return hr;
5167 break;
5170 case WINED3DRTYPE_VOLUMETEXTURE:
5172 IWineD3DVolume *src_volume;
5173 IWineD3DVolume *dst_volume;
5175 for (i = 0; i < level_count; ++i)
5177 src_volume = (IWineD3DVolume *)volume_from_resource(wined3d_texture_get_sub_resource(src_texture, i));
5178 dst_volume = (IWineD3DVolume *)volume_from_resource(wined3d_texture_get_sub_resource(dst_texture, i));
5179 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
5180 if (FAILED(hr))
5182 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
5183 return hr;
5186 break;
5189 default:
5190 FIXME("Unsupported texture type %#x.\n", type);
5191 return WINED3DERR_INVALIDCALL;
5194 return WINED3D_OK;
5197 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,
5198 UINT swapchain_idx, IWineD3DSurface *dst_surface)
5200 IWineD3DSwapChain *swapchain;
5201 HRESULT hr;
5203 TRACE("iface %p, swapchain_idx %u, dst_surface %p.\n", iface, swapchain_idx, dst_surface);
5205 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5206 if (FAILED(hr)) return hr;
5208 hr = IWineD3DSwapChain_GetFrontBufferData(swapchain, dst_surface);
5209 IWineD3DSwapChain_Release(swapchain);
5211 return hr;
5214 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD *pNumPasses)
5216 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5217 const struct wined3d_state *state = &This->stateBlock->state;
5218 struct wined3d_texture *texture;
5219 DWORD i;
5221 TRACE("(%p) : %p\n", This, pNumPasses);
5223 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5225 if (state->sampler_states[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE)
5227 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5228 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5230 if (state->sampler_states[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE)
5232 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5233 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5236 texture = state->textures[i];
5237 if (!texture || texture->resource.format->flags & WINED3DFMT_FLAG_FILTERING) continue;
5239 if (state->sampler_states[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT)
5241 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5242 return E_FAIL;
5244 if (state->sampler_states[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT)
5246 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5247 return E_FAIL;
5249 if (state->sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE
5250 && state->sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT)
5252 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5253 return E_FAIL;
5257 if (state->render_states[WINED3DRS_ZENABLE] || state->render_states[WINED3DRS_ZWRITEENABLE] ||
5258 state->render_states[WINED3DRS_STENCILENABLE])
5260 IWineD3DSurfaceImpl *ds = This->depth_stencil;
5261 IWineD3DSurfaceImpl *target = This->render_targets[0];
5263 if(ds && target
5264 && (ds->resource.width < target->resource.width || ds->resource.height < target->resource.height))
5266 WARN("Depth stencil is smaller than the color buffer, returning D3DERR_CONFLICTINGRENDERSTATE\n");
5267 return WINED3DERR_CONFLICTINGRENDERSTATE;
5271 /* return a sensible default */
5272 *pNumPasses = 1;
5274 TRACE("returning D3D_OK\n");
5275 return WINED3D_OK;
5278 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5280 int i;
5282 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5284 struct wined3d_texture *texture = device->stateBlock->state.textures[i];
5285 if (texture && (texture->resource.format->id == WINED3DFMT_P8_UINT
5286 || texture->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM))
5288 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5293 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5294 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5295 int j;
5296 UINT NewSize;
5297 PALETTEENTRY **palettes;
5299 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5301 if (PaletteNumber >= MAX_PALETTES) {
5302 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5303 return WINED3DERR_INVALIDCALL;
5306 if (PaletteNumber >= This->NumberOfPalettes) {
5307 NewSize = This->NumberOfPalettes;
5308 do {
5309 NewSize *= 2;
5310 } while(PaletteNumber >= NewSize);
5311 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5312 if (!palettes) {
5313 ERR("Out of memory!\n");
5314 return E_OUTOFMEMORY;
5316 This->palettes = palettes;
5317 This->NumberOfPalettes = NewSize;
5320 if (!This->palettes[PaletteNumber]) {
5321 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5322 if (!This->palettes[PaletteNumber]) {
5323 ERR("Out of memory!\n");
5324 return E_OUTOFMEMORY;
5328 for (j = 0; j < 256; ++j) {
5329 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5330 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5331 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5332 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5334 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5335 TRACE("(%p) : returning\n", This);
5336 return WINED3D_OK;
5339 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5340 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5341 int j;
5342 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5343 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5344 /* What happens in such situation isn't documented; Native seems to silently abort
5345 on such conditions. Return Invalid Call. */
5346 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5347 return WINED3DERR_INVALIDCALL;
5349 for (j = 0; j < 256; ++j) {
5350 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5351 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5352 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5353 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5355 TRACE("(%p) : returning\n", This);
5356 return WINED3D_OK;
5359 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5360 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5361 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5362 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5363 (tested with reference rasterizer). Return Invalid Call. */
5364 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5365 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5366 return WINED3DERR_INVALIDCALL;
5368 /*TODO: stateblocks */
5369 if (This->currentPalette != PaletteNumber) {
5370 This->currentPalette = PaletteNumber;
5371 dirtify_p8_texture_samplers(This);
5373 TRACE("(%p) : returning\n", This);
5374 return WINED3D_OK;
5377 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5378 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5380 if (!PaletteNumber)
5382 WARN("(%p) : returning Invalid Call\n", This);
5383 return WINED3DERR_INVALIDCALL;
5385 /*TODO: stateblocks */
5386 *PaletteNumber = This->currentPalette;
5387 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5388 return WINED3D_OK;
5391 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5392 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5393 static BOOL warned;
5394 if (!warned)
5396 FIXME("(%p) : stub\n", This);
5397 warned = TRUE;
5400 This->softwareVertexProcessing = bSoftware;
5401 return WINED3D_OK;
5405 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5406 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5407 static BOOL warned;
5408 if (!warned)
5410 FIXME("(%p) : stub\n", This);
5411 warned = TRUE;
5413 return This->softwareVertexProcessing;
5416 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5417 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5419 IWineD3DSwapChain *swapchain;
5420 HRESULT hr;
5422 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5423 iface, swapchain_idx, raster_status);
5425 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5426 if (FAILED(hr))
5428 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5429 return hr;
5432 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5433 IWineD3DSwapChain_Release(swapchain);
5434 if (FAILED(hr))
5436 WARN("Failed to get raster status, hr %#x.\n", hr);
5437 return hr;
5440 return WINED3D_OK;
5443 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5445 static BOOL warned;
5446 if(nSegments != 0.0f) {
5447 if (!warned)
5449 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5450 warned = TRUE;
5453 return WINED3D_OK;
5456 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5458 static BOOL warned;
5459 if (!warned)
5461 FIXME("iface %p stub!\n", iface);
5462 warned = TRUE;
5464 return 0.0f;
5467 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface,
5468 IWineD3DSurface *src_surface, const RECT *src_rect,
5469 IWineD3DSurface *dst_surface, const POINT *dst_point)
5471 IWineD3DSurfaceImpl *src_impl = (IWineD3DSurfaceImpl *)src_surface;
5472 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)dst_surface;
5473 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5474 const struct wined3d_format *src_format;
5475 const struct wined3d_format *dst_format;
5476 const struct wined3d_gl_info *gl_info;
5477 struct wined3d_context *context;
5478 const unsigned char *data;
5479 UINT update_w, update_h;
5480 CONVERT_TYPES convert;
5481 UINT src_w, src_h;
5482 UINT dst_x, dst_y;
5483 DWORD sampler;
5484 struct wined3d_format format;
5486 TRACE("iface %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s.\n",
5487 iface, src_surface, wine_dbgstr_rect(src_rect),
5488 dst_surface, wine_dbgstr_point(dst_point));
5490 if (src_impl->resource.pool != WINED3DPOOL_SYSTEMMEM || dst_impl->resource.pool != WINED3DPOOL_DEFAULT)
5492 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
5493 src_surface, dst_surface);
5494 return WINED3DERR_INVALIDCALL;
5497 src_format = src_impl->resource.format;
5498 dst_format = dst_impl->resource.format;
5500 if (src_format->id != dst_format->id)
5502 WARN("Source and destination surfaces should have the same format.\n");
5503 return WINED3DERR_INVALIDCALL;
5506 dst_x = dst_point ? dst_point->x : 0;
5507 dst_y = dst_point ? dst_point->y : 0;
5509 /* This call loads the OpenGL surface directly, instead of copying the
5510 * surface to the destination's sysmem copy. If surface conversion is
5511 * needed, use BltFast instead to copy in sysmem and use regular surface
5512 * loading. */
5513 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &format, &convert);
5514 if (convert != NO_CONVERSION || format.convert)
5515 return IWineD3DSurface_BltFast(dst_surface, dst_x, dst_y, src_surface, src_rect, 0);
5517 context = context_acquire(This, NULL);
5518 gl_info = context->gl_info;
5520 ENTER_GL();
5521 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5522 checkGLcall("glActiveTextureARB");
5523 LEAVE_GL();
5525 /* Make sure the surface is loaded and up to date */
5526 surface_internal_preload(dst_impl, SRGB_RGB);
5527 surface_bind(dst_impl, gl_info, FALSE);
5529 src_w = src_impl->resource.width;
5530 src_h = src_impl->resource.height;
5531 update_w = src_rect ? src_rect->right - src_rect->left : src_w;
5532 update_h = src_rect ? src_rect->bottom - src_rect->top : src_h;
5534 data = src_impl->resource.allocatedMemory;
5535 if (!data) ERR("Source surface has no allocated memory, but should be a sysmem surface.\n");
5537 ENTER_GL();
5539 if (dst_format->flags & WINED3DFMT_FLAG_COMPRESSED)
5541 UINT row_length = wined3d_format_calculate_size(src_format, 1, update_w, 1);
5542 UINT row_count = (update_h + src_format->block_height - 1) / src_format->block_height;
5543 UINT src_pitch = wined3d_format_calculate_size(src_format, 1, src_w, 1);
5545 if (src_rect)
5547 data += (src_rect->top / src_format->block_height) * src_pitch;
5548 data += (src_rect->left / src_format->block_width) * src_format->block_byte_count;
5551 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
5552 "format %#x, image_size %#x, data %p.\n", dst_impl->texture_target, dst_impl->texture_level,
5553 dst_x, dst_y, update_w, update_h, dst_format->glFormat, row_count * row_length, data);
5555 if (row_length == src_pitch)
5557 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5558 dst_x, dst_y, update_w, update_h, dst_format->glInternal, row_count * row_length, data));
5560 else
5562 UINT row, y;
5564 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
5565 * can't use the unpack row length like below. */
5566 for (row = 0, y = dst_y; row < row_count; ++row)
5568 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5569 dst_x, y, update_w, src_format->block_height, dst_format->glInternal, row_length, data));
5570 y += src_format->block_height;
5571 data += src_pitch;
5574 checkGLcall("glCompressedTexSubImage2DARB");
5576 else
5578 if (src_rect)
5580 data += src_rect->top * src_w * src_format->byte_count;
5581 data += src_rect->left * src_format->byte_count;
5584 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, data %p.\n",
5585 dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5586 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5588 glPixelStorei(GL_UNPACK_ROW_LENGTH, src_w);
5589 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5590 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5591 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
5592 checkGLcall("glTexSubImage2D");
5595 LEAVE_GL();
5596 context_release(context);
5598 surface_modify_location(dst_impl, SFLAG_INTEXTURE, TRUE);
5599 sampler = This->rev_tex_unit_map[0];
5600 if (sampler != WINED3D_UNMAPPED_STAGE)
5602 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5605 return WINED3D_OK;
5608 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5609 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5610 struct WineD3DRectPatch *patch;
5611 GLenum old_primitive_type;
5612 unsigned int i;
5613 struct list *e;
5614 BOOL found;
5615 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5617 if(!(Handle || pRectPatchInfo)) {
5618 /* TODO: Write a test for the return value, thus the FIXME */
5619 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5620 return WINED3DERR_INVALIDCALL;
5623 if(Handle) {
5624 i = PATCHMAP_HASHFUNC(Handle);
5625 found = FALSE;
5626 LIST_FOR_EACH(e, &This->patches[i]) {
5627 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5628 if(patch->Handle == Handle) {
5629 found = TRUE;
5630 break;
5634 if(!found) {
5635 TRACE("Patch does not exist. Creating a new one\n");
5636 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5637 patch->Handle = Handle;
5638 list_add_head(&This->patches[i], &patch->entry);
5639 } else {
5640 TRACE("Found existing patch %p\n", patch);
5642 } else {
5643 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5644 * attributes we have to tesselate, read back, and draw. This needs a patch
5645 * management structure instance. Create one.
5647 * A possible improvement is to check if a vertex shader is used, and if not directly
5648 * draw the patch.
5650 FIXME("Drawing an uncached patch. This is slow\n");
5651 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5654 if (pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1]
5655 || pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3]
5656 || (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo))))
5658 HRESULT hr;
5659 TRACE("Tesselation density or patch info changed, retesselating\n");
5661 if(pRectPatchInfo) {
5662 patch->RectPatchInfo = *pRectPatchInfo;
5664 patch->numSegs[0] = pNumSegs[0];
5665 patch->numSegs[1] = pNumSegs[1];
5666 patch->numSegs[2] = pNumSegs[2];
5667 patch->numSegs[3] = pNumSegs[3];
5669 hr = tesselate_rectpatch(This, patch);
5670 if(FAILED(hr)) {
5671 WARN("Patch tesselation failed\n");
5673 /* Do not release the handle to store the params of the patch */
5674 if(!Handle) {
5675 HeapFree(GetProcessHeap(), 0, patch);
5677 return hr;
5681 This->currentPatch = patch;
5682 old_primitive_type = This->stateBlock->state.gl_primitive_type;
5683 This->stateBlock->state.gl_primitive_type = GL_TRIANGLES;
5684 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5685 This->stateBlock->state.gl_primitive_type = old_primitive_type;
5686 This->currentPatch = NULL;
5688 /* Destroy uncached patches */
5689 if(!Handle) {
5690 HeapFree(GetProcessHeap(), 0, patch->mem);
5691 HeapFree(GetProcessHeap(), 0, patch);
5693 return WINED3D_OK;
5696 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5697 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5699 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5700 iface, handle, segment_count, patch_info);
5702 return WINED3D_OK;
5705 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5706 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5707 int i;
5708 struct WineD3DRectPatch *patch;
5709 struct list *e;
5710 TRACE("(%p) Handle(%d)\n", This, Handle);
5712 i = PATCHMAP_HASHFUNC(Handle);
5713 LIST_FOR_EACH(e, &This->patches[i]) {
5714 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5715 if(patch->Handle == Handle) {
5716 TRACE("Deleting patch %p\n", patch);
5717 list_remove(&patch->entry);
5718 HeapFree(GetProcessHeap(), 0, patch->mem);
5719 HeapFree(GetProcessHeap(), 0, patch);
5720 return WINED3D_OK;
5724 /* TODO: Write a test for the return value */
5725 FIXME("Attempt to destroy nonexistent patch\n");
5726 return WINED3DERR_INVALIDCALL;
5729 /* Do not call while under the GL lock. */
5730 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5731 IWineD3DSurface *surface, const RECT *rect, const WINED3DCOLORVALUE *color)
5733 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)surface;
5735 TRACE("iface %p, surface %p, rect %s, color {%.8e, %.8e, %.8e, %.8e}.\n",
5736 iface, surface, wine_dbgstr_rect(rect),
5737 color->r, color->g, color->b, color->a);
5739 if (s->resource.pool != WINED3DPOOL_DEFAULT && s->resource.pool != WINED3DPOOL_SYSTEMMEM)
5741 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5742 return WINED3DERR_INVALIDCALL;
5745 return surface_color_fill(s, rect, color);
5748 /* Do not call while under the GL lock. */
5749 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5750 IWineD3DRendertargetView *rendertarget_view, const WINED3DCOLORVALUE *color)
5752 struct wined3d_resource *resource;
5753 HRESULT hr;
5755 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5756 if (FAILED(hr))
5758 ERR("Failed to get resource, hr %#x\n", hr);
5759 return;
5762 if (resource->resourceType != WINED3DRTYPE_SURFACE)
5764 FIXME("Only supported on surface resources\n");
5765 return;
5768 hr = surface_color_fill(surface_from_resource(resource), NULL, color);
5769 if (FAILED(hr)) ERR("Color fill failed, hr %#x.\n", hr);
5772 /* rendertarget and depth stencil functions */
5773 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice *iface,
5774 DWORD render_target_idx, IWineD3DSurface **render_target)
5776 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5778 TRACE("iface %p, render_target_idx %u, render_target %p.\n",
5779 iface, render_target_idx, render_target);
5781 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5783 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5784 return WINED3DERR_INVALIDCALL;
5787 *render_target = (IWineD3DSurface *)device->render_targets[render_target_idx];
5788 if (*render_target) IWineD3DSurface_AddRef(*render_target);
5790 TRACE("Returning render target %p.\n", *render_target);
5792 return WINED3D_OK;
5795 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface **depth_stencil)
5797 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5799 TRACE("iface %p, depth_stencil %p.\n", iface, depth_stencil);
5801 *depth_stencil = (IWineD3DSurface *)device->depth_stencil;
5802 TRACE("Returning depth/stencil surface %p.\n", *depth_stencil);
5803 if (!*depth_stencil) return WINED3DERR_NOTFOUND;
5804 IWineD3DSurface_AddRef(*depth_stencil);
5806 return WINED3D_OK;
5809 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface,
5810 DWORD render_target_idx, IWineD3DSurface *render_target, BOOL set_viewport)
5812 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5813 IWineD3DSurfaceImpl *prev;
5815 TRACE("iface %p, render_target_idx %u, render_target %p, set_viewport %#x.\n",
5816 iface, render_target_idx, render_target, set_viewport);
5818 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5820 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5821 return WINED3DERR_INVALIDCALL;
5824 prev = device->render_targets[render_target_idx];
5825 if (render_target == (IWineD3DSurface *)prev)
5827 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5828 return WINED3D_OK;
5831 /* Render target 0 can't be set to NULL. */
5832 if (!render_target && !render_target_idx)
5834 WARN("Trying to set render target 0 to NULL.\n");
5835 return WINED3DERR_INVALIDCALL;
5838 if (render_target && !(((IWineD3DSurfaceImpl *)render_target)->resource.usage & WINED3DUSAGE_RENDERTARGET))
5840 FIXME("Surface %p doesn't have render target usage.\n", render_target);
5841 return WINED3DERR_INVALIDCALL;
5844 if (render_target) IWineD3DSurface_AddRef(render_target);
5845 device->render_targets[render_target_idx] = (IWineD3DSurfaceImpl *)render_target;
5846 /* Release after the assignment, to prevent device_resource_released()
5847 * from seeing the surface as still in use. */
5848 if (prev) IWineD3DSurface_Release((IWineD3DSurface *)prev);
5850 /* Render target 0 is special. */
5851 if (!render_target_idx && set_viewport)
5853 /* Set the viewport and scissor rectangles, if requested. Tests show
5854 * that stateblock recording is ignored, the change goes directly
5855 * into the primary stateblock. */
5856 device->stateBlock->state.viewport.Height = device->render_targets[0]->resource.height;
5857 device->stateBlock->state.viewport.Width = device->render_targets[0]->resource.width;
5858 device->stateBlock->state.viewport.X = 0;
5859 device->stateBlock->state.viewport.Y = 0;
5860 device->stateBlock->state.viewport.MaxZ = 1.0f;
5861 device->stateBlock->state.viewport.MinZ = 0.0f;
5862 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_VIEWPORT);
5864 device->stateBlock->state.scissor_rect.top = 0;
5865 device->stateBlock->state.scissor_rect.left = 0;
5866 device->stateBlock->state.scissor_rect.right = device->stateBlock->state.viewport.Width;
5867 device->stateBlock->state.scissor_rect.bottom = device->stateBlock->state.viewport.Height;
5868 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SCISSORRECT);
5871 return WINED3D_OK;
5874 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil)
5876 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5877 IWineD3DSurfaceImpl *tmp;
5879 TRACE("device %p, depth_stencil %p, old depth_stencil %p.\n", This, depth_stencil, This->depth_stencil);
5881 if (This->depth_stencil == (IWineD3DSurfaceImpl *)depth_stencil)
5883 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5884 return WINED3D_OK;
5887 if (This->depth_stencil)
5889 if (This->swapchains[0]->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5890 || This->depth_stencil->flags & SFLAG_DISCARD)
5892 surface_modify_ds_location(This->depth_stencil, SFLAG_DS_DISCARDED,
5893 This->depth_stencil->resource.width,
5894 This->depth_stencil->resource.height);
5895 if (This->depth_stencil == This->onscreen_depth_stencil)
5897 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
5898 This->onscreen_depth_stencil = NULL;
5903 tmp = This->depth_stencil;
5904 This->depth_stencil = (IWineD3DSurfaceImpl *)depth_stencil;
5905 if (This->depth_stencil) IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
5906 if (tmp) IWineD3DSurface_Release((IWineD3DSurface *)tmp);
5908 if ((!tmp && depth_stencil) || (!depth_stencil && tmp))
5910 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5911 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5912 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5913 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5916 return WINED3D_OK;
5919 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice *iface,
5920 UINT XHotSpot, UINT YHotSpot, IWineD3DSurface *cursor_image)
5922 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5923 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)cursor_image;
5924 WINED3DLOCKED_RECT lockedRect;
5926 TRACE("iface %p, hotspot_x %u, hotspot_y %u, cursor_image %p.\n",
5927 iface, XHotSpot, YHotSpot, cursor_image);
5929 /* some basic validation checks */
5930 if (This->cursorTexture)
5932 struct wined3d_context *context = context_acquire(This, NULL);
5933 ENTER_GL();
5934 glDeleteTextures(1, &This->cursorTexture);
5935 LEAVE_GL();
5936 context_release(context);
5937 This->cursorTexture = 0;
5940 if (s->resource.width == 32 && s->resource.height == 32)
5941 This->haveHardwareCursor = TRUE;
5942 else
5943 This->haveHardwareCursor = FALSE;
5945 if (cursor_image)
5947 WINED3DLOCKED_RECT rect;
5949 /* MSDN: Cursor must be A8R8G8B8 */
5950 if (s->resource.format->id != WINED3DFMT_B8G8R8A8_UNORM)
5952 WARN("surface %p has an invalid format.\n", cursor_image);
5953 return WINED3DERR_INVALIDCALL;
5956 /* MSDN: Cursor must be smaller than the display mode */
5957 if (s->resource.width > This->ddraw_width
5958 || s->resource.height > This->ddraw_height)
5960 WARN("Surface %p dimensions are %ux%u, but screen dimensions are %ux%u.\n",
5961 s, s->resource.width, s->resource.height, This->ddraw_width, This->ddraw_height);
5962 return WINED3DERR_INVALIDCALL;
5965 if (!This->haveHardwareCursor) {
5966 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5968 /* Do not store the surface's pointer because the application may
5969 * release it after setting the cursor image. Windows doesn't
5970 * addref the set surface, so we can't do this either without
5971 * creating circular refcount dependencies. Copy out the gl texture
5972 * instead.
5974 This->cursorWidth = s->resource.width;
5975 This->cursorHeight = s->resource.height;
5976 if (SUCCEEDED(IWineD3DSurface_Map(cursor_image, &rect, NULL, WINED3DLOCK_READONLY)))
5978 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
5979 const struct wined3d_format *format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM);
5980 struct wined3d_context *context;
5981 char *mem, *bits = rect.pBits;
5982 GLint intfmt = format->glInternal;
5983 GLint gl_format = format->glFormat;
5984 GLint type = format->glType;
5985 INT height = This->cursorHeight;
5986 INT width = This->cursorWidth;
5987 INT bpp = format->byte_count;
5988 DWORD sampler;
5989 INT i;
5991 /* Reformat the texture memory (pitch and width can be
5992 * different) */
5993 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5994 for(i = 0; i < height; i++)
5995 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5996 IWineD3DSurface_Unmap(cursor_image);
5998 context = context_acquire(This, NULL);
6000 ENTER_GL();
6002 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6004 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6005 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6008 /* Make sure that a proper texture unit is selected */
6009 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6010 checkGLcall("glActiveTextureARB");
6011 sampler = This->rev_tex_unit_map[0];
6012 if (sampler != WINED3D_UNMAPPED_STAGE)
6014 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6016 /* Create a new cursor texture */
6017 glGenTextures(1, &This->cursorTexture);
6018 checkGLcall("glGenTextures");
6019 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6020 checkGLcall("glBindTexture");
6021 /* Copy the bitmap memory into the cursor texture */
6022 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, gl_format, type, mem);
6023 checkGLcall("glTexImage2D");
6024 HeapFree(GetProcessHeap(), 0, mem);
6026 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6028 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6029 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6032 LEAVE_GL();
6034 context_release(context);
6036 else
6038 FIXME("A cursor texture was not returned.\n");
6039 This->cursorTexture = 0;
6042 else
6044 /* Draw a hardware cursor */
6045 ICONINFO cursorInfo;
6046 HCURSOR cursor;
6047 /* Create and clear maskBits because it is not needed for
6048 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6049 * chunks. */
6050 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6051 (s->resource.width * s->resource.height / 8));
6052 IWineD3DSurface_Map(cursor_image, &lockedRect, NULL,
6053 WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY);
6054 TRACE("width: %u height: %u.\n", s->resource.width, s->resource.height);
6056 cursorInfo.fIcon = FALSE;
6057 cursorInfo.xHotspot = XHotSpot;
6058 cursorInfo.yHotspot = YHotSpot;
6059 cursorInfo.hbmMask = CreateBitmap(s->resource.width, s->resource.height, 1, 1, maskBits);
6060 cursorInfo.hbmColor = CreateBitmap(s->resource.width, s->resource.height, 1, 32, lockedRect.pBits);
6061 IWineD3DSurface_Unmap(cursor_image);
6062 /* Create our cursor and clean up. */
6063 cursor = CreateIconIndirect(&cursorInfo);
6064 SetCursor(cursor);
6065 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6066 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6067 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6068 This->hardwareCursor = cursor;
6069 HeapFree(GetProcessHeap(), 0, maskBits);
6073 This->xHotSpot = XHotSpot;
6074 This->yHotSpot = YHotSpot;
6075 return WINED3D_OK;
6078 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice *iface,
6079 int XScreenSpace, int YScreenSpace, DWORD flags)
6081 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6083 TRACE("iface %p, x %d, y %d, flags %#x.\n",
6084 iface, XScreenSpace, YScreenSpace, flags);
6086 This->xScreenSpace = XScreenSpace;
6087 This->yScreenSpace = YScreenSpace;
6090 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6091 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6092 BOOL oldVisible = This->bCursorVisible;
6093 POINT pt;
6095 TRACE("(%p) : visible(%d)\n", This, bShow);
6098 * When ShowCursor is first called it should make the cursor appear at the OS's last
6099 * known cursor position. Because of this, some applications just repetitively call
6100 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6102 GetCursorPos(&pt);
6103 This->xScreenSpace = pt.x;
6104 This->yScreenSpace = pt.y;
6106 if (This->haveHardwareCursor) {
6107 This->bCursorVisible = bShow;
6108 if (bShow)
6109 SetCursor(This->hardwareCursor);
6110 else
6111 SetCursor(NULL);
6113 else
6115 if (This->cursorTexture)
6116 This->bCursorVisible = bShow;
6119 return oldVisible;
6122 static HRESULT WINAPI evict_managed_resource(struct wined3d_resource *resource, void *data)
6124 TRACE("checking resource %p for eviction\n", resource);
6126 if (resource->pool == WINED3DPOOL_MANAGED)
6128 TRACE("Evicting %p.\n", resource);
6129 resource->resource_ops->resource_unload(resource);
6132 return S_OK;
6135 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6137 TRACE("iface %p.\n", iface);
6139 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6140 /* Invalidate stream sources, the buffer(s) may have been evicted. */
6141 IWineD3DDeviceImpl_MarkStateDirty((IWineD3DDeviceImpl *)iface, STATE_STREAMSRC);
6143 return WINED3D_OK;
6146 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6148 IWineD3DDeviceImpl *device = surface->resource.device;
6149 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6151 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6152 if (surface->flags & SFLAG_DIBSECTION)
6154 /* Release the DC */
6155 SelectObject(surface->hDC, surface->dib.holdbitmap);
6156 DeleteDC(surface->hDC);
6157 /* Release the DIB section */
6158 DeleteObject(surface->dib.DIBsection);
6159 surface->dib.bitmap_data = NULL;
6160 surface->resource.allocatedMemory = NULL;
6161 surface->flags &= ~SFLAG_DIBSECTION;
6163 surface->resource.width = pPresentationParameters->BackBufferWidth;
6164 surface->resource.height = pPresentationParameters->BackBufferHeight;
6165 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6166 || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
6168 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6169 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6170 } else {
6171 surface->pow2Width = surface->pow2Height = 1;
6172 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6173 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6176 if (surface->texture_name)
6178 struct wined3d_context *context = context_acquire(device, NULL);
6179 ENTER_GL();
6180 glDeleteTextures(1, &surface->texture_name);
6181 LEAVE_GL();
6182 context_release(context);
6183 surface->texture_name = 0;
6184 surface->flags &= ~SFLAG_CLIENT;
6186 if (surface->pow2Width != pPresentationParameters->BackBufferWidth
6187 || surface->pow2Height != pPresentationParameters->BackBufferHeight)
6189 surface->flags |= SFLAG_NONPOW2;
6191 else
6193 surface->flags &= ~SFLAG_NONPOW2;
6195 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6196 surface->resource.allocatedMemory = NULL;
6197 surface->resource.heapMemory = NULL;
6198 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6200 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6201 * to a FBO */
6202 if (!surface_init_sysmem(surface))
6204 return E_OUTOFMEMORY;
6206 return WINED3D_OK;
6209 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6211 UINT i, count;
6212 WINED3DDISPLAYMODE m;
6213 HRESULT hr;
6215 /* All Windowed modes are supported, as is leaving the current mode */
6216 if(pp->Windowed) return TRUE;
6217 if(!pp->BackBufferWidth) return TRUE;
6218 if(!pp->BackBufferHeight) return TRUE;
6220 count = wined3d_get_adapter_mode_count(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6221 for (i = 0; i < count; ++i)
6223 memset(&m, 0, sizeof(m));
6224 hr = wined3d_enum_adapter_modes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6225 if (FAILED(hr))
6226 ERR("Failed to enumerate adapter mode.\n");
6227 if (m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight)
6228 /* Mode found, it is supported. */
6229 return TRUE;
6231 /* Mode not found -> not supported */
6232 return FALSE;
6235 /* Do not call while under the GL lock. */
6236 static void delete_opengl_contexts(IWineD3DDeviceImpl *device, IWineD3DSwapChainImpl *swapchain)
6238 const struct wined3d_gl_info *gl_info;
6239 struct wined3d_context *context;
6240 IWineD3DBaseShaderImpl *shader;
6242 context = context_acquire(device, NULL);
6243 gl_info = context->gl_info;
6245 IWineD3DDevice_EnumResources((IWineD3DDevice *)device, device_unload_resource, NULL);
6246 LIST_FOR_EACH_ENTRY(shader, &device->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry)
6248 device->shader_backend->shader_destroy(shader);
6251 ENTER_GL();
6252 if (device->depth_blt_texture)
6254 glDeleteTextures(1, &device->depth_blt_texture);
6255 device->depth_blt_texture = 0;
6257 if (device->depth_blt_rb)
6259 gl_info->fbo_ops.glDeleteRenderbuffers(1, &device->depth_blt_rb);
6260 device->depth_blt_rb = 0;
6261 device->depth_blt_rb_w = 0;
6262 device->depth_blt_rb_h = 0;
6264 LEAVE_GL();
6266 device->blitter->free_private(device);
6267 device->frag_pipe->free_private(device);
6268 device->shader_backend->shader_free_private(device);
6269 destroy_dummy_textures(device, gl_info);
6271 context_release(context);
6273 while (device->numContexts)
6275 context_destroy(device, device->contexts[0]);
6277 HeapFree(GetProcessHeap(), 0, swapchain->context);
6278 swapchain->context = NULL;
6279 swapchain->num_contexts = 0;
6282 /* Do not call while under the GL lock. */
6283 static HRESULT create_primary_opengl_context(IWineD3DDeviceImpl *device, IWineD3DSwapChainImpl *swapchain)
6285 struct wined3d_context *context;
6286 HRESULT hr;
6287 IWineD3DSurfaceImpl *target;
6289 /* Recreate the primary swapchain's context */
6290 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6291 if (!swapchain->context)
6293 ERR("Failed to allocate memory for swapchain context array.\n");
6294 return E_OUTOFMEMORY;
6297 target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer;
6298 if (!(context = context_create(swapchain, target, swapchain->ds_format)))
6300 WARN("Failed to create context.\n");
6301 HeapFree(GetProcessHeap(), 0, swapchain->context);
6302 return E_FAIL;
6305 swapchain->context[0] = context;
6306 swapchain->num_contexts = 1;
6307 create_dummy_textures(device);
6308 context_release(context);
6310 hr = device->shader_backend->shader_alloc_private(device);
6311 if (FAILED(hr))
6313 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6314 goto err;
6317 hr = device->frag_pipe->alloc_private(device);
6318 if (FAILED(hr))
6320 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6321 device->shader_backend->shader_free_private(device);
6322 goto err;
6325 hr = device->blitter->alloc_private(device);
6326 if (FAILED(hr))
6328 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6329 device->frag_pipe->free_private(device);
6330 device->shader_backend->shader_free_private(device);
6331 goto err;
6334 return WINED3D_OK;
6336 err:
6337 context_acquire(device, NULL);
6338 destroy_dummy_textures(device, context->gl_info);
6339 context_release(context);
6340 context_destroy(device, context);
6341 HeapFree(GetProcessHeap(), 0, swapchain->context);
6342 swapchain->num_contexts = 0;
6343 return hr;
6346 /* Do not call while under the GL lock. */
6347 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice *iface,
6348 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
6350 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6351 IWineD3DSwapChainImpl *swapchain;
6352 HRESULT hr;
6353 BOOL DisplayModeChanged = FALSE;
6354 WINED3DDISPLAYMODE mode;
6355 TRACE("(%p)\n", This);
6357 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6358 if(FAILED(hr)) {
6359 ERR("Failed to get the first implicit swapchain\n");
6360 return hr;
6363 if(!is_display_mode_supported(This, pPresentationParameters)) {
6364 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6365 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6366 pPresentationParameters->BackBufferHeight);
6367 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6368 return WINED3DERR_INVALIDCALL;
6371 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6372 * on an existing gl context, so there's no real need for recreation.
6374 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6376 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6378 TRACE("New params:\n");
6379 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6380 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6381 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6382 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6383 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6384 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6385 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6386 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6387 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6388 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6389 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6390 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6391 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6393 /* No special treatment of these parameters. Just store them */
6394 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6395 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6396 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6397 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6399 /* What to do about these? */
6400 if (pPresentationParameters->BackBufferCount
6401 && pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount)
6402 ERR("Cannot change the back buffer count yet\n");
6404 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6405 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6406 ERR("Cannot change the back buffer format yet\n");
6409 if (pPresentationParameters->hDeviceWindow
6410 && pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow)
6411 ERR("Cannot change the device window yet\n");
6413 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil)
6415 HRESULT hrc;
6417 TRACE("Creating the depth stencil buffer\n");
6419 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6420 pPresentationParameters->BackBufferWidth,
6421 pPresentationParameters->BackBufferHeight,
6422 pPresentationParameters->AutoDepthStencilFormat,
6423 pPresentationParameters->MultiSampleType,
6424 pPresentationParameters->MultiSampleQuality,
6425 FALSE,
6426 (IWineD3DSurface **)&This->auto_depth_stencil);
6428 if (FAILED(hrc)) {
6429 ERR("Failed to create the depth stencil buffer\n");
6430 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6431 return WINED3DERR_INVALIDCALL;
6435 if (This->onscreen_depth_stencil)
6437 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
6438 This->onscreen_depth_stencil = NULL;
6441 /* Reset the depth stencil */
6442 if (pPresentationParameters->EnableAutoDepthStencil)
6443 IWineD3DDevice_SetDepthStencilSurface(iface, (IWineD3DSurface *)This->auto_depth_stencil);
6444 else
6445 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6447 TRACE("Resetting stateblock\n");
6448 wined3d_stateblock_decref(This->updateStateBlock);
6449 wined3d_stateblock_decref(This->stateBlock);
6451 delete_opengl_contexts(This, swapchain);
6453 if(pPresentationParameters->Windowed) {
6454 mode.Width = swapchain->orig_width;
6455 mode.Height = swapchain->orig_height;
6456 mode.RefreshRate = 0;
6457 mode.Format = swapchain->presentParms.BackBufferFormat;
6458 } else {
6459 mode.Width = pPresentationParameters->BackBufferWidth;
6460 mode.Height = pPresentationParameters->BackBufferHeight;
6461 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6462 mode.Format = swapchain->presentParms.BackBufferFormat;
6465 /* Should Width == 800 && Height == 0 set 800x600? */
6466 if (pPresentationParameters->BackBufferWidth && pPresentationParameters->BackBufferHeight
6467 && (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth
6468 || pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6470 UINT i;
6472 if(!pPresentationParameters->Windowed) {
6473 DisplayModeChanged = TRUE;
6475 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6476 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6478 hr = updateSurfaceDesc(swapchain->front_buffer, pPresentationParameters);
6479 if(FAILED(hr))
6481 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6482 return hr;
6485 for (i = 0; i < swapchain->presentParms.BackBufferCount; ++i)
6487 hr = updateSurfaceDesc(swapchain->back_buffers[i], pPresentationParameters);
6488 if(FAILED(hr))
6490 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6491 return hr;
6494 if (This->auto_depth_stencil)
6496 hr = updateSurfaceDesc(This->auto_depth_stencil, pPresentationParameters);
6497 if(FAILED(hr))
6499 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6500 return hr;
6505 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
6506 || DisplayModeChanged)
6508 BOOL filter = This->filter_messages;
6509 This->filter_messages = TRUE;
6511 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6513 if (!pPresentationParameters->Windowed)
6515 if (swapchain->presentParms.Windowed)
6517 HWND focus_window = This->createParms.hFocusWindow;
6518 if (!focus_window) focus_window = pPresentationParameters->hDeviceWindow;
6519 if (FAILED(hr = IWineD3DDevice_AcquireFocusWindow(iface, focus_window)))
6521 ERR("Failed to acquire focus window, hr %#x.\n", hr);
6522 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6523 return hr;
6526 /* switch from windowed to fs */
6527 IWineD3DDevice_SetupFullscreenWindow(iface, swapchain->device_window,
6528 pPresentationParameters->BackBufferWidth,
6529 pPresentationParameters->BackBufferHeight);
6531 else
6533 /* Fullscreen -> fullscreen mode change */
6534 MoveWindow(swapchain->device_window, 0, 0,
6535 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6536 TRUE);
6539 else if (!swapchain->presentParms.Windowed)
6541 /* Fullscreen -> windowed switch */
6542 IWineD3DDevice_RestoreFullscreenWindow(iface, swapchain->device_window);
6543 IWineD3DDevice_ReleaseFocusWindow(iface);
6545 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6547 This->filter_messages = filter;
6549 else if (!pPresentationParameters->Windowed)
6551 DWORD style = This->style, exStyle = This->exStyle;
6552 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6553 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6554 * Reset to clear up their mess. Guild Wars also loses the device during that.
6556 This->style = 0;
6557 This->exStyle = 0;
6558 IWineD3DDevice_SetupFullscreenWindow(iface, swapchain->device_window,
6559 pPresentationParameters->BackBufferWidth,
6560 pPresentationParameters->BackBufferHeight);
6561 This->style = style;
6562 This->exStyle = exStyle;
6565 /* Note: No parent needed for initial internal stateblock */
6566 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, &This->stateBlock);
6567 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6568 else TRACE("Created stateblock %p\n", This->stateBlock);
6569 This->updateStateBlock = This->stateBlock;
6570 wined3d_stateblock_incref(This->updateStateBlock);
6572 stateblock_init_default_state(This->stateBlock);
6574 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6576 RECT client_rect;
6577 GetClientRect(swapchain->win_handle, &client_rect);
6579 if(!swapchain->presentParms.BackBufferCount)
6581 TRACE("Single buffered rendering\n");
6582 swapchain->render_to_fbo = FALSE;
6584 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6585 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6587 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6588 swapchain->presentParms.BackBufferWidth,
6589 swapchain->presentParms.BackBufferHeight,
6590 client_rect.right, client_rect.bottom);
6591 swapchain->render_to_fbo = TRUE;
6593 else
6595 TRACE("Rendering directly to GL_BACK\n");
6596 swapchain->render_to_fbo = FALSE;
6600 hr = create_primary_opengl_context(This, swapchain);
6601 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6603 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6604 * first use
6606 return hr;
6609 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6611 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6613 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6615 return WINED3D_OK;
6619 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6620 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6621 TRACE("(%p) : pParameters %p\n", This, pParameters);
6623 *pParameters = This->createParms;
6624 return WINED3D_OK;
6627 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice *iface,
6628 UINT iSwapChain, DWORD flags, const WINED3DGAMMARAMP *pRamp)
6630 IWineD3DSwapChain *swapchain;
6632 TRACE("Relaying to swapchain\n");
6634 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK)
6636 IWineD3DSwapChain_SetGammaRamp(swapchain, flags, pRamp);
6637 IWineD3DSwapChain_Release(swapchain);
6641 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6642 IWineD3DSwapChain *swapchain;
6644 TRACE("Relaying to swapchain\n");
6646 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6647 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6648 IWineD3DSwapChain_Release(swapchain);
6652 void device_resource_add(struct IWineD3DDeviceImpl *device, struct wined3d_resource *resource)
6654 TRACE("device %p, resource %p.\n", device, resource);
6656 list_add_head(&device->resources, &resource->resource_list_entry);
6659 static void device_resource_remove(struct IWineD3DDeviceImpl *device, struct wined3d_resource *resource)
6661 TRACE("device %p, resource %p.\n", device, resource);
6663 list_remove(&resource->resource_list_entry);
6666 void device_resource_released(struct IWineD3DDeviceImpl *device, struct wined3d_resource *resource)
6668 WINED3DRESOURCETYPE type = resource->resourceType;
6669 unsigned int i;
6671 TRACE("device %p, resource %p, type %s.\n", device, resource, debug_d3dresourcetype(type));
6673 context_resource_released(device, resource, type);
6675 switch (type)
6677 case WINED3DRTYPE_SURFACE:
6679 IWineD3DSurfaceImpl *surface = surface_from_resource(resource);
6681 if (!device->d3d_initialized) break;
6683 for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i)
6685 if (device->render_targets[i] == surface)
6687 ERR("Surface %p is still in use as render target %u.\n", surface, i);
6688 device->render_targets[i] = NULL;
6692 if (device->depth_stencil == surface)
6694 ERR("Surface %p is still in use as depth/stencil buffer.\n", surface);
6695 device->depth_stencil = NULL;
6698 break;
6700 case WINED3DRTYPE_TEXTURE:
6701 case WINED3DRTYPE_CUBETEXTURE:
6702 case WINED3DRTYPE_VOLUMETEXTURE:
6703 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
6705 struct wined3d_texture *texture = wined3d_texture_from_resource(resource);
6707 if (device->stateBlock && device->stateBlock->state.textures[i] == texture)
6709 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6710 texture, device->stateBlock, i);
6711 device->stateBlock->state.textures[i] = NULL;
6714 if (device->updateStateBlock != device->stateBlock
6715 && device->updateStateBlock->state.textures[i] == texture)
6717 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6718 texture, device->updateStateBlock, i);
6719 device->updateStateBlock->state.textures[i] = NULL;
6722 break;
6724 case WINED3DRTYPE_BUFFER:
6726 struct wined3d_buffer *buffer = buffer_from_resource(resource);
6728 for (i = 0; i < MAX_STREAMS; ++i)
6730 if (device->stateBlock && device->stateBlock->state.streams[i].buffer == buffer)
6732 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6733 buffer, device->stateBlock, i);
6734 device->stateBlock->state.streams[i].buffer = NULL;
6737 if (device->updateStateBlock != device->stateBlock
6738 && device->updateStateBlock->state.streams[i].buffer == buffer)
6740 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6741 buffer, device->updateStateBlock, i);
6742 device->updateStateBlock->state.streams[i].buffer = NULL;
6747 if (device->stateBlock && device->stateBlock->state.index_buffer == buffer)
6749 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6750 buffer, device->stateBlock);
6751 device->stateBlock->state.index_buffer = NULL;
6754 if (device->updateStateBlock != device->stateBlock
6755 && device->updateStateBlock->state.index_buffer == buffer)
6757 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6758 buffer, device->updateStateBlock);
6759 device->updateStateBlock->state.index_buffer = NULL;
6762 break;
6764 default:
6765 break;
6768 /* Remove the resource from the resourceStore */
6769 device_resource_remove(device, resource);
6771 TRACE("Resource released.\n");
6774 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface,
6775 D3DCB_ENUMRESOURCES callback, void *data)
6777 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6778 struct wined3d_resource *resource, *cursor;
6780 TRACE("iface %p, callback %p, data %p.\n", iface, callback, data);
6782 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, struct wined3d_resource, resource_list_entry)
6784 TRACE("enumerating resource %p.\n", resource);
6785 if (callback(resource, data) == S_FALSE)
6787 TRACE("Canceling enumeration.\n");
6788 break;
6792 return WINED3D_OK;
6795 static HRESULT WINAPI IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice *iface, HDC dc, IWineD3DSurface **surface)
6797 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6798 struct wined3d_resource *resource;
6800 LIST_FOR_EACH_ENTRY(resource, &This->resources, struct wined3d_resource, resource_list_entry)
6802 if (resource->resourceType == WINED3DRTYPE_SURFACE)
6804 IWineD3DSurfaceImpl *s = surface_from_resource(resource);
6806 if (s->hDC == dc)
6808 TRACE("Found surface %p for dc %p.\n", s, dc);
6809 *surface = (IWineD3DSurface *)s;
6810 return WINED3D_OK;
6815 return WINED3DERR_INVALIDCALL;
6818 /**********************************************************
6819 * IWineD3DDevice VTbl follows
6820 **********************************************************/
6822 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6824 /*** IUnknown methods ***/
6825 IWineD3DDeviceImpl_QueryInterface,
6826 IWineD3DDeviceImpl_AddRef,
6827 IWineD3DDeviceImpl_Release,
6828 /*** IWineD3DDevice methods ***/
6829 /*** Creation methods**/
6830 IWineD3DDeviceImpl_CreateBuffer,
6831 IWineD3DDeviceImpl_CreateVertexBuffer,
6832 IWineD3DDeviceImpl_CreateIndexBuffer,
6833 IWineD3DDeviceImpl_CreateStateBlock,
6834 IWineD3DDeviceImpl_CreateSurface,
6835 IWineD3DDeviceImpl_CreateRendertargetView,
6836 IWineD3DDeviceImpl_CreateTexture,
6837 IWineD3DDeviceImpl_CreateVolumeTexture,
6838 IWineD3DDeviceImpl_CreateVolume,
6839 IWineD3DDeviceImpl_CreateCubeTexture,
6840 IWineD3DDeviceImpl_CreateQuery,
6841 IWineD3DDeviceImpl_CreateSwapChain,
6842 IWineD3DDeviceImpl_CreateVertexDeclaration,
6843 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6844 IWineD3DDeviceImpl_CreateVertexShader,
6845 IWineD3DDeviceImpl_CreateGeometryShader,
6846 IWineD3DDeviceImpl_CreatePixelShader,
6847 IWineD3DDeviceImpl_CreatePalette,
6848 /*** Odd functions **/
6849 IWineD3DDeviceImpl_Init3D,
6850 IWineD3DDeviceImpl_InitGDI,
6851 IWineD3DDeviceImpl_Uninit3D,
6852 IWineD3DDeviceImpl_UninitGDI,
6853 IWineD3DDeviceImpl_SetMultithreaded,
6854 IWineD3DDeviceImpl_EvictManagedResources,
6855 IWineD3DDeviceImpl_GetAvailableTextureMem,
6856 IWineD3DDeviceImpl_GetBackBuffer,
6857 IWineD3DDeviceImpl_GetCreationParameters,
6858 IWineD3DDeviceImpl_GetDeviceCaps,
6859 IWineD3DDeviceImpl_GetDirect3D,
6860 IWineD3DDeviceImpl_GetDisplayMode,
6861 IWineD3DDeviceImpl_SetDisplayMode,
6862 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6863 IWineD3DDeviceImpl_GetRasterStatus,
6864 IWineD3DDeviceImpl_GetSwapChain,
6865 IWineD3DDeviceImpl_Reset,
6866 IWineD3DDeviceImpl_SetDialogBoxMode,
6867 IWineD3DDeviceImpl_SetCursorProperties,
6868 IWineD3DDeviceImpl_SetCursorPosition,
6869 IWineD3DDeviceImpl_ShowCursor,
6870 /*** Getters and setters **/
6871 IWineD3DDeviceImpl_SetClipPlane,
6872 IWineD3DDeviceImpl_GetClipPlane,
6873 IWineD3DDeviceImpl_SetClipStatus,
6874 IWineD3DDeviceImpl_GetClipStatus,
6875 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6876 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6877 IWineD3DDeviceImpl_SetDepthStencilSurface,
6878 IWineD3DDeviceImpl_GetDepthStencilSurface,
6879 IWineD3DDeviceImpl_SetGammaRamp,
6880 IWineD3DDeviceImpl_GetGammaRamp,
6881 IWineD3DDeviceImpl_SetIndexBuffer,
6882 IWineD3DDeviceImpl_GetIndexBuffer,
6883 IWineD3DDeviceImpl_SetBaseVertexIndex,
6884 IWineD3DDeviceImpl_GetBaseVertexIndex,
6885 IWineD3DDeviceImpl_SetLight,
6886 IWineD3DDeviceImpl_GetLight,
6887 IWineD3DDeviceImpl_SetLightEnable,
6888 IWineD3DDeviceImpl_GetLightEnable,
6889 IWineD3DDeviceImpl_SetMaterial,
6890 IWineD3DDeviceImpl_GetMaterial,
6891 IWineD3DDeviceImpl_SetNPatchMode,
6892 IWineD3DDeviceImpl_GetNPatchMode,
6893 IWineD3DDeviceImpl_SetPaletteEntries,
6894 IWineD3DDeviceImpl_GetPaletteEntries,
6895 IWineD3DDeviceImpl_SetPixelShader,
6896 IWineD3DDeviceImpl_GetPixelShader,
6897 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6898 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6899 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6900 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6901 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6902 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6903 IWineD3DDeviceImpl_SetRenderState,
6904 IWineD3DDeviceImpl_GetRenderState,
6905 IWineD3DDeviceImpl_SetRenderTarget,
6906 IWineD3DDeviceImpl_GetRenderTarget,
6907 IWineD3DDeviceImpl_SetSamplerState,
6908 IWineD3DDeviceImpl_GetSamplerState,
6909 IWineD3DDeviceImpl_SetScissorRect,
6910 IWineD3DDeviceImpl_GetScissorRect,
6911 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6912 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6913 IWineD3DDeviceImpl_SetStreamSource,
6914 IWineD3DDeviceImpl_GetStreamSource,
6915 IWineD3DDeviceImpl_SetStreamSourceFreq,
6916 IWineD3DDeviceImpl_GetStreamSourceFreq,
6917 IWineD3DDeviceImpl_SetTexture,
6918 IWineD3DDeviceImpl_GetTexture,
6919 IWineD3DDeviceImpl_SetTextureStageState,
6920 IWineD3DDeviceImpl_GetTextureStageState,
6921 IWineD3DDeviceImpl_SetTransform,
6922 IWineD3DDeviceImpl_GetTransform,
6923 IWineD3DDeviceImpl_SetVertexDeclaration,
6924 IWineD3DDeviceImpl_GetVertexDeclaration,
6925 IWineD3DDeviceImpl_SetVertexShader,
6926 IWineD3DDeviceImpl_GetVertexShader,
6927 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6928 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6929 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6930 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6931 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6932 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6933 IWineD3DDeviceImpl_SetViewport,
6934 IWineD3DDeviceImpl_GetViewport,
6935 IWineD3DDeviceImpl_MultiplyTransform,
6936 IWineD3DDeviceImpl_ValidateDevice,
6937 IWineD3DDeviceImpl_ProcessVertices,
6938 /*** State block ***/
6939 IWineD3DDeviceImpl_BeginStateBlock,
6940 IWineD3DDeviceImpl_EndStateBlock,
6941 /*** Scene management ***/
6942 IWineD3DDeviceImpl_BeginScene,
6943 IWineD3DDeviceImpl_EndScene,
6944 IWineD3DDeviceImpl_Present,
6945 IWineD3DDeviceImpl_Clear,
6946 IWineD3DDeviceImpl_ClearRendertargetView,
6947 /*** Drawing ***/
6948 IWineD3DDeviceImpl_SetPrimitiveType,
6949 IWineD3DDeviceImpl_GetPrimitiveType,
6950 IWineD3DDeviceImpl_DrawPrimitive,
6951 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6952 IWineD3DDeviceImpl_DrawPrimitiveUP,
6953 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6954 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6955 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6956 IWineD3DDeviceImpl_DrawRectPatch,
6957 IWineD3DDeviceImpl_DrawTriPatch,
6958 IWineD3DDeviceImpl_DeletePatch,
6959 IWineD3DDeviceImpl_ColorFill,
6960 IWineD3DDeviceImpl_UpdateTexture,
6961 IWineD3DDeviceImpl_UpdateSurface,
6962 IWineD3DDeviceImpl_GetFrontBufferData,
6963 /*** object tracking ***/
6964 IWineD3DDeviceImpl_EnumResources,
6965 IWineD3DDeviceImpl_GetSurfaceFromDC,
6966 IWineD3DDeviceImpl_AcquireFocusWindow,
6967 IWineD3DDeviceImpl_ReleaseFocusWindow,
6968 IWineD3DDeviceImpl_SetupFullscreenWindow,
6969 IWineD3DDeviceImpl_RestoreFullscreenWindow,
6972 HRESULT device_init(IWineD3DDeviceImpl *device, struct wined3d *wined3d,
6973 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
6974 IWineD3DDeviceParent *device_parent)
6976 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
6977 const struct fragment_pipeline *fragment_pipeline;
6978 struct shader_caps shader_caps;
6979 struct fragment_caps ffp_caps;
6980 WINED3DDISPLAYMODE mode;
6981 unsigned int i;
6982 HRESULT hr;
6984 device->lpVtbl = &IWineD3DDevice_Vtbl;
6985 device->ref = 1;
6986 device->wined3d = wined3d;
6987 wined3d_incref(device->wined3d);
6988 device->adapter = wined3d->adapter_count ? adapter : NULL;
6989 device->device_parent = device_parent;
6990 list_init(&device->resources);
6991 list_init(&device->shaders);
6993 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
6995 /* Get the initial screen setup for ddraw. */
6996 hr = wined3d_get_adapter_display_mode(wined3d, adapter_idx, &mode);
6997 if (FAILED(hr))
6999 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
7000 wined3d_decref(device->wined3d);
7001 return hr;
7003 device->ddraw_width = mode.Width;
7004 device->ddraw_height = mode.Height;
7005 device->ddraw_format = mode.Format;
7007 /* Save the creation parameters. */
7008 device->createParms.AdapterOrdinal = adapter_idx;
7009 device->createParms.DeviceType = device_type;
7010 device->createParms.hFocusWindow = focus_window;
7011 device->createParms.BehaviorFlags = flags;
7013 device->devType = device_type;
7014 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
7016 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
7017 device->shader_backend = adapter->shader_backend;
7019 if (device->shader_backend)
7021 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
7022 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
7023 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
7024 device->vs_clipping = shader_caps.VSClipping;
7026 fragment_pipeline = adapter->fragment_pipe;
7027 device->frag_pipe = fragment_pipeline;
7028 if (fragment_pipeline)
7030 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
7031 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
7033 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
7034 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
7035 if (FAILED(hr))
7037 ERR("Failed to compile state table, hr %#x.\n", hr);
7038 wined3d_decref(device->wined3d);
7039 return hr;
7042 device->blitter = adapter->blitter;
7044 return WINED3D_OK;
7048 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7049 DWORD rep = This->StateTable[state].representative;
7050 struct wined3d_context *context;
7051 DWORD idx;
7052 BYTE shift;
7053 UINT i;
7055 for(i = 0; i < This->numContexts; i++) {
7056 context = This->contexts[i];
7057 if(isStateDirty(context, rep)) continue;
7059 context->dirtyArray[context->numDirtyEntries++] = rep;
7060 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
7061 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
7062 context->isStateDirty[idx] |= (1 << shift);
7066 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7068 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7069 *width = context->current_rt->pow2Width;
7070 *height = context->current_rt->pow2Height;
7073 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7075 IWineD3DSwapChainImpl *swapchain = context->swapchain;
7076 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7077 * current context's drawable, which is the size of the back buffer of the swapchain
7078 * the active context belongs to. */
7079 *width = swapchain->presentParms.BackBufferWidth;
7080 *height = swapchain->presentParms.BackBufferHeight;
7083 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window, BOOL unicode,
7084 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
7086 if (device->filter_messages)
7088 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
7089 window, message, wparam, lparam);
7090 if (unicode)
7091 return DefWindowProcW(window, message, wparam, lparam);
7092 else
7093 return DefWindowProcA(window, message, wparam, lparam);
7096 if (message == WM_DESTROY)
7098 TRACE("unregister window %p.\n", window);
7099 wined3d_unregister_window(window);
7101 if (device->focus_window == window) device->focus_window = NULL;
7102 else ERR("Window %p is not the focus window for device %p.\n", window, device);
7105 if (unicode)
7106 return CallWindowProcW(proc, window, message, wparam, lparam);
7107 else
7108 return CallWindowProcA(proc, window, message, wparam, lparam);